From 3ca56fc2490f8b21cc3bdfda1f344cf6bf0ce660 Mon Sep 17 00:00:00 2001 From: giacomomagni Date: Thu, 18 Dec 2025 11:52:09 +0100 Subject: [PATCH 1/6] update splittings python --- doc/source/refs.bib | 11 ++ doc/source/theory/N3LO_ad.rst | 2 +- .../unpolarized/space_like/as4/fhmruvv/ggg.py | 41 ++++- .../unpolarized/space_like/as4/fhmruvv/ggq.py | 169 ++++++++++-------- .../unpolarized/space_like/as4/fhmruvv/gps.py | 32 +++- .../unpolarized/space_like/as4/fhmruvv/gqg.py | 49 ++++- .../unpolarized/space_like/test_as4_fhmv.py | 12 +- 7 files changed, 219 insertions(+), 97 deletions(-) diff --git a/doc/source/refs.bib b/doc/source/refs.bib index 6b201ca72..4f52305b2 100644 --- a/doc/source/refs.bib +++ b/doc/source/refs.bib @@ -1103,3 +1103,14 @@ @article{Barontini:2024xgu pages = "004", year = "2024" } + +@article{Falcioni:2025hfz, + author = "Falcioni, G. and Herzog, F. and Moch, S. and Pelloni, A. and Vogt, A.", + title = "{Additional results on the four-loop flavour-singlet splitting functions in QCD}", + eprint = "2512.10783", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "DESY-25-138, LTH 1410", + month = "12", + year = "2025" +} diff --git a/doc/source/theory/N3LO_ad.rst b/doc/source/theory/N3LO_ad.rst index 81ab1ab67..3522b541d 100644 --- a/doc/source/theory/N3LO_ad.rst +++ b/doc/source/theory/N3LO_ad.rst @@ -14,7 +14,7 @@ which is set to ``(0,0,0,0,0,0,0)`` as default, can be varied to obtain parametr In particular: * ``use_fhmruvv = True`` (default option) adopts the parametrizations as provided - in :cite:`Moch:2017uml,Falcioni:2023luc,Falcioni:2023vqq,Falcioni:2024xyt,Falcioni:2024qpd`. + in :cite:`Moch:2017uml,Falcioni:2023luc,Falcioni:2023vqq,Falcioni:2024xyt,Falcioni:2024qpd,Falcioni:2025hfz`. For each of the 7 splitting functions, the approximation error can be obtained by varying the entries of ``n3lo_ad_variation`` in the range: ``0``, cental value (default), ``1`` down variation, ``2`` up variation. diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py index cd680c765..6c4fc3ba4 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py @@ -2,9 +2,8 @@ :math:`\gamma_{gg}^{(3)}`.""" import numba as nb -import numpy as np -from eko.constants import zeta3 +from eko.constants import zeta2, zeta3 from ......harmonics import cache as c from ......harmonics.log_functions import ( @@ -23,7 +22,8 @@ def gamma_gg(n, nf, cache, variation): r"""Compute the |N3LO| gluon-gluon singlet anomalous dimension. - The routine is taken from :cite:`Falcioni:2024qpd`. + The routine is taken from :cite:`Falcioni:2024qpd`, + with the update for :math:`n_f=6` from :cite:`Falcioni:2025hfz`. A previous version based only on the lowest 10 moments was given in :cite:`Moch:2023tdj`. @@ -127,11 +127,7 @@ def gamma_gg(n, nf, cache, variation): + 84068.0 * Lm11m1 + 346318.0 * Lm12m1 + 315725.0 - * ( - -3 * S1**2 - + n * S1 * (np.pi**2 - 6 * S2) - - 3 * (S2 + 2 * n * (S3 - zeta3)) - ) + * (-3 * S1**2 + n * S1 * 6 * (zeta2 - S2) - 3 * (S2 + 2 * n * (S3 - zeta3))) / (3 * n**2) ) elif nf == 4: @@ -188,8 +184,35 @@ def gamma_gg(n, nf, cache, variation): + 19295.0 * Lm12m1 - 13719.0 * lm12m2(n, S1, S2) ) + elif nf == 6: + P3ggApp1 = ( + P3gg01 + - 476018.0 * (-(1 / (-1 + n) ** 2) + 1 / n**2) + - 469289.0 * 1 / ((-1 + n) * n) + + 2049351.0 * (1 / (n + n**2)) + - 1589000.0 * (1 / (2 + 3 * n + n**2)) + + 3185549.0 * (-(1 / n**2) + 1 / (1 + n) ** 2) + + 1994521.0 * 2 / n**3 + + 527723.0 * (-(6 / n**4)) + - 340674.0 * Lm11m1 + + 22460.0 * Lm12m1 + - 394556.0 * (S1 - n * (zeta2 - S2)) / n**2 + ) + P3ggApp2 = ( + P3gg01 + - 709863.0 * (-(1 / (-1 + n) ** 2) + 1 / n**2) + - 2134347.0 * 1 / ((-1 + n) * n) + + 1605315.0 * (1 / (2 + 3 * n + n**2)) + + 360743.0 * ((12 + 9 * n + n**2) / (6 * n + 11 * n**2 + 6 * n**3 + n**4)) + - 2426250.0 * (-(1 / n**2) + 1 / (1 + n) ** 2) + + 230631.0 * 2 / n**3 + - 185804.0 * (-(6 / n**4)) + - 7992.9 * Lm11m1 + + 15918.0 * Lm12m1 + - 32771.0 * lm11m2(n, S1) + ) else: - raise NotImplementedError("nf=6 is not available at N3LO") + raise NotImplementedError("Select nf=3,..,6 for N3LO evolution") # We return (for now) one of the two error-band representatives # or the present best estimate, their average diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py index 1affbff95..a2cc39ebf 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py @@ -9,7 +9,6 @@ from ......harmonics.log_functions import ( lm11, lm12, - lm12m1, lm13, lm14, lm14m1, @@ -22,8 +21,9 @@ def gamma_gq(n, nf, cache, variation): r"""Compute the |N3LO| gluon-quark singlet anomalous dimension. - The routine is taken from :cite:`Falcioni:2024xyt`. - A previous version based only on the lowest 10 moments + The routine is taken from :cite:`Falcioni:2025hfz`. + A previous version was given in :cite:`Falcioni:2024xyt`. + While a version based only on the lowest 10 moments was given in :cite:`Moch:2023tdj`. @@ -83,92 +83,121 @@ def gamma_gq(n, nf, cache, variation): if nf == 3: P3gqApp1 = ( P3GQ01 - + 6.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - - 744384.0 * 1 / ((-1 + n) * n) - + 2453640.0 * 1 / n - - 1540404.0 * (2 / (1 + n) + 1 / (2 + n)) - + 1933026.0 * -1 / n**2 - + 1142069.0 * 2 / n**3 - + 162196.0 * -6 / n**4 - - 2172.1 * lm13(n, S1, S2, S3) - - 93264.1 * lm12(n, S1, S2) - - 786973.0 * lm11(n, S1) - + 875383.0 * lm12m1(n, S1, S2) + + 3.5 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 27891.0 * 1 / ((-1 + n) * n) + - 309124.0 * 1 / n + + 1056866.0 * (3 + n) / (2 + 3 * n + n**2) + - 124735.0 * -1 / n**2 + - 16246.0 * 2 / n**3 + + 131175.0 * -6 / n**4 + + 4970.1 * lm13(n, S1, S2, S3) + + 60041.0 * lm12(n, S1, S2) + + 343181.0 * lm11(n, S1) + - 958330.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3gqApp2 = ( P3GQ01 - + 3.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - + 142414.0 * 1 / ((-1 + n) * n) - - 326525.0 * 1 / n - + 2159787.0 * ((3 + n) / (2 + 3 * n + n**2)) - - 289064.0 * -1 / n**2 - - 176358.0 * 2 / n**3 - + 156541.0 * -6 / n**4 - + 9016.5 * lm13(n, S1, S2, S3) - + 136063.0 * lm12(n, S1, S2) - + 829482.0 * lm11(n, S1) - - 2359050.0 * (S1 - n * (zeta2 - S2)) / n**2 + + 7.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 1139334.0 * 1 / ((-1 + n) * n) + + 143008.0 * 1 / n + - 290390.0 * (3 + n) / (2 + 3 * n + n**2) + - 659492.0 * -1 / n**2 + + 303685.0 * 2 / n**3 + - 81867.0 * -6 / n**4 + + 1811.8 * lm13(n, S1, S2, S3) + - 465.9 * lm12(n, S1, S2) + - 51206.0 * lm11(n, S1) + + 274249.0 * (S1 - n * (zeta2 - S2)) / n**2 ) elif nf == 4: P3gqApp1 = ( P3GQ01 - + 6.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - - 743535.0 * 1 / ((-1 + n) * n) - + 2125286.0 * 1 / n - - 1332472.0 * (2 / (1 + n) + 1 / (2 + n)) - + 1631173.0 * -1 / n**2 - + 1015255.0 * 2 / n**3 - + 142612.0 * -6 / n**4 - - 1910.4 * lm13(n, S1, S2, S3) - - 80851.0 * lm12(n, S1, S2) - - 680219.0 * lm11(n, S1) - + 752733.0 * lm12m1(n, S1, S2) + + 3.5 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 8302.8 * 1 / ((-1 + n) * n) + - 347706.0 * 1 / n + + 1105306.0 * (3 + n) / (2 + 3 * n + n**2) + - 127650.0 * -1 / n**2 + - 29728.0 * 2 / n**3 + + 137537.0 * -6 / n**4 + + 4658.1 * lm13(n, S1, S2, S3) + + 59205.0 * lm12(n, S1, S2) + + 345513.0 * lm11(n, S1) + - 995120.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3gqApp2 = ( P3GQ01 - + 3.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - + 160568.0 * 1 / ((-1 + n) * n) - - 361207.0 * 1 / n - + 2048948.0 * ((3 + n) / (2 + 3 * n + n**2)) - - 245963.0 * -1 / n**2 - - 171312.0 * 2 / n**3 - + 163099.0 * -6 / n**4 - + 8132.2 * lm13(n, S1, S2, S3) - + 124425.0 * lm12(n, S1, S2) - + 762435.0 * lm11(n, S1) - - 2193335.0 * (S1 - n * (zeta2 - S2)) / n**2 + + 7.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 1129822.0 * 1 / ((-1 + n) * n) + + 108527.0 * 1 / n + - 254166.0 * (3 + n) / (2 + 3 * n + n**2) + - 667254.0 * -1 / n**2 + + 293099.0 * 2 / n**3 + - 77437.0 * -6 / n**4 + + 1471.3 * lm13(n, S1, S2, S3) + - 1850.3 * lm12(n, S1, S2) + - 52451.0 * lm11(n, S1) + + 248634.0 * (S1 - n * (zeta2 - S2)) / n**2 ) elif nf == 5: P3gqApp1 = ( P3GQ01 - + 6.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - - 785864.0 * 1 / ((-1 + n) * n) - + 285034.0 * 1 / n - - 131648.0 * (2 / (1 + n) + 1 / (2 + n)) - - 162840.0 * -1 / n**2 - + 321220.0 * 2 / n**3 - + 12688.0 * -6 / n**4 - + 1423.4 * lm13(n, S1, S2, S3) - + 1278.9 * lm12(n, S1, S2) - - 30919.9 * lm11(n, S1) - + 47588.0 * lm12m1(n, S1, S2) + + 3.5 * bfkl1 * (-(1 / (-1 + n) ** 2)) + + 14035.0 * 1 / ((-1 + n) * n) + - 384003.0 * 1 / n + + 1152711.0 * (3 + n) / (2 + 3 * n + n**2) + - 126346.0 * -1 / n**2 + - 42967.0 * 2 / n**3 + + 144270.0 * -6 / n**4 + + 4385.5 * lm13(n, S1, S2, S3) + + 58688.0 * lm12(n, S1, S2) + + 348988.0 * lm11(n, S1) + - 1031165.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3gqApp2 = ( P3GQ01 - + 3.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) - + 177094.0 * 1 / ((-1 + n) * n) - - 470694.0 * 1 / n - + 1348823.0 * ((3 + n) / (2 + 3 * n + n**2)) - - 52985.0 * -1 / n**2 - - 87354.0 * 2 / n**3 - + 176885.0 * -6 / n**4 - + 4748.8 * lm13(n, S1, S2, S3) - + 65811.9 * lm12(n, S1, S2) - + 396390.0 * lm11(n, S1) - - 1190212.0 * (S1 - n * (zeta2 - S2)) / n**2 + + 7.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 1117561.0 * 1 / ((-1 + n) * n) + + 76329.0 * 1 / n + - 218973.0 * (3 + n) / (2 + 3 * n + n**2) + - 670799.0 * -1 / n**2 + + 282763.0 * 2 / n**3 + - 72633.0 * -6 / n**4 + + 1170.0 * lm13(n, S1, S2, S3) + - 2915.5 * lm12(n, S1, S2) + - 52548.0 * lm11(n, S1) + + 223771.0 * (S1 - n * (zeta2 - S2)) / n**2 + ) + elif nf == 6: + P3gqApp1 = ( + P3GQ01 + + 3.5 * bfkl1 * (-(1 / (-1 + n) ** 2)) + + 39203.0 * 1 / ((-1 + n) * n) + - 417914.0 * 1 / n + + 1199042.0 * (3 + n) / (2 + 3 * n + n**2) + - 120750.0 * -1 / n**2 + - 55941.0 * 2 / n**3 + + 151383.0 * -6 / n**4 + + 4149.2 * lm13(n, S1, S2, S3) + + 58466.0 * lm12(n, S1, S2) + + 353589.0 * lm11(n, S1) + - 1066510.0 * (S1 - n * (zeta2 - S2)) / n**2 + ) + P3gqApp2 = ( + P3GQ01 + + 7.0 * bfkl1 * (-(1 / (-1 + n) ** 2)) + - 1102470.0 * 1 / ((-1 + n) * n) + + 46517.0 * 1 / n + - 184858.0 * (3 + n) / (2 + 3 * n + n**2) + - 670056.0 * -1 / n**2 + + 272689.0 * 2 / n**3 + - 67453.0 * -6 / n**4 + + 905.0 * lm13(n, S1, S2, S3) + - 3686.2 * lm12(n, S1, S2) + - 51523.0 * lm11(n, S1) + + 199594.0 * (S1 - n * (zeta2 - S2)) / n**2 ) else: - raise NotImplementedError("nf=6 is not available at N3LO") + raise NotImplementedError("Select nf=3,..,6 for N3LO evolution") # We return (for now) one of the two error-band representatives # or the present best estimate, their average diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py index f1dfe4668..74cacf8fc 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py @@ -19,7 +19,8 @@ def gamma_ps(n, nf, cache, variation): r"""Compute the |N3LO| pure singlet quark-quark anomalous dimension. - The routine is taken from :cite:`Falcioni:2023luc`. + The routine is taken from :cite:`Falcioni:2023luc`, + with the update for :math:`n_f=6` from :cite:`Falcioni:2025hfz`. Parameters ---------- @@ -152,8 +153,35 @@ def gamma_ps(n, nf, cache, variation): - 1760.8 * lm12m1(n, S1, S2) - 10295.0 * lm12m2(n, S1, S2) ) + elif nf == 6: + P3psApp1 = ( + P3ps01 + + 134701.0 * xm1lm1 + + 518318.0 * 1 / ((-1 + n) * n) + - 195241.0 * (1 / n - n / (2 + 3 * n + n**2)) + + 66517.0 * 1 / (6 + 5 * n + n**2) + + 658832.0 * (-(1 / n**2) + 1 / (1 + n) ** 2) + + 19605.0 * 2 / n**3 + + 76125.0 * -6 / n**4 + - 4734.5 * lm11m1(n, S1) + - 2035.2 * lm12m1(n, S1, S2) + + 1633.1 * lm12m2(n, S1, S2) + ) + P3psApp2 = ( + P3ps01 + + 110032.0 * xm1lm1 + + 341158.0 * 1 / ((-1 + n) * n) + - 365676.0 * 1 / (n + n**2) + + 25934.0 * 2 / (3 + 4 * n + n**2) + + 3614.4 * (-(1 / n**2) + 1 / (1 + n) ** 2) + - 194868.0 * 2 / n**3 + - 4172.2 * -6 / n**4 + + 3924.3 * lm11m1(n, S1) + - 1324.9 * lm12m1(n, S1, S2) + - 12520.0 * lm12m2(n, S1, S2) + ) else: - raise NotImplementedError("nf=6 is not available at N3LO") + raise NotImplementedError("Select nf=3,..,6 for N3LO evolution") # We return (for now) one of the two error-band boundaries # or the present best estimate, their average diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py index 39d8107b7..840224f96 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py @@ -2,7 +2,8 @@ :math:`\gamma_{qg}^{(3)}`.""" import numba as nb -import numpy as np + +from eko.constants import zeta2 from ......harmonics import cache as c from ......harmonics.log_functions import lm11, lm12, lm13, lm14, lm14m1, lm15, lm15m1 @@ -12,7 +13,8 @@ def gamma_qg(n, nf, cache, variation): r"""Compute the |N3LO| quark-gluon singlet anomalous dimension. - The routine is taken from :cite:`Falcioni:2023vqq`. + The routine is taken from :cite:`Falcioni:2023vqq`, + with the update for :math:`n_f=6` from :cite:`Falcioni:2025hfz`. Parameters ---------- @@ -77,7 +79,7 @@ def gamma_qg(n, nf, cache, variation): + 119.8 * lm13(n, S1, S2, S3) + 7156.3 * lm12(n, S1, S2) + 45790.0 * lm11(n, S1) - - 95682.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + - 95682.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3qgApp2 = ( P3QG01 @@ -91,7 +93,7 @@ def gamma_qg(n, nf, cache, variation): - 850.1 * lm13(n, S1, S2, S3) - 11425.0 * lm12(n, S1, S2) - 75323.0 * lm11(n, S1) - + 282836.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + + 282836.0 * (S1 - n * (zeta2 - S2)) / n**2 ) elif nf == 4: P3qgApp1 = ( @@ -106,7 +108,7 @@ def gamma_qg(n, nf, cache, variation): + 272.4 * lm13(n, S1, S2, S3) + 10911.0 * lm12(n, S1, S2) + 60563.0 * lm11(n, S1) - - 161448.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + - 161448.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3qgApp2 = ( P3QG01 @@ -120,7 +122,7 @@ def gamma_qg(n, nf, cache, variation): - 1020.8 * lm13(n, S1, S2, S3) - 13864.0 * lm12(n, S1, S2) - 100922.0 * lm11(n, S1) - + 343243.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + + 343243.0 * (S1 - n * (zeta2 - S2)) / n**2 ) elif nf == 5: P3qgApp1 = ( @@ -135,7 +137,7 @@ def gamma_qg(n, nf, cache, variation): + 472.7 * lm13(n, S1, S2, S3) + 15415.0 * lm12(n, S1, S2) + 75644.0 * lm11(n, S1) - - 244869.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + - 244869.0 * (S1 - n * (zeta2 - S2)) / n**2 ) P3qgApp2 = ( P3QG01 @@ -149,10 +151,39 @@ def gamma_qg(n, nf, cache, variation): - 1143.8 * lm13(n, S1, S2, S3) - 15553.0 * lm12(n, S1, S2) - 126212.0 * lm11(n, S1) - + 385995.0 * (S1 - n * (np.pi**2 / 6 - S2)) / n**2 + + 385995.0 * (S1 - n * (zeta2 - S2)) / n**2 + ) + elif nf == 6: + P3qgApp1 = ( + P3QG01 + + 375000.0 * -(1 / (-1 + n) ** 2) + + 1595330.0 * -(1 / (-1 + n) ** 2) + - 477729.0 * 1 / n + + 637552.0 * (3 + n) / (2 + 3 * n + n**2) + + 931556.0 * -1 / n**2 + - 387017.0 * 2 / n**3 + + 187509.0 * -6 / n**4 + + 715.5 * lm13(n, S1, S2, S3) + + 20710.0 * lm12(n, S1, S2) + + 91373.0 * lm11(n, S1) + - 346374.0 * (S1 - n * (zeta2 - S2)) / n**2 + ) + P3qgApp2 = ( + P3QG01 + + 270000.0 * -(1 / (-1 + n) ** 2) + + 912695.0 * -(1 / (-1 + n) ** 2) + - 200034.0 * 1 / n + - 189918.0 * (3 + n) / (2 + 3 * n + n**2) + + 603114.0 * -1 / n**2 + - 190521.0 * 2 / n**3 + + 56661.0 * -6 / n**4 + - 1224.3 * lm13(n, S1, S2, S3) + - 16453.0 * lm12(n, S1, S2) + - 150856.0 * lm11(n, S1) + + 410661.0 * (S1 - n * (zeta2 - S2)) / n**2 ) else: - raise NotImplementedError("nf=6 is not available at N3LO") + raise NotImplementedError("Select nf=3,..,6 for N3LO evolution") # We return one of the two error-band representatives # or the present best estimate, their average diff --git a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py index 30891649e..d9cc3f40c 100644 --- a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py +++ b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py @@ -45,8 +45,8 @@ def test_momentum_conservation(): # total np.testing.assert_allclose( g_singlet[:, 0, 0] + g_singlet[:, 1, 0], - [0.053441, 0.225674, -0.118792], - atol=2e-5, + [0.040173 + 0.0j, 0.260616, -0.18027], + atol=1e-6, ) np.testing.assert_allclose( g_singlet[:, 0, 1] + g_singlet[:, 1, 1], @@ -194,10 +194,10 @@ def gq3_moment(N, nf): ) with pytest.raises(NotImplementedError): - gps.gamma_ps(N, 6, cache, variation) - gqg.gamma_qg(N, 6, cache, variation) - ggg.gamma_gg(N, 6, cache, variation) - ggq.gamma_gq(N, 6, cache, variation) + gps.gamma_ps(N, 7, cache, variation) + gqg.gamma_qg(N, 7, cache, variation) + ggg.gamma_gg(N, 7, cache, variation) + ggq.gamma_gq(N, 7, cache, variation) def test_non_singlet_reference_moments(): From f9516dca4d7bdc1a36218204ca279d65e413962a Mon Sep 17 00:00:00 2001 From: giacomomagni Date: Thu, 18 Dec 2025 13:57:10 +0100 Subject: [PATCH 2/6] minor fix --- .../unpolarized/space_like/as4/fhmruvv/ggg.py | 2 +- .../unpolarized/space_like/as4/fhmruvv/ggq.py | 2 +- .../unpolarized/space_like/as4/fhmruvv/gps.py | 2 +- .../unpolarized/space_like/as4/fhmruvv/gqg.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py index 6c4fc3ba4..f1431fe44 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggg.py @@ -100,7 +100,7 @@ def gamma_gg(n, nf, cache, variation): + x1L3cff * lm13m1(n, S1, S2, S3) ) - # The selected approximations for nf = 3, 4, 5 + # The selected approximations for nf = 3, 4, 5, 6 if nf == 3: P3ggApp1 = ( P3gg01 diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py index a2cc39ebf..ac66a3c66 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/ggq.py @@ -79,7 +79,7 @@ def gamma_gq(n, nf, cache, variation): + y1L5cff * lm15m1(n, S1, S2, S3, S4, S5) ) - # The selected approximations for nf = 3, 4, 5 + # The selected approximations for nf = 3, 4, 5, 6 if nf == 3: P3gqApp1 = ( P3GQ01 diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py index 74cacf8fc..01ace9028 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gps.py @@ -71,7 +71,7 @@ def gamma_ps(n, nf, cache, variation): + y1L4cff * lm14m2(n, S1, S2, S3, S4) ) - # The selected approximations for nf = 3, 4, 5 + # The selected approximations for nf = 3, 4, 5, 6 if nf == 3: P3psApp1 = ( P3ps01 diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py index 840224f96..191543d49 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py @@ -65,7 +65,7 @@ def gamma_qg(n, nf, cache, variation): + y1L5cff * lm15m1(n, S1, S2, S3, S4, S5) ) - # The selected approximations for nf = 3, 4, 5 + # The selected approximations for nf = 3, 4, 5, 6 if nf == 3: P3qgApp1 = ( P3QG01 From 0d74f8340e695781ab8251ca31657d0129616e60 Mon Sep 17 00:00:00 2001 From: giacomomagni Date: Thu, 18 Dec 2025 14:04:08 +0100 Subject: [PATCH 3/6] update rust --- .../unpolarized/spacelike/as4/ggg.rs | 36 +++- .../unpolarized/spacelike/as4/ggq.rs | 168 ++++++++++-------- .../unpolarized/spacelike/as4/gps.rs | 30 +++- .../unpolarized/spacelike/as4/gqg.rs | 34 +++- 4 files changed, 182 insertions(+), 86 deletions(-) diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggg.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggg.rs index 8f02ec240..bf22e27c7 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggg.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggg.rs @@ -10,9 +10,10 @@ use crate::harmonics::log_functions::{ /// Compute the singlet gluon-to-gluon anomalous dimension. /// -/// The routine is taken from [\[Falcioni:2024qpd\]][crate::bib::Falcioni2024qpd]. +/// The routine is taken from [\[Falcioni:2024qpd\]][crate::bib::Falcioni2024qpd], +/// with the update for :math:`n_f=6` from [\[Falcioni:2025hfz\]][crate::bib::Falcioni:2025hfz]. /// -/// These are approximations for fixed `nf` = 3, 4 and 5 based on the +/// These are approximations for fixed `nf` = 3, 4, 5 and 6 based on the /// first 10 even moments together with small-x/large-x constraints. /// The two sets providing the error estimate are called via `variation = 1` /// and `variation = 2`. Any other value of `variation` invokes their average. @@ -70,7 +71,7 @@ pub fn gamma_gg(c: &mut Cache, nf: u8, variation: u8) -> Complex { + x1L4cff * lm14m1(c) + x1L3cff * lm13m1(c); - // The selected approximations for nf = 3, 4, 5 + // The selected approximations for nf = 3, 4, 5, 6 let P3ggApp1: Complex; let P3ggApp2: Complex; if nf == 3 { @@ -147,8 +148,33 @@ pub fn gamma_gg(c: &mut Cache, nf: u8, variation: u8) -> Complex { + 2285.0 * lm11m1(c) + 19295.0 * lm12m1(c) - 13719.0 * lm12m2(c); + } else if nf == 6 { + P3ggApp1 = P3gg01 + - 476018.0 * (-(1. / (-1. + n).powu(2)) + 1. / n.powu(2)) + - 469289.0 * 1. / ((-1. + n) * n) + + 2049351.0 * (1. / (n + n.powu(2))) + - 1589000.0 * (1. / (2. + 3. * n + n.powu(2))) + + 3185549.0 * (-(1. / n.powu(2)) + 1. / (1. + n).powu(2)) + + 1994521.0 * 2. / n.powu(3) + + 527723.0 * (-(6. / n.powu(4))) + - 340674.0 * lm11m1(c) + + 22460.0 * lm12m1(c) + - 394556.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3ggApp2 = P3gg01 + - 709863.0 * (-(1. / (-1. + n).powu(2)) + 1. / n.powu(2)) + - 2134347.0 * 1. / ((-1. + n) * n) + + 1605315.0 * (1. / (2. + 3. * n + n.powu(2))) + + 360743.0 + * ((12. + 9. * n + n.powu(2)) + / (6. * n + 11. * n.powu(2) + 6. * n.powu(3) + n.powu(4))) + - 2426250.0 * (-(1. / n.powu(2)) + 1. / (1. + n).powu(2)) + + 230631.0 * 2. / n.powu(3) + - 185804.0 * (-(6. / n.powu(4))) + - 7992.9 * lm11m1(c) + + 15918.0 * lm12m1(c) + - 32771.0 * lm11m2(c); } else { - panic!("nf=6 is not available at N3LO"); + panic!("Select nf=3,..,6 for N3LO evolution"); } // We return (for now) one of the two error-band representatives @@ -196,7 +222,7 @@ mod tests { mom_list[(N - 2) / 2] } for variation in [0, 1, 2] { - for NF in [3, 4, 5] { + for NF in [3, 4, 5, 6] { for N in [2.0, 4.0, 6.0, 8.0, 10., 12., 14., 16., 18., 20.] { let mut c = Cache::new(cmplx!(N, 0.)); let test_value = gamma_gg(&mut c, NF, variation); diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs index 7eedf7a8f..20397eb51 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs @@ -8,9 +8,11 @@ use crate::harmonics::log_functions::{lm11, lm12, lm12m1, lm13, lm14, lm14m1, lm /// Compute the singlet quark-to-gluon anomalous dimension. /// -/// The routine is taken from [\[Falcioni:2024xyt\]][crate::bib::Falcioni2024xyt]. +/// The routine is taken from [\[Falcioni:2025hfz\]][crate::bib::Falcioni2025hfz]. +/// A previous version was given in [\[Falcioni:2024xyt\]][crate::bib::Falcioni2024xyt], +/// while a version based only on the lowest 10 moments was given in [\[Moch:2023tdj\]][crate::bib::Moch2023tdj]. /// -/// These are approximations for fixed `nf` = 3, 4 and 5 based on the +/// These are approximations for fixed `nf` = 3, 4, 5 and 6 based on the /// first 10 even moments together with small-x/large-x constraints. /// The two sets providing the error estimate are called via `variation = 1` /// and `variation = 2`. Any other value of `variation` invokes their average. @@ -48,80 +50,104 @@ pub fn gamma_gq(c: &mut Cache, nf: u8, variation: u8) -> Complex { + y1L4cff * lm14m1(c) + y1L5cff * lm15m1(c); - // The selected approximations for nf = 3, 4, 5 + // The selected approximations for nf = 3, 4, 5, 6 let P3gqApp1: Complex; let P3gqApp2: Complex; if nf == 3 { - P3gqApp1 = P3GQ01 + 6.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) - - 744384.0 * 1. / ((-1. + n) * n) - + 2453640.0 * 1. / n - - 1540404.0 * (2. / (1. + n) + 1. / (2. + n)) - + 1933026.0 * -1. / n.powu(2) - + 1142069.0 * 2. / n.powu(3) - + 162196.0 * -6. / n.powu(4) - - 2172.1 * lm13(c) - - 93264.1 * lm12(c) - - 786973.0 * lm11(c) - + 875383.0 * lm12m1(c); - P3gqApp2 = - P3GQ01 + 3.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + 142414.0 * 1. / ((-1. + n) * n) - - 326525.0 * 1. / n - + 2159787.0 * ((3. + n) / (2. + 3. * n + n.powu(2))) - - 289064.0 * -1. / n.powu(2) - - 176358.0 * 2. / n.powu(3) - + 156541.0 * -6. / n.powu(4) - + 9016.5 * lm13(c) - + 136063.0 * lm12(c) - + 829482.0 * lm11(c) - - 2359050.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp1 = P3GQ01 + 3.5 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 27891.0 * 1. / ((-1. + n) * n) + - 309124.0 * 1. / n + + 1056866.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 124735.0 * -1. / n.powu(2) + - 16246.0 * 2. / n.powu(3) + + 131175.0 * -6. / n.powu(4) + + 4970.1 * lm13(c) + + 60041.0 * lm12(c) + + 343181.0 * lm11(c) + - 958330.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp2 = P3GQ01 + 7.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 1139334.0 * 1. / ((-1. + n) * n) + + 143008.0 * 1. / n + - 290390.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 659492.0 * -1. / n.powu(2) + + 303685.0 * 2. / n.powu(3) + - 81867.0 * -6. / n.powu(4) + + 1811.8 * lm13(c) + - 465.9 * lm12(c) + - 51206.0 * lm11(c) + + 274249.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else if nf == 4 { - P3gqApp1 = P3GQ01 + 6.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) - - 743535.0 * 1. / ((-1. + n) * n) - + 2125286.0 * 1. / n - - 1332472.0 * (2. / (1. + n) + 1. / (2. + n)) - + 1631173.0 * -1. / n.powu(2) - + 1015255.0 * 2. / n.powu(3) - + 142612.0 * -6. / n.powu(4) - - 1910.4 * lm13(c) - - 80851.0 * lm12(c) - - 680219.0 * lm11(c) - + 752733.0 * lm12m1(c); - P3gqApp2 = - P3GQ01 + 3.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + 160568.0 * 1. / ((-1. + n) * n) - - 361207.0 * 1. / n - + 2048948.0 * ((3. + n) / (2. + 3. * n + n.powu(2))) - - 245963.0 * -1. / n.powu(2) - - 171312.0 * 2. / n.powu(3) - + 163099.0 * -6. / n.powu(4) - + 8132.2 * lm13(c) - + 124425.0 * lm12(c) - + 762435.0 * lm11(c) - - 2193335.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp1 = P3GQ01 + 3.5 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 8302.8 * 1. / ((-1. + n) * n) + - 347706.0 * 1. / n + + 1105306.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 127650.0 * -1. / n.powu(2) + - 29728.0 * 2. / n.powu(3) + + 137537.0 * -6. / n.powu(4) + + 4658.1 * lm13(c) + + 59205.0 * lm12(c) + + 345513.0 * lm11(c) + - 995120.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp2 = P3GQ01 + 7.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 1129822.0 * 1. / ((-1. + n) * n) + + 108527.0 * 1. / n + - 254166.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 667254.0 * -1. / n.powu(2) + + 293099.0 * 2. / n.powu(3) + - 77437.0 * -6. / n.powu(4) + + 1471.3 * lm13(c) + - 1850.3 * lm12(c) + - 52451.0 * lm11(c) + + 248634.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else if nf == 5 { - P3gqApp1 = P3GQ01 + 6.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) - - 785864.0 * 1. / ((-1. + n) * n) - + 285034.0 * 1. / n - - 131648.0 * (2. / (1. + n) + 1. / (2. + n)) - - 162840.0 * -1. / n.powu(2) - + 321220.0 * 2. / n.powu(3) - + 12688.0 * -6. / n.powu(4) - + 1423.4 * lm13(c) - + 1278.9 * lm12(c) - - 30919.9 * lm11(c) - + 47588.0 * lm12m1(c); - P3gqApp2 = - P3GQ01 + 3.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + 177094.0 * 1. / ((-1. + n) * n) - - 470694.0 * 1. / n - + 1348823.0 * ((3. + n) / (2. + 3. * n + n.powu(2))) - - 52985.0 * -1. / n.powu(2) - - 87354.0 * 2. / n.powu(3) - + 176885.0 * -6. / n.powu(4) - + 4748.8 * lm13(c) - + 65811.9 * lm12(c) - + 396390.0 * lm11(c) - - 1190212.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp1 = + P3GQ01 + 3.5 * bfkl1 * (-(1. / (-1. + n).powu(2))) + 14035.0 * 1. / ((-1. + n) * n) + - 384003.0 * 1. / n + + 1152711.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 126346.0 * -1. / n.powu(2) + - 42967.0 * 2. / n.powu(3) + + 144270.0 * -6. / n.powu(4) + + 4385.5 * lm13(c) + + 58688.0 * lm12(c) + + 348988.0 * lm11(c) + - 1031165.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3gqApp2 = P3GQ01 + 7.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 1117561.0 * 1. / ((-1. + n) * n) + + 76329.0 * 1. / n + - 218973.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 670799.0 * -1. / n.powu(2) + + 282763.0 * 2. / n.powu(3) + - 72633.0 * -6. / n.powu(4) + + 1170.0 * lm13(c) + - 2915.5 * lm12(c) + - 52548.0 * lm11(c) + + 223771.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + } else if nf == 6 { + P3gqApp1 = + P3GQ01 + 3.5 * bfkl1 * (-(1. / (-1. + n).powu(2))) + 39203.0 * 1. / ((-1. + n) * n) + - 417914.0 * 1. / n + + 1199042.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 120750.0 * -1. / n.powu(2) + - 55941.0 * 2. / n.powu(3) + + 151383.0 * -6. / n.powu(4) + + 4149.2 * lm13(c) + + 58466.0 * lm12(c) + + 353589.0 * lm11(c) + - 1066510.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + + P3gqApp2 = P3GQ01 + 7.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) + - 1102470.0 * 1. / ((-1. + n) * n) + + 46517.0 * 1. / n + - 184858.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + - 670056.0 * 1. / n.powu(2) + + 272689.0 * 2. / n.powu(3) + - 67453.0 * -6. / n.powu(4) + + 905.0 * lm13(c) + - 3686.2 * lm12(c) + - 51523.0 * lm11(c) + + 199594.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else { - panic!("nf=6 is not available at N3LO"); + panic!("Select nf = 3..6 for N3LO evolution"); } // We return (for now) one of the two error-band boundaries @@ -172,7 +198,7 @@ mod tests { mom_list[(N - 2) / 2] } for variation in [0, 1, 2] { - for NF in [3, 4, 5] { + for NF in [3, 4, 5, 6] { for N in [2.0, 4.0, 6.0, 8.0, 10., 12., 14., 16., 18., 20.] { let mut c = Cache::new(cmplx!(N, 0.)); let test_value = gamma_gq(&mut c, NF, variation); diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs index 70ae4d42b..db104ba19 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs @@ -7,9 +7,10 @@ use crate::harmonics::log_functions::{lm11m1, lm12m1, lm12m2, lm13m1, lm13m2, lm /// Compute the pure-singlet quark-to-quark anomalous dimension. /// -/// The routine is taken from [\[Falcioni:2023luc\]][crate::bib::Falcioni2023luc]. +/// The routine is taken from [\[Falcioni:2023luc\]][crate::bib::Falcioni2023luc], +/// with the update for :math:`n_f=6` from [\[Falcioni:2025hfz\]][crate::bib::Falcioni:2025hfz]. /// -/// These are approximations for fixed `nf` = 3, 4 and 5 based on the +/// These are approximations for fixed `nf` = 3, 4, 5 and 6 based on the /// first ten even moments together with small-x/large-x constraints. /// The two sets spanning the error estimate are called via `variation = 1` /// and `variation = 2`. Any other value of `variation` invokes their average. @@ -43,7 +44,7 @@ pub fn gamma_ps(c: &mut Cache, nf: u8, variation: u8) -> Complex { + y1L3cff * lm13m2(c) + y1L4cff * lm14m2(c); - // The selected approximations for nf = 3, 4, 5 + // The selected approximations for nf = 3, 4, 5, 6 let P3psApp1: Complex; let P3psApp2: Complex; if nf == 3 { @@ -103,8 +104,27 @@ pub fn gamma_ps(c: &mut Cache, nf: u8, variation: u8) -> Complex { + 804.5 * lm11m1(c) - 1760.8 * lm12m1(c) - 10295.0 * lm12m2(c); + } else if nf == 6 { + P3psApp1 = P3ps01 + 134701.0 * xm1lm1 + 518318.0 * 1. / ((-1. + n) * n) + - 195241.0 * (1. / n - n / (2. + 3. * n + n.powu(2))) + + 66517.0 * 1. / (6. + 5. * n + n.powu(2)) + + 658832.0 * (-(1. / n.powu(2)) + 1. / (1. + n).powu(2)) + + 19605.0 * 2. / n.powu(3) + + 76125.0 * -6. / n.powu(4) + - 4734.5 * lm11m1(c) + - 2035.2 * lm12m1(c) + + 1633.1 * lm12m2(c); + P3psApp2 = P3ps01 + 110032.0 * xm1lm1 + 341158.0 * 1. / ((-1. + n) * n) + - 365676.0 * 1. / (n + n.powu(2)) + + 25934.0 * 2. / (3. + 4. * n + n.powu(2)) + + 3614.4 * (-(1. / n.powu(2)) + 1. / (1. + n).powu(2)) + - 194868.0 * 2. / n.powu(3) + - 4172.2 * -6. / n.powu(4) + + 3924.3 * lm11m1(c) + - 1324.9 * lm12m1(c) + - 12520.0 * lm12m2(c); } else { - panic!("nf=6 is not available at N3LO"); + panic!("Select nf=3,..,6 for N3LO evolution"); } // We return (for now) one of the two error-band boundaries // or the present best estimate, their average @@ -162,7 +182,7 @@ mod tests { mom_list[(N - 2) / 2] } for variation in [0, 1, 2] { - for NF in [3, 4, 5] { + for NF in [3, 4, 5, 6] { for N in [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0] { let mut c = Cache::new(cmplx!(N, 0.)); let test_value = gamma_ps(&mut c, NF, variation); diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs index 19cb4dda9..9d805429a 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs @@ -8,9 +8,10 @@ use crate::harmonics::log_functions::{lm11, lm12, lm13, lm14, lm14m1, lm15, lm15 /// Compute the singlet gluon-to-quark anomalous dimension. /// -/// The routine is taken from [\[Falcioni:2023vqq\]][crate::bib::Falcioni2023vqq]. +/// The routine is taken from [\[Falcioni:2023vqq\]][crate::bib::Falcioni2023vqq], +/// with the update for :math:`n_f=6` from [\[Falcioni:2025hfz\]][crate::bib::Falcioni:2025hfz]. /// -/// These are approximations for fixed `nf` = 3, 4 and 5 based on the +/// These are approximations for fixed `nf` = 3, 4, 5 and 6 based on the /// first 10 even moments together with small-x/large-x constraints. /// The two sets indicating the error estimate are called via `variation = 1` /// and `variation = 2`. Any other value of `variation` invokes their average. @@ -45,7 +46,7 @@ pub fn gamma_qg(c: &mut Cache, nf: u8, variation: u8) -> Complex { + y1L4cff * lm14m1(c) + y1L5cff * lm15m1(c); - // The selected approximations for nf = 3, 4, 5 + // The selected approximations for nf = 3, 4, 5, 6 let P3qgApp1: Complex; let P3qgApp2: Complex; if nf == 3 { @@ -111,8 +112,31 @@ pub fn gamma_qg(c: &mut Cache, nf: u8, variation: u8) -> Complex { - 15553.0 * lm12(c) - 126212.0 * lm11(c) + 385995.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + } else if nf == 6 { + P3qgApp1 = + P3QG01 + 375000.0 * -(1. / (-1. + n).powu(2)) + 1595330.0 * -(1. / (-1. + n).powu(2)) + - 477729.0 * 1. / n + + 637552.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + + 931556.0 * -1. / n.powu(2) + - 387017.0 * 2. / n.powu(3) + + 187509.0 * -6. / n.powu(4) + + 715.5 * lm13(c) + + 20710.0 * lm12(c) + + 91373.0 * lm11(c) + - 346374.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3qgApp2 = + P3QG01 + 270000.0 * -(1. / (-1. + n).powu(2)) + 912695.0 * -(1. / (-1. + n).powu(2)) + - 200034.0 * 1. / n + - 189918.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + + 603114.0 * -1. / n.powu(2) + - 190521.0 * 2. / n.powu(3) + + 56661.0 * -6. / n.powu(4) + - 1224.3 * lm13(c) + - 16453.0 * lm12(c) + - 150856.0 * lm11(c) + + 410661.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else { - panic!("nf=6 is not available at N3LO"); + panic!("Select nf=3,..,6 for N3LO evolution"); } // We return (for now) one of the two error-band boundaries @@ -154,7 +178,7 @@ mod tests { mom_list[(N - 2) / 2] } for variation in [0, 1, 2] { - for NF in [3, 4, 5] { + for NF in [3, 4, 5, 6] { for N in [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0] { let mut c = Cache::new(cmplx!(N, 0.)); let test_value = gamma_qg(&mut c, NF, variation); From 3ab54eeae48305ccf91a59f5959774fc22ff6300 Mon Sep 17 00:00:00 2001 From: giacomomagni Date: Thu, 18 Dec 2025 14:50:09 +0100 Subject: [PATCH 4/6] extend tests and fix minor signs --- .../src/anomalous_dimensions/unpolarized/spacelike/as4.rs | 2 +- .../anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs | 5 ++--- .../anomalous_dimensions/unpolarized/spacelike/as4/gps.rs | 2 +- .../anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs | 4 ++-- .../unpolarized/space_like/as4/fhmruvv/gqg.py | 4 ++-- .../unpolarized/space_like/test_as4_fhmv.py | 6 +++--- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4.rs index 7f21e14e2..5505870f9 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4.rs @@ -44,7 +44,7 @@ mod tests { let NF = 5; let mut c = Cache::new(cmplx!(2., 0.)); // Numbers are coming from the python implementation. - let quark_refs: [f64; 3] = [0.053441, 0.225674, -0.118792]; + let quark_refs: [f64; 3] = [0.040173, 0.260616, -0.18027]; let gluon_refs: [f64; 3] = [-0.0300842, 0.283004, -0.343172]; for imod in [[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2]] { let g_singlet = gamma_singlet(&mut c, NF, imod); diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs index 20397eb51..71e3dc939 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/ggq.rs @@ -134,12 +134,11 @@ pub fn gamma_gq(c: &mut Cache, nf: u8, variation: u8) -> Complex { + 58466.0 * lm12(c) + 353589.0 * lm11(c) - 1066510.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); - P3gqApp2 = P3GQ01 + 7.0 * bfkl1 * (-(1. / (-1. + n).powu(2))) - 1102470.0 * 1. / ((-1. + n) * n) + 46517.0 * 1. / n - 184858.0 * (3. + n) / (2. + 3. * n + n.powu(2)) - - 670056.0 * 1. / n.powu(2) + - 670056.0 * -1. / n.powu(2) + 272689.0 * 2. / n.powu(3) - 67453.0 * -6. / n.powu(4) + 905.0 * lm13(c) @@ -206,7 +205,7 @@ mod tests { f64, test_value, cmplx!(gq3_moment(N as usize, NF as f64), 0.), - rel = 4e-4 + rel = if NF != 6 { 4e-4 } else { 2e-3 } ); } } diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs index db104ba19..b50470ef3 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gps.rs @@ -190,7 +190,7 @@ mod tests { f64, test_value, cmplx!(qq3ps_moment(N as usize, NF as f64), 0.), - rel = 4e-4 + rel = if NF != 6 { 4e-4 } else { 2e-3 } ); } } diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs index 9d805429a..4bf3ae18d 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs @@ -114,7 +114,7 @@ pub fn gamma_qg(c: &mut Cache, nf: u8, variation: u8) -> Complex { + 385995.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else if nf == 6 { P3qgApp1 = - P3QG01 + 375000.0 * -(1. / (-1. + n).powu(2)) + 1595330.0 * -(1. / (-1. + n).powu(2)) + P3QG01 + 375000.0 * -(1. / (-1. + n).powu(2)) + 1595330.0 * 1. / ((-1. + n) * n) - 477729.0 * 1. / n + 637552.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + 931556.0 * -1. / n.powu(2) @@ -125,7 +125,7 @@ pub fn gamma_qg(c: &mut Cache, nf: u8, variation: u8) -> Complex { + 91373.0 * lm11(c) - 346374.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); P3qgApp2 = - P3QG01 + 270000.0 * -(1. / (-1. + n).powu(2)) + 912695.0 * -(1. / (-1. + n).powu(2)) + P3QG01 + 270000.0 * -(1. / (-1. + n).powu(2)) + 912695.0 * 1. / ((-1. + n) * n) - 200034.0 * 1. / n - 189918.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + 603114.0 * -1. / n.powu(2) diff --git a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py index 191543d49..11f3e99f3 100644 --- a/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py +++ b/src/ekore/anomalous_dimensions/unpolarized/space_like/as4/fhmruvv/gqg.py @@ -157,7 +157,7 @@ def gamma_qg(n, nf, cache, variation): P3qgApp1 = ( P3QG01 + 375000.0 * -(1 / (-1 + n) ** 2) - + 1595330.0 * -(1 / (-1 + n) ** 2) + + 1595330.0 * 1 / ((-1 + n) * n) - 477729.0 * 1 / n + 637552.0 * (3 + n) / (2 + 3 * n + n**2) + 931556.0 * -1 / n**2 @@ -171,7 +171,7 @@ def gamma_qg(n, nf, cache, variation): P3qgApp2 = ( P3QG01 + 270000.0 * -(1 / (-1 + n) ** 2) - + 912695.0 * -(1 / (-1 + n) ** 2) + + 912695.0 * 1 / ((-1 + n) * n) - 200034.0 * 1 / n - 189918.0 * (3 + n) / (2 + 3 * n + n**2) + 603114.0 * -1 / n**2 diff --git a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py index d9cc3f40c..d9ea408c2 100644 --- a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py +++ b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py @@ -170,11 +170,11 @@ def gq3_moment(N, nf): for N in [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]: cache = h.cache.reset() for variation in [0, 1, 2]: - for nf in [3, 4, 5]: + for nf in [3, 4, 5, 6]: np.testing.assert_allclose( gps.gamma_ps(N, nf, cache, variation), qq3ps_moment(N, nf), - rtol=4e-4, + rtol=4e-4 if nf != 6 else 2e-3, ) np.testing.assert_allclose( gqg.gamma_qg(N, nf, cache, variation), @@ -190,7 +190,7 @@ def gq3_moment(N, nf): np.testing.assert_allclose( ggq.gamma_gq(N, nf, cache, variation), gq3_moment(N, nf), - rtol=4e-4, + rtol=4e-4 if nf != 6 else 2e-3, ) with pytest.raises(NotImplementedError): From baf38bd60f950a2046492155adcba4b1298b662c Mon Sep 17 00:00:00 2001 From: giacomomagni Date: Thu, 18 Dec 2025 14:51:46 +0100 Subject: [PATCH 5/6] lint --- .../unpolarized/spacelike/as4/gqg.rs | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs index 4bf3ae18d..4f6d17b4b 100644 --- a/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs +++ b/crates/ekore/src/anomalous_dimensions/unpolarized/spacelike/as4/gqg.rs @@ -113,28 +113,26 @@ pub fn gamma_qg(c: &mut Cache, nf: u8, variation: u8) -> Complex { - 126212.0 * lm11(c) + 385995.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else if nf == 6 { - P3qgApp1 = - P3QG01 + 375000.0 * -(1. / (-1. + n).powu(2)) + 1595330.0 * 1. / ((-1. + n) * n) - - 477729.0 * 1. / n - + 637552.0 * (3. + n) / (2. + 3. * n + n.powu(2)) - + 931556.0 * -1. / n.powu(2) - - 387017.0 * 2. / n.powu(3) - + 187509.0 * -6. / n.powu(4) - + 715.5 * lm13(c) - + 20710.0 * lm12(c) - + 91373.0 * lm11(c) - - 346374.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); - P3qgApp2 = - P3QG01 + 270000.0 * -(1. / (-1. + n).powu(2)) + 912695.0 * 1. / ((-1. + n) * n) - - 200034.0 * 1. / n - - 189918.0 * (3. + n) / (2. + 3. * n + n.powu(2)) - + 603114.0 * -1. / n.powu(2) - - 190521.0 * 2. / n.powu(3) - + 56661.0 * -6. / n.powu(4) - - 1224.3 * lm13(c) - - 16453.0 * lm12(c) - - 150856.0 * lm11(c) - + 410661.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3qgApp1 = P3QG01 + 375000.0 * -(1. / (-1. + n).powu(2)) + 1595330.0 * 1. / ((-1. + n) * n) + - 477729.0 * 1. / n + + 637552.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + + 931556.0 * -1. / n.powu(2) + - 387017.0 * 2. / n.powu(3) + + 187509.0 * -6. / n.powu(4) + + 715.5 * lm13(c) + + 20710.0 * lm12(c) + + 91373.0 * lm11(c) + - 346374.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); + P3qgApp2 = P3QG01 + 270000.0 * -(1. / (-1. + n).powu(2)) + 912695.0 * 1. / ((-1. + n) * n) + - 200034.0 * 1. / n + - 189918.0 * (3. + n) / (2. + 3. * n + n.powu(2)) + + 603114.0 * -1. / n.powu(2) + - 190521.0 * 2. / n.powu(3) + + 56661.0 * -6. / n.powu(4) + - 1224.3 * lm13(c) + - 16453.0 * lm12(c) + - 150856.0 * lm11(c) + + 410661.0 * (S1 - n * (ZETA2 - S2)) / n.powu(2); } else { panic!("Select nf=3,..,6 for N3LO evolution"); } From b200b2688102571ca16b1dc4ec2af2c7b09b9511 Mon Sep 17 00:00:00 2001 From: Giacomo Magni <39065935+giacomomagni@users.noreply.github.com> Date: Fri, 19 Dec 2025 17:53:00 +0100 Subject: [PATCH 6/6] Update tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py Co-authored-by: Felix Hekhorn --- .../unpolarized/space_like/test_as4_fhmv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py index d9ea408c2..93200bd74 100644 --- a/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py +++ b/tests/ekore/anomalous_dimensions/unpolarized/space_like/test_as4_fhmv.py @@ -45,7 +45,7 @@ def test_momentum_conservation(): # total np.testing.assert_allclose( g_singlet[:, 0, 0] + g_singlet[:, 1, 0], - [0.040173 + 0.0j, 0.260616, -0.18027], + [0.040173, 0.260616, -0.18027], atol=1e-6, ) np.testing.assert_allclose(