passagemath-schemes 10.6.38__cp314-cp314t-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.21.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.38.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.38.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.38.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.38.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.38.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,2632 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
# sage.doctest: needs sage.combinat
|
|
3
|
+
r"""
|
|
4
|
+
Algebra of motivic multiple zeta values
|
|
5
|
+
|
|
6
|
+
This file contains an implementation of the algebra of motivic
|
|
7
|
+
multiple zeta values.
|
|
8
|
+
|
|
9
|
+
The elements of this algebra are not the usual multiple zeta values as
|
|
10
|
+
real numbers defined by concrete iterated integrals, but abstract
|
|
11
|
+
symbols that satisfy all the linear relations between formal iterated
|
|
12
|
+
integrals that come from algebraic geometry (motivic
|
|
13
|
+
relations). Although this set of relations is not explicit, one can
|
|
14
|
+
test the equality as explained in the article [Brown2012]_. One can
|
|
15
|
+
map these motivic multiple zeta values to the associated real
|
|
16
|
+
numbers. Conjecturally, this period map should be injective.
|
|
17
|
+
|
|
18
|
+
The implementation follows closely all the conventions from [Brown2012]_.
|
|
19
|
+
|
|
20
|
+
As a convenient abbreviation, the elements will be called multizetas.
|
|
21
|
+
|
|
22
|
+
EXAMPLES:
|
|
23
|
+
|
|
24
|
+
One can input multizetas using compositions as arguments::
|
|
25
|
+
|
|
26
|
+
sage: Multizeta(3)
|
|
27
|
+
ζ(3)
|
|
28
|
+
sage: Multizeta(2,3,2)
|
|
29
|
+
ζ(2,3,2)
|
|
30
|
+
|
|
31
|
+
as well as linear combinations of them::
|
|
32
|
+
|
|
33
|
+
sage: Multizeta(5)+6*Multizeta(2,3)
|
|
34
|
+
6*ζ(2,3) + ζ(5)
|
|
35
|
+
|
|
36
|
+
This creates elements of the class :class:`Multizetas`.
|
|
37
|
+
|
|
38
|
+
One can multiply such elements::
|
|
39
|
+
|
|
40
|
+
sage: Multizeta(2)*Multizeta(3)
|
|
41
|
+
6*ζ(1,4) + 3*ζ(2,3) + ζ(3,2)
|
|
42
|
+
|
|
43
|
+
and their linear combinations::
|
|
44
|
+
|
|
45
|
+
sage: (Multizeta(2)+Multizeta(1,2))*Multizeta(3)
|
|
46
|
+
9*ζ(1,1,4) + 5*ζ(1,2,3) + 2*ζ(1,3,2) + 6*ζ(1,4) + 2*ζ(2,1,3) + ζ(2,2,2)
|
|
47
|
+
+ 3*ζ(2,3) + ζ(3,1,2) + ζ(3,2)
|
|
48
|
+
|
|
49
|
+
The algebra is graded by the weight, which is the sum of the arguments. One
|
|
50
|
+
can extract homogeneous components::
|
|
51
|
+
|
|
52
|
+
sage: z = Multizeta(6)+6*Multizeta(2,3)
|
|
53
|
+
sage: z.homogeneous_component(5)
|
|
54
|
+
6*ζ(2,3)
|
|
55
|
+
|
|
56
|
+
One can also use the ring of multiple zeta values as a base ring for other
|
|
57
|
+
constructions::
|
|
58
|
+
|
|
59
|
+
sage: Z = Multizeta
|
|
60
|
+
sage: M = matrix(2,2,[Z(2),Z(3),Z(4),Z(5)])
|
|
61
|
+
sage: M.det()
|
|
62
|
+
-10*ζ(1,6) - 5*ζ(2,5) - ζ(3,4) + ζ(4,3) + ζ(5,2)
|
|
63
|
+
|
|
64
|
+
.. rubric:: Auxiliary class for alternative notation
|
|
65
|
+
|
|
66
|
+
One can also use sequences of 0 and 1 as arguments::
|
|
67
|
+
|
|
68
|
+
sage: Multizeta(1,1,0)+3*Multizeta(1,0,0)
|
|
69
|
+
I(110) + 3*I(100)
|
|
70
|
+
|
|
71
|
+
This creates an element of the auxiliary class :class:`Multizetas_iterated`.
|
|
72
|
+
This class is used to represent multiple zeta values as iterated integrals.
|
|
73
|
+
|
|
74
|
+
One can also multiply such elements::
|
|
75
|
+
|
|
76
|
+
sage: Multizeta(1,0)*Multizeta(1,0)
|
|
77
|
+
4*I(1100) + 2*I(1010)
|
|
78
|
+
|
|
79
|
+
Back-and-forth conversion between the two classes can be done using
|
|
80
|
+
the methods "composition" and "iterated"::
|
|
81
|
+
|
|
82
|
+
sage: (Multizeta(2)*Multizeta(3)).iterated()
|
|
83
|
+
6*I(11000) + 3*I(10100) + I(10010)
|
|
84
|
+
|
|
85
|
+
sage: (Multizeta(1,0)*Multizeta(1,0)).composition()
|
|
86
|
+
4*ζ(1,3) + 2*ζ(2,2)
|
|
87
|
+
|
|
88
|
+
Beware that the conversion between these two classes, besides
|
|
89
|
+
exchanging the indexing by words in 0 and 1 and the indexing by
|
|
90
|
+
compositions, also involves the sign `(-1)^w` where `w` is the length
|
|
91
|
+
of the composition and the number of `1` in the associated word in 0
|
|
92
|
+
and 1. For example, one has the equality
|
|
93
|
+
|
|
94
|
+
.. MATH:: \zeta(2,3,4) = (-1)^3 I(1,0,1,0,0,1,0,0,0).
|
|
95
|
+
|
|
96
|
+
.. rubric:: Approximate period map
|
|
97
|
+
|
|
98
|
+
The period map, or rather an approximation, is also available under
|
|
99
|
+
the generic numerical approximation method::
|
|
100
|
+
|
|
101
|
+
sage: z = Multizeta(5)+6*Multizeta(2,3)
|
|
102
|
+
sage: z.n()
|
|
103
|
+
2.40979014076349
|
|
104
|
+
sage: z.n(prec=100)
|
|
105
|
+
2.4097901407634924849438423801
|
|
106
|
+
|
|
107
|
+
Behind the scene, all the numerical work is done by the PARI implementation
|
|
108
|
+
of numerical multiple zeta values.
|
|
109
|
+
|
|
110
|
+
.. rubric:: Searching for linear relations
|
|
111
|
+
|
|
112
|
+
All this can be used to find linear dependencies between any set of
|
|
113
|
+
multiple zeta values. Let us illustrate this by an example.
|
|
114
|
+
|
|
115
|
+
Let us first build our sample set::
|
|
116
|
+
|
|
117
|
+
sage: Z = Multizeta
|
|
118
|
+
sage: L = [Z(*c) for c in [(1, 1, 4), (1, 2, 3), (1, 5), (6,)]]
|
|
119
|
+
|
|
120
|
+
Then one can compute the space of relations::
|
|
121
|
+
|
|
122
|
+
sage: M = matrix([Zc.phi_as_vector() for Zc in L])
|
|
123
|
+
sage: K = M.kernel(); K
|
|
124
|
+
Vector space of degree 4 and dimension 2 over Rational Field
|
|
125
|
+
Basis matrix:
|
|
126
|
+
[ 1 0 -2 1/16]
|
|
127
|
+
[ 0 1 6 -13/48]
|
|
128
|
+
|
|
129
|
+
and check that the first relation holds::
|
|
130
|
+
|
|
131
|
+
sage: relation = L[0]-2*L[2]+1/16*L[3]; relation
|
|
132
|
+
ζ(1,1,4) - 2*ζ(1,5) + 1/16*ζ(6)
|
|
133
|
+
sage: relation.phi()
|
|
134
|
+
0
|
|
135
|
+
sage: relation.is_zero()
|
|
136
|
+
True
|
|
137
|
+
|
|
138
|
+
.. WARNING::
|
|
139
|
+
|
|
140
|
+
Because this code uses an hardcoded multiplicative basis that is
|
|
141
|
+
available up to weight 17 included, some parts will not work
|
|
142
|
+
in larger weights, in particular the test of equality.
|
|
143
|
+
|
|
144
|
+
REFERENCES:
|
|
145
|
+
|
|
146
|
+
.. [Brown2012] Francis C. S. Brown, *On the decomposition of motivic
|
|
147
|
+
multiple zeta values*, Advanced Studies in Pure Mathematics 63,
|
|
148
|
+
2012. Galois-Teichmuller Theory and Arithmetic Geometry.
|
|
149
|
+
|
|
150
|
+
.. [Brown2019] Francis C. S. Brown, *From the Deligne-Ihara conjecture to
|
|
151
|
+
multiple modular values*, :arxiv:`1904.00179`
|
|
152
|
+
|
|
153
|
+
.. [Deli2012] Pierre Deligne, *Multizêtas, d’après Francis Brown*,
|
|
154
|
+
Séminaire Bourbaki, janvier 2012. http://www.bourbaki.ens.fr/TEXTES/1048.pdf
|
|
155
|
+
|
|
156
|
+
.. [Stie2020] \S. Stieberger, *Periods and Superstring Amplitudes*,
|
|
157
|
+
Periods in Quantum Field Theory and Arithmetic, Springer Proceedings
|
|
158
|
+
in Mathematics and Statistics 314, 2020
|
|
159
|
+
"""
|
|
160
|
+
# ****************************************************************************
|
|
161
|
+
# Copyright (C) 2020 Frédéric Chapoton
|
|
162
|
+
#
|
|
163
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
164
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
165
|
+
# the License, or (at your option) any later version.
|
|
166
|
+
#
|
|
167
|
+
# https://www.gnu.org/licenses/
|
|
168
|
+
# ****************************************************************************
|
|
169
|
+
from __future__ import annotations
|
|
170
|
+
import numbers
|
|
171
|
+
from collections.abc import Iterator
|
|
172
|
+
from itertools import product
|
|
173
|
+
|
|
174
|
+
from sage.misc.fast_methods import Singleton
|
|
175
|
+
from sage.structure.richcmp import op_EQ, op_NE
|
|
176
|
+
from sage.structure.element import parent
|
|
177
|
+
from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis
|
|
178
|
+
from sage.categories.rings import Rings
|
|
179
|
+
from sage.categories.domains import Domains
|
|
180
|
+
from sage.combinat.composition import Compositions
|
|
181
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
182
|
+
from sage.combinat.integer_vector import IntegerVectors
|
|
183
|
+
from sage.combinat.partition import Partitions
|
|
184
|
+
from sage.combinat.words.finite_word import FiniteWord_class
|
|
185
|
+
from sage.combinat.words.word import Word
|
|
186
|
+
from sage.combinat.words.words import Words
|
|
187
|
+
from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 as shuffle
|
|
188
|
+
from sage.matrix.constructor import matrix
|
|
189
|
+
from sage.misc.cachefunc import cached_function, cached_method
|
|
190
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
191
|
+
from sage.misc.lazy_import import lazy_import
|
|
192
|
+
from sage.misc.misc_c import prod
|
|
193
|
+
from sage.modular.multiple_zeta_F_algebra import F_algebra
|
|
194
|
+
from sage.modules.free_module import VectorSpace
|
|
195
|
+
from sage.rings.integer_ring import ZZ
|
|
196
|
+
from sage.rings.rational_field import QQ
|
|
197
|
+
from sage.sets.positive_integers import PositiveIntegers
|
|
198
|
+
|
|
199
|
+
lazy_import('sage.libs.pari', 'pari')
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# multiplicative generators for weight <= 17
|
|
203
|
+
# using the following convention
|
|
204
|
+
# (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0]
|
|
205
|
+
# taken from the Maple implementation by F. Brown
|
|
206
|
+
B_data: list[list[tuple]] = [[], [], [(2,)], [(3,)], [], [(5,)], [],
|
|
207
|
+
[(7,)], [(3, 5)], [(9,)],
|
|
208
|
+
[(3, 7)], [(11,), (3, 3, 5)],
|
|
209
|
+
[(5, 7), (5, 3, 2, 2)],
|
|
210
|
+
[(13,), (3, 5, 5), (3, 3, 7)],
|
|
211
|
+
[(5, 9), (3, 11), (3, 3, 3, 5)],
|
|
212
|
+
[(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)],
|
|
213
|
+
[(11, 5), (13, 3), (5, 5, 3, 3),
|
|
214
|
+
(7, 3, 3, 3), (7, 5, 2, 2)],
|
|
215
|
+
[(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3),
|
|
216
|
+
(11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]]
|
|
217
|
+
|
|
218
|
+
Words10 = Words((1, 0), infinite=False)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def coproduct_iterator(paire) -> Iterator[list]:
|
|
222
|
+
"""
|
|
223
|
+
Return an iterator for terms in the coproduct.
|
|
224
|
+
|
|
225
|
+
This is an auxiliary function.
|
|
226
|
+
|
|
227
|
+
INPUT:
|
|
228
|
+
|
|
229
|
+
- ``paire`` -- a pair (list of indices, end of word)
|
|
230
|
+
|
|
231
|
+
OUTPUT: iterator for terms in the motivic coproduct
|
|
232
|
+
|
|
233
|
+
Each term is seen as a list of positions.
|
|
234
|
+
|
|
235
|
+
EXAMPLES::
|
|
236
|
+
|
|
237
|
+
sage: from sage.modular.multiple_zeta import coproduct_iterator
|
|
238
|
+
sage: list(coproduct_iterator(([0],[0,1,0,1])))
|
|
239
|
+
[[0, 1, 2, 3]]
|
|
240
|
+
sage: list(coproduct_iterator(([0],[0,1,0,1,1,0,1])))
|
|
241
|
+
[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 6], [0, 1, 5, 6], [0, 4, 5, 6], [0, 6]]
|
|
242
|
+
"""
|
|
243
|
+
head, tail = paire
|
|
244
|
+
n = len(tail)
|
|
245
|
+
if n == 1:
|
|
246
|
+
yield head
|
|
247
|
+
return
|
|
248
|
+
start_value = tail[0]
|
|
249
|
+
last_index = head[-1]
|
|
250
|
+
yield from coproduct_iterator((head + [last_index + 1], tail[1:]))
|
|
251
|
+
for step in range(4, n):
|
|
252
|
+
if step == 5:
|
|
253
|
+
continue
|
|
254
|
+
if tail[step] != start_value:
|
|
255
|
+
yield from coproduct_iterator((head + [last_index + step],
|
|
256
|
+
tail[step:]))
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def composition_to_iterated(w, reverse=False) -> tuple[int, ...]:
|
|
260
|
+
"""
|
|
261
|
+
Convert a composition to a word in 0 and 1.
|
|
262
|
+
|
|
263
|
+
By default, the chosen convention maps (2,3) to (1,0,1,0,0),
|
|
264
|
+
respecting the reading order from left to right.
|
|
265
|
+
|
|
266
|
+
The inverse map is given by :func:`iterated_to_composition`.
|
|
267
|
+
|
|
268
|
+
EXAMPLES::
|
|
269
|
+
|
|
270
|
+
sage: from sage.modular.multiple_zeta import composition_to_iterated
|
|
271
|
+
sage: composition_to_iterated((1,2))
|
|
272
|
+
(1, 1, 0)
|
|
273
|
+
sage: composition_to_iterated((3,1,2))
|
|
274
|
+
(1, 0, 0, 1, 1, 0)
|
|
275
|
+
sage: composition_to_iterated((3,1,2,4))
|
|
276
|
+
(1, 0, 0, 1, 1, 0, 1, 0, 0, 0)
|
|
277
|
+
|
|
278
|
+
TESTS::
|
|
279
|
+
|
|
280
|
+
sage: composition_to_iterated((1,2), True)
|
|
281
|
+
(1, 0, 1)
|
|
282
|
+
"""
|
|
283
|
+
word = ()
|
|
284
|
+
loop_over = reversed(w) if reverse else w
|
|
285
|
+
for letter in loop_over:
|
|
286
|
+
word += (1,) + (0,) * (letter - 1)
|
|
287
|
+
return word
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def iterated_to_composition(w, reverse=False) -> tuple[int, ...]:
|
|
291
|
+
"""
|
|
292
|
+
Convert a word in 0 and 1 to a composition.
|
|
293
|
+
|
|
294
|
+
By default, the chosen convention maps (1,0,1,0,0) to (2,3).
|
|
295
|
+
|
|
296
|
+
The inverse map is given by :func:`composition_to_iterated`.
|
|
297
|
+
|
|
298
|
+
EXAMPLES::
|
|
299
|
+
|
|
300
|
+
sage: from sage.modular.multiple_zeta import iterated_to_composition
|
|
301
|
+
sage: iterated_to_composition([1,0,1,0,0])
|
|
302
|
+
(2, 3)
|
|
303
|
+
sage: iterated_to_composition(Word([1,1,0]))
|
|
304
|
+
(1, 2)
|
|
305
|
+
sage: iterated_to_composition(Word([1,1,0,1,1,0,0]))
|
|
306
|
+
(1, 2, 1, 3)
|
|
307
|
+
|
|
308
|
+
TESTS::
|
|
309
|
+
|
|
310
|
+
sage: iterated_to_composition([1,0,1,0,0], True)
|
|
311
|
+
(3, 2)
|
|
312
|
+
"""
|
|
313
|
+
b = []
|
|
314
|
+
count = 1
|
|
315
|
+
for letter in reversed(w):
|
|
316
|
+
if letter == 0:
|
|
317
|
+
count += 1
|
|
318
|
+
else:
|
|
319
|
+
b.append(count)
|
|
320
|
+
count = 1
|
|
321
|
+
return tuple(b) if reverse else tuple(reversed(b))
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def dual_composition(c) -> tuple[int, ...]:
|
|
325
|
+
"""
|
|
326
|
+
Return the dual composition of ``c``.
|
|
327
|
+
|
|
328
|
+
This is an involution on compositions such that associated
|
|
329
|
+
multizetas are equal.
|
|
330
|
+
|
|
331
|
+
INPUT:
|
|
332
|
+
|
|
333
|
+
- ``c`` -- a composition
|
|
334
|
+
|
|
335
|
+
OUTPUT: a composition
|
|
336
|
+
|
|
337
|
+
EXAMPLES::
|
|
338
|
+
|
|
339
|
+
sage: from sage.modular.multiple_zeta import dual_composition
|
|
340
|
+
sage: dual_composition([3])
|
|
341
|
+
(1, 2)
|
|
342
|
+
sage: dual_composition(dual_composition([3,4,5])) == (3,4,5)
|
|
343
|
+
True
|
|
344
|
+
"""
|
|
345
|
+
i = composition_to_iterated(c)
|
|
346
|
+
ri = [1 - x for x in reversed(i)]
|
|
347
|
+
return iterated_to_composition(ri)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def minimize_term(w, cf):
|
|
351
|
+
"""
|
|
352
|
+
Return the largest among ``w`` and the dual word of ``w``.
|
|
353
|
+
|
|
354
|
+
INPUT:
|
|
355
|
+
|
|
356
|
+
- ``w`` -- a word in the letters 0 and 1
|
|
357
|
+
|
|
358
|
+
- ``cf`` -- a coefficient
|
|
359
|
+
|
|
360
|
+
OUTPUT:
|
|
361
|
+
|
|
362
|
+
(word, coefficient)
|
|
363
|
+
|
|
364
|
+
The chosen order is lexicographic with 1 < 0.
|
|
365
|
+
|
|
366
|
+
If the dual word is chosen, the sign of the coefficient is changed,
|
|
367
|
+
otherwise the coefficient is returned unchanged.
|
|
368
|
+
|
|
369
|
+
EXAMPLES::
|
|
370
|
+
|
|
371
|
+
sage: from sage.modular.multiple_zeta import minimize_term, Words10
|
|
372
|
+
sage: minimize_term(Words10((1,1,0)), 1)
|
|
373
|
+
(word: 100, -1)
|
|
374
|
+
sage: minimize_term(Words10((1,0,0)), 1)
|
|
375
|
+
(word: 100, 1)
|
|
376
|
+
"""
|
|
377
|
+
reverse_w = tuple(1 - t for t in reversed(w))
|
|
378
|
+
for x, y in zip(w, reverse_w):
|
|
379
|
+
if x < y:
|
|
380
|
+
return (w, cf)
|
|
381
|
+
if x > y:
|
|
382
|
+
return (Words10(reverse_w, check=False),
|
|
383
|
+
-cf if len(w) % 2 else cf)
|
|
384
|
+
return (w, cf)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# numerical values
|
|
388
|
+
|
|
389
|
+
class MultizetaValues(Singleton):
|
|
390
|
+
"""
|
|
391
|
+
Custom cache for numerical values of multiple zetas.
|
|
392
|
+
|
|
393
|
+
Computations are performed using the PARI/GP :pari:`zetamultall` (for the
|
|
394
|
+
cache) and :pari:`zetamult` (for indices/precision outside of the cache).
|
|
395
|
+
|
|
396
|
+
EXAMPLES::
|
|
397
|
+
|
|
398
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
399
|
+
sage: M = MultizetaValues()
|
|
400
|
+
|
|
401
|
+
sage: M((1,2))
|
|
402
|
+
1.202056903159594285399738161511449990764986292340...
|
|
403
|
+
sage: parent(M((2,3)))
|
|
404
|
+
Real Field with 1024 bits of precision
|
|
405
|
+
|
|
406
|
+
sage: M((2,3), prec=53)
|
|
407
|
+
0.228810397603354
|
|
408
|
+
sage: parent(M((2,3), prec=53))
|
|
409
|
+
Real Field with 53 bits of precision
|
|
410
|
+
|
|
411
|
+
sage: M((2,3), reverse=False) == M((3,2))
|
|
412
|
+
True
|
|
413
|
+
|
|
414
|
+
sage: M((2,3,4,5))
|
|
415
|
+
2.9182061974731261426525583710934944310404272413...e-6
|
|
416
|
+
sage: M((2,3,4,5), reverse=False)
|
|
417
|
+
0.0011829360522243605614404196778185433287651...
|
|
418
|
+
|
|
419
|
+
sage: parent(M((2,3,4,5)))
|
|
420
|
+
Real Field with 1024 bits of precision
|
|
421
|
+
sage: parent(M((2,3,4,5), prec=128))
|
|
422
|
+
Real Field with 128 bits of precision
|
|
423
|
+
"""
|
|
424
|
+
def __init__(self) -> None:
|
|
425
|
+
"""
|
|
426
|
+
When first called, pre-compute up to weight 8 at precision 1024.
|
|
427
|
+
|
|
428
|
+
TESTS::
|
|
429
|
+
|
|
430
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
431
|
+
sage: M = MultizetaValues()
|
|
432
|
+
"""
|
|
433
|
+
self.max_weight = 0
|
|
434
|
+
self.prec = 0
|
|
435
|
+
self.reset()
|
|
436
|
+
|
|
437
|
+
def __repr__(self) -> str:
|
|
438
|
+
r"""
|
|
439
|
+
TESTS::
|
|
440
|
+
|
|
441
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
442
|
+
sage: MultizetaValues()
|
|
443
|
+
Cached multiple zeta values at precision 1024 up to weight 8
|
|
444
|
+
"""
|
|
445
|
+
return f"Cached multiple zeta values at precision {self.prec} up to weight {self.max_weight}"
|
|
446
|
+
|
|
447
|
+
def reset(self, max_weight=8, prec=1024) -> None:
|
|
448
|
+
r"""
|
|
449
|
+
Reset the cache to its default values or to given arguments.
|
|
450
|
+
|
|
451
|
+
TESTS::
|
|
452
|
+
|
|
453
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
454
|
+
sage: M = MultizetaValues()
|
|
455
|
+
sage: M
|
|
456
|
+
Cached multiple zeta values at precision 1024 up to weight 8
|
|
457
|
+
sage: M.reset(5, 64)
|
|
458
|
+
sage: M
|
|
459
|
+
Cached multiple zeta values at precision 64 up to weight 5
|
|
460
|
+
sage: M.reset()
|
|
461
|
+
sage: M
|
|
462
|
+
Cached multiple zeta values at precision 1024 up to weight 8
|
|
463
|
+
"""
|
|
464
|
+
self.prec = int(prec)
|
|
465
|
+
self.max_weight = int(max_weight)
|
|
466
|
+
self._data = pari.zetamultall(self.max_weight, precision=self.prec)
|
|
467
|
+
|
|
468
|
+
def update(self, max_weight, prec) -> None:
|
|
469
|
+
"""
|
|
470
|
+
Compute and store more values if needed.
|
|
471
|
+
|
|
472
|
+
TESTS::
|
|
473
|
+
|
|
474
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
475
|
+
sage: M = MultizetaValues()
|
|
476
|
+
sage: M
|
|
477
|
+
Cached multiple zeta values at precision 1024 up to weight 8
|
|
478
|
+
sage: M.update(5, 64)
|
|
479
|
+
sage: M
|
|
480
|
+
Cached multiple zeta values at precision 1024 up to weight 8
|
|
481
|
+
sage: M.update(5, 2048)
|
|
482
|
+
sage: M
|
|
483
|
+
Cached multiple zeta values at precision 2048 up to weight 8
|
|
484
|
+
sage: M.reset()
|
|
485
|
+
"""
|
|
486
|
+
if self.prec < prec or self.max_weight < max_weight:
|
|
487
|
+
self.reset(max(self.max_weight, max_weight), max(self.prec, prec))
|
|
488
|
+
|
|
489
|
+
def pari_eval(self, index):
|
|
490
|
+
r"""
|
|
491
|
+
TESTS::
|
|
492
|
+
|
|
493
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
494
|
+
sage: M = MultizetaValues()
|
|
495
|
+
sage: [M.pari_eval((n,)) for n in range(2,20)]
|
|
496
|
+
[1.64493406684823, 1.20205690315959, 1.08232323371114, 1.03692775514337, ... 1.00000381729326, 1.00000190821272]
|
|
497
|
+
"""
|
|
498
|
+
weight = sum(index)
|
|
499
|
+
index = list(reversed(index))
|
|
500
|
+
if weight <= self.max_weight:
|
|
501
|
+
index = pari.zetamultconvert(index, 2)
|
|
502
|
+
return self._data[index - 1]
|
|
503
|
+
return pari.zetamult(index, precision=self.prec)
|
|
504
|
+
|
|
505
|
+
def __call__(self, index, prec=None, reverse=True):
|
|
506
|
+
r"""
|
|
507
|
+
Numerical multiple zeta value as a Sage real floating point number.
|
|
508
|
+
|
|
509
|
+
TESTS::
|
|
510
|
+
|
|
511
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
512
|
+
|
|
513
|
+
sage: V = MultizetaValues()
|
|
514
|
+
sage: V((3,2))
|
|
515
|
+
0.7115661975505724320969738060864026120925612044383392364...
|
|
516
|
+
sage: V((3,2), reverse=False)
|
|
517
|
+
0.2288103976033537597687461489416887919325093427198821602...
|
|
518
|
+
sage: V((3,2), prec=128)
|
|
519
|
+
0.71156619755057243209697380608640261209
|
|
520
|
+
sage: V((3,2), prec=128, reverse=False)
|
|
521
|
+
0.22881039760335375976874614894168879193
|
|
522
|
+
|
|
523
|
+
sage: V((1,3))
|
|
524
|
+
0.2705808084277845478790009241352919756936877379796817269...
|
|
525
|
+
sage: V((3,1), reverse=False)
|
|
526
|
+
0.2705808084277845478790009241352919756936877379796817269...
|
|
527
|
+
|
|
528
|
+
sage: V((3,1))
|
|
529
|
+
Traceback (most recent call last):
|
|
530
|
+
...
|
|
531
|
+
ValueError: divergent zeta value
|
|
532
|
+
sage: V((1,3), reverse=False)
|
|
533
|
+
Traceback (most recent call last):
|
|
534
|
+
...
|
|
535
|
+
ValueError: divergent zeta value
|
|
536
|
+
"""
|
|
537
|
+
if reverse:
|
|
538
|
+
index = list(reversed(index))
|
|
539
|
+
if index[0] == 1:
|
|
540
|
+
raise ValueError("divergent zeta value")
|
|
541
|
+
if prec is None:
|
|
542
|
+
prec = self.prec
|
|
543
|
+
weight = sum(index)
|
|
544
|
+
if weight <= self.max_weight and prec <= self.prec:
|
|
545
|
+
index = pari.zetamultconvert(index, 2)
|
|
546
|
+
value = self._data[index - 1]
|
|
547
|
+
return value.sage().n(prec=prec)
|
|
548
|
+
return pari.zetamult(index, precision=prec).sage().n(prec=prec)
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
Values = MultizetaValues()
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def extend_multiplicative_basis(B, n) -> Iterator[tuple]:
|
|
555
|
+
"""
|
|
556
|
+
Extend a multiplicative basis into a basis.
|
|
557
|
+
|
|
558
|
+
This is an iterator.
|
|
559
|
+
|
|
560
|
+
INPUT:
|
|
561
|
+
|
|
562
|
+
- ``B`` -- function mapping integer to list of tuples of compositions
|
|
563
|
+
|
|
564
|
+
- ``n`` -- integer
|
|
565
|
+
|
|
566
|
+
OUTPUT: each term is a tuple of tuples of compositions
|
|
567
|
+
|
|
568
|
+
EXAMPLES::
|
|
569
|
+
|
|
570
|
+
sage: from sage.modular.multiple_zeta import extend_multiplicative_basis
|
|
571
|
+
sage: from sage.modular.multiple_zeta import B_data
|
|
572
|
+
sage: list(extend_multiplicative_basis(B_data,5))
|
|
573
|
+
[((5,),), ((3,), (2,))]
|
|
574
|
+
sage: list(extend_multiplicative_basis(B_data,6))
|
|
575
|
+
[((3,), (3,)), ((2,), (2,), (2,))]
|
|
576
|
+
sage: list(extend_multiplicative_basis(B_data,7))
|
|
577
|
+
[((7,),), ((5,), (2,)), ((3,), (2,), (2,))]
|
|
578
|
+
"""
|
|
579
|
+
for pi in Partitions(n, min_part=2):
|
|
580
|
+
yield from product(*[B[i] for i in pi])
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
# several classes for the algebra of MZV
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def Multizeta(*args):
|
|
587
|
+
r"""
|
|
588
|
+
Common entry point for multiple zeta values.
|
|
589
|
+
|
|
590
|
+
If the argument is a sequence of 0 and 1, an element of
|
|
591
|
+
:class:`Multizetas_iterated` will be returned.
|
|
592
|
+
|
|
593
|
+
Otherwise, an element of :class:`Multizetas` will be returned.
|
|
594
|
+
|
|
595
|
+
The base ring is `\QQ`.
|
|
596
|
+
|
|
597
|
+
EXAMPLES::
|
|
598
|
+
|
|
599
|
+
sage: Z = Multizeta
|
|
600
|
+
sage: Z(1,0,1,0)
|
|
601
|
+
I(1010)
|
|
602
|
+
sage: Z(3,2,2)
|
|
603
|
+
ζ(3,2,2)
|
|
604
|
+
|
|
605
|
+
TESTS::
|
|
606
|
+
|
|
607
|
+
sage: Z(3,2,2).iterated().composition()
|
|
608
|
+
ζ(3,2,2)
|
|
609
|
+
sage: Z(1,0,1,0).composition().iterated()
|
|
610
|
+
I(1010)
|
|
611
|
+
"""
|
|
612
|
+
if 0 in args:
|
|
613
|
+
return Multizetas_iterated(QQ)(tuple(args))
|
|
614
|
+
return Multizetas(QQ)(tuple(args))
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
class Multizetas(CombinatorialFreeModule):
|
|
618
|
+
r"""
|
|
619
|
+
Main class for the algebra of multiple zeta values.
|
|
620
|
+
|
|
621
|
+
The convention is chosen so that `\zeta(1,2)` is convergent.
|
|
622
|
+
|
|
623
|
+
EXAMPLES::
|
|
624
|
+
|
|
625
|
+
sage: M = Multizetas(QQ)
|
|
626
|
+
sage: x = M((2,))
|
|
627
|
+
sage: y = M((4,3))
|
|
628
|
+
sage: x+5*y
|
|
629
|
+
ζ(2) + 5*ζ(4,3)
|
|
630
|
+
sage: x*y
|
|
631
|
+
6*ζ(1,4,4) + 8*ζ(1,5,3) + 3*ζ(2,3,4) + 4*ζ(2,4,3) + 3*ζ(3,2,4)
|
|
632
|
+
+ 2*ζ(3,3,3) + 6*ζ(4,1,4) + 3*ζ(4,2,3) + ζ(4,3,2)
|
|
633
|
+
|
|
634
|
+
TESTS::
|
|
635
|
+
|
|
636
|
+
sage: A = QQ['u']
|
|
637
|
+
sage: u = A.gen()
|
|
638
|
+
sage: M = Multizetas(A)
|
|
639
|
+
sage: (u*M((2,))+M((3,)))*M((2,))
|
|
640
|
+
4*u*ζ(1,3) + 6*ζ(1,4) + 2*u*ζ(2,2) + 3*ζ(2,3) + ζ(3,2)
|
|
641
|
+
|
|
642
|
+
Check for :issue:`30925`::
|
|
643
|
+
|
|
644
|
+
sage: M = Multizetas(QQ)
|
|
645
|
+
sage: l = [1,2,3]
|
|
646
|
+
sage: z = M(l)
|
|
647
|
+
sage: l[0] = 19
|
|
648
|
+
sage: z
|
|
649
|
+
ζ(1,2,3)
|
|
650
|
+
"""
|
|
651
|
+
def __init__(self, R) -> None:
|
|
652
|
+
"""
|
|
653
|
+
TESTS::
|
|
654
|
+
|
|
655
|
+
sage: M = Multizetas(QQ)
|
|
656
|
+
sage: TestSuite(M).run() # not tested
|
|
657
|
+
sage: M.category()
|
|
658
|
+
Category of commutative no zero divisors graded algebras
|
|
659
|
+
with basis over Rational Field
|
|
660
|
+
"""
|
|
661
|
+
if R not in Rings():
|
|
662
|
+
raise TypeError("argument R must be a ring")
|
|
663
|
+
cat = GradedAlgebrasWithBasis(R).Commutative()
|
|
664
|
+
if R in Domains():
|
|
665
|
+
cat = cat & Domains()
|
|
666
|
+
W = Words(PositiveIntegers(), infinite=False)
|
|
667
|
+
CombinatorialFreeModule.__init__(self, R, W, prefix='Z', category=cat)
|
|
668
|
+
|
|
669
|
+
def _repr_(self) -> str:
|
|
670
|
+
r"""
|
|
671
|
+
Return a string representation of the algebra.
|
|
672
|
+
|
|
673
|
+
EXAMPLES::
|
|
674
|
+
|
|
675
|
+
sage: M = Multizetas(QQ); M
|
|
676
|
+
Algebra of motivic multiple zeta values indexed by compositions over Rational Field
|
|
677
|
+
"""
|
|
678
|
+
txt = "Algebra of motivic multiple zeta values indexed by compositions over {}"
|
|
679
|
+
return txt.format(self.base_ring())
|
|
680
|
+
|
|
681
|
+
def _repr_term(self, m) -> str:
|
|
682
|
+
"""
|
|
683
|
+
Return a custom string representation for the monomials.
|
|
684
|
+
|
|
685
|
+
EXAMPLES::
|
|
686
|
+
|
|
687
|
+
sage: Multizeta(2,3) # indirect doctest
|
|
688
|
+
ζ(2,3)
|
|
689
|
+
"""
|
|
690
|
+
return "ζ(" + ','.join(str(letter) for letter in m) + ")"
|
|
691
|
+
|
|
692
|
+
def _latex_term(self, m) -> str:
|
|
693
|
+
r"""
|
|
694
|
+
Return a custom latex representation for the monomials.
|
|
695
|
+
|
|
696
|
+
EXAMPLES::
|
|
697
|
+
|
|
698
|
+
sage: latex(Multizeta(2,3) - 3/5 * Multizeta(1,1,2)) # indirect doctest
|
|
699
|
+
-\frac{3}{5} \zeta(1,1,2) + \zeta(2,3)
|
|
700
|
+
"""
|
|
701
|
+
return "\\zeta(" + ','.join(str(letter) for letter in m) + ")"
|
|
702
|
+
|
|
703
|
+
@cached_method
|
|
704
|
+
def one_basis(self):
|
|
705
|
+
r"""
|
|
706
|
+
Return the index of the unit for the algebra.
|
|
707
|
+
|
|
708
|
+
This is the empty word.
|
|
709
|
+
|
|
710
|
+
EXAMPLES::
|
|
711
|
+
|
|
712
|
+
sage: M = Multizetas(QQ)
|
|
713
|
+
sage: M.one_basis()
|
|
714
|
+
word:
|
|
715
|
+
"""
|
|
716
|
+
return self.basis().keys()([], check=False)
|
|
717
|
+
|
|
718
|
+
def some_elements(self) -> tuple:
|
|
719
|
+
r"""
|
|
720
|
+
Return some elements of the algebra.
|
|
721
|
+
|
|
722
|
+
EXAMPLES::
|
|
723
|
+
|
|
724
|
+
sage: M = Multizetas(QQ)
|
|
725
|
+
sage: M.some_elements()
|
|
726
|
+
(ζ(), ζ(2), ζ(3), ζ(4), ζ(1,2))
|
|
727
|
+
"""
|
|
728
|
+
return self([]), self([2]), self([3]), self([4]), self((1, 2))
|
|
729
|
+
|
|
730
|
+
def _an_element_(self):
|
|
731
|
+
r"""
|
|
732
|
+
Return an element of the algebra.
|
|
733
|
+
|
|
734
|
+
EXAMPLES::
|
|
735
|
+
|
|
736
|
+
sage: M = Multizetas(QQ)
|
|
737
|
+
sage: M.an_element()
|
|
738
|
+
ζ() + ζ(1,2) + 1/2*ζ(5)
|
|
739
|
+
"""
|
|
740
|
+
cf = self.base_ring().an_element()
|
|
741
|
+
return self([]) + self([1, 2]) + cf * self([5])
|
|
742
|
+
|
|
743
|
+
def product_on_basis(self, w1, w2):
|
|
744
|
+
r"""
|
|
745
|
+
Compute the product of two monomials.
|
|
746
|
+
|
|
747
|
+
This is done by converting to iterated integrals and
|
|
748
|
+
using the shuffle product.
|
|
749
|
+
|
|
750
|
+
INPUT:
|
|
751
|
+
|
|
752
|
+
- ``w1``, ``w2`` -- compositions as words
|
|
753
|
+
|
|
754
|
+
EXAMPLES::
|
|
755
|
+
|
|
756
|
+
sage: M = Multizetas(QQ)
|
|
757
|
+
sage: W = M.basis().keys()
|
|
758
|
+
sage: M.product_on_basis(W([2]),W([2]))
|
|
759
|
+
4*ζ(1,3) + 2*ζ(2,2)
|
|
760
|
+
sage: x = M((2,))
|
|
761
|
+
sage: x*x
|
|
762
|
+
4*ζ(1,3) + 2*ζ(2,2)
|
|
763
|
+
"""
|
|
764
|
+
if not w1:
|
|
765
|
+
return self._monomial(w2)
|
|
766
|
+
if not w2:
|
|
767
|
+
return self._monomial(w1)
|
|
768
|
+
p1 = self.iterated_on_basis(w1)
|
|
769
|
+
p2 = self.iterated_on_basis(w2)
|
|
770
|
+
p1p2 = p1 * p2
|
|
771
|
+
MZV_it = p1p2.parent()
|
|
772
|
+
return MZV_it.composition(p1p2)
|
|
773
|
+
|
|
774
|
+
def half_product(self, w1, w2):
|
|
775
|
+
r"""
|
|
776
|
+
Compute half of the product of two elements.
|
|
777
|
+
|
|
778
|
+
This comes from half of the shuffle product.
|
|
779
|
+
|
|
780
|
+
.. WARNING:: This is not a motivic operation.
|
|
781
|
+
|
|
782
|
+
INPUT:
|
|
783
|
+
|
|
784
|
+
- ``w1``, ``w2`` -- elements
|
|
785
|
+
|
|
786
|
+
EXAMPLES::
|
|
787
|
+
|
|
788
|
+
sage: M = Multizetas(QQ)
|
|
789
|
+
sage: M.half_product(M([2]),M([2]))
|
|
790
|
+
2*ζ(1,3) + ζ(2,2)
|
|
791
|
+
|
|
792
|
+
TESTS:
|
|
793
|
+
|
|
794
|
+
sage: M.half_product(M.one(), M([2]))
|
|
795
|
+
Traceback (most recent call last):
|
|
796
|
+
...
|
|
797
|
+
ValueError: not defined on the unit
|
|
798
|
+
"""
|
|
799
|
+
empty = self.one_basis()
|
|
800
|
+
if w1.coefficient(empty) or w2.coefficient(empty):
|
|
801
|
+
raise ValueError('not defined on the unit')
|
|
802
|
+
p1 = self.iterated(w1)
|
|
803
|
+
p2 = self.iterated(w2)
|
|
804
|
+
MZV_it = p1.parent()
|
|
805
|
+
p1p2 = MZV_it.half_product(p1, p2)
|
|
806
|
+
return MZV_it.composition(p1p2)
|
|
807
|
+
|
|
808
|
+
@lazy_attribute
|
|
809
|
+
def iterated(self):
|
|
810
|
+
"""
|
|
811
|
+
Convert to the algebra of iterated integrals.
|
|
812
|
+
|
|
813
|
+
This is also available as a method of elements.
|
|
814
|
+
|
|
815
|
+
EXAMPLES::
|
|
816
|
+
|
|
817
|
+
sage: M = Multizetas(QQ)
|
|
818
|
+
sage: x = M((3,2))
|
|
819
|
+
sage: M.iterated(3*x)
|
|
820
|
+
3*I(10010)
|
|
821
|
+
sage: x = M((2,3,2))
|
|
822
|
+
sage: M.iterated(4*x)
|
|
823
|
+
-4*I(1010010)
|
|
824
|
+
"""
|
|
825
|
+
cod = Multizetas_iterated(self.base_ring())
|
|
826
|
+
return self.module_morphism(self.iterated_on_basis, codomain=cod)
|
|
827
|
+
|
|
828
|
+
def iterated_on_basis(self, w):
|
|
829
|
+
"""
|
|
830
|
+
Convert to the algebra of iterated integrals.
|
|
831
|
+
|
|
832
|
+
Beware that this conversion involves signs in our chosen convention.
|
|
833
|
+
|
|
834
|
+
INPUT:
|
|
835
|
+
|
|
836
|
+
- ``w`` -- a word
|
|
837
|
+
|
|
838
|
+
EXAMPLES::
|
|
839
|
+
|
|
840
|
+
sage: M = Multizetas(QQ)
|
|
841
|
+
sage: x = M.basis().keys()((3,2))
|
|
842
|
+
sage: M.iterated_on_basis(x)
|
|
843
|
+
I(10010)
|
|
844
|
+
sage: x = M.basis().keys()((2,3,2))
|
|
845
|
+
sage: M.iterated_on_basis(x)
|
|
846
|
+
-I(1010010)
|
|
847
|
+
"""
|
|
848
|
+
codomain = Multizetas_iterated(self.base_ring())
|
|
849
|
+
image = codomain(composition_to_iterated(w))
|
|
850
|
+
return -image if len(w) % 2 else image
|
|
851
|
+
|
|
852
|
+
def degree_on_basis(self, w):
|
|
853
|
+
"""
|
|
854
|
+
Return the degree of the monomial ``w``.
|
|
855
|
+
|
|
856
|
+
This is the sum of terms in ``w``.
|
|
857
|
+
|
|
858
|
+
INPUT:
|
|
859
|
+
|
|
860
|
+
- ``w`` -- a composition
|
|
861
|
+
|
|
862
|
+
EXAMPLES::
|
|
863
|
+
|
|
864
|
+
sage: M = Multizetas(QQ)
|
|
865
|
+
sage: x = (2,3)
|
|
866
|
+
sage: M.degree_on_basis(x) # indirect doctest
|
|
867
|
+
5
|
|
868
|
+
"""
|
|
869
|
+
return ZZ(sum(w))
|
|
870
|
+
|
|
871
|
+
@lazy_attribute
|
|
872
|
+
def phi(self):
|
|
873
|
+
r"""
|
|
874
|
+
Return the morphism ``phi``.
|
|
875
|
+
|
|
876
|
+
This sends multiple zeta values to the auxiliary F-algebra,
|
|
877
|
+
which is a shuffle algebra in odd generators `f_3,f_5,f_7,\dots`
|
|
878
|
+
over the polynomial ring in one variable `f_2`.
|
|
879
|
+
|
|
880
|
+
This is a ring isomorphism, that depends on the choice of a
|
|
881
|
+
multiplicative basis for the ring of motivic multiple zeta
|
|
882
|
+
values. Here we use one specific hardcoded basis.
|
|
883
|
+
|
|
884
|
+
For the precise definition of ``phi`` by induction, see [Brown2012]_.
|
|
885
|
+
|
|
886
|
+
EXAMPLES::
|
|
887
|
+
|
|
888
|
+
sage: M = Multizetas(QQ)
|
|
889
|
+
sage: m = Multizeta(2,2) + 2*Multizeta(1,3); m
|
|
890
|
+
2*ζ(1,3) + ζ(2,2)
|
|
891
|
+
sage: M.phi(m)
|
|
892
|
+
1/2*f2^2
|
|
893
|
+
|
|
894
|
+
sage: Z = Multizeta
|
|
895
|
+
sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)]
|
|
896
|
+
sage: [M.phi(b) for b in B5]
|
|
897
|
+
[-1/2*f5 + f2*f3, 1/2*f5]
|
|
898
|
+
"""
|
|
899
|
+
M_it = Multizetas_iterated(self.base_ring())
|
|
900
|
+
return M_it.phi * self.iterated
|
|
901
|
+
|
|
902
|
+
def _element_constructor_(self, x):
|
|
903
|
+
r"""
|
|
904
|
+
Convert ``x`` into ``self``.
|
|
905
|
+
|
|
906
|
+
INPUT:
|
|
907
|
+
|
|
908
|
+
- ``x`` -- either a list, tuple, word or a multiple zeta value
|
|
909
|
+
|
|
910
|
+
EXAMPLES::
|
|
911
|
+
|
|
912
|
+
sage: M = Multizetas(QQ)
|
|
913
|
+
sage: M(Word((2,3)))
|
|
914
|
+
ζ(2,3)
|
|
915
|
+
sage: M(Word([2,3]))
|
|
916
|
+
ζ(2,3)
|
|
917
|
+
sage: x = M((2,3)); x
|
|
918
|
+
ζ(2,3)
|
|
919
|
+
sage: M(x) == x
|
|
920
|
+
True
|
|
921
|
+
|
|
922
|
+
sage: M() == M(0) == M.zero()
|
|
923
|
+
True
|
|
924
|
+
sage: M([]) == M(1) == M.one()
|
|
925
|
+
True
|
|
926
|
+
|
|
927
|
+
sage: M('heyho')
|
|
928
|
+
Traceback (most recent call last):
|
|
929
|
+
...
|
|
930
|
+
TypeError: invalid input for building a multizeta value
|
|
931
|
+
"""
|
|
932
|
+
if isinstance(x, (FiniteWord_class, tuple, list)):
|
|
933
|
+
if not all(isinstance(letter, numbers.Integral) for letter in x):
|
|
934
|
+
raise ValueError('invalid input for building a multizeta value')
|
|
935
|
+
if x and x[-1] == 1:
|
|
936
|
+
raise ValueError('divergent zeta value')
|
|
937
|
+
W = self.basis().keys()
|
|
938
|
+
if isinstance(x, list):
|
|
939
|
+
x = tuple(x)
|
|
940
|
+
return self._monomial(W(x, check=False))
|
|
941
|
+
if isinstance(parent(x), Multizetas_iterated):
|
|
942
|
+
return x.composition()
|
|
943
|
+
raise TypeError('invalid input for building a multizeta value')
|
|
944
|
+
|
|
945
|
+
def algebra_generators(self, n) -> list:
|
|
946
|
+
"""
|
|
947
|
+
Return a set of multiplicative generators in weight ``n``.
|
|
948
|
+
|
|
949
|
+
This is obtained from hardcoded data, available only up to weight 17.
|
|
950
|
+
|
|
951
|
+
INPUT:
|
|
952
|
+
|
|
953
|
+
- ``n`` -- integer
|
|
954
|
+
|
|
955
|
+
EXAMPLES::
|
|
956
|
+
|
|
957
|
+
sage: M = Multizetas(QQ)
|
|
958
|
+
sage: M.algebra_generators(5)
|
|
959
|
+
[ζ(5)]
|
|
960
|
+
sage: M.algebra_generators(8)
|
|
961
|
+
[ζ(3,5)]
|
|
962
|
+
"""
|
|
963
|
+
W = self.basis().keys()
|
|
964
|
+
return [self._monomial(W(b, check=False)) for b in B_data[n]]
|
|
965
|
+
|
|
966
|
+
def basis_data(self, basering, n) -> Iterator:
|
|
967
|
+
"""
|
|
968
|
+
Return an iterator for a basis in weight ``n``.
|
|
969
|
+
|
|
970
|
+
This is obtained from hardcoded data, available only up to weight 17.
|
|
971
|
+
|
|
972
|
+
INPUT:
|
|
973
|
+
|
|
974
|
+
- ``n`` -- integer
|
|
975
|
+
|
|
976
|
+
EXAMPLES::
|
|
977
|
+
|
|
978
|
+
sage: M = Multizetas(QQ)
|
|
979
|
+
sage: list(M.basis_data(QQ, 4))
|
|
980
|
+
[4*ζ(1,3) + 2*ζ(2,2)]
|
|
981
|
+
"""
|
|
982
|
+
basis_MZV = extend_multiplicative_basis(B_data, n)
|
|
983
|
+
W = self.basis().keys()
|
|
984
|
+
return (prod(self._monomial(W(compo, check=False))
|
|
985
|
+
for compo in term) for term in basis_MZV)
|
|
986
|
+
|
|
987
|
+
def basis_brown(self, n) -> list:
|
|
988
|
+
r"""
|
|
989
|
+
Return a basis of the algebra of multiple zeta values in weight ``n``.
|
|
990
|
+
|
|
991
|
+
It was proved by Francis Brown that this is a basis of motivic
|
|
992
|
+
multiple zeta values.
|
|
993
|
+
|
|
994
|
+
This is made of all `\zeta(n_1, ..., n_r)` with parts in {2,3}.
|
|
995
|
+
|
|
996
|
+
INPUT:
|
|
997
|
+
|
|
998
|
+
- ``n`` -- integer
|
|
999
|
+
|
|
1000
|
+
EXAMPLES::
|
|
1001
|
+
|
|
1002
|
+
sage: M = Multizetas(QQ)
|
|
1003
|
+
sage: M.basis_brown(3)
|
|
1004
|
+
[ζ(3)]
|
|
1005
|
+
sage: M.basis_brown(4)
|
|
1006
|
+
[ζ(2,2)]
|
|
1007
|
+
sage: M.basis_brown(5)
|
|
1008
|
+
[ζ(3,2), ζ(2,3)]
|
|
1009
|
+
sage: M.basis_brown(6)
|
|
1010
|
+
[ζ(3,3), ζ(2,2,2)]
|
|
1011
|
+
"""
|
|
1012
|
+
W = self.basis().keys()
|
|
1013
|
+
return [self._monomial(W(tuple(c), check=False))
|
|
1014
|
+
for c in IntegerVectors(n, min_part=2, max_part=3)]
|
|
1015
|
+
|
|
1016
|
+
@cached_method
|
|
1017
|
+
def basis_filtration(self, d, reverse=False):
|
|
1018
|
+
r"""
|
|
1019
|
+
Return a module basis of the homogeneous components of weight ``d`` compatible with
|
|
1020
|
+
the length filtration.
|
|
1021
|
+
|
|
1022
|
+
INPUT:
|
|
1023
|
+
|
|
1024
|
+
- ``d`` -- nonnegative integer; the weight
|
|
1025
|
+
|
|
1026
|
+
- ``reverse`` -- boolean (default: ``False``); change the ordering of compositions
|
|
1027
|
+
|
|
1028
|
+
EXAMPLES::
|
|
1029
|
+
|
|
1030
|
+
sage: M = Multizetas(QQ)
|
|
1031
|
+
|
|
1032
|
+
sage: M.basis_filtration(5)
|
|
1033
|
+
[ζ(5), ζ(1,4)]
|
|
1034
|
+
sage: M.basis_filtration(6)
|
|
1035
|
+
[ζ(6), ζ(1,5)]
|
|
1036
|
+
sage: M.basis_filtration(8)
|
|
1037
|
+
[ζ(8), ζ(1,7), ζ(2,6), ζ(1,1,6)]
|
|
1038
|
+
sage: M.basis_filtration(8, reverse=True)
|
|
1039
|
+
[ζ(8), ζ(6,2), ζ(5,3), ζ(5,1,2)]
|
|
1040
|
+
|
|
1041
|
+
sage: M.basis_filtration(0)
|
|
1042
|
+
[ζ()]
|
|
1043
|
+
sage: M.basis_filtration(1)
|
|
1044
|
+
[]
|
|
1045
|
+
"""
|
|
1046
|
+
if d < 0:
|
|
1047
|
+
raise ValueError('d must be a nonnegative integer')
|
|
1048
|
+
if d == 0:
|
|
1049
|
+
return [self([])]
|
|
1050
|
+
if d == 1:
|
|
1051
|
+
return []
|
|
1052
|
+
|
|
1053
|
+
W = self.basis().keys()
|
|
1054
|
+
Values.reset(max_weight=d)
|
|
1055
|
+
dim = len(self((d,)).phi_as_vector())
|
|
1056
|
+
V = VectorSpace(QQ, dim)
|
|
1057
|
+
U = V.subspace([])
|
|
1058
|
+
basis: list = []
|
|
1059
|
+
k = 1
|
|
1060
|
+
while len(basis) < dim:
|
|
1061
|
+
for c in Compositions(d, length=k):
|
|
1062
|
+
if reverse:
|
|
1063
|
+
if c[-1] == 1:
|
|
1064
|
+
continue
|
|
1065
|
+
c = tuple(c)
|
|
1066
|
+
else:
|
|
1067
|
+
if c[0] == 1:
|
|
1068
|
+
continue
|
|
1069
|
+
c = c[::-1]
|
|
1070
|
+
mon_c = self._monomial(W(c, check=False))
|
|
1071
|
+
v = mon_c.phi_as_vector()
|
|
1072
|
+
if v in U:
|
|
1073
|
+
continue
|
|
1074
|
+
U = V.subspace(U.basis() + [v])
|
|
1075
|
+
basis.append(mon_c)
|
|
1076
|
+
k += 1
|
|
1077
|
+
return basis
|
|
1078
|
+
|
|
1079
|
+
class Element(CombinatorialFreeModule.Element):
|
|
1080
|
+
def iterated(self):
|
|
1081
|
+
"""
|
|
1082
|
+
Convert to the algebra of iterated integrals.
|
|
1083
|
+
|
|
1084
|
+
Beware that this conversion involves signs.
|
|
1085
|
+
|
|
1086
|
+
EXAMPLES::
|
|
1087
|
+
|
|
1088
|
+
sage: M = Multizetas(QQ)
|
|
1089
|
+
sage: x = M((2,3,4))
|
|
1090
|
+
sage: x.iterated()
|
|
1091
|
+
-I(101001000)
|
|
1092
|
+
"""
|
|
1093
|
+
return self.parent().iterated(self)
|
|
1094
|
+
|
|
1095
|
+
def single_valued(self):
|
|
1096
|
+
r"""
|
|
1097
|
+
Return the single-valued version of ``self``.
|
|
1098
|
+
|
|
1099
|
+
This is the projection map onto the sub-algebra of
|
|
1100
|
+
single-valued motivic multiple zeta values, as defined by
|
|
1101
|
+
F. Brown in [Bro2013]_.
|
|
1102
|
+
|
|
1103
|
+
This morphism of algebras sends in particular `\zeta(2)` to `0`.
|
|
1104
|
+
|
|
1105
|
+
EXAMPLES::
|
|
1106
|
+
|
|
1107
|
+
sage: M = Multizetas(QQ)
|
|
1108
|
+
sage: x = M((2,))
|
|
1109
|
+
sage: x.single_valued()
|
|
1110
|
+
0
|
|
1111
|
+
sage: x = M((3,))
|
|
1112
|
+
sage: x.single_valued()
|
|
1113
|
+
2*ζ(3)
|
|
1114
|
+
sage: x = M((5,))
|
|
1115
|
+
sage: x.single_valued()
|
|
1116
|
+
2*ζ(5)
|
|
1117
|
+
sage: x = M((2,3))
|
|
1118
|
+
sage: x.single_valued()
|
|
1119
|
+
-11*ζ(5)
|
|
1120
|
+
|
|
1121
|
+
sage: Z = Multizeta
|
|
1122
|
+
sage: Z(3,5).single_valued() == -10*Z(3)*Z(5)
|
|
1123
|
+
True
|
|
1124
|
+
sage: Z(5,3).single_valued() == 14*Z(3)*Z(5)
|
|
1125
|
+
True
|
|
1126
|
+
"""
|
|
1127
|
+
return rho_inverse(self.phi().single_valued())
|
|
1128
|
+
|
|
1129
|
+
def simplify(self):
|
|
1130
|
+
"""
|
|
1131
|
+
Gather terms using the duality relations.
|
|
1132
|
+
|
|
1133
|
+
This can help to lower the number of monomials.
|
|
1134
|
+
|
|
1135
|
+
EXAMPLES::
|
|
1136
|
+
|
|
1137
|
+
sage: M = Multizetas(QQ)
|
|
1138
|
+
sage: z = 3*M((3,)) + 5*M((1,2))
|
|
1139
|
+
sage: z.simplify()
|
|
1140
|
+
8*ζ(3)
|
|
1141
|
+
"""
|
|
1142
|
+
return self.iterated().simplify().composition()
|
|
1143
|
+
|
|
1144
|
+
def simplify_full(self, basis=None):
|
|
1145
|
+
r"""
|
|
1146
|
+
Rewrite the term in a given basis.
|
|
1147
|
+
|
|
1148
|
+
INPUT:
|
|
1149
|
+
|
|
1150
|
+
- ``basis`` -- either ``None`` (default) or a function such that
|
|
1151
|
+
``basis(d)`` is a basis of the weight ``d`` multiple zeta values.
|
|
1152
|
+
If ``None``, the Hoffman basis is used.
|
|
1153
|
+
|
|
1154
|
+
EXAMPLES::
|
|
1155
|
+
|
|
1156
|
+
sage: z = Multizeta(5) + Multizeta(1,4) + Multizeta(3,2) - 5 * Multizeta(2,3)
|
|
1157
|
+
sage: z.simplify_full()
|
|
1158
|
+
-22/5*ζ(2,3) + 12/5*ζ(3,2)
|
|
1159
|
+
sage: z.simplify_full(basis=z.parent().basis_filtration)
|
|
1160
|
+
18*ζ(1,4) - ζ(5)
|
|
1161
|
+
|
|
1162
|
+
sage: z == z.simplify_full() == z.simplify_full(basis=z.parent().basis_filtration)
|
|
1163
|
+
True
|
|
1164
|
+
|
|
1165
|
+
Be careful, that this does not optimize the number of terms::
|
|
1166
|
+
|
|
1167
|
+
sage: Multizeta(7).simplify_full()
|
|
1168
|
+
352/151*ζ(2,2,3) + 672/151*ζ(2,3,2) + 528/151*ζ(3,2,2)
|
|
1169
|
+
|
|
1170
|
+
TESTS::
|
|
1171
|
+
|
|
1172
|
+
sage: Multizetas(QQ).one().simplify_full()
|
|
1173
|
+
ζ()
|
|
1174
|
+
"""
|
|
1175
|
+
if basis is None:
|
|
1176
|
+
basis = self.parent().basis_brown
|
|
1177
|
+
support = {sum(d) for d in self.support()}
|
|
1178
|
+
result = self.parent().zero()
|
|
1179
|
+
for d in sorted(support):
|
|
1180
|
+
h = self.homogeneous_component(d)
|
|
1181
|
+
v = h.phi_as_vector()
|
|
1182
|
+
if v:
|
|
1183
|
+
Bd = basis(d)
|
|
1184
|
+
P = matrix(QQ, [z.phi_as_vector() for z in Bd])
|
|
1185
|
+
result += sum(x * z for x, z in zip(P.solve_left(v), Bd))
|
|
1186
|
+
return result
|
|
1187
|
+
|
|
1188
|
+
def __bool__(self) -> bool:
|
|
1189
|
+
r"""
|
|
1190
|
+
EXAMPLES::
|
|
1191
|
+
|
|
1192
|
+
sage: bool(Multizeta(2))
|
|
1193
|
+
True
|
|
1194
|
+
sage: bool(3*Multizeta(4) - 4*Multizeta(2,2))
|
|
1195
|
+
False
|
|
1196
|
+
"""
|
|
1197
|
+
return bool(self.iterated())
|
|
1198
|
+
|
|
1199
|
+
def is_zero(self) -> bool:
|
|
1200
|
+
r"""
|
|
1201
|
+
Return whether this element is zero.
|
|
1202
|
+
|
|
1203
|
+
EXAMPLES::
|
|
1204
|
+
|
|
1205
|
+
sage: M = Multizeta
|
|
1206
|
+
|
|
1207
|
+
sage: (4*M(2,3) + 6*M(3,2) - 5*M(5)).is_zero()
|
|
1208
|
+
True
|
|
1209
|
+
sage: (3*M(4) - 4*M(2,2)).is_zero()
|
|
1210
|
+
True
|
|
1211
|
+
sage: (4*M(2,3) + 6*M(3,2) + 3*M(4) - 5*M(5) - 4*M(2,2)).is_zero()
|
|
1212
|
+
True
|
|
1213
|
+
|
|
1214
|
+
sage: (4*M(2,3) + 6*M(3,2) - 4*M(5)).is_zero()
|
|
1215
|
+
False
|
|
1216
|
+
sage: (M(4) - M(2,2)).is_zero()
|
|
1217
|
+
False
|
|
1218
|
+
sage: (4*M(2,3) + 6*M(3,2) + 3*M(4) - 4*M(5) - 4*M(2,2)).is_zero()
|
|
1219
|
+
False
|
|
1220
|
+
"""
|
|
1221
|
+
return not self
|
|
1222
|
+
|
|
1223
|
+
def _richcmp_(self, other, op) -> bool:
|
|
1224
|
+
"""
|
|
1225
|
+
Comparison.
|
|
1226
|
+
|
|
1227
|
+
This means equality as motivic multiple zeta value, computed
|
|
1228
|
+
using the morphism ``phi``.
|
|
1229
|
+
|
|
1230
|
+
EXAMPLES::
|
|
1231
|
+
|
|
1232
|
+
sage: M = Multizeta
|
|
1233
|
+
sage: 4*M(1,3) == M(4)
|
|
1234
|
+
True
|
|
1235
|
+
sage: our_pi2 = 6*M(2)
|
|
1236
|
+
sage: Multizeta(2,2,2) == our_pi2**3 / 7.factorial()
|
|
1237
|
+
True
|
|
1238
|
+
|
|
1239
|
+
sage: M(2,2,2) != M(6)
|
|
1240
|
+
True
|
|
1241
|
+
|
|
1242
|
+
sage: M(4) == M(66) + M(33,33)
|
|
1243
|
+
False
|
|
1244
|
+
sage: M(33) + M(22,11) == M(3)
|
|
1245
|
+
False
|
|
1246
|
+
sage: M(5) == 1
|
|
1247
|
+
False
|
|
1248
|
+
sage: M() == 1
|
|
1249
|
+
True
|
|
1250
|
+
sage: (0*M()) == 0
|
|
1251
|
+
True
|
|
1252
|
+
"""
|
|
1253
|
+
if op not in [op_EQ, op_NE]:
|
|
1254
|
+
raise TypeError('invalid comparison for multizetas')
|
|
1255
|
+
return self.iterated()._richcmp_(other.iterated(), op)
|
|
1256
|
+
|
|
1257
|
+
def __hash__(self) -> int:
|
|
1258
|
+
"""
|
|
1259
|
+
Return the hash of ``self``.
|
|
1260
|
+
|
|
1261
|
+
EXAMPLES::
|
|
1262
|
+
|
|
1263
|
+
sage: M = Multizeta
|
|
1264
|
+
sage: hash(M(1,2)) != hash(M(6))
|
|
1265
|
+
True
|
|
1266
|
+
"""
|
|
1267
|
+
return hash(self.iterated().phi())
|
|
1268
|
+
|
|
1269
|
+
def phi(self):
|
|
1270
|
+
"""
|
|
1271
|
+
Return the image of ``self`` by the morphism ``phi``.
|
|
1272
|
+
|
|
1273
|
+
This sends multiple zeta values to the auxiliary F-algebra.
|
|
1274
|
+
|
|
1275
|
+
EXAMPLES::
|
|
1276
|
+
|
|
1277
|
+
sage: M = Multizetas(QQ)
|
|
1278
|
+
sage: M((1,2)).phi()
|
|
1279
|
+
f3
|
|
1280
|
+
|
|
1281
|
+
TESTS::
|
|
1282
|
+
|
|
1283
|
+
sage: A = QQ['u']
|
|
1284
|
+
sage: u = A.gen()
|
|
1285
|
+
sage: M = Multizetas(A)
|
|
1286
|
+
sage: tst = u*M((1,2))+M((3,))
|
|
1287
|
+
sage: tst.phi()
|
|
1288
|
+
(u+1)*f3
|
|
1289
|
+
"""
|
|
1290
|
+
return self.parent().phi(self)
|
|
1291
|
+
|
|
1292
|
+
def phi_as_vector(self):
|
|
1293
|
+
"""
|
|
1294
|
+
Return the image of ``self`` by the morphism ``phi`` as a vector.
|
|
1295
|
+
|
|
1296
|
+
The morphism ``phi`` sends multiple zeta values to the algebra
|
|
1297
|
+
:func:`F_ring`. Then the image is expressed as a vector in
|
|
1298
|
+
a fixed basis of one graded component of this algebra.
|
|
1299
|
+
|
|
1300
|
+
This is only defined for homogeneous elements.
|
|
1301
|
+
|
|
1302
|
+
EXAMPLES::
|
|
1303
|
+
|
|
1304
|
+
sage: M = Multizetas(QQ)
|
|
1305
|
+
sage: M((3,2)).phi_as_vector()
|
|
1306
|
+
(9/2, -2)
|
|
1307
|
+
sage: M(0).phi_as_vector()
|
|
1308
|
+
()
|
|
1309
|
+
|
|
1310
|
+
TESTS::
|
|
1311
|
+
|
|
1312
|
+
sage: (M((4,))+M((1,2))).phi_as_vector()
|
|
1313
|
+
Traceback (most recent call last):
|
|
1314
|
+
...
|
|
1315
|
+
ValueError: only defined for homogeneous elements
|
|
1316
|
+
"""
|
|
1317
|
+
if not self.is_homogeneous():
|
|
1318
|
+
raise ValueError('only defined for homogeneous elements')
|
|
1319
|
+
return self.parent().phi(self).homogeneous_to_vector()
|
|
1320
|
+
|
|
1321
|
+
def _numerical_approx_pari(self):
|
|
1322
|
+
r"""
|
|
1323
|
+
The numerical values of individual multiple zeta are obtained via
|
|
1324
|
+
the class :class:`MultizetaValues` that performs some caching.
|
|
1325
|
+
|
|
1326
|
+
TESTS::
|
|
1327
|
+
|
|
1328
|
+
sage: M = Multizetas(QQ)
|
|
1329
|
+
sage: a = M((3,2)) - 2*M((7,))
|
|
1330
|
+
sage: a._numerical_approx_pari()
|
|
1331
|
+
-1.30513235721327
|
|
1332
|
+
sage: type(a._numerical_approx_pari())
|
|
1333
|
+
<class 'cypari2.gen.Gen'>
|
|
1334
|
+
"""
|
|
1335
|
+
return sum(cf * Values.pari_eval(tuple(w)) for w, cf in self.monomial_coefficients().items())
|
|
1336
|
+
|
|
1337
|
+
def numerical_approx(self, prec=None, digits=None, algorithm=None):
|
|
1338
|
+
"""
|
|
1339
|
+
Return a numerical value for this element.
|
|
1340
|
+
|
|
1341
|
+
EXAMPLES::
|
|
1342
|
+
|
|
1343
|
+
sage: M = Multizetas(QQ)
|
|
1344
|
+
sage: M(Word((3,2))).n() # indirect doctest
|
|
1345
|
+
0.711566197550572
|
|
1346
|
+
sage: parent(M(Word((3,2))).n())
|
|
1347
|
+
Real Field with 53 bits of precision
|
|
1348
|
+
|
|
1349
|
+
sage: (M((3,)) * M((2,))).n(prec=80)
|
|
1350
|
+
1.9773043502972961181971
|
|
1351
|
+
sage: M((1,2)).n(70)
|
|
1352
|
+
1.2020569031595942854
|
|
1353
|
+
|
|
1354
|
+
sage: M((3,)).n(digits=10)
|
|
1355
|
+
1.202056903
|
|
1356
|
+
|
|
1357
|
+
If you plan to use intensively numerical approximation at high precision,
|
|
1358
|
+
you might want to add more values and/or accuracy to the cache::
|
|
1359
|
+
|
|
1360
|
+
sage: from sage.modular.multiple_zeta import MultizetaValues
|
|
1361
|
+
sage: M = MultizetaValues()
|
|
1362
|
+
sage: M.update(max_weight=9, prec=2048)
|
|
1363
|
+
sage: M
|
|
1364
|
+
Cached multiple zeta values at precision 2048 up to weight 9
|
|
1365
|
+
sage: M.reset() # restore precision for the other doctests
|
|
1366
|
+
|
|
1367
|
+
TESTS::
|
|
1368
|
+
|
|
1369
|
+
sage: Multizetas(QQ).zero().n()
|
|
1370
|
+
0.000000000000000
|
|
1371
|
+
"""
|
|
1372
|
+
if prec is None:
|
|
1373
|
+
if digits:
|
|
1374
|
+
from sage.arith.numerical_approx import digits_to_bits
|
|
1375
|
+
prec = digits_to_bits(digits)
|
|
1376
|
+
else:
|
|
1377
|
+
prec = 53
|
|
1378
|
+
if algorithm is not None:
|
|
1379
|
+
raise ValueError("unknown algorithm")
|
|
1380
|
+
if not self.monomial_coefficients():
|
|
1381
|
+
return ZZ(0).n(prec=prec, digits=digits, algorithm=algorithm)
|
|
1382
|
+
if prec < Values.prec:
|
|
1383
|
+
s = sum(cf * Values(tuple(w)) for w, cf in self.monomial_coefficients().items())
|
|
1384
|
+
return s.n(prec=prec)
|
|
1385
|
+
return sum(cf * Values(tuple(w), prec=prec) for w, cf in self.monomial_coefficients().items())
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
class Multizetas_iterated(CombinatorialFreeModule):
|
|
1389
|
+
r"""
|
|
1390
|
+
Secondary class for the algebra of multiple zeta values.
|
|
1391
|
+
|
|
1392
|
+
This is used to represent multiple zeta values as iterated integrals
|
|
1393
|
+
of the differential forms `\omega_0 = dt/t` and `\omega_1 = dt/(t-1)`.
|
|
1394
|
+
|
|
1395
|
+
EXAMPLES::
|
|
1396
|
+
|
|
1397
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1398
|
+
sage: M = Multizetas_iterated(QQ); M
|
|
1399
|
+
Algebra of motivic multiple zeta values as convergent iterated
|
|
1400
|
+
integrals over Rational Field
|
|
1401
|
+
sage: M((1,0))
|
|
1402
|
+
I(10)
|
|
1403
|
+
sage: M((1,0))**2
|
|
1404
|
+
4*I(1100) + 2*I(1010)
|
|
1405
|
+
sage: M((1,0))*M((1,0,0))
|
|
1406
|
+
6*I(11000) + 3*I(10100) + I(10010)
|
|
1407
|
+
"""
|
|
1408
|
+
def __init__(self, R) -> None:
|
|
1409
|
+
"""
|
|
1410
|
+
TESTS::
|
|
1411
|
+
|
|
1412
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1413
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1414
|
+
sage: TestSuite(M).run() # not tested
|
|
1415
|
+
sage: M.category()
|
|
1416
|
+
Category of commutative no zero divisors graded algebras
|
|
1417
|
+
with basis over Rational Field
|
|
1418
|
+
"""
|
|
1419
|
+
if R not in Rings():
|
|
1420
|
+
raise TypeError("argument R must be a ring")
|
|
1421
|
+
cat = GradedAlgebrasWithBasis(R).Commutative()
|
|
1422
|
+
if R in Domains():
|
|
1423
|
+
cat = cat & Domains()
|
|
1424
|
+
CombinatorialFreeModule.__init__(self, R, Words10, prefix='I',
|
|
1425
|
+
category=cat)
|
|
1426
|
+
|
|
1427
|
+
def _repr_(self) -> str:
|
|
1428
|
+
"""
|
|
1429
|
+
Return a string representation for the ring.
|
|
1430
|
+
|
|
1431
|
+
EXAMPLES::
|
|
1432
|
+
|
|
1433
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1434
|
+
sage: M = Multizetas_iterated(QQ); M
|
|
1435
|
+
Algebra of motivic multiple zeta values
|
|
1436
|
+
as convergent iterated integrals over Rational Field
|
|
1437
|
+
"""
|
|
1438
|
+
return f"Algebra of motivic multiple zeta values as convergent iterated integrals over {self.base_ring()}"
|
|
1439
|
+
|
|
1440
|
+
def _repr_term(self, m) -> str:
|
|
1441
|
+
"""
|
|
1442
|
+
Return a custom string representation for the monomials.
|
|
1443
|
+
|
|
1444
|
+
EXAMPLES::
|
|
1445
|
+
|
|
1446
|
+
sage: Multizeta(1,0,1,0) # indirect doctest
|
|
1447
|
+
I(1010)
|
|
1448
|
+
"""
|
|
1449
|
+
return "I(" + ''.join(str(letter) for letter in m) + ")"
|
|
1450
|
+
|
|
1451
|
+
@cached_method
|
|
1452
|
+
def one_basis(self):
|
|
1453
|
+
r"""
|
|
1454
|
+
Return the index of the unit for the algebra.
|
|
1455
|
+
|
|
1456
|
+
This is the empty word.
|
|
1457
|
+
|
|
1458
|
+
EXAMPLES::
|
|
1459
|
+
|
|
1460
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1461
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1462
|
+
sage: M.one_basis()
|
|
1463
|
+
word:
|
|
1464
|
+
"""
|
|
1465
|
+
return self.basis().keys()([], check=False)
|
|
1466
|
+
|
|
1467
|
+
def product_on_basis(self, w1, w2):
|
|
1468
|
+
r"""
|
|
1469
|
+
Compute the product of two monomials.
|
|
1470
|
+
|
|
1471
|
+
This is the shuffle product.
|
|
1472
|
+
|
|
1473
|
+
INPUT:
|
|
1474
|
+
|
|
1475
|
+
- ``w1``, ``w2`` -- words in 0 and 1
|
|
1476
|
+
|
|
1477
|
+
EXAMPLES::
|
|
1478
|
+
|
|
1479
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1480
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1481
|
+
sage: x = Word([1,0])
|
|
1482
|
+
sage: M.product_on_basis(x,x)
|
|
1483
|
+
4*I(1100) + 2*I(1010)
|
|
1484
|
+
sage: y = Word([1,1,0])
|
|
1485
|
+
sage: M.product_on_basis(y,x)
|
|
1486
|
+
I(10110) + 3*I(11010) + 6*I(11100)
|
|
1487
|
+
"""
|
|
1488
|
+
return self._sum_of_monomials(shuffle(w1, w2, False))
|
|
1489
|
+
|
|
1490
|
+
def half_product_on_basis(self, w1, w2):
|
|
1491
|
+
r"""
|
|
1492
|
+
Compute half of the product of two monomials.
|
|
1493
|
+
|
|
1494
|
+
This is half of the shuffle product.
|
|
1495
|
+
|
|
1496
|
+
.. WARNING:: This is not a motivic operation.
|
|
1497
|
+
|
|
1498
|
+
INPUT:
|
|
1499
|
+
|
|
1500
|
+
- ``w1``, ``w2`` -- monomials
|
|
1501
|
+
|
|
1502
|
+
EXAMPLES::
|
|
1503
|
+
|
|
1504
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1505
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1506
|
+
sage: x = Word([1,0])
|
|
1507
|
+
sage: M.half_product_on_basis(x,x)
|
|
1508
|
+
2*I(1100) + I(1010)
|
|
1509
|
+
"""
|
|
1510
|
+
assert w1
|
|
1511
|
+
W = self.basis().keys()
|
|
1512
|
+
u1 = W([w1[0]], check=False)
|
|
1513
|
+
r1 = w1[1:]
|
|
1514
|
+
B = self.basis()
|
|
1515
|
+
return sum(B[u1 + u] for u in shuffle(r1, w2, False))
|
|
1516
|
+
|
|
1517
|
+
@lazy_attribute
|
|
1518
|
+
def half_product(self):
|
|
1519
|
+
r"""
|
|
1520
|
+
Compute half of the product of two elements.
|
|
1521
|
+
|
|
1522
|
+
This is half of the shuffle product.
|
|
1523
|
+
|
|
1524
|
+
.. WARNING:: This is not a motivic operation.
|
|
1525
|
+
|
|
1526
|
+
INPUT:
|
|
1527
|
+
|
|
1528
|
+
- ``w1``, ``w2`` -- elements
|
|
1529
|
+
|
|
1530
|
+
EXAMPLES::
|
|
1531
|
+
|
|
1532
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1533
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1534
|
+
sage: x = M(Word([1,0]))
|
|
1535
|
+
sage: M.half_product(x,x)
|
|
1536
|
+
2*I(1100) + I(1010)
|
|
1537
|
+
"""
|
|
1538
|
+
half = self.half_product_on_basis
|
|
1539
|
+
return self._module_morphism(self._module_morphism(half, position=0,
|
|
1540
|
+
codomain=self),
|
|
1541
|
+
position=1)
|
|
1542
|
+
|
|
1543
|
+
def coproduct_on_basis(self, w):
|
|
1544
|
+
"""
|
|
1545
|
+
Return the motivic coproduct of a monomial.
|
|
1546
|
+
|
|
1547
|
+
EXAMPLES::
|
|
1548
|
+
|
|
1549
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1550
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1551
|
+
sage: M.coproduct_on_basis([1,0])
|
|
1552
|
+
I() # I(10)
|
|
1553
|
+
|
|
1554
|
+
sage: M.coproduct_on_basis((1,0,1,0))
|
|
1555
|
+
I() # I(1010)
|
|
1556
|
+
"""
|
|
1557
|
+
seq = [0] + list(w) + [1]
|
|
1558
|
+
terms = coproduct_iterator(([0], seq))
|
|
1559
|
+
M_all = All_iterated(self.base_ring())
|
|
1560
|
+
|
|
1561
|
+
def split_word(indices):
|
|
1562
|
+
L = self.one()
|
|
1563
|
+
for i in range(len(indices) - 1):
|
|
1564
|
+
w = Word(seq[indices[i]:indices[i + 1] + 1])
|
|
1565
|
+
if len(w) == 2: # this factor is one
|
|
1566
|
+
continue
|
|
1567
|
+
if len(w) <= 4 or len(w) == 6 or w[0] == w[-1]:
|
|
1568
|
+
# vanishing factors
|
|
1569
|
+
return self.zero()
|
|
1570
|
+
value = M_all(w)
|
|
1571
|
+
L *= value.regularise().simplify()
|
|
1572
|
+
return L
|
|
1573
|
+
|
|
1574
|
+
resu = self.tensor_square().zero()
|
|
1575
|
+
for indices in terms:
|
|
1576
|
+
resu += split_word(indices).tensor(
|
|
1577
|
+
M_all(Word(seq[i] for i in indices)).regularise().simplify())
|
|
1578
|
+
return resu
|
|
1579
|
+
|
|
1580
|
+
@lazy_attribute
|
|
1581
|
+
def coproduct(self):
|
|
1582
|
+
"""
|
|
1583
|
+
Return the motivic coproduct of an element.
|
|
1584
|
+
|
|
1585
|
+
EXAMPLES::
|
|
1586
|
+
|
|
1587
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1588
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1589
|
+
sage: a = 3*Multizeta(1,4) + Multizeta(2,3)
|
|
1590
|
+
sage: M.coproduct(a.iterated())
|
|
1591
|
+
3*I() # I(11000) + I() # I(10100) + 3*I(11000) # I()
|
|
1592
|
+
+ I(10100) # I()
|
|
1593
|
+
"""
|
|
1594
|
+
cop = self.coproduct_on_basis
|
|
1595
|
+
return self._module_morphism(cop, codomain=self.tensor_square())
|
|
1596
|
+
|
|
1597
|
+
@lazy_attribute
|
|
1598
|
+
def composition(self):
|
|
1599
|
+
"""
|
|
1600
|
+
Convert to the algebra of multiple zeta values of composition style.
|
|
1601
|
+
|
|
1602
|
+
This means the algebra :class:`Multizetas`.
|
|
1603
|
+
|
|
1604
|
+
This is also available as a method of elements.
|
|
1605
|
+
|
|
1606
|
+
EXAMPLES::
|
|
1607
|
+
|
|
1608
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1609
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1610
|
+
sage: x = M((1,0))
|
|
1611
|
+
sage: M.composition(2*x)
|
|
1612
|
+
-2*ζ(2)
|
|
1613
|
+
sage: x = M((1,0,1,0,0))
|
|
1614
|
+
sage: M.composition(x)
|
|
1615
|
+
ζ(2,3)
|
|
1616
|
+
"""
|
|
1617
|
+
cod = Multizetas(self.base_ring())
|
|
1618
|
+
return self.module_morphism(self.composition_on_basis, codomain=cod)
|
|
1619
|
+
|
|
1620
|
+
def composition_on_basis(self, w, basering=None):
|
|
1621
|
+
"""
|
|
1622
|
+
Convert to the algebra of multiple zeta values of composition style.
|
|
1623
|
+
|
|
1624
|
+
INPUT:
|
|
1625
|
+
|
|
1626
|
+
- ``basering`` -- (optional) choice of the coefficient ring
|
|
1627
|
+
|
|
1628
|
+
EXAMPLES::
|
|
1629
|
+
|
|
1630
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1631
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1632
|
+
sage: x = Word((1,0,1,0,0))
|
|
1633
|
+
sage: M.composition_on_basis(x)
|
|
1634
|
+
ζ(2,3)
|
|
1635
|
+
sage: x = Word((1,0,1,0,0,1,0))
|
|
1636
|
+
sage: M.composition_on_basis(x)
|
|
1637
|
+
-ζ(2,3,2)
|
|
1638
|
+
"""
|
|
1639
|
+
if basering is None:
|
|
1640
|
+
basering = self.base_ring()
|
|
1641
|
+
codomain = Multizetas(basering)
|
|
1642
|
+
return (-1)**w.count(1) * codomain(iterated_to_composition(w))
|
|
1643
|
+
|
|
1644
|
+
def dual_on_basis(self, w):
|
|
1645
|
+
"""
|
|
1646
|
+
Return the order of the word and exchange letters 0 and 1.
|
|
1647
|
+
|
|
1648
|
+
This is an involution.
|
|
1649
|
+
|
|
1650
|
+
INPUT:
|
|
1651
|
+
|
|
1652
|
+
- ``w`` -- a word in 0 and 1
|
|
1653
|
+
|
|
1654
|
+
EXAMPLES::
|
|
1655
|
+
|
|
1656
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1657
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1658
|
+
sage: x = Word((1,0,1,0,0))
|
|
1659
|
+
sage: M.dual_on_basis(x)
|
|
1660
|
+
-I(11010)
|
|
1661
|
+
"""
|
|
1662
|
+
rev = [1 - x for x in reversed(w)]
|
|
1663
|
+
image = self._monomial(self.basis().keys()(rev, check=False))
|
|
1664
|
+
return -image if len(w) % 2 else image
|
|
1665
|
+
|
|
1666
|
+
def degree_on_basis(self, w):
|
|
1667
|
+
"""
|
|
1668
|
+
Return the degree of the monomial ``w``.
|
|
1669
|
+
|
|
1670
|
+
This is the length of the word.
|
|
1671
|
+
|
|
1672
|
+
INPUT:
|
|
1673
|
+
|
|
1674
|
+
- ``w`` -- a word in 0 and 1
|
|
1675
|
+
|
|
1676
|
+
EXAMPLES::
|
|
1677
|
+
|
|
1678
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1679
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1680
|
+
sage: x = Word((1,0,1,0,0))
|
|
1681
|
+
sage: M.degree_on_basis(x)
|
|
1682
|
+
5
|
|
1683
|
+
"""
|
|
1684
|
+
return ZZ(len(w))
|
|
1685
|
+
|
|
1686
|
+
def D_on_basis(self, k, w):
|
|
1687
|
+
"""
|
|
1688
|
+
Return the action of the operator `D_k` on the monomial ``w``.
|
|
1689
|
+
|
|
1690
|
+
This is one main tool in the procedure that allows
|
|
1691
|
+
to map the algebra of multiple zeta values to
|
|
1692
|
+
the F Ring.
|
|
1693
|
+
|
|
1694
|
+
INPUT:
|
|
1695
|
+
|
|
1696
|
+
- ``k`` -- an odd integer, at least 3
|
|
1697
|
+
|
|
1698
|
+
- ``w`` -- a word in 0 and 1
|
|
1699
|
+
|
|
1700
|
+
EXAMPLES::
|
|
1701
|
+
|
|
1702
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1703
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1704
|
+
sage: M.D_on_basis(3,(1,1,1,0,0))
|
|
1705
|
+
I(110) # I(10) + 2*I(100) # I(10)
|
|
1706
|
+
|
|
1707
|
+
sage: M.D_on_basis(3,(1,0,1,0,0))
|
|
1708
|
+
3*I(100) # I(10)
|
|
1709
|
+
sage: M.D_on_basis(5,(1,0,0,0,1,0,0,1,0,0))
|
|
1710
|
+
10*I(10000) # I(10100)
|
|
1711
|
+
"""
|
|
1712
|
+
Im = All_iterated(self.base_ring())
|
|
1713
|
+
MZV_MZV = self.tensor_square()
|
|
1714
|
+
N = len(w)
|
|
1715
|
+
it = [0] + list(w) + [1]
|
|
1716
|
+
coprod = MZV_MZV.zero()
|
|
1717
|
+
for p in range(N + 1 - k):
|
|
1718
|
+
left = Im(it[p: p + k + 2])
|
|
1719
|
+
right = Im(it[:p + 1] + it[p + k + 1:])
|
|
1720
|
+
if left and right:
|
|
1721
|
+
coprod += left.regularise().tensor(right.regularise())
|
|
1722
|
+
return coprod
|
|
1723
|
+
|
|
1724
|
+
def D(self, k):
|
|
1725
|
+
"""
|
|
1726
|
+
Return the operator `D_k`.
|
|
1727
|
+
|
|
1728
|
+
INPUT:
|
|
1729
|
+
|
|
1730
|
+
- ``k`` -- an odd integer, at least 3
|
|
1731
|
+
|
|
1732
|
+
EXAMPLES::
|
|
1733
|
+
|
|
1734
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1735
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1736
|
+
sage: D3 = M.D(3)
|
|
1737
|
+
sage: elt = M((1,0,1,0,0)) + 2 * M((1,1,0,0,1,0))
|
|
1738
|
+
sage: D3(elt)
|
|
1739
|
+
-6*I(100) # I(110) + 3*I(100) # I(10)
|
|
1740
|
+
"""
|
|
1741
|
+
def map_on_basis(elt):
|
|
1742
|
+
return self.D_on_basis(k, elt)
|
|
1743
|
+
cod = Multizetas_iterated(self.base_ring()).tensor_square()
|
|
1744
|
+
return self.module_morphism(map_on_basis, position=0,
|
|
1745
|
+
codomain=cod)
|
|
1746
|
+
|
|
1747
|
+
@cached_method
|
|
1748
|
+
def phi_extended(self, w):
|
|
1749
|
+
r"""
|
|
1750
|
+
Return the image of the monomial ``w`` by the morphism ``phi``.
|
|
1751
|
+
|
|
1752
|
+
INPUT:
|
|
1753
|
+
|
|
1754
|
+
- ``w`` -- a word in 0 and 1
|
|
1755
|
+
|
|
1756
|
+
OUTPUT: an element in the auxiliary F-algebra
|
|
1757
|
+
|
|
1758
|
+
The coefficients are in the base ring.
|
|
1759
|
+
|
|
1760
|
+
EXAMPLES::
|
|
1761
|
+
|
|
1762
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1763
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1764
|
+
sage: M.phi_extended((1,0))
|
|
1765
|
+
-f2
|
|
1766
|
+
sage: M.phi_extended((1,0,0))
|
|
1767
|
+
-f3
|
|
1768
|
+
sage: M.phi_extended((1,1,0))
|
|
1769
|
+
f3
|
|
1770
|
+
sage: M.phi_extended((1,0,1,0,0))
|
|
1771
|
+
-11/2*f5 + 3*f2*f3
|
|
1772
|
+
|
|
1773
|
+
More complicated examples::
|
|
1774
|
+
|
|
1775
|
+
sage: from sage.modular.multiple_zeta import composition_to_iterated
|
|
1776
|
+
sage: M.phi_extended(composition_to_iterated((4,3)))
|
|
1777
|
+
-18*f7 + 10*f2*f5 + 2/5*f2^2*f3
|
|
1778
|
+
|
|
1779
|
+
sage: M.phi_extended(composition_to_iterated((3,4)))
|
|
1780
|
+
17*f7 - 10*f2*f5
|
|
1781
|
+
|
|
1782
|
+
sage: M.phi_extended(composition_to_iterated((4,2)))
|
|
1783
|
+
-2*f3f3 + 10/21*f2^3
|
|
1784
|
+
sage: M.phi_extended(composition_to_iterated((3,5)))
|
|
1785
|
+
-5*f5f3
|
|
1786
|
+
sage: M.phi_extended(composition_to_iterated((3,7)))
|
|
1787
|
+
-6*f5f5 - 14*f7f3
|
|
1788
|
+
|
|
1789
|
+
sage: M.phi_extended(composition_to_iterated((3,3,2)))
|
|
1790
|
+
9*f3f5 - 9/2*f5f3 - 4*f2*f3f3 - 793/875*f2^4
|
|
1791
|
+
|
|
1792
|
+
TESTS::
|
|
1793
|
+
|
|
1794
|
+
sage: M.phi_extended(tuple())
|
|
1795
|
+
1
|
|
1796
|
+
"""
|
|
1797
|
+
# this is now hardcoded
|
|
1798
|
+
# prec = 1024
|
|
1799
|
+
F = F_algebra(self.base_ring())
|
|
1800
|
+
f = F.gen
|
|
1801
|
+
if not w:
|
|
1802
|
+
return F.one()
|
|
1803
|
+
N = len(w)
|
|
1804
|
+
compo = tuple(iterated_to_composition(w))
|
|
1805
|
+
if compo in B_data[N]:
|
|
1806
|
+
# do not forget the sign
|
|
1807
|
+
return (-1)**len(compo) * phi_on_multiplicative_basis(compo)
|
|
1808
|
+
u = compute_u_on_basis(w)
|
|
1809
|
+
rho_inverse_u = rho_inverse(u)
|
|
1810
|
+
xi = self.composition_on_basis(w, QQ)
|
|
1811
|
+
c_xi = (xi - rho_inverse_u)._numerical_approx_pari()
|
|
1812
|
+
c_xi /= Multizeta(N)._numerical_approx_pari()
|
|
1813
|
+
c_xi = c_xi.bestappr().sage() # in QQ
|
|
1814
|
+
return u + c_xi * f(N)
|
|
1815
|
+
|
|
1816
|
+
@lazy_attribute
|
|
1817
|
+
def phi(self):
|
|
1818
|
+
"""
|
|
1819
|
+
Return the morphism ``phi``.
|
|
1820
|
+
|
|
1821
|
+
This sends multiple zeta values to the auxiliary F-algebra.
|
|
1822
|
+
|
|
1823
|
+
EXAMPLES::
|
|
1824
|
+
|
|
1825
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1826
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1827
|
+
sage: m = Multizeta(1,0,1,0) + 2*Multizeta(1,1,0,0); m
|
|
1828
|
+
2*I(1100) + I(1010)
|
|
1829
|
+
sage: M.phi(m)
|
|
1830
|
+
1/2*f2^2
|
|
1831
|
+
|
|
1832
|
+
sage: Z = Multizeta
|
|
1833
|
+
sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)]
|
|
1834
|
+
sage: [M.phi(b.iterated()) for b in B5]
|
|
1835
|
+
[-1/2*f5 + f2*f3, 1/2*f5]
|
|
1836
|
+
|
|
1837
|
+
sage: B6 = [6*Z(1,5) + 3*Z(2,4) + Z(3,3),
|
|
1838
|
+
....: 6*Z(1,1,4) + 4*Z(1,2,3) + 2*Z(1,3,2) + 2*Z(2,1,3) + Z(2,2,2)]
|
|
1839
|
+
sage: [M.phi(b.iterated()) for b in B6]
|
|
1840
|
+
[f3f3, 1/6*f2^3]
|
|
1841
|
+
"""
|
|
1842
|
+
cod = F_algebra(self.base_ring())
|
|
1843
|
+
return self.module_morphism(self.phi_extended, codomain=cod)
|
|
1844
|
+
|
|
1845
|
+
def _element_constructor_(self, x):
|
|
1846
|
+
r"""
|
|
1847
|
+
Convert ``x`` into ``self``.
|
|
1848
|
+
|
|
1849
|
+
INPUT:
|
|
1850
|
+
|
|
1851
|
+
- ``x`` -- either a list, tuple, word or a multiple zeta value
|
|
1852
|
+
|
|
1853
|
+
EXAMPLES::
|
|
1854
|
+
|
|
1855
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1856
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1857
|
+
sage: x = Word((1,0,1,0,0))
|
|
1858
|
+
sage: M(x)
|
|
1859
|
+
I(10100)
|
|
1860
|
+
sage: y = M((1,1,0,0)); y
|
|
1861
|
+
I(1100)
|
|
1862
|
+
sage: y == M(y)
|
|
1863
|
+
True
|
|
1864
|
+
"""
|
|
1865
|
+
if isinstance(x, (str, (FiniteWord_class, tuple, list))):
|
|
1866
|
+
if x:
|
|
1867
|
+
assert all(letter in (0, 1) for letter in x), 'bad letter'
|
|
1868
|
+
assert x[0] == 1, 'bad first letter, should be 1'
|
|
1869
|
+
assert x[-1] == 0, 'bad last letter, should be 0'
|
|
1870
|
+
W = self.basis().keys()
|
|
1871
|
+
if isinstance(x, list):
|
|
1872
|
+
x = tuple(x)
|
|
1873
|
+
return self._monomial(W(x, check=False))
|
|
1874
|
+
|
|
1875
|
+
P = x.parent()
|
|
1876
|
+
if isinstance(P, Multizetas_iterated):
|
|
1877
|
+
if P is self:
|
|
1878
|
+
return x
|
|
1879
|
+
if P is not self.base_ring():
|
|
1880
|
+
return self.element_class(self, x.monomial_coefficients())
|
|
1881
|
+
elif isinstance(P, Multizetas):
|
|
1882
|
+
return x.iterated()
|
|
1883
|
+
|
|
1884
|
+
R = self.base_ring()
|
|
1885
|
+
# coercion via base ring
|
|
1886
|
+
x = R(x)
|
|
1887
|
+
if x == 0:
|
|
1888
|
+
return self.element_class(self, {})
|
|
1889
|
+
return self.from_base_ring_from_one_basis(x)
|
|
1890
|
+
|
|
1891
|
+
class Element(CombinatorialFreeModule.Element):
|
|
1892
|
+
def simplify(self):
|
|
1893
|
+
"""
|
|
1894
|
+
Gather terms using the duality relations.
|
|
1895
|
+
|
|
1896
|
+
This can help to lower the number of monomials.
|
|
1897
|
+
|
|
1898
|
+
EXAMPLES::
|
|
1899
|
+
|
|
1900
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1901
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1902
|
+
sage: z = 4*M((1,0,0)) + 3*M((1,1,0))
|
|
1903
|
+
sage: z.simplify()
|
|
1904
|
+
I(100)
|
|
1905
|
+
"""
|
|
1906
|
+
summing = self.parent().sum_of_terms
|
|
1907
|
+
return summing(minimize_term(w, cf)
|
|
1908
|
+
for w, cf in self.monomial_coefficients().items())
|
|
1909
|
+
|
|
1910
|
+
def coproduct(self):
|
|
1911
|
+
"""
|
|
1912
|
+
Return the coproduct of ``self``.
|
|
1913
|
+
|
|
1914
|
+
EXAMPLES::
|
|
1915
|
+
|
|
1916
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1917
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1918
|
+
sage: a = 3*Multizeta(1,3) + Multizeta(2,3)
|
|
1919
|
+
sage: a.iterated().coproduct()
|
|
1920
|
+
3*I() # I(1100) + I() # I(10100) + I(10100) # I() + 3*I(100) # I(10)
|
|
1921
|
+
"""
|
|
1922
|
+
return self.parent().coproduct(self)
|
|
1923
|
+
|
|
1924
|
+
def composition(self):
|
|
1925
|
+
"""
|
|
1926
|
+
Convert to the algebra of multiple zeta values of composition style.
|
|
1927
|
+
|
|
1928
|
+
This means the algebra :class:`Multizetas`.
|
|
1929
|
+
|
|
1930
|
+
EXAMPLES::
|
|
1931
|
+
|
|
1932
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1933
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1934
|
+
sage: x = M((1,0,1,0))
|
|
1935
|
+
sage: x.composition()
|
|
1936
|
+
ζ(2,2)
|
|
1937
|
+
sage: x = M((1,0,1,0,0))
|
|
1938
|
+
sage: x.composition()
|
|
1939
|
+
ζ(2,3)
|
|
1940
|
+
sage: x = M((1,0,1,0,0,1,0))
|
|
1941
|
+
sage: x.composition()
|
|
1942
|
+
-ζ(2,3,2)
|
|
1943
|
+
"""
|
|
1944
|
+
return self.parent().composition(self)
|
|
1945
|
+
|
|
1946
|
+
def numerical_approx(self, prec=None, digits=None, algorithm=None):
|
|
1947
|
+
"""
|
|
1948
|
+
Return a numerical approximation as a sage real.
|
|
1949
|
+
|
|
1950
|
+
EXAMPLES::
|
|
1951
|
+
|
|
1952
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1953
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1954
|
+
sage: x = M((1,0,1,0))
|
|
1955
|
+
sage: y = M((1, 0, 0))
|
|
1956
|
+
sage: (3*x+y).n() # indirect doctest
|
|
1957
|
+
1.23317037269047
|
|
1958
|
+
"""
|
|
1959
|
+
return self.composition().numerical_approx(prec=prec, digits=digits, algorithm=algorithm)
|
|
1960
|
+
|
|
1961
|
+
def phi(self):
|
|
1962
|
+
"""
|
|
1963
|
+
Return the image of ``self`` by the morphism ``phi``.
|
|
1964
|
+
|
|
1965
|
+
This sends multiple zeta values to the auxiliary F-algebra.
|
|
1966
|
+
|
|
1967
|
+
EXAMPLES::
|
|
1968
|
+
|
|
1969
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1970
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1971
|
+
sage: M((1,1,0)).phi()
|
|
1972
|
+
f3
|
|
1973
|
+
"""
|
|
1974
|
+
return self.parent().phi(self)
|
|
1975
|
+
|
|
1976
|
+
def __bool__(self) -> bool:
|
|
1977
|
+
r"""
|
|
1978
|
+
TESTS::
|
|
1979
|
+
|
|
1980
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
1981
|
+
sage: M = Multizetas_iterated(QQ)
|
|
1982
|
+
sage: bool(M(0))
|
|
1983
|
+
False
|
|
1984
|
+
sage: bool(M(1))
|
|
1985
|
+
True
|
|
1986
|
+
sage: bool(M((1,0,0)))
|
|
1987
|
+
True
|
|
1988
|
+
"""
|
|
1989
|
+
P = self.parent()
|
|
1990
|
+
deg = P.degree_on_basis
|
|
1991
|
+
phi = P.phi
|
|
1992
|
+
for d in sorted({deg(w) for w in self.support()}):
|
|
1993
|
+
z = self.homogeneous_component(d)
|
|
1994
|
+
if not phi(z).is_zero():
|
|
1995
|
+
return True
|
|
1996
|
+
return False
|
|
1997
|
+
|
|
1998
|
+
def is_zero(self) -> bool:
|
|
1999
|
+
r"""
|
|
2000
|
+
Return whether this element is zero.
|
|
2001
|
+
|
|
2002
|
+
EXAMPLES::
|
|
2003
|
+
|
|
2004
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
2005
|
+
sage: M = Multizetas_iterated(QQ)
|
|
2006
|
+
sage: M(0).is_zero()
|
|
2007
|
+
True
|
|
2008
|
+
sage: M(1).is_zero()
|
|
2009
|
+
False
|
|
2010
|
+
sage: (M((1,1,0)) - -M((1,0,0))).is_zero()
|
|
2011
|
+
True
|
|
2012
|
+
"""
|
|
2013
|
+
return not self
|
|
2014
|
+
|
|
2015
|
+
def _richcmp_(self, other, op) -> bool:
|
|
2016
|
+
"""
|
|
2017
|
+
Test for equality.
|
|
2018
|
+
|
|
2019
|
+
This means equality as motivic multiple zeta value, computed
|
|
2020
|
+
using the morphism ``phi``.
|
|
2021
|
+
|
|
2022
|
+
EXAMPLES::
|
|
2023
|
+
|
|
2024
|
+
sage: from sage.modular.multiple_zeta import Multizetas_iterated
|
|
2025
|
+
sage: M = Multizetas_iterated(QQ)
|
|
2026
|
+
sage: M((1,1,0)) == -M((1,0,0))
|
|
2027
|
+
True
|
|
2028
|
+
|
|
2029
|
+
sage: M = Multizetas(QQ)
|
|
2030
|
+
sage: a = 28*M((3,9))+150*M((5,7))+168*M((7,5))
|
|
2031
|
+
sage: b = 5197/691*M((12,))
|
|
2032
|
+
sage: a.iterated() == b.iterated() # not tested, long time (20s)
|
|
2033
|
+
True
|
|
2034
|
+
"""
|
|
2035
|
+
if op not in [op_EQ, op_NE]:
|
|
2036
|
+
raise TypeError('invalid comparison for multizetas')
|
|
2037
|
+
return (self - other).is_zero() == (op == op_EQ)
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
class All_iterated(CombinatorialFreeModule):
|
|
2041
|
+
r"""
|
|
2042
|
+
Auxiliary class for multiple zeta value as generalized iterated integrals.
|
|
2043
|
+
|
|
2044
|
+
This is used to represent multiple zeta values as possibly
|
|
2045
|
+
divergent iterated integrals
|
|
2046
|
+
of the differential forms `\omega_0 = dt/t` and `\omega_1 = dt/(t-1)`.
|
|
2047
|
+
|
|
2048
|
+
This means that the elements are symbols
|
|
2049
|
+
`I(a_0 ; a_1,a_2,...a_n ; a_{n+1})`
|
|
2050
|
+
where all arguments, including the starting and ending points
|
|
2051
|
+
can be 0 or 1.
|
|
2052
|
+
|
|
2053
|
+
This comes with a "regularise" method mapping
|
|
2054
|
+
to :class:`Multizetas_iterated`.
|
|
2055
|
+
|
|
2056
|
+
EXAMPLES::
|
|
2057
|
+
|
|
2058
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2059
|
+
sage: M = All_iterated(QQ); M
|
|
2060
|
+
Space of motivic multiple zeta values as general iterated integrals
|
|
2061
|
+
over Rational Field
|
|
2062
|
+
sage: M((0,1,0,1))
|
|
2063
|
+
I(0;10;1)
|
|
2064
|
+
sage: x = M((1,1,0,0)); x
|
|
2065
|
+
I(1;10;0)
|
|
2066
|
+
sage: x.regularise()
|
|
2067
|
+
-I(10)
|
|
2068
|
+
"""
|
|
2069
|
+
def __init__(self, R) -> None:
|
|
2070
|
+
"""
|
|
2071
|
+
TESTS::
|
|
2072
|
+
|
|
2073
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2074
|
+
sage: M = All_iterated(QQ)
|
|
2075
|
+
sage: TestSuite(M).run() # not tested
|
|
2076
|
+
"""
|
|
2077
|
+
if R not in Rings():
|
|
2078
|
+
raise TypeError("argument R must be a ring")
|
|
2079
|
+
CombinatorialFreeModule.__init__(self, R, Words10, prefix='I')
|
|
2080
|
+
|
|
2081
|
+
def _repr_(self) -> str:
|
|
2082
|
+
"""
|
|
2083
|
+
Return a string representation of the module.
|
|
2084
|
+
|
|
2085
|
+
EXAMPLES::
|
|
2086
|
+
|
|
2087
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2088
|
+
sage: M = All_iterated(QQ); M
|
|
2089
|
+
Space of motivic multiple zeta values as general iterated integrals over Rational Field
|
|
2090
|
+
"""
|
|
2091
|
+
txt = "Space of motivic multiple zeta values as general iterated integrals over {}"
|
|
2092
|
+
return txt.format(self.base_ring())
|
|
2093
|
+
|
|
2094
|
+
def _repr_term(self, m) -> str:
|
|
2095
|
+
"""
|
|
2096
|
+
Return a custom string representation for the monomials.
|
|
2097
|
+
|
|
2098
|
+
EXAMPLES::
|
|
2099
|
+
|
|
2100
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2101
|
+
sage: M = All_iterated(QQ)
|
|
2102
|
+
sage: x = Word((1,0,1,0,0))
|
|
2103
|
+
sage: M(x) # indirect doctest
|
|
2104
|
+
I(1;010;0)
|
|
2105
|
+
"""
|
|
2106
|
+
start = str(m[0])
|
|
2107
|
+
end = str(m[-1])
|
|
2108
|
+
mid = ''.join(str(letter) for letter in m[1:-1])
|
|
2109
|
+
return "I(" + start + ";" + mid + ";" + end + ")"
|
|
2110
|
+
|
|
2111
|
+
def _element_constructor_(self, x):
|
|
2112
|
+
r"""
|
|
2113
|
+
Convert ``x`` into ``self``.
|
|
2114
|
+
|
|
2115
|
+
INPUT:
|
|
2116
|
+
|
|
2117
|
+
- ``x`` -- either a list, tuple, word
|
|
2118
|
+
|
|
2119
|
+
EXAMPLES::
|
|
2120
|
+
|
|
2121
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2122
|
+
sage: M = All_iterated(QQ)
|
|
2123
|
+
sage: y = M((1,1,0,0)); y
|
|
2124
|
+
I(1;10;0)
|
|
2125
|
+
sage: y == M(y)
|
|
2126
|
+
True
|
|
2127
|
+
|
|
2128
|
+
sage: M((1,0,1,0,1))
|
|
2129
|
+
0
|
|
2130
|
+
sage: M((1,0,0,0,0))
|
|
2131
|
+
0
|
|
2132
|
+
"""
|
|
2133
|
+
if not isinstance(x, (FiniteWord_class, tuple, list)):
|
|
2134
|
+
raise TypeError('invalid input for building iterated integral')
|
|
2135
|
+
if not x:
|
|
2136
|
+
return self.zero()
|
|
2137
|
+
if any(letter not in (0, 1) for letter in x):
|
|
2138
|
+
raise ValueError('bad letter')
|
|
2139
|
+
|
|
2140
|
+
W = self.basis().keys()
|
|
2141
|
+
w = W(x, check=False)
|
|
2142
|
+
# condition R1 of F. Brown
|
|
2143
|
+
if w[0] == w[-1] or (len(w) >= 4 and
|
|
2144
|
+
all(x == w[1] for x in w[2:-1])):
|
|
2145
|
+
return self.zero()
|
|
2146
|
+
return self._monomial(w)
|
|
2147
|
+
|
|
2148
|
+
def dual_on_basis(self, w):
|
|
2149
|
+
"""
|
|
2150
|
+
Reverse the word and exchange the letters 0 and 1.
|
|
2151
|
+
|
|
2152
|
+
This is the operation R4 in [Brown2012]_.
|
|
2153
|
+
|
|
2154
|
+
This should be used only when `a_0 = 0` and `a_{n+1} = 1`.
|
|
2155
|
+
|
|
2156
|
+
EXAMPLES::
|
|
2157
|
+
|
|
2158
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2159
|
+
sage: M = All_iterated(QQ)
|
|
2160
|
+
sage: x = Word((0,0,1,0,1))
|
|
2161
|
+
sage: M.dual_on_basis(x)
|
|
2162
|
+
I(0;010;1)
|
|
2163
|
+
sage: x = Word((0,1,0,1,1))
|
|
2164
|
+
sage: M.dual_on_basis(x)
|
|
2165
|
+
-I(0;010;1)
|
|
2166
|
+
"""
|
|
2167
|
+
W = self.basis().keys()
|
|
2168
|
+
if w[-2] == 0:
|
|
2169
|
+
return self._monomial(w)
|
|
2170
|
+
rev = [1 - x for x in reversed(w)]
|
|
2171
|
+
image = self._monomial(W(rev, check=False))
|
|
2172
|
+
return -image if len(w) % 2 else image
|
|
2173
|
+
|
|
2174
|
+
@lazy_attribute
|
|
2175
|
+
def dual(self):
|
|
2176
|
+
"""
|
|
2177
|
+
Reverse words and exchange the letters 0 and 1.
|
|
2178
|
+
|
|
2179
|
+
This is the operation R4 in [Brown2012]_.
|
|
2180
|
+
|
|
2181
|
+
This should be used only when `a_0 = 0` and `a_{n+1} = 1`.
|
|
2182
|
+
|
|
2183
|
+
EXAMPLES::
|
|
2184
|
+
|
|
2185
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2186
|
+
sage: M = All_iterated(QQ)
|
|
2187
|
+
sage: x = Word((0,0,1,1,1))
|
|
2188
|
+
sage: y = Word((0,0,1,0,1))
|
|
2189
|
+
sage: M.dual(M(x)+5*M(y))
|
|
2190
|
+
5*I(0;010;1) - I(0;001;1)
|
|
2191
|
+
"""
|
|
2192
|
+
return self.module_morphism(self.dual_on_basis, codomain=self)
|
|
2193
|
+
|
|
2194
|
+
def reversal_on_basis(self, w):
|
|
2195
|
+
"""
|
|
2196
|
+
Reverse the word if necessary.
|
|
2197
|
+
|
|
2198
|
+
This is the operation R3 in [Brown2012]_.
|
|
2199
|
+
|
|
2200
|
+
This reverses the word only if `a_0 = 0` and `a_{n+1} = 1`.
|
|
2201
|
+
|
|
2202
|
+
EXAMPLES::
|
|
2203
|
+
|
|
2204
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2205
|
+
sage: M = All_iterated(QQ)
|
|
2206
|
+
sage: x = Word((1,0,1,0,0))
|
|
2207
|
+
sage: M.reversal_on_basis(x)
|
|
2208
|
+
-I(0;010;1)
|
|
2209
|
+
sage: x = Word((0,0,1,1,1))
|
|
2210
|
+
sage: M.reversal_on_basis(x)
|
|
2211
|
+
I(0;011;1)
|
|
2212
|
+
"""
|
|
2213
|
+
if w[0] == 0 and w[-1] == 1:
|
|
2214
|
+
return self._monomial(w)
|
|
2215
|
+
W = self.basis().keys()
|
|
2216
|
+
image = self._monomial(W(list(reversed(w)), check=False))
|
|
2217
|
+
return -image if len(w) % 2 else image
|
|
2218
|
+
|
|
2219
|
+
@lazy_attribute
|
|
2220
|
+
def reversal(self):
|
|
2221
|
+
"""
|
|
2222
|
+
Reverse words if necessary.
|
|
2223
|
+
|
|
2224
|
+
This is the operation R3 in [Brown2012]_.
|
|
2225
|
+
|
|
2226
|
+
This reverses the word only if `a_0 = 0` and `a_{n+1} = 1`.
|
|
2227
|
+
|
|
2228
|
+
EXAMPLES::
|
|
2229
|
+
|
|
2230
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2231
|
+
sage: M = All_iterated(QQ)
|
|
2232
|
+
sage: x = Word((1,0,1,0,0))
|
|
2233
|
+
sage: y = Word((0,0,1,1,1))
|
|
2234
|
+
sage: M.reversal(M(x)+2*M(y))
|
|
2235
|
+
2*I(0;011;1) - I(0;010;1)
|
|
2236
|
+
"""
|
|
2237
|
+
return self.module_morphism(self.reversal_on_basis, codomain=self)
|
|
2238
|
+
|
|
2239
|
+
def expand_on_basis(self, w):
|
|
2240
|
+
"""
|
|
2241
|
+
Perform an expansion as a linear combination.
|
|
2242
|
+
|
|
2243
|
+
This is the operation R2 in [Brown2012]_.
|
|
2244
|
+
|
|
2245
|
+
This should be used only when `a_0 = 0` and `a_{n+1} = 1`.
|
|
2246
|
+
|
|
2247
|
+
EXAMPLES::
|
|
2248
|
+
|
|
2249
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2250
|
+
sage: M = All_iterated(QQ)
|
|
2251
|
+
sage: x = Word((0,0,1,0,1))
|
|
2252
|
+
sage: M.expand_on_basis(x)
|
|
2253
|
+
-2*I(0;100;1)
|
|
2254
|
+
|
|
2255
|
+
sage: x = Word((0,0,0,1,0,1,0,0,1))
|
|
2256
|
+
sage: M.expand_on_basis(x)
|
|
2257
|
+
6*I(0;1010000;1) + 6*I(0;1001000;1) + 3*I(0;1000100;1)
|
|
2258
|
+
|
|
2259
|
+
sage: x = Word((0,1,1,0,1))
|
|
2260
|
+
sage: M.expand_on_basis(x)
|
|
2261
|
+
I(0;110;1)
|
|
2262
|
+
"""
|
|
2263
|
+
if w[1] == 1:
|
|
2264
|
+
return self._monomial(w)
|
|
2265
|
+
|
|
2266
|
+
W = self.basis().keys()
|
|
2267
|
+
n_zeros = []
|
|
2268
|
+
k = 0
|
|
2269
|
+
for x in w[1:-1]:
|
|
2270
|
+
if x == 0:
|
|
2271
|
+
k += 1
|
|
2272
|
+
else:
|
|
2273
|
+
n_zeros.append(k)
|
|
2274
|
+
k = 1
|
|
2275
|
+
n_zeros.append(k)
|
|
2276
|
+
k = n_zeros[0]
|
|
2277
|
+
n_zeros = n_zeros[1:]
|
|
2278
|
+
r = len(n_zeros)
|
|
2279
|
+
|
|
2280
|
+
resu = self.zero()
|
|
2281
|
+
for idx in IntegerVectors(k, r):
|
|
2282
|
+
coeff = ZZ.prod(ZZ(nj + ij - 1).binomial(ij)
|
|
2283
|
+
for nj, ij in zip(n_zeros, idx))
|
|
2284
|
+
indice = [0]
|
|
2285
|
+
for nj, ij in zip(n_zeros, idx):
|
|
2286
|
+
indice += [1] + [0] * (nj + ij - 1)
|
|
2287
|
+
resu += coeff * self._monomial(W(tuple(indice + [1]),
|
|
2288
|
+
check=False))
|
|
2289
|
+
return (-1)**k * resu # attention au signe
|
|
2290
|
+
|
|
2291
|
+
@lazy_attribute
|
|
2292
|
+
def expand(self):
|
|
2293
|
+
"""
|
|
2294
|
+
Perform an expansion as a linear combination.
|
|
2295
|
+
|
|
2296
|
+
This is the operation R2 in [Brown2012]_.
|
|
2297
|
+
|
|
2298
|
+
This should be used only when `a_0 = 0` and `a_{n+1} = 1`.
|
|
2299
|
+
|
|
2300
|
+
EXAMPLES::
|
|
2301
|
+
|
|
2302
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2303
|
+
sage: M = All_iterated(QQ)
|
|
2304
|
+
sage: x = Word((0,0,1,0,1))
|
|
2305
|
+
sage: y = Word((0,0,1,1,1))
|
|
2306
|
+
sage: M.expand(M(x)+2*M(y))
|
|
2307
|
+
-2*I(0;110;1) - 2*I(0;101;1) - 2*I(0;100;1)
|
|
2308
|
+
sage: M.expand(M([0,1,1,0,1]))
|
|
2309
|
+
I(0;110;1)
|
|
2310
|
+
sage: M.expand(M([0,1,0,0,1]))
|
|
2311
|
+
I(0;100;1)
|
|
2312
|
+
"""
|
|
2313
|
+
return self.module_morphism(self.expand_on_basis, codomain=self)
|
|
2314
|
+
|
|
2315
|
+
class Element(CombinatorialFreeModule.Element):
|
|
2316
|
+
def conversion(self):
|
|
2317
|
+
"""
|
|
2318
|
+
Conversion to the :class:`Multizetas_iterated`.
|
|
2319
|
+
|
|
2320
|
+
This assumed that the element has been prepared.
|
|
2321
|
+
|
|
2322
|
+
Not to be used directly.
|
|
2323
|
+
|
|
2324
|
+
EXAMPLES::
|
|
2325
|
+
|
|
2326
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2327
|
+
sage: M = All_iterated(QQ)
|
|
2328
|
+
sage: x = Word((0,1,0,0,1))
|
|
2329
|
+
sage: y = M(x).conversion(); y
|
|
2330
|
+
I(100)
|
|
2331
|
+
sage: y.parent()
|
|
2332
|
+
Algebra of motivic multiple zeta values as convergent iterated
|
|
2333
|
+
integrals over Rational Field
|
|
2334
|
+
"""
|
|
2335
|
+
M = Multizetas_iterated(self.parent().base_ring())
|
|
2336
|
+
return M.sum_of_terms((w[1:-1], cf) for w, cf in self)
|
|
2337
|
+
|
|
2338
|
+
def regularise(self):
|
|
2339
|
+
"""
|
|
2340
|
+
Conversion to the :class:`Multizetas_iterated`.
|
|
2341
|
+
|
|
2342
|
+
This is the regularisation procedure, done in several steps.
|
|
2343
|
+
|
|
2344
|
+
EXAMPLES::
|
|
2345
|
+
|
|
2346
|
+
sage: from sage.modular.multiple_zeta import All_iterated
|
|
2347
|
+
sage: M = All_iterated(QQ)
|
|
2348
|
+
sage: x = Word((0,0,1,0,1))
|
|
2349
|
+
sage: M(x).regularise()
|
|
2350
|
+
-2*I(100)
|
|
2351
|
+
sage: x = Word((0,1,1,0,1))
|
|
2352
|
+
sage: M(x).regularise()
|
|
2353
|
+
I(110)
|
|
2354
|
+
|
|
2355
|
+
sage: x = Word((1,0,1,0,0))
|
|
2356
|
+
sage: M(x).regularise()
|
|
2357
|
+
2*I(100)
|
|
2358
|
+
"""
|
|
2359
|
+
P = self.parent()
|
|
2360
|
+
step1 = P.reversal(self) # R3
|
|
2361
|
+
step2 = P.expand(step1) # R2
|
|
2362
|
+
step3 = P.dual(step2) # R4
|
|
2363
|
+
step4 = P.expand(step3) # R2
|
|
2364
|
+
return step4.conversion() # dans Multizetas_iterated
|
|
2365
|
+
|
|
2366
|
+
|
|
2367
|
+
# **************** procedures after F. Brown ************
|
|
2368
|
+
|
|
2369
|
+
def coeff_phi(w):
|
|
2370
|
+
"""
|
|
2371
|
+
Return the coefficient of `f_k` in the image by ``phi``.
|
|
2372
|
+
|
|
2373
|
+
INPUT:
|
|
2374
|
+
|
|
2375
|
+
- ``w`` -- a word in 0 and 1 with `k` letters (where `k` is odd)
|
|
2376
|
+
|
|
2377
|
+
OUTPUT: a rational number
|
|
2378
|
+
|
|
2379
|
+
EXAMPLES::
|
|
2380
|
+
|
|
2381
|
+
sage: from sage.modular.multiple_zeta import coeff_phi
|
|
2382
|
+
sage: coeff_phi(Word([1,0,0]))
|
|
2383
|
+
-1
|
|
2384
|
+
sage: coeff_phi(Word([1,1,0]))
|
|
2385
|
+
1
|
|
2386
|
+
sage: coeff_phi(Word([1,1,0,1,0]))
|
|
2387
|
+
11/2
|
|
2388
|
+
sage: coeff_phi(Word([1,1,0,0,0,1,0]))
|
|
2389
|
+
109/16
|
|
2390
|
+
"""
|
|
2391
|
+
if all(x == 0 for x in w[1:]):
|
|
2392
|
+
return -1 # beware the sign
|
|
2393
|
+
k = len(w)
|
|
2394
|
+
assert k % 2
|
|
2395
|
+
M = Multizetas_iterated(QQ)
|
|
2396
|
+
z = M.phi_extended(w)
|
|
2397
|
+
W = z.parent().basis().keys()
|
|
2398
|
+
w = W((0, [k]))
|
|
2399
|
+
return z.coefficient(w) # in QQ
|
|
2400
|
+
|
|
2401
|
+
|
|
2402
|
+
def phi_on_multiplicative_basis(compo):
|
|
2403
|
+
"""
|
|
2404
|
+
Compute ``phi`` on one single multiple zeta value.
|
|
2405
|
+
|
|
2406
|
+
INPUT:
|
|
2407
|
+
|
|
2408
|
+
- ``compo`` -- a composition (in the hardcoded multiplicative base)
|
|
2409
|
+
|
|
2410
|
+
OUTPUT: an element in :func:`F_ring` with rational coefficients
|
|
2411
|
+
|
|
2412
|
+
EXAMPLES::
|
|
2413
|
+
|
|
2414
|
+
sage: from sage.modular.multiple_zeta import phi_on_multiplicative_basis
|
|
2415
|
+
sage: phi_on_multiplicative_basis((2,))
|
|
2416
|
+
f2
|
|
2417
|
+
sage: phi_on_multiplicative_basis((3,))
|
|
2418
|
+
f3
|
|
2419
|
+
"""
|
|
2420
|
+
f = F_algebra(QQ).gen
|
|
2421
|
+
|
|
2422
|
+
if tuple(compo) == (2,):
|
|
2423
|
+
return f(2)
|
|
2424
|
+
|
|
2425
|
+
if len(compo) == 1:
|
|
2426
|
+
n, = compo
|
|
2427
|
+
return f(n)
|
|
2428
|
+
|
|
2429
|
+
return compute_u_on_compo(compo)
|
|
2430
|
+
|
|
2431
|
+
|
|
2432
|
+
def phi_on_basis(L):
|
|
2433
|
+
"""
|
|
2434
|
+
Compute the value of phi on the hardcoded basis.
|
|
2435
|
+
|
|
2436
|
+
INPUT:
|
|
2437
|
+
|
|
2438
|
+
- ``L`` -- list of compositions; each composition in the hardcoded basis
|
|
2439
|
+
|
|
2440
|
+
This encodes a product of multiple zeta values.
|
|
2441
|
+
|
|
2442
|
+
OUTPUT: an element in :func:`F_ring`
|
|
2443
|
+
|
|
2444
|
+
EXAMPLES::
|
|
2445
|
+
|
|
2446
|
+
sage: from sage.modular.multiple_zeta import phi_on_basis
|
|
2447
|
+
sage: phi_on_basis([(3,),(3,)])
|
|
2448
|
+
2*f3f3
|
|
2449
|
+
sage: phi_on_basis([(2,),(2,)])
|
|
2450
|
+
f2^2
|
|
2451
|
+
sage: phi_on_basis([(2,),(3,),(3,)])
|
|
2452
|
+
2*f2*f3f3
|
|
2453
|
+
"""
|
|
2454
|
+
F = F_algebra(QQ)
|
|
2455
|
+
return F.prod(phi_on_multiplicative_basis(compo) for compo in L)
|
|
2456
|
+
|
|
2457
|
+
|
|
2458
|
+
def D_on_compo(k, compo):
|
|
2459
|
+
"""
|
|
2460
|
+
Return the value of the operator `D_k` on a multiple zeta value.
|
|
2461
|
+
|
|
2462
|
+
This is now only used as a place to keep many doctests.
|
|
2463
|
+
|
|
2464
|
+
INPUT:
|
|
2465
|
+
|
|
2466
|
+
- ``k`` -- an odd integer
|
|
2467
|
+
|
|
2468
|
+
- ``compo`` -- a composition
|
|
2469
|
+
|
|
2470
|
+
EXAMPLES::
|
|
2471
|
+
|
|
2472
|
+
sage: from sage.modular.multiple_zeta import D_on_compo
|
|
2473
|
+
sage: D_on_compo(3,(2,3))
|
|
2474
|
+
3*I(100) # I(10)
|
|
2475
|
+
|
|
2476
|
+
sage: D_on_compo(3,(4,3))
|
|
2477
|
+
I(100) # I(1000)
|
|
2478
|
+
sage: D_on_compo(5,(4,3))
|
|
2479
|
+
10*I(10000) # I(10)
|
|
2480
|
+
|
|
2481
|
+
sage: [D_on_compo(k, [3,5]) for k in (3,5,7)]
|
|
2482
|
+
[0, -5*I(10000) # I(100), 0]
|
|
2483
|
+
|
|
2484
|
+
sage: [D_on_compo(k, [3,7]) for k in (3,5,7,9)]
|
|
2485
|
+
[0, -6*I(10000) # I(10000), -14*I(1000000) # I(100), 0]
|
|
2486
|
+
|
|
2487
|
+
sage: D_on_compo(3,(4,3,3))
|
|
2488
|
+
-I(100) # I(1000100)
|
|
2489
|
+
sage: D_on_compo(5,(4,3,3))
|
|
2490
|
+
-10*I(10000) # I(10100)
|
|
2491
|
+
sage: D_on_compo(7,(4,3,3))
|
|
2492
|
+
4*I(1001000) # I(100) + 2*I(1000100) # I(100)
|
|
2493
|
+
|
|
2494
|
+
sage: [D_on_compo(k,(1,3,1,3,1,3)) for k in range(3,10,2)]
|
|
2495
|
+
[0, 0, 0, 0]
|
|
2496
|
+
"""
|
|
2497
|
+
it = composition_to_iterated(compo)
|
|
2498
|
+
M = Multizetas_iterated(QQ)
|
|
2499
|
+
return (-1)**len(compo) * M.D_on_basis(k, it)
|
|
2500
|
+
|
|
2501
|
+
|
|
2502
|
+
def compute_u_on_compo(compo):
|
|
2503
|
+
r"""
|
|
2504
|
+
Compute the value of the map ``u`` on a multiple zeta value.
|
|
2505
|
+
|
|
2506
|
+
INPUT:
|
|
2507
|
+
|
|
2508
|
+
- ``compo`` -- a composition
|
|
2509
|
+
|
|
2510
|
+
OUTPUT: an element of :func:`F_ring` over `\QQ`
|
|
2511
|
+
|
|
2512
|
+
EXAMPLES::
|
|
2513
|
+
|
|
2514
|
+
sage: from sage.modular.multiple_zeta import compute_u_on_compo
|
|
2515
|
+
sage: compute_u_on_compo((2,4))
|
|
2516
|
+
2*f3f3
|
|
2517
|
+
sage: compute_u_on_compo((2,3,2))
|
|
2518
|
+
-11/2*f2*f5
|
|
2519
|
+
sage: compute_u_on_compo((3,2,3,2))
|
|
2520
|
+
-75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3
|
|
2521
|
+
"""
|
|
2522
|
+
it = composition_to_iterated(compo)
|
|
2523
|
+
return (-1)**len(compo) * compute_u_on_basis(it)
|
|
2524
|
+
|
|
2525
|
+
|
|
2526
|
+
def compute_u_on_basis(w):
|
|
2527
|
+
r"""
|
|
2528
|
+
Compute the value of ``u`` on a multiple zeta value.
|
|
2529
|
+
|
|
2530
|
+
INPUT:
|
|
2531
|
+
|
|
2532
|
+
- ``w`` -- a word in 0,1
|
|
2533
|
+
|
|
2534
|
+
OUTPUT: an element of :func:`F_ring` over `\QQ`
|
|
2535
|
+
|
|
2536
|
+
EXAMPLES::
|
|
2537
|
+
|
|
2538
|
+
sage: from sage.modular.multiple_zeta import compute_u_on_basis
|
|
2539
|
+
sage: compute_u_on_basis((1,0,0,0,1,0))
|
|
2540
|
+
-2*f3f3
|
|
2541
|
+
|
|
2542
|
+
sage: compute_u_on_basis((1,1,1,0,0))
|
|
2543
|
+
f2*f3
|
|
2544
|
+
|
|
2545
|
+
sage: compute_u_on_basis((1,0,0,1,0,0,0,0))
|
|
2546
|
+
-5*f5f3
|
|
2547
|
+
|
|
2548
|
+
sage: compute_u_on_basis((1,0,1,0,0,1,0))
|
|
2549
|
+
11/2*f2*f5
|
|
2550
|
+
|
|
2551
|
+
sage: compute_u_on_basis((1,0,0,1,0,1,0,0,1,0))
|
|
2552
|
+
-75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3
|
|
2553
|
+
"""
|
|
2554
|
+
M = Multizetas_iterated(QQ)
|
|
2555
|
+
F = F_algebra(QQ)
|
|
2556
|
+
N = len(w)
|
|
2557
|
+
xi_dict = {}
|
|
2558
|
+
for k in range(3, N, 2):
|
|
2559
|
+
xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1]))
|
|
2560
|
+
for ww, cf in M.D_on_basis(k, w))
|
|
2561
|
+
return F.sum(F.half_product(F.gen(k), xi_dict[k])
|
|
2562
|
+
for k in range(3, N, 2))
|
|
2563
|
+
|
|
2564
|
+
|
|
2565
|
+
@cached_function
|
|
2566
|
+
def rho_matrix_inverse(n):
|
|
2567
|
+
"""
|
|
2568
|
+
Return the matrix of the inverse of ``rho``.
|
|
2569
|
+
|
|
2570
|
+
This is the matrix in the chosen bases, namely the hardcoded basis
|
|
2571
|
+
of multiple zeta values and the natural basis of the F ring.
|
|
2572
|
+
|
|
2573
|
+
INPUT:
|
|
2574
|
+
|
|
2575
|
+
- ``n`` -- integer
|
|
2576
|
+
|
|
2577
|
+
EXAMPLES::
|
|
2578
|
+
|
|
2579
|
+
sage: from sage.modular.multiple_zeta import rho_matrix_inverse
|
|
2580
|
+
sage: rho_matrix_inverse(3)
|
|
2581
|
+
[1]
|
|
2582
|
+
sage: rho_matrix_inverse(8)
|
|
2583
|
+
[-1/5 0 0 0]
|
|
2584
|
+
[ 1/5 1 0 0]
|
|
2585
|
+
[ 0 0 1/2 0]
|
|
2586
|
+
[ 0 0 0 1]
|
|
2587
|
+
"""
|
|
2588
|
+
base = extend_multiplicative_basis(B_data, n)
|
|
2589
|
+
resu = []
|
|
2590
|
+
for b in base:
|
|
2591
|
+
phi_b = phi_on_basis(b)
|
|
2592
|
+
resu.append(phi_b.homogeneous_to_vector())
|
|
2593
|
+
dN = len(resu)
|
|
2594
|
+
return ~matrix(QQ, dN, dN, resu)
|
|
2595
|
+
|
|
2596
|
+
|
|
2597
|
+
def rho_inverse(elt):
|
|
2598
|
+
"""
|
|
2599
|
+
Return the image by the inverse of ``rho``.
|
|
2600
|
+
|
|
2601
|
+
INPUT:
|
|
2602
|
+
|
|
2603
|
+
- ``elt`` -- an homogeneous element of the F ring
|
|
2604
|
+
|
|
2605
|
+
OUTPUT: a linear combination of multiple zeta values
|
|
2606
|
+
|
|
2607
|
+
EXAMPLES::
|
|
2608
|
+
|
|
2609
|
+
sage: from sage.modular.multiple_zeta import rho_inverse
|
|
2610
|
+
sage: from sage.modular.multiple_zeta_F_algebra import F_algebra
|
|
2611
|
+
sage: A = F_algebra(QQ)
|
|
2612
|
+
sage: f = A.gen
|
|
2613
|
+
sage: rho_inverse(f(3))
|
|
2614
|
+
ζ(3)
|
|
2615
|
+
sage: rho_inverse(f(9))
|
|
2616
|
+
ζ(9)
|
|
2617
|
+
sage: rho_inverse(A("53"))
|
|
2618
|
+
-1/5*ζ(3,5)
|
|
2619
|
+
"""
|
|
2620
|
+
pa = elt.parent()
|
|
2621
|
+
BR = pa.base_ring().base_ring()
|
|
2622
|
+
M_BR = Multizetas(BR)
|
|
2623
|
+
if elt == pa.zero():
|
|
2624
|
+
return M_BR.zero()
|
|
2625
|
+
|
|
2626
|
+
pw, _ = next(iter(elt))
|
|
2627
|
+
p, w = pw
|
|
2628
|
+
N = 2 * p + sum(int(c) for c in w)
|
|
2629
|
+
|
|
2630
|
+
v = elt.homogeneous_to_vector()
|
|
2631
|
+
w = v * rho_matrix_inverse(N)
|
|
2632
|
+
return sum(cf * b for cf, b in zip(w, M_BR.basis_data(BR, N)))
|