From 9f95d0f989b0d2094f3138c55bdea18b409a5756 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 17:58:04 -0600 Subject: [PATCH 01/14] Use ruff to lint the source code and tests --- .ruff.toml | 5 + drudge/drudge.py | 8 +- drudge/nuclear.py | 6 +- drudge/utils.py | 1 - pyproject.toml | 7 + tests/genquad_test.py | 1 - tests/name_injection_test.py | 4 +- tests/spin_one_half_test.py | 1 - uv.lock | 765 +++++++++++++++++++++-------------- 9 files changed, 486 insertions(+), 312 deletions(-) create mode 100644 .ruff.toml diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..871e690f --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,5 @@ +[lint] +ignore = ["E741"] + +[format] +docstring-code-format = true diff --git a/drudge/drudge.py b/drudge/drudge.py index 93ec7f79..42d371f9 100644 --- a/drudge/drudge.py +++ b/drudge/drudge.py @@ -15,7 +15,7 @@ from IPython.display import Math, display from pyspark import RDD, SparkContext from sympy import ( - IndexedBase, Symbol, Indexed, Wild, symbols, sympify, Expr, Add, Matrix, Mul + IndexedBase, Symbol, Indexed, Wild, sympify, Expr, Add, Matrix, Mul ) from sympy.concrete.summations import eval_sum_symbolic @@ -967,7 +967,7 @@ def _decr_vecs(vecs: typing.Tuple[Vec]): @staticmethod def _restore(term: Term, decr_vars=None): - if decr_vars != None: + if decr_vars is not None: restore_vars = {decr_var: var for var, decr_var in decr_vars.items()} else: suffix_index = -len(_DECR_SUFFIX) @@ -987,7 +987,8 @@ def _restore(term: Term, decr_vars=None): name[:suffix_index], **var._assumptions ) - func = lambda x: x.xreplace(restore_vars) + def func(x): + return x.xreplace(restore_vars) new_vecs = tuple( Vec(label=vec.label[0], indices=vec.indices) @@ -1066,6 +1067,7 @@ def subst( .. doctest:: + >>> from sympy import symbols >>> dr = Drudge(SparkContext()) >>> r = Range('R') >>> a, b = dr.set_dumms(r, symbols('a b c d e f'))[:2] diff --git a/drudge/nuclear.py b/drudge/nuclear.py index b4f9a704..00b43203 100644 --- a/drudge/nuclear.py +++ b/drudge/nuclear.py @@ -1412,11 +1412,11 @@ def _sum_2_3j_to_delta(expr: Sum, resolvers, sums_dict): indices0 = wigner_3js[0].indices indices1 = wigner_3js[1].indices - j1, m1 = indices0[0].j, indices0[0].m - j2, m2 = indices0[1].j, indices0[1].m - j3, m3 = indices0[2].j, indices0[2].m + m1 = indices0[0].m + m2 = indices0[1].m assert m1 == indices1[0].m assert m2 == indices1[1].m + j3, m3 = indices0[2].j, indices0[2].m j4, m4 = indices1[2].j, indices1[2].m return KroneckerDelta(j3, j4) * KroneckerDelta( diff --git a/drudge/utils.py b/drudge/utils.py index a688e4d3..bf1c1292 100644 --- a/drudge/utils.py +++ b/drudge/utils.py @@ -11,7 +11,6 @@ sympify, Symbol, Expr, SympifyError, count_ops, default_sort_key, AtomicExpr, Integer, S ) -from sympy.core.assumptions import ManagedProperties from sympy.core.sympify import CantSympify diff --git a/pyproject.toml b/pyproject.toml index 12cf0f63..cbbee879 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,3 +51,10 @@ Homepage = "https://github.com/DrudgeCAS/drudge" [project.scripts] drudge = "drudge.drs:main" + +[dependency-groups] +dev = [ + "pytest", + "ruff>=0.14.5", + "pre-commit", +] diff --git a/tests/genquad_test.py b/tests/genquad_test.py index a163db1b..2d21fe92 100644 --- a/tests/genquad_test.py +++ b/tests/genquad_test.py @@ -1,6 +1,5 @@ """Tests for the general quadratic algebra drudge.""" -import pytest from sympy import Integer from drudge import Vec, GenQuadLatticeDrudge diff --git a/tests/name_injection_test.py b/tests/name_injection_test.py index cc6ff24d..06df9721 100644 --- a/tests/name_injection_test.py +++ b/tests/name_injection_test.py @@ -17,5 +17,5 @@ def test_drudge_injects_names(): dr.inject_names(suffix='_') - assert string_name_ == string_name - assert one_ == 1 + assert string_name_ == string_name # noqa: F821 + assert one_ == 1 # noqa: F821 diff --git a/tests/spin_one_half_test.py b/tests/spin_one_half_test.py index fffc8a18..9816f7d5 100644 --- a/tests/spin_one_half_test.py +++ b/tests/spin_one_half_test.py @@ -92,7 +92,6 @@ def test_spin_one_half_particle_hole_drudge_has_basic_properties(parthole): """Test basic properties of spin one-half particle-hole drudge.""" dr = parthole - p = dr.names assert dr.orig_ham.n_terms == 8 + 4 * 2 ** 4 diff --git a/uv.lock b/uv.lock index 9ef0cfcf..d5967e10 100644 --- a/uv.lock +++ b/uv.lock @@ -1,49 +1,50 @@ version = 1 +revision = 3 requires-python = ">=3.12" [[package]] name = "alabaster" version = "1.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 }, + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] [[package]] name = "asttokens" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, ] [[package]] name = "babel" version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] [[package]] name = "certifi" version = "2025.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386 } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216 }, + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, ] [[package]] @@ -53,153 +54,171 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 }, - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230 }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043 }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446 }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101 }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948 }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422 }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499 }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928 }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302 }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320 }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487 }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049 }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793 }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300 }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244 }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828 }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926 }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773 }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013 }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593 }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354 }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480 }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584 }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443 }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437 }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 }, +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655 }, - { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223 }, - { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366 }, - { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104 }, - { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830 }, - { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854 }, - { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670 }, - { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501 }, - { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173 }, - { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822 }, - { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543 }, - { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326 }, - { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008 }, - { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196 }, - { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819 }, - { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350 }, - { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644 }, - { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468 }, - { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187 }, - { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699 }, - { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580 }, - { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366 }, - { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342 }, - { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995 }, - { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640 }, - { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636 }, - { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939 }, - { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580 }, - { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870 }, - { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797 }, - { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224 }, - { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086 }, - { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400 }, - { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175 }, +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, ] [[package]] name = "debugpy" version = "1.8.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129 } +sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522 }, - { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417 }, - { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130 }, - { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053 }, - { url = "https://files.pythonhosted.org/packages/50/76/597e5cb97d026274ba297af8d89138dfd9e695767ba0e0895edb20963f40/debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464", size = 2538386 }, - { url = "https://files.pythonhosted.org/packages/5f/60/ce5c34fcdfec493701f9d1532dba95b21b2f6394147234dce21160bd923f/debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088", size = 4292100 }, - { url = "https://files.pythonhosted.org/packages/e8/95/7873cf2146577ef71d2a20bf553f12df865922a6f87b9e8ee1df04f01785/debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83", size = 5277002 }, - { url = "https://files.pythonhosted.org/packages/46/11/18c79a1cee5ff539a94ec4aa290c1c069a5580fd5cfd2fb2e282f8e905da/debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420", size = 5319047 }, - { url = "https://files.pythonhosted.org/packages/de/45/115d55b2a9da6de812696064ceb505c31e952c5d89c4ed1d9bb983deec34/debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1", size = 2536899 }, - { url = "https://files.pythonhosted.org/packages/5a/73/2aa00c7f1f06e997ef57dc9b23d61a92120bec1437a012afb6d176585197/debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f", size = 4268254 }, - { url = "https://files.pythonhosted.org/packages/86/b5/ed3e65c63c68a6634e3ba04bd10255c8e46ec16ebed7d1c79e4816d8a760/debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670", size = 5277203 }, - { url = "https://files.pythonhosted.org/packages/b0/26/394276b71c7538445f29e792f589ab7379ae70fd26ff5577dfde71158e96/debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c", size = 5318493 }, - { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210 }, + { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522, upload-time = "2025-09-17T16:33:38.466Z" }, + { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417, upload-time = "2025-09-17T16:33:41.299Z" }, + { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130, upload-time = "2025-09-17T16:33:43.554Z" }, + { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053, upload-time = "2025-09-17T16:33:53.033Z" }, + { url = "https://files.pythonhosted.org/packages/50/76/597e5cb97d026274ba297af8d89138dfd9e695767ba0e0895edb20963f40/debugpy-1.8.17-cp313-cp313-macosx_15_0_universal2.whl", hash = "sha256:857c1dd5d70042502aef1c6d1c2801211f3ea7e56f75e9c335f434afb403e464", size = 2538386, upload-time = "2025-09-17T16:33:54.594Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/ce5c34fcdfec493701f9d1532dba95b21b2f6394147234dce21160bd923f/debugpy-1.8.17-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:3bea3b0b12f3946e098cce9b43c3c46e317b567f79570c3f43f0b96d00788088", size = 4292100, upload-time = "2025-09-17T16:33:56.353Z" }, + { url = "https://files.pythonhosted.org/packages/e8/95/7873cf2146577ef71d2a20bf553f12df865922a6f87b9e8ee1df04f01785/debugpy-1.8.17-cp313-cp313-win32.whl", hash = "sha256:e34ee844c2f17b18556b5bbe59e1e2ff4e86a00282d2a46edab73fd7f18f4a83", size = 5277002, upload-time = "2025-09-17T16:33:58.231Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/18c79a1cee5ff539a94ec4aa290c1c069a5580fd5cfd2fb2e282f8e905da/debugpy-1.8.17-cp313-cp313-win_amd64.whl", hash = "sha256:6c5cd6f009ad4fca8e33e5238210dc1e5f42db07d4b6ab21ac7ffa904a196420", size = 5319047, upload-time = "2025-09-17T16:34:00.586Z" }, + { url = "https://files.pythonhosted.org/packages/de/45/115d55b2a9da6de812696064ceb505c31e952c5d89c4ed1d9bb983deec34/debugpy-1.8.17-cp314-cp314-macosx_15_0_universal2.whl", hash = "sha256:045290c010bcd2d82bc97aa2daf6837443cd52f6328592698809b4549babcee1", size = 2536899, upload-time = "2025-09-17T16:34:02.657Z" }, + { url = "https://files.pythonhosted.org/packages/5a/73/2aa00c7f1f06e997ef57dc9b23d61a92120bec1437a012afb6d176585197/debugpy-1.8.17-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:b69b6bd9dba6a03632534cdf67c760625760a215ae289f7489a452af1031fe1f", size = 4268254, upload-time = "2025-09-17T16:34:04.486Z" }, + { url = "https://files.pythonhosted.org/packages/86/b5/ed3e65c63c68a6634e3ba04bd10255c8e46ec16ebed7d1c79e4816d8a760/debugpy-1.8.17-cp314-cp314-win32.whl", hash = "sha256:5c59b74aa5630f3a5194467100c3b3d1c77898f9ab27e3f7dc5d40fc2f122670", size = 5277203, upload-time = "2025-09-17T16:34:06.65Z" }, + { url = "https://files.pythonhosted.org/packages/b0/26/394276b71c7538445f29e792f589ab7379ae70fd26ff5577dfde71158e96/debugpy-1.8.17-cp314-cp314-win_amd64.whl", hash = "sha256:893cba7bb0f55161de4365584b025f7064e1f88913551bcd23be3260b231429c", size = 5318493, upload-time = "2025-09-17T16:34:08.483Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" }, ] [[package]] name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "docutils" version = "0.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, ] [[package]] @@ -223,6 +242,13 @@ docs = [ { name = "sphinx" }, ] +[package.dev-dependencies] +dev = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "ruff" }, +] + [package.metadata] requires-dist = [ { name = "dummyrdd", git = "https://github.com/DrudgeCAS/DummyRDD.git?rev=master" }, @@ -234,6 +260,14 @@ requires-dist = [ { name = "sphinx", marker = "extra == 'docs'" }, { name = "sympy", specifier = ">=1.14" }, ] +provides-extras = ["docs", "dev"] + +[package.metadata.requires-dev] +dev = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "ruff", specifier = ">=0.14.5" }, +] [[package]] name = "dummyrdd" @@ -244,36 +278,54 @@ source = { git = "https://github.com/DrudgeCAS/DummyRDD.git?rev=master#0f53b93b6 name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, +] + +[[package]] +name = "identify" +version = "2.6.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, ] [[package]] name = "idna" version = "3.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, ] [[package]] name = "imagesize" version = "1.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, ] [[package]] name = "iniconfig" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] [[package]] @@ -295,9 +347,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, ] [[package]] @@ -316,9 +368,9 @@ dependencies = [ { name = "stack-data" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932 } +sdist = { url = "https://files.pythonhosted.org/packages/2a/34/29b18c62e39ee2f7a6a3bba7efd952729d8aadd45ca17efc34453b717665/ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731", size = 4396932, upload-time = "2025-09-29T10:55:53.948Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170 }, + { url = "https://files.pythonhosted.org/packages/48/c5/d5e07995077e48220269c28a221e168c91123ad5ceee44d548f54a057fc0/ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196", size = 616170, upload-time = "2025-09-29T10:55:47.676Z" }, ] [[package]] @@ -328,9 +380,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393 } +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074 }, + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, ] [[package]] @@ -340,9 +392,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, ] [[package]] @@ -352,9 +404,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] @@ -368,9 +420,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, ] [[package]] @@ -381,47 +433,47 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, ] [[package]] name = "markupsafe" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, ] [[package]] @@ -431,45 +483,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] [[package]] name = "parso" version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] [[package]] @@ -479,27 +540,43 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] [[package]] name = "platformdirs" version = "4.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632 } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651 }, + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/49/7845c2d7bf6474efd8e27905b51b11e6ce411708c91e829b93f324de9929/pre_commit-4.4.0.tar.gz", hash = "sha256:f0233ebab440e9f17cabbb558706eb173d19ace965c68cdce2c081042b4fab15", size = 197501, upload-time = "2025-11-08T21:12:11.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, + { url = "https://files.pythonhosted.org/packages/27/11/574fe7d13acf30bfd0a8dd7fa1647040f2b8064f13f43e8c963b1e65093b/pre_commit-4.4.0-py2.py3-none-any.whl", hash = "sha256:b35ea52957cbf83dcc5d8ee636cbead8624e3a15fbfa61a370e42158ac8a5813", size = 226049, upload-time = "2025-11-08T21:12:10.228Z" }, ] [[package]] @@ -509,80 +586,80 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] [[package]] name = "psutil" version = "7.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/ec/7b8e6b9b1d22708138630ef34c53ab2b61032c04f16adfdbb96791c8c70c/psutil-7.1.2.tar.gz", hash = "sha256:aa225cdde1335ff9684708ee8c72650f6598d5ed2114b9a7c5802030b1785018", size = 487424 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/d9/b56cc9f883140ac10021a8c9b0f4e16eed1ba675c22513cdcbce3ba64014/psutil-7.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0cc5c6889b9871f231ed5455a9a02149e388fffcb30b607fb7a8896a6d95f22e", size = 238575 }, - { url = "https://files.pythonhosted.org/packages/36/eb/28d22de383888deb252c818622196e709da98816e296ef95afda33f1c0a2/psutil-7.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8e9e77a977208d84aa363a4a12e0f72189d58bbf4e46b49aae29a2c6e93ef206", size = 239297 }, - { url = "https://files.pythonhosted.org/packages/89/5d/220039e2f28cc129626e54d63892ab05c0d56a29818bfe7268dcb5008932/psutil-7.1.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d9623a5e4164d2220ecceb071f4b333b3c78866141e8887c072129185f41278", size = 280420 }, - { url = "https://files.pythonhosted.org/packages/ba/7a/286f0e1c167445b2ef4a6cbdfc8c59fdb45a5a493788950cf8467201dc73/psutil-7.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:364b1c10fe4ed59c89ec49e5f1a70da353b27986fa8233b4b999df4742a5ee2f", size = 283049 }, - { url = "https://files.pythonhosted.org/packages/aa/cc/7eb93260794a42e39b976f3a4dde89725800b9f573b014fac142002a5c98/psutil-7.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f101ef84de7e05d41310e3ccbdd65a6dd1d9eed85e8aaf0758405d022308e204", size = 248713 }, - { url = "https://files.pythonhosted.org/packages/ab/1a/0681a92b53366e01f0a099f5237d0c8a2f79d322ac589cccde5e30c8a4e2/psutil-7.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:20c00824048a95de67f00afedc7b08b282aa08638585b0206a9fb51f28f1a165", size = 244644 }, - { url = "https://files.pythonhosted.org/packages/56/9e/f1c5c746b4ed5320952acd3002d3962fe36f30524c00ea79fdf954cc6779/psutil-7.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e09cfe92aa8e22b1ec5e2d394820cf86c5dff6367ac3242366485dfa874d43bc", size = 238640 }, - { url = "https://files.pythonhosted.org/packages/32/ee/fd26216a735395cc25c3899634e34aeb41fb1f3dbb44acc67d9e594be562/psutil-7.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa6342cf859c48b19df3e4aa170e4cfb64aadc50b11e06bb569c6c777b089c9e", size = 239303 }, - { url = "https://files.pythonhosted.org/packages/3c/cd/7d96eaec4ef7742b845a9ce2759a2769ecce4ab7a99133da24abacbc9e41/psutil-7.1.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:625977443498ee7d6c1e63e93bacca893fd759a66c5f635d05e05811d23fb5ee", size = 281717 }, - { url = "https://files.pythonhosted.org/packages/bc/1a/7f0b84bdb067d35fe7fade5fff888408688caf989806ce2d6dae08c72dd5/psutil-7.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a24bcd7b7f2918d934af0fb91859f621b873d6aa81267575e3655cd387572a7", size = 284575 }, - { url = "https://files.pythonhosted.org/packages/de/05/7820ef8f7b275268917e0c750eada5834581206d9024ca88edce93c4b762/psutil-7.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:329f05610da6380982e6078b9d0881d9ab1e9a7eb7c02d833bfb7340aa634e31", size = 249491 }, - { url = "https://files.pythonhosted.org/packages/db/9a/58de399c7cb58489f08498459ff096cd76b3f1ddc4f224ec2c5ef729c7d0/psutil-7.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:7b04c29e3c0c888e83ed4762b70f31e65c42673ea956cefa8ced0e31e185f582", size = 244880 }, - { url = "https://files.pythonhosted.org/packages/ae/89/b9f8d47ddbc52d7301fc868e8224e5f44ed3c7f55e6d0f54ecaf5dd9ff5e/psutil-7.1.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9ba5c19f2d46203ee8c152c7b01df6eec87d883cfd8ee1af2ef2727f6b0f814", size = 237244 }, - { url = "https://files.pythonhosted.org/packages/c8/7a/8628c2f6b240680a67d73d8742bb9ff39b1820a693740e43096d5dcb01e5/psutil-7.1.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a486030d2fe81bec023f703d3d155f4823a10a47c36784c84f1cc7f8d39bedb", size = 238101 }, - { url = "https://files.pythonhosted.org/packages/30/28/5e27f4d5a0e347f8e3cc16cd7d35533dbce086c95807f1f0e9cd77e26c10/psutil-7.1.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3efd8fc791492e7808a51cb2b94889db7578bfaea22df931424f874468e389e3", size = 258675 }, - { url = "https://files.pythonhosted.org/packages/e5/5c/79cf60c9acf36d087f0db0f82066fca4a780e97e5b3a2e4c38209c03d170/psutil-7.1.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2aeb9b64f481b8eabfc633bd39e0016d4d8bbcd590d984af764d80bf0851b8a", size = 260203 }, - { url = "https://files.pythonhosted.org/packages/f7/03/0a464404c51685dcb9329fdd660b1721e076ccd7b3d97dee066bcc9ffb15/psutil-7.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:8e17852114c4e7996fe9da4745c2bdef001ebbf2f260dec406290e66628bdb91", size = 246714 }, - { url = "https://files.pythonhosted.org/packages/6a/32/97ca2090f2f1b45b01b6aa7ae161cfe50671de097311975ca6eea3e7aabc/psutil-7.1.2-cp37-abi3-win_arm64.whl", hash = "sha256:3e988455e61c240cc879cb62a008c2699231bf3e3d061d7fce4234463fd2abb4", size = 243742 }, +sdist = { url = "https://files.pythonhosted.org/packages/cd/ec/7b8e6b9b1d22708138630ef34c53ab2b61032c04f16adfdbb96791c8c70c/psutil-7.1.2.tar.gz", hash = "sha256:aa225cdde1335ff9684708ee8c72650f6598d5ed2114b9a7c5802030b1785018", size = 487424, upload-time = "2025-10-25T10:46:34.931Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/d9/b56cc9f883140ac10021a8c9b0f4e16eed1ba675c22513cdcbce3ba64014/psutil-7.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0cc5c6889b9871f231ed5455a9a02149e388fffcb30b607fb7a8896a6d95f22e", size = 238575, upload-time = "2025-10-25T10:46:38.728Z" }, + { url = "https://files.pythonhosted.org/packages/36/eb/28d22de383888deb252c818622196e709da98816e296ef95afda33f1c0a2/psutil-7.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8e9e77a977208d84aa363a4a12e0f72189d58bbf4e46b49aae29a2c6e93ef206", size = 239297, upload-time = "2025-10-25T10:46:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/89/5d/220039e2f28cc129626e54d63892ab05c0d56a29818bfe7268dcb5008932/psutil-7.1.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d9623a5e4164d2220ecceb071f4b333b3c78866141e8887c072129185f41278", size = 280420, upload-time = "2025-10-25T10:46:44.122Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7a/286f0e1c167445b2ef4a6cbdfc8c59fdb45a5a493788950cf8467201dc73/psutil-7.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:364b1c10fe4ed59c89ec49e5f1a70da353b27986fa8233b4b999df4742a5ee2f", size = 283049, upload-time = "2025-10-25T10:46:47.095Z" }, + { url = "https://files.pythonhosted.org/packages/aa/cc/7eb93260794a42e39b976f3a4dde89725800b9f573b014fac142002a5c98/psutil-7.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f101ef84de7e05d41310e3ccbdd65a6dd1d9eed85e8aaf0758405d022308e204", size = 248713, upload-time = "2025-10-25T10:46:49.573Z" }, + { url = "https://files.pythonhosted.org/packages/ab/1a/0681a92b53366e01f0a099f5237d0c8a2f79d322ac589cccde5e30c8a4e2/psutil-7.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:20c00824048a95de67f00afedc7b08b282aa08638585b0206a9fb51f28f1a165", size = 244644, upload-time = "2025-10-25T10:46:51.924Z" }, + { url = "https://files.pythonhosted.org/packages/56/9e/f1c5c746b4ed5320952acd3002d3962fe36f30524c00ea79fdf954cc6779/psutil-7.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e09cfe92aa8e22b1ec5e2d394820cf86c5dff6367ac3242366485dfa874d43bc", size = 238640, upload-time = "2025-10-25T10:46:54.089Z" }, + { url = "https://files.pythonhosted.org/packages/32/ee/fd26216a735395cc25c3899634e34aeb41fb1f3dbb44acc67d9e594be562/psutil-7.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa6342cf859c48b19df3e4aa170e4cfb64aadc50b11e06bb569c6c777b089c9e", size = 239303, upload-time = "2025-10-25T10:46:56.932Z" }, + { url = "https://files.pythonhosted.org/packages/3c/cd/7d96eaec4ef7742b845a9ce2759a2769ecce4ab7a99133da24abacbc9e41/psutil-7.1.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:625977443498ee7d6c1e63e93bacca893fd759a66c5f635d05e05811d23fb5ee", size = 281717, upload-time = "2025-10-25T10:46:59.116Z" }, + { url = "https://files.pythonhosted.org/packages/bc/1a/7f0b84bdb067d35fe7fade5fff888408688caf989806ce2d6dae08c72dd5/psutil-7.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a24bcd7b7f2918d934af0fb91859f621b873d6aa81267575e3655cd387572a7", size = 284575, upload-time = "2025-10-25T10:47:00.944Z" }, + { url = "https://files.pythonhosted.org/packages/de/05/7820ef8f7b275268917e0c750eada5834581206d9024ca88edce93c4b762/psutil-7.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:329f05610da6380982e6078b9d0881d9ab1e9a7eb7c02d833bfb7340aa634e31", size = 249491, upload-time = "2025-10-25T10:47:03.174Z" }, + { url = "https://files.pythonhosted.org/packages/db/9a/58de399c7cb58489f08498459ff096cd76b3f1ddc4f224ec2c5ef729c7d0/psutil-7.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:7b04c29e3c0c888e83ed4762b70f31e65c42673ea956cefa8ced0e31e185f582", size = 244880, upload-time = "2025-10-25T10:47:05.228Z" }, + { url = "https://files.pythonhosted.org/packages/ae/89/b9f8d47ddbc52d7301fc868e8224e5f44ed3c7f55e6d0f54ecaf5dd9ff5e/psutil-7.1.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9ba5c19f2d46203ee8c152c7b01df6eec87d883cfd8ee1af2ef2727f6b0f814", size = 237244, upload-time = "2025-10-25T10:47:07.086Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7a/8628c2f6b240680a67d73d8742bb9ff39b1820a693740e43096d5dcb01e5/psutil-7.1.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a486030d2fe81bec023f703d3d155f4823a10a47c36784c84f1cc7f8d39bedb", size = 238101, upload-time = "2025-10-25T10:47:09.523Z" }, + { url = "https://files.pythonhosted.org/packages/30/28/5e27f4d5a0e347f8e3cc16cd7d35533dbce086c95807f1f0e9cd77e26c10/psutil-7.1.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3efd8fc791492e7808a51cb2b94889db7578bfaea22df931424f874468e389e3", size = 258675, upload-time = "2025-10-25T10:47:11.082Z" }, + { url = "https://files.pythonhosted.org/packages/e5/5c/79cf60c9acf36d087f0db0f82066fca4a780e97e5b3a2e4c38209c03d170/psutil-7.1.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2aeb9b64f481b8eabfc633bd39e0016d4d8bbcd590d984af764d80bf0851b8a", size = 260203, upload-time = "2025-10-25T10:47:13.226Z" }, + { url = "https://files.pythonhosted.org/packages/f7/03/0a464404c51685dcb9329fdd660b1721e076ccd7b3d97dee066bcc9ffb15/psutil-7.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:8e17852114c4e7996fe9da4745c2bdef001ebbf2f260dec406290e66628bdb91", size = 246714, upload-time = "2025-10-25T10:47:15.093Z" }, + { url = "https://files.pythonhosted.org/packages/6a/32/97ca2090f2f1b45b01b6aa7ae161cfe50671de097311975ca6eea3e7aabc/psutil-7.1.2-cp37-abi3-win_arm64.whl", hash = "sha256:3e988455e61c240cc879cb62a008c2699231bf3e3d061d7fce4234463fd2abb4", size = 243742, upload-time = "2025-10-25T10:47:17.302Z" }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] [[package]] name = "py4j" version = "0.10.9.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/f2/b34255180c72c36ff7097f7c2cdca02abcbd89f5eebf7c7c41262a9a0637/py4j-0.10.9.7.tar.gz", hash = "sha256:0b6e5315bb3ada5cf62ac651d107bb2ebc02def3dee9d9548e3baac644ea8dbb", size = 1508234 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/f2/b34255180c72c36ff7097f7c2cdca02abcbd89f5eebf7c7c41262a9a0637/py4j-0.10.9.7.tar.gz", hash = "sha256:0b6e5315bb3ada5cf62ac651d107bb2ebc02def3dee9d9548e3baac644ea8dbb", size = 1508234, upload-time = "2022-08-12T22:49:09.792Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/30/a58b32568f1623aaad7db22aa9eafc4c6c194b429ff35bdc55ca2726da47/py4j-0.10.9.7-py2.py3-none-any.whl", hash = "sha256:85defdfd2b2376eb3abf5ca6474b51ab7e0de341c75a02f46dc9b5976f5a5c1b", size = 200481 }, + { url = "https://files.pythonhosted.org/packages/10/30/a58b32568f1623aaad7db22aa9eafc4c6c194b429ff35bdc55ca2726da47/py4j-0.10.9.7-py2.py3-none-any.whl", hash = "sha256:85defdfd2b2376eb3abf5ca6474b51ab7e0de341c75a02f46dc9b5976f5a5c1b", size = 200481, upload-time = "2022-08-12T22:49:07.05Z" }, ] [[package]] name = "pycparser" version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] @@ -592,7 +669,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py4j" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/62/36e50d38e5fe158e97cddec983b44f9417b1e205b02320e3c463b5f802fa/pyspark-3.5.6.tar.gz", hash = "sha256:f8b1c4360e41ab398c64904fae08740503bcb6bd389457d659fa6d9f2952cc48", size = 317359167 } +sdist = { url = "https://files.pythonhosted.org/packages/2e/62/36e50d38e5fe158e97cddec983b44f9417b1e205b02320e3c463b5f802fa/pyspark-3.5.6.tar.gz", hash = "sha256:f8b1c4360e41ab398c64904fae08740503bcb6bd389457d659fa6d9f2952cc48", size = 317359167, upload-time = "2025-05-27T08:24:20.82Z" } [[package]] name = "pytest" @@ -605,9 +682,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750 }, + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, ] [[package]] @@ -617,9 +694,55 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] @@ -629,40 +752,40 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, - { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436 }, - { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301 }, - { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197 }, - { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275 }, - { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469 }, - { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961 }, - { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282 }, - { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468 }, - { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394 }, - { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964 }, - { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029 }, - { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541 }, - { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197 }, - { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175 }, - { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427 }, - { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929 }, - { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193 }, - { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388 }, - { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316 }, - { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472 }, - { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401 }, - { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170 }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/84a13459c51da6cec1b7b1dc1a47e6db6da50b77ad7fd9c145842750a011/pyzmq-27.1.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:93ad4b0855a664229559e45c8d23797ceac03183c7b6f5b4428152a6b06684a5", size = 1122436, upload-time = "2025-09-08T23:08:20.801Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/94414759a69a26c3dd674570a81813c46a078767d931a6c70ad29fc585cb/pyzmq-27.1.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:fbb4f2400bfda24f12f009cba62ad5734148569ff4949b1b6ec3b519444342e6", size = 1156301, upload-time = "2025-09-08T23:08:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ad/15906493fd40c316377fd8a8f6b1f93104f97a752667763c9b9c1b71d42d/pyzmq-27.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:e343d067f7b151cfe4eb3bb796a7752c9d369eed007b91231e817071d2c2fec7", size = 1341197, upload-time = "2025-09-08T23:08:24.286Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d343f3ce13db53a54cb8946594e567410b2125394dafcc0268d8dda027e0/pyzmq-27.1.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:08363b2011dec81c354d694bdecaef4770e0ae96b9afea70b3f47b973655cc05", size = 897275, upload-time = "2025-09-08T23:08:26.063Z" }, + { url = "https://files.pythonhosted.org/packages/69/2d/d83dd6d7ca929a2fc67d2c3005415cdf322af7751d773524809f9e585129/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d54530c8c8b5b8ddb3318f481297441af102517602b569146185fa10b63f4fa9", size = 660469, upload-time = "2025-09-08T23:08:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/9822a7af117f4bc0f1952dbe9ef8358eb50a24928efd5edf54210b850259/pyzmq-27.1.0-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f3afa12c392f0a44a2414056d730eebc33ec0926aae92b5ad5cf26ebb6cc128", size = 847961, upload-time = "2025-09-08T23:08:29.672Z" }, + { url = "https://files.pythonhosted.org/packages/9a/12/f003e824a19ed73be15542f172fd0ec4ad0b60cf37436652c93b9df7c585/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c65047adafe573ff023b3187bb93faa583151627bc9c51fc4fb2c561ed689d39", size = 1650282, upload-time = "2025-09-08T23:08:31.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/e82d788ed58e9a23995cee70dbc20c9aded3d13a92d30d57ec2291f1e8a3/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:90e6e9441c946a8b0a667356f7078d96411391a3b8f80980315455574177ec97", size = 2024468, upload-time = "2025-09-08T23:08:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/d9/94/2da0a60841f757481e402b34bf4c8bf57fa54a5466b965de791b1e6f747d/pyzmq-27.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:add071b2d25f84e8189aaf0882d39a285b42fa3853016ebab234a5e78c7a43db", size = 1885394, upload-time = "2025-09-08T23:08:35.51Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6f/55c10e2e49ad52d080dc24e37adb215e5b0d64990b57598abc2e3f01725b/pyzmq-27.1.0-cp313-cp313t-win32.whl", hash = "sha256:7ccc0700cfdf7bd487bea8d850ec38f204478681ea02a582a8da8171b7f90a1c", size = 574964, upload-time = "2025-09-08T23:08:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/87/4d/2534970ba63dd7c522d8ca80fb92777f362c0f321900667c615e2067cb29/pyzmq-27.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:8085a9fba668216b9b4323be338ee5437a235fe275b9d1610e422ccc279733e2", size = 641029, upload-time = "2025-09-08T23:08:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/87/45/19efbb3000956e82d0331bafca5d9ac19ea2857722fa2caacefb6042f39d/pyzmq-27.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce980af330231615756acd5154f29813d553ea555485ae712c491cd483df6b7a", size = 1341197, upload-time = "2025-09-08T23:08:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/48/43/d72ccdbf0d73d1343936296665826350cb1e825f92f2db9db3e61c2162a2/pyzmq-27.1.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1779be8c549e54a1c38f805e56d2a2e5c009d26de10921d7d51cfd1c8d4632ea", size = 897175, upload-time = "2025-09-08T23:08:46.601Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2e/a483f73a10b65a9ef0161e817321d39a770b2acf8bcf3004a28d90d14a94/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7200bb0f03345515df50d99d3db206a0a6bee1955fbb8c453c76f5bf0e08fb96", size = 660427, upload-time = "2025-09-08T23:08:48.187Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d2/5f36552c2d3e5685abe60dfa56f91169f7a2d99bbaf67c5271022ab40863/pyzmq-27.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01c0e07d558b06a60773744ea6251f769cd79a41a97d11b8bf4ab8f034b0424d", size = 847929, upload-time = "2025-09-08T23:08:49.76Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2a/404b331f2b7bf3198e9945f75c4c521f0c6a3a23b51f7a4a401b94a13833/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:80d834abee71f65253c91540445d37c4c561e293ba6e741b992f20a105d69146", size = 1650193, upload-time = "2025-09-08T23:08:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/1c/0b/f4107e33f62a5acf60e3ded67ed33d79b4ce18de432625ce2fc5093d6388/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:544b4e3b7198dde4a62b8ff6685e9802a9a1ebf47e77478a5eb88eca2a82f2fd", size = 2024388, upload-time = "2025-09-08T23:08:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/0d/01/add31fe76512642fd6e40e3a3bd21f4b47e242c8ba33efb6809e37076d9b/pyzmq-27.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cedc4c68178e59a4046f97eca31b148ddcf51e88677de1ef4e78cf06c5376c9a", size = 1885316, upload-time = "2025-09-08T23:08:55.702Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/a5f38970f9bf07cee96128de79590bb354917914a9be11272cfc7ff26af0/pyzmq-27.1.0-cp314-cp314t-win32.whl", hash = "sha256:1f0b2a577fd770aa6f053211a55d1c47901f4d537389a034c690291485e5fe92", size = 587472, upload-time = "2025-09-08T23:08:58.18Z" }, + { url = "https://files.pythonhosted.org/packages/70/d8/78b1bad170f93fcf5e3536e70e8fadac55030002275c9a29e8f5719185de/pyzmq-27.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:19c9468ae0437f8074af379e986c5d3d7d7bfe033506af442e8c879732bedbe0", size = 661401, upload-time = "2025-09-08T23:08:59.802Z" }, + { url = "https://files.pythonhosted.org/packages/81/d6/4bfbb40c9a0b42fc53c7cf442f6385db70b40f74a783130c5d0a5aa62228/pyzmq-27.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dc5dbf68a7857b59473f7df42650c621d7e8923fb03fa74a526890f4d33cc4d7", size = 575170, upload-time = "2025-09-08T23:09:01.418Z" }, ] [[package]] @@ -675,36 +798,62 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] name = "roman-numerals-py" version = "3.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 } +sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017, upload-time = "2025-02-22T07:34:54.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742, upload-time = "2025-02-22T07:34:52.422Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/fa/fbb67a5780ae0f704876cb8ac92d6d76da41da4dc72b7ed3565ab18f2f52/ruff-0.14.5.tar.gz", hash = "sha256:8d3b48d7d8aad423d3137af7ab6c8b1e38e4de104800f0d596990f6ada1a9fc1", size = 5615944, upload-time = "2025-11-13T19:58:51.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 }, + { url = "https://files.pythonhosted.org/packages/68/31/c07e9c535248d10836a94e4f4e8c5a31a1beed6f169b31405b227872d4f4/ruff-0.14.5-py3-none-linux_armv6l.whl", hash = "sha256:f3b8248123b586de44a8018bcc9fefe31d23dda57a34e6f0e1e53bd51fd63594", size = 13171630, upload-time = "2025-11-13T19:57:54.894Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/283c62516dca697cd604c2796d1487396b7a436b2f0ecc3fd412aca470e0/ruff-0.14.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f7a75236570318c7a30edd7f5491945f0169de738d945ca8784500b517163a72", size = 13413925, upload-time = "2025-11-13T19:57:59.181Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f3/aa319f4afc22cb6fcba2b9cdfc0f03bbf747e59ab7a8c5e90173857a1361/ruff-0.14.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d146132d1ee115f8802356a2dc9a634dbf58184c51bff21f313e8cd1c74899a", size = 12574040, upload-time = "2025-11-13T19:58:02.056Z" }, + { url = "https://files.pythonhosted.org/packages/f9/7f/cb5845fcc7c7e88ed57f58670189fc2ff517fe2134c3821e77e29fd3b0c8/ruff-0.14.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2380596653dcd20b057794d55681571a257a42327da8894b93bbd6111aa801f", size = 13009755, upload-time = "2025-11-13T19:58:05.172Z" }, + { url = "https://files.pythonhosted.org/packages/21/d2/bcbedbb6bcb9253085981730687ddc0cc7b2e18e8dc13cf4453de905d7a0/ruff-0.14.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d1fa985a42b1f075a098fa1ab9d472b712bdb17ad87a8ec86e45e7fa6273e68", size = 12937641, upload-time = "2025-11-13T19:58:08.345Z" }, + { url = "https://files.pythonhosted.org/packages/a4/58/e25de28a572bdd60ffc6bb71fc7fd25a94ec6a076942e372437649cbb02a/ruff-0.14.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88f0770d42b7fa02bbefddde15d235ca3aa24e2f0137388cc15b2dcbb1f7c7a7", size = 13610854, upload-time = "2025-11-13T19:58:11.419Z" }, + { url = "https://files.pythonhosted.org/packages/7d/24/43bb3fd23ecee9861970978ea1a7a63e12a204d319248a7e8af539984280/ruff-0.14.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3676cb02b9061fee7294661071c4709fa21419ea9176087cb77e64410926eb78", size = 15061088, upload-time = "2025-11-13T19:58:14.551Z" }, + { url = "https://files.pythonhosted.org/packages/23/44/a022f288d61c2f8c8645b24c364b719aee293ffc7d633a2ca4d116b9c716/ruff-0.14.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b595bedf6bc9cab647c4a173a61acf4f1ac5f2b545203ba82f30fcb10b0318fb", size = 14734717, upload-time = "2025-11-13T19:58:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/58/81/5c6ba44de7e44c91f68073e0658109d8373b0590940efe5bd7753a2585a3/ruff-0.14.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f55382725ad0bdb2e8ee2babcbbfb16f124f5a59496a2f6a46f1d9d99d93e6e2", size = 14028812, upload-time = "2025-11-13T19:58:20.533Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ef/41a8b60f8462cb320f68615b00299ebb12660097c952c600c762078420f8/ruff-0.14.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7497d19dce23976bdaca24345ae131a1d38dcfe1b0850ad8e9e6e4fa321a6e19", size = 13825656, upload-time = "2025-11-13T19:58:23.345Z" }, + { url = "https://files.pythonhosted.org/packages/7c/00/207e5de737fdb59b39eb1fac806904fe05681981b46d6a6db9468501062e/ruff-0.14.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:410e781f1122d6be4f446981dd479470af86537fb0b8857f27a6e872f65a38e4", size = 13959922, upload-time = "2025-11-13T19:58:26.537Z" }, + { url = "https://files.pythonhosted.org/packages/bc/7e/fa1f5c2776db4be405040293618846a2dece5c70b050874c2d1f10f24776/ruff-0.14.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c01be527ef4c91a6d55e53b337bfe2c0f82af024cc1a33c44792d6844e2331e1", size = 12932501, upload-time = "2025-11-13T19:58:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/67/d8/d86bf784d693a764b59479a6bbdc9515ae42c340a5dc5ab1dabef847bfaa/ruff-0.14.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f66e9bb762e68d66e48550b59c74314168ebb46199886c5c5aa0b0fbcc81b151", size = 12927319, upload-time = "2025-11-13T19:58:32.923Z" }, + { url = "https://files.pythonhosted.org/packages/ac/de/ee0b304d450ae007ce0cb3e455fe24fbcaaedae4ebaad6c23831c6663651/ruff-0.14.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d93be8f1fa01022337f1f8f3bcaa7ffee2d0b03f00922c45c2207954f351f465", size = 13206209, upload-time = "2025-11-13T19:58:35.952Z" }, + { url = "https://files.pythonhosted.org/packages/33/aa/193ca7e3a92d74f17d9d5771a765965d2cf42c86e6f0fd95b13969115723/ruff-0.14.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c135d4b681f7401fe0e7312017e41aba9b3160861105726b76cfa14bc25aa367", size = 13953709, upload-time = "2025-11-13T19:58:39.002Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f1/7119e42aa1d3bf036ffc9478885c2e248812b7de9abea4eae89163d2929d/ruff-0.14.5-py3-none-win32.whl", hash = "sha256:c83642e6fccfb6dea8b785eb9f456800dcd6a63f362238af5fc0c83d027dd08b", size = 12925808, upload-time = "2025-11-13T19:58:42.779Z" }, + { url = "https://files.pythonhosted.org/packages/3b/9d/7c0a255d21e0912114784e4a96bf62af0618e2190cae468cd82b13625ad2/ruff-0.14.5-py3-none-win_amd64.whl", hash = "sha256:9d55d7af7166f143c94eae1db3312f9ea8f95a4defef1979ed516dbb38c27621", size = 14331546, upload-time = "2025-11-13T19:58:45.691Z" }, + { url = "https://files.pythonhosted.org/packages/e5/80/69756670caedcf3b9be597a6e12276a6cf6197076eb62aad0c608f8efce0/ruff-0.14.5-py3-none-win_arm64.whl", hash = "sha256:4b700459d4649e2594b31f20a9de33bc7c19976d4746d8d0798ad959621d64a4", size = 13433331, upload-time = "2025-11-13T19:58:48.434Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "snowballstemmer" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575 } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274 }, + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, ] [[package]] @@ -730,63 +879,63 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 } +sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 }, + { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741, upload-time = "2025-03-02T22:31:56.836Z" }, ] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, ] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, ] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, ] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, ] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, ] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] [[package]] @@ -798,9 +947,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] [[package]] @@ -810,53 +959,67 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] [[package]] name = "tornado" version = "6.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821 } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563 }, - { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729 }, - { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295 }, - { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644 }, - { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878 }, - { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549 }, - { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973 }, - { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954 }, - { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023 }, - { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427 }, - { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456 }, + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] [[package]] name = "urllib3" version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185 } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.35.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795 }, + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] [[package]] name = "wcwidth" version = "0.2.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, ] From 6b2387a50fffe726c441a200aca165a9cd6a66c9 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 18:08:37 -0600 Subject: [PATCH 02/14] Make linting pass --- .ruff.toml | 5 +++++ docs/conf.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.ruff.toml b/.ruff.toml index 871e690f..b82772c2 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,5 +1,10 @@ +exclude = ["deps"] + [lint] ignore = ["E741"] [format] docstring-code-format = true + +[lint.per-file-ignores] +"*.ipynb" = ["F403", "F405"] diff --git a/docs/conf.py b/docs/conf.py index 41a7997a..0bf53d2d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -62,7 +62,7 @@ # built documents. # # The short X.Y version. -from drudge import __version__ +from drudge import __version__ # noqa: E402 version = __version__ # The full version, including alpha/beta/rc tags. release = __version__ From f59f775d9b0bc3bb33bcf55f224d4fd2da94a4c3 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 18:33:33 -0600 Subject: [PATCH 03/14] Update the ruff configuration --- .ruff.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ruff.toml b/.ruff.toml index b82772c2..1b506446 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,3 +1,5 @@ +target-version = "py312" +line-length = 79 exclude = ["deps"] [lint] From 74c9bc3d129600e8166154b11aae8eed96b6b582 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 19:39:16 -0600 Subject: [PATCH 04/14] Format the source code --- drudge/__init__.py | 106 +++--- drudge/_tceparser.py | 88 ++--- drudge/bcs.py | 87 +++-- drudge/canon.py | 51 ++- drudge/clifford.py | 24 +- drudge/drs.py | 97 +++-- drudge/drudge.py | 868 +++++++++++++++++++++++-------------------- drudge/fock.py | 463 +++++++++++++---------- drudge/genquad.py | 147 ++++---- drudge/nuclear.py | 465 +++++++++++------------ drudge/report.py | 85 ++--- drudge/su2.py | 43 ++- drudge/term.py | 594 ++++++++++++++--------------- drudge/utils.py | 114 +++--- drudge/wick.py | 79 ++-- 15 files changed, 1709 insertions(+), 1602 deletions(-) diff --git a/drudge/__init__.py b/drudge/__init__.py index a5df06c0..c4c35230 100644 --- a/drudge/__init__.py +++ b/drudge/__init__.py @@ -10,9 +10,19 @@ from .drudge import Tensor, TensorDef, Drudge from .wick import WickDrudge from .fock import ( - CR, AN, FERMI, BOSE, FockDrudge, GenMBDrudge, PartHoleDrudge, - UP, DOWN, SpinOneHalfGenDrudge, SpinOneHalfPartHoleDrudge, - RestrictedPartHoleDrudge, BogoliubovDrudge + CR, + AN, + FERMI, + BOSE, + FockDrudge, + GenMBDrudge, + PartHoleDrudge, + UP, + DOWN, + SpinOneHalfGenDrudge, + SpinOneHalfPartHoleDrudge, + RestrictedPartHoleDrudge, + BogoliubovDrudge, ) from .genquad import GenQuadDrudge, GenQuadLatticeDrudge from .su2 import SU2LatticeDrudge @@ -22,59 +32,65 @@ from .report import Report, ScalarLatexPrinter from .utils import sum_, prod_, Stopwatch, CallByIndex, InvariantIndexable -__version__ = '0.11.1' +__version__ = "0.11.1" __all__ = [ # Canonpy. - 'Perm', - 'Group', - + "Perm", + "Group", + # # Vec. - 'Vec', - + "Vec", + # # Term. - 'Range', - 'Term', - + "Range", + "Term", + # # Canon. - 'IDENT', - 'NEG', - 'CONJ', - + "IDENT", + "NEG", + "CONJ", + # # Drudge. - 'Tensor', - 'TensorDef', - 'Drudge', - + "Tensor", + "TensorDef", + "Drudge", + # # Different problem-specific drudges. # # Base Wick algebra. - 'WickDrudge', - + "WickDrudge", + # # Many-body theories. - 'CR', 'AN', 'FERMI', 'BOSE', - 'FockDrudge', - 'GenMBDrudge', 'PartHoleDrudge', - 'UP', 'DOWN', - 'SpinOneHalfGenDrudge', 'SpinOneHalfPartHoleDrudge', - 'RestrictedPartHoleDrudge', - 'BogoliubovDrudge', - + "CR", + "AN", + "FERMI", + "BOSE", + "FockDrudge", + "GenMBDrudge", + "PartHoleDrudge", + "UP", + "DOWN", + "SpinOneHalfGenDrudge", + "SpinOneHalfPartHoleDrudge", + "RestrictedPartHoleDrudge", + "BogoliubovDrudge", + # # Other algebraic systems. - 'GenQuadDrudge', - 'GenQuadLatticeDrudge', - 'SU2LatticeDrudge', - 'CliffordDrudge', - 'ReducedBCSDrudge', - 'NuclearBogoliubovDrudge', - 'inner_by_delta', - + "GenQuadDrudge", + "GenQuadLatticeDrudge", + "SU2LatticeDrudge", + "CliffordDrudge", + "ReducedBCSDrudge", + "NuclearBogoliubovDrudge", + "inner_by_delta", + # # Small user utilities. - 'sum_', - 'prod_', - 'Stopwatch', - 'CallByIndex', - 'InvariantIndexable', - 'Report', - 'ScalarLatexPrinter' + "sum_", + "prod_", + "Stopwatch", + "CallByIndex", + "InvariantIndexable", + "Report", + "ScalarLatexPrinter", ] diff --git a/drudge/_tceparser.py b/drudge/_tceparser.py index 3c42f242..a64b2bc0 100644 --- a/drudge/_tceparser.py +++ b/drudge/_tceparser.py @@ -36,10 +36,12 @@ def parse_tce_out(tce_out, range_cb, base_cb): continue free_vars = collections.defaultdict(set) - return list(itertools.chain.from_iterable( - _parse_tce_line(line, range_cb, base_cb, free_vars) - for line in lines - )), free_vars + return list( + itertools.chain.from_iterable( + _parse_tce_line(line, range_cb, base_cb, free_vars) + for line in lines + ) + ), free_vars # @@ -49,20 +51,16 @@ def parse_tce_out(tce_out, range_cb, base_cb): def _parse_tce_line(line, range_cb, base_cb, free_vars): - """Parse a TCE output line into a list of terms. - """ + """Parse a TCE output line into a list of terms.""" # Get the initial part in the bracket and the actual term specification # part after it. - match_res = re.match( - r'^\s*\[(?P.*)\](?P[^\[\]]+)$', - line - ) + match_res = re.match(r"^\s*\[(?P.*)\](?P[^\[\]]+)$", line) if match_res is None: - raise ValueError('Invalid TCE output line', line) + raise ValueError("Invalid TCE output line", line) - factors_str = match_res.group('factors').strip() - term_str = match_res.group('term').strip() + factors_str = match_res.group("factors").strip() + term_str = match_res.group("term").strip() # Get the actual term in its raw form. raw_term = _parse_term(term_str, range_cb, base_cb, free_vars) @@ -77,7 +75,7 @@ def _parse_tce_line(line, range_cb, base_cb, free_vars): # -_SUM_BASE = 'Sum' +_SUM_BASE = "Sum" # @@ -86,15 +84,14 @@ def _parse_tce_line(line, range_cb, base_cb, free_vars): def _parse_term(term_str, range_cb, base_cb, free_vars): - """Parse the term string after the square bracket into a Term. - """ + """Parse the term string after the square bracket into a Term.""" # First break the string into indexed values. summed_vars, idxed_vals = _break_into_idxed(term_str) sums = tuple((Symbol(i), range_cb(i)) for i in summed_vars) dumms = {i[0] for i in sums} - amp = sympify('1') + amp = sympify("1") for base, indices in idxed_vals: indices_symbs = tuple(Symbol(i) for i in indices) @@ -118,24 +115,23 @@ def _break_into_idxed(term_str): """ # First break it into fields separated by the multiplication asterisk. - fields = (i for i in re.split(r'\s*\*\s*', term_str) if len(i) > 0) + fields = (i for i in re.split(r"\s*\*\s*", term_str) if len(i) > 0) # Parse the fields one-by-one. idxed_vals = [] for field in fields: - # Break the field into the base part and the indices part. - match_res = re.match( - r'(?P\w+)\s*\((?P.*)\)', field - ) + match_res = re.match(r"(?P\w+)\s*\((?P.*)\)", field) if match_res is None: - raise ValueError('Invalid indexed value', field) + raise ValueError("Invalid indexed value", field) # Generate the final result. - idxed_vals.append(( - match_res.group('base'), - tuple(match_res.group('indices').split()) - )) + idxed_vals.append( + ( + match_res.group("base"), + tuple(match_res.group("indices").split()), + ) + ) continue @@ -162,37 +158,41 @@ def _gen_terms(factors_str, raw_term): """ # The regular expression for a factor. - factor_regex = r'\s*'.join([ - r'(?P[+-])', - r'(?P[0-9.]+)', - r'(?:\*\s*P\((?P[^=>]*)=>(?P[^)]*)\))?', - ]) + r'\s*' - mismatch_regex = r'.' - regex = '(?P{})|(?P{})'.format( + factor_regex = ( + r"\s*".join( + [ + r"(?P[+-])", + r"(?P[0-9.]+)", + r"(?:\*\s*P\((?P[^=>]*)=>(?P[^)]*)\))?", + ] + ) + + r"\s*" + ) + mismatch_regex = r"." + regex = "(?P{})|(?P{})".format( factor_regex, mismatch_regex ) # Iterate over the factors. terms = [] for match_res in re.finditer(regex, factors_str): - # Test if the result matches a factor. - if match_res.group('factor') is None: - raise ValueError('Invalid factor string', factors_str) + if match_res.group("factor") is None: + raise ValueError("Invalid factor string", factors_str) # The value of the factor. - factor_value = nsimplify(''.join( - match_res.group('sign', 'factor_number') - ), rational=True) + factor_value = nsimplify( + "".join(match_res.group("sign", "factor_number")), rational=True + ) # Get the substitution for the permutation of the indices. - if match_res.group('perm_from') is not None: - from_vars = match_res.group('perm_from').split() - to_vars = match_res.group('perm_to').split() + if match_res.group("perm_from") is not None: + from_vars = match_res.group("perm_from").split() + to_vars = match_res.group("perm_to").split() subs = { Symbol(from_var): Symbol(to_var) for from_var, to_var in zip(from_vars, to_vars) - } + } else: subs = {} diff --git a/drudge/bcs.py b/drudge/bcs.py index 6f215918..e588264b 100644 --- a/drudge/bcs.py +++ b/drudge/bcs.py @@ -43,28 +43,40 @@ class ReducedBCSDrudge(SU2LatticeDrudge): """ - DEFAULT_CARTAN = Vec('N') - DEFAULT_RAISE = Vec(r'P^\dagger') - DEFAULT_LOWER = Vec('P') + DEFAULT_CARTAN = Vec("N") + DEFAULT_RAISE = Vec(r"P^\dagger") + DEFAULT_LOWER = Vec("P") def __init__( - self, ctx, - part_range=Range('V', 0, Symbol('nv')), - part_dumms=PartHoleDrudge.DEFAULT_PART_DUMMS, - hole_range=Range('O', 0, Symbol('no')), - hole_dumms=PartHoleDrudge.DEFAULT_HOLE_DUMMS, - all_orb_dumms=PartHoleDrudge.DEFAULT_ORB_DUMMS, - energies=IndexedBase('epsilon'), interact=IndexedBase('G'), - cartan=DEFAULT_CARTAN, raise_=DEFAULT_RAISE, lower=DEFAULT_LOWER, - root=Integer(2), norm=Integer(1), shift=Integer(-1), - **kwargs + self, + ctx, + part_range=Range("V", 0, Symbol("nv")), + part_dumms=PartHoleDrudge.DEFAULT_PART_DUMMS, + hole_range=Range("O", 0, Symbol("no")), + hole_dumms=PartHoleDrudge.DEFAULT_HOLE_DUMMS, + all_orb_dumms=PartHoleDrudge.DEFAULT_ORB_DUMMS, + energies=IndexedBase("epsilon"), + interact=IndexedBase("G"), + cartan=DEFAULT_CARTAN, + raise_=DEFAULT_RAISE, + lower=DEFAULT_LOWER, + root=Integer(2), + norm=Integer(1), + shift=Integer(-1), + **kwargs, ): """Initialize the drudge object.""" # Initialize the base su2 problem. super().__init__( - ctx, cartan=cartan, raise_=raise_, lower=lower, root=root, - norm=norm, shift=shift, **kwargs + ctx, + cartan=cartan, + raise_=raise_, + lower=lower, + root=root, + norm=norm, + shift=shift, + **kwargs, ) # Set the range and dummies. @@ -76,9 +88,9 @@ def __init__( self.all_orb_dumms = tuple(all_orb_dumms) self.set_name(*self.all_orb_dumms) - self.add_resolver({ - i: (self.part_range, self.hole_range) for i in all_orb_dumms - }) + self.add_resolver( + {i: (self.part_range, self.hole_range) for i in all_orb_dumms} + ) # Make additional name definition for the operators. self.set_name(cartan, lower, Pdag=raise_) @@ -86,8 +98,9 @@ def __init__( # Create the underlying particle-hole drudge with spin. Note that this # drudge is only use internally for VEV evaluation. ph_dr = SpinOneHalfPartHoleDrudge( - ctx, part_orb=(part_range, part_dumms), - hole_orb=(hole_range, hole_dumms) + ctx, + part_orb=(part_range, part_dumms), + hole_orb=(hole_range, hole_dumms), ) self._ph_dr = ph_dr @@ -98,9 +111,10 @@ def __init__( gen_idx, gen_idx2 = self.all_orb_dumms[:2] cartan_def = self.define( - cartan, gen_idx, - cr[gen_idx, up] * an[gen_idx, up] + - cr[gen_idx, down] * an[gen_idx, down] + cartan, + gen_idx, + cr[gen_idx, up] * an[gen_idx, up] + + cr[gen_idx, down] * an[gen_idx, down], ) raise_def = self.define( raise_, gen_idx, cr[gen_idx, up] * cr[gen_idx, down] @@ -108,19 +122,17 @@ def __init__( lower_def = self.define( lower, gen_idx, an[gen_idx, down] * an[gen_idx, up] ) - self._defs = [ - cartan_def, raise_def, lower_def - ] + self._defs = [cartan_def, raise_def, lower_def] # Define the Hamiltonian. ham = self.einst( - energies[gen_idx] * cartan[gen_idx] + - interact[gen_idx, gen_idx2] * raise_[gen_idx] * lower[gen_idx2] + energies[gen_idx] * cartan[gen_idx] + + interact[gen_idx, gen_idx2] * raise_[gen_idx] * lower[gen_idx2] ) self.ham = ham.simplify() # Set additional tensor methods. - self.set_tensor_method('eval_vev', self.eval_vev) + self.set_tensor_method("eval_vev", self.eval_vev) # # Additional customization of the simplification @@ -137,10 +149,14 @@ def normal_order(self, terms, **kwargs): """ noed = super().normal_order(terms, **kwargs) - return noed.filter(functools.partial( - _nonzero_by_cartan, - raise_=self.raise_, cartan=self.cartan, lower=self.lower - )) + return noed.filter( + functools.partial( + _nonzero_by_cartan, + raise_=self.raise_, + cartan=self.cartan, + lower=self.lower, + ) + ) # # Vacuum expectation value @@ -152,10 +168,7 @@ def _transl2fermi(self, tensor: Tensor): This is an internally utility. The resulted tensor has the internal fermion drudge object as its owner. """ - return Tensor( - self._ph_dr, - tensor.subst_all(self._defs).terms - ) + return Tensor(self._ph_dr, tensor.subst_all(self._defs).terms) def eval_vev(self, tensor: Tensor): r"""Evaluate the vacuum expectation value. diff --git a/drudge/canon.py b/drudge/canon.py index 39d2f9f1..4edae9c1 100644 --- a/drudge/canon.py +++ b/drudge/canon.py @@ -59,10 +59,12 @@ def int_colour(self): int_colour = [None for _ in self.colours] - group_res = enumerate(itertools.groupby( - sorted((v, i) for i, v in enumerate(self.colours)), - lambda x: x[0] - )) + group_res = enumerate( + itertools.groupby( + sorted((v, i) for i, v in enumerate(self.colours)), + lambda x: x[0], + ) + ) for i, v in group_res: _, g = v @@ -130,16 +132,14 @@ def canon_factors(sums, factors, symms): # Sums are guaranteed to be in the initial segment of the nodes, but they # might not be at the beginning any more after the canonicalization. - sums_res = [sums[i] for i in node_order if - eldag.colours[i][0] == _SUM] + sums_res = [sums[i] for i in node_order if eldag.colours[i][0] == _SUM] coeff = 1 factors_res = [] for i, v in enumerate(factors): - factor = v[0] - if hasattr(factor, 'indices'): + if hasattr(factor, "indices"): indices = factor.indices is_indexed = True else: @@ -168,7 +168,7 @@ def canon_factors(sums, factors, symms): # TODO: Allow vectors to have their own dagger form, maybe. if if_vector: raise ValueError( - 'Vector', factor, 'cannot have conjugation symmetry' + "Vector", factor, "cannot have conjugation symmetry" ) factor_res = conjugate(factor_res) @@ -227,9 +227,9 @@ def _build_eldag(sums, factors, symms): free_var_keys.sort() # Unbounded comes before bounded, those without dummy involvement comes # before those with. - eldag.add_node(edges, None, ( - _SUM, i.label, bounded, with_dummy, free_var_keys - )) + eldag.add_node( + edges, None, (_SUM, i.label, bounded, with_dummy, free_var_keys) + ) continue # Real work, factors. @@ -238,7 +238,7 @@ def _build_eldag(sums, factors, symms): dumms = {v[0]: i for i, v in enumerate(sums)} for factor, colour in factors: - if hasattr(factor, 'base'): + if hasattr(factor, "base"): base = factor.base indices = factor.indices else: @@ -250,11 +250,10 @@ def _build_eldag(sums, factors, symms): factor_symms = None else: prim_keys = [base] - if hasattr(base, 'label'): + if hasattr(base, "label"): prim_keys.append(base.label) keys = itertools.chain( - ((i, n_indices) for i in prim_keys), - prim_keys + ((i, n_indices) for i in prim_keys), prim_keys ) for i in keys: if i in symms: @@ -266,9 +265,7 @@ def _build_eldag(sums, factors, symms): factor_symms = None index_nodes = _proc_indices(indices, dumms, eldag) - idx = eldag.add_node( - index_nodes, factor_symms, (_FACTOR, colour) - ) + idx = eldag.add_node(index_nodes, factor_symms, (_FACTOR, colour)) factor_idxes.append(idx) continue @@ -281,7 +278,7 @@ class _Placeholders(dict): def __missing__(self, key): """Add the placeholder for the given dummy.""" - return Symbol('internalDummyPlaceholder{}'.format(key)) + return Symbol("internalDummyPlaceholder{}".format(key)) _placeholders = _Placeholders() @@ -296,7 +293,6 @@ def _proc_indices(indices, dumms, eldag): nodes = [] for expr in indices: - involved = {} # Sum node index -> actual dummy. for i in expr.atoms(Symbol): if i in dumms: @@ -312,14 +308,14 @@ def _proc_indices(indices, dumms, eldag): if len(sum_nodes) > 2: warnings.warn( - "Index expression", expr, - "contains too many summed dummies, something might be wrong" + "Index expression", + expr, + "contains too many summed dummies, something might be wrong", ) for edges in itertools.permutations(sum_nodes): substs = { - involved[v]: _placeholders[i] - for i, v in enumerate(edges) + involved[v]: _placeholders[i] for i, v in enumerate(edges) } form = expr.xreplace(substs) @@ -336,8 +332,9 @@ def _proc_indices(indices, dumms, eldag): # Now the order of the edges are determined. idx = eldag.add_node( - curr_edges, Group(curr_symms) if len(curr_symms) > 0 else None, - (_EXPR, curr_order) + curr_edges, + Group(curr_symms) if len(curr_symms) > 0 else None, + (_EXPR, curr_order), ) nodes.append(idx) diff --git a/drudge/clifford.py b/drudge/clifford.py index 8275d33f..bdc93641 100644 --- a/drudge/clifford.py +++ b/drudge/clifford.py @@ -23,12 +23,14 @@ def inner_by_delta(vec1: Vec, vec2: Vec): indices2 = vec2.indices if vec1.label != vec2.label or len(indices1) != len(indices2): raise ValueError( - 'Invalid vectors to computer inner product by delta', (vec1, vec2) + "Invalid vectors to computer inner product by delta", (vec1, vec2) ) - return functools.reduce(operator.mul, ( - KroneckerDelta(i, j) for i, j in zip(indices1, indices2) - ), Integer(1)) + return functools.reduce( + operator.mul, + (KroneckerDelta(i, j) for i, j in zip(indices1, indices2)), + Integer(1), + ) class CliffordDrudge(WickDrudge): @@ -74,12 +76,8 @@ def __init__(self, ctx, inner: Inner = inner_by_delta, **kwargs): super().__init__(ctx, **kwargs) self._inner = inner - self._contractor = functools.partial( - _contract4clifford, inner=inner - ) - self._collapse = functools.partial( - _collapse4clifford, inner=inner - ) + self._contractor = functools.partial(_contract4clifford, inner=inner) + self._collapse = functools.partial(_collapse4clifford, inner=inner) @property def phase(self): @@ -118,10 +116,7 @@ def _compare_by_sort_key(vec1: Vec, vec2: Vec, _: Term): return vec1.sort_key > vec2.sort_key -def _contract4clifford( - vec1: Vec, vec2: Vec, _: Term, *, - inner -): +def _contract4clifford(vec1: Vec, vec2: Vec, _: Term, *, inner): """Contract two vectors by Clifford rules.""" return inner(vec1, vec2) * Integer(2) @@ -132,7 +127,6 @@ def _collapse4clifford(term: Term, *, inner): vecs = [] amp = term.amp for k, g in itertools.groupby(term.vecs): - n_vecs = sum(1 for _ in g) n_inners = n_vecs // 2 n_rem = n_vecs % 2 diff --git a/drudge/drs.py b/drudge/drs.py index 9fe03ee0..b87740e1 100644 --- a/drudge/drs.py +++ b/drudge/drs.py @@ -17,8 +17,7 @@ class _Definable: - """Mixin for definable objects in drudge scripts. - """ + """Mixin for definable objects in drudge scripts.""" __slots__ = [] @@ -45,10 +44,7 @@ class DrsSymbol(_Definable, Symbol): dictionaries. """ - __slots__ = [ - '_drudge', - '_orig' - ] + __slots__ = ["_drudge", "_orig"] def __new__(cls, drudge, name): """Create a symbol object.""" @@ -94,19 +90,19 @@ def __iter__(self): which makes the symbols unable to be used as subscripts for indexed objects. """ - raise TypeError('Drudge script symbol cannot be iterated over.') + raise TypeError("Drudge script symbol cannot be iterated over.") def __call__(self, *args, **kwargs): """Make a call to a tensor method.""" name = self.name if len(args) == 0: - raise NameError('Undefined function', name) + raise NameError("Undefined function", name) else: target = args[0] rest = args[1:] - err = NameError('Invalid method', name, 'for', str(type(target))) + err = NameError("Invalid method", name, "for", str(type(target))) if not hasattr(target, name): # It is possible that a tensor method is tried to be called on # an input. @@ -137,7 +133,7 @@ def __getnewargs__(self): def __getnewargs_ex__(self): """Get the arguments and keyword arguments for __new__. - + This method takes precedence over __getnewargs__ in Python 3.6+ and is used by SymPy v1.9+. We need to override it to ensure proper pickling/unpickling of DrsSymbol objects. @@ -152,6 +148,7 @@ def __getstate__(self): def __setstate__(self, state): """Set the state according to pickled content.""" from .drudge import current_drudge + if current_drudge is None: raise ValueError(_PICKLE_ENV_ERR) self.__init__(current_drudge, self.name) @@ -160,7 +157,7 @@ def __setstate__(self, state): def __getattr__(self, item): """Report undefined attributes.""" raise AttributeError( - 'Invalid operation `{}` on Drudge symbol `{}`'.format( + "Invalid operation `{}` on Drudge symbol `{}`".format( item, self.name ) ) @@ -169,10 +166,7 @@ def __getattr__(self, item): class DrsIndexed(_Definable, Indexed): """Indexed objects for drudge scripts.""" - __slots__ = [ - '_drudge', - '_orig' - ] + __slots__ = ["_drudge", "_orig"] def __new__(cls, drudge, base, *args, **kwargs): """Create an indexed object for drudge scripts.""" @@ -217,7 +211,7 @@ def __getnewargs__(self): def __getnewargs_ex__(self): """Get the arguments and keyword arguments for __new__. - + This method takes precedence over __getnewargs__ in Python 3.6+ and is used by SymPy v1.9+. We need to override it to ensure proper pickling/unpickling of DrsIndexed objects. @@ -228,19 +222,20 @@ def __getstate__(self): """Get the state for pickling.""" # Return a non-None state to ensure __setstate__ is called return {} - + def __setstate__(self, state): """Set the state according to pickled content.""" from .drudge import current_drudge + if current_drudge is None: raise ValueError(_PICKLE_ENV_ERR) self.__init__(current_drudge, self.base, *self.indices) -_PICKLE_ENV_ERR = ''' +_PICKLE_ENV_ERR = """ Failed to unpickle, not inside a pickling environment from pickle_env or inside a drudge script. -''' +""" # @@ -259,7 +254,7 @@ def visit_Constant(self, node: ast.Constant): """Update the number nodes.""" val = node.value if isinstance(val, int): - constr = ast.Name(id='Integer', ctx=ast.Load()) + constr = ast.Name(id="Integer", ctx=ast.Load()) ast.copy_location(constr, node) fixed = ast.Call(func=constr, args=[node], keywords=[]) ast.copy_location(fixed, node) @@ -268,7 +263,7 @@ def visit_Constant(self, node: ast.Constant): return node -_DEF_METH_NAME = 'def_as' +_DEF_METH_NAME = "def_as" class _DefFixer(ast.NodeTransformer): @@ -285,13 +280,11 @@ def visit_AugAssign(self, node: ast.AugAssign): return node lhs = node.target - if hasattr(lhs, 'ctx'): + if hasattr(lhs, "ctx"): lhs.ctx = ast.Load() rhs = node.value - deleg = ast.Attribute( - value=lhs, attr=_DEF_METH_NAME, ctx=ast.Load() - ) + deleg = ast.Attribute(value=lhs, attr=_DEF_METH_NAME, ctx=ast.Load()) ast.copy_location(deleg, lhs) call = ast.Call(func=deleg, args=[rhs], keywords=[]) ast.copy_location(call, node) @@ -313,7 +306,7 @@ def compile_drs(src, filename): root = i.visit(root) continue - return compile(root, filename, mode='exec') + return compile(root, filename, mode="exec") # @@ -323,8 +316,7 @@ def compile_drs(src, filename): class DrsEnv(dict): - """The global scope for drudge script execution. - """ + """The global scope for drudge script execution.""" def __init__(self, dr, specials=None): """Initialize the scope.""" @@ -340,6 +332,7 @@ def __init__(self, dr, specials=None): path.append((dr, frozenset())) import drudge + path.append((drudge, frozenset())) try: @@ -350,11 +343,11 @@ def __init__(self, dr, specials=None): path.append((gristmill, frozenset())) import sympy - path.append((sympy, frozenset([ - 'N' - ]))) + + path.append((sympy, frozenset(["N"]))) import builtins + path.append((builtins, frozenset())) def __missing__(self, key: str): @@ -364,7 +357,7 @@ def __missing__(self, key: str): surprise. """ - if key.startswith('__') and key.endswith('__'): + if key.startswith("__") and key.endswith("__"): raise KeyError(key) for entry, excl in self._path: @@ -383,48 +376,52 @@ def __missing__(self, key: str): # -_DRUDGE_MAGIC = 'DRUDGE' +_DRUDGE_MAGIC = "DRUDGE" -_CONF_HELP = ''' +_CONF_HELP = """ The config file for the drudge to be used, it needs to be a Python script finally setting a global variable named ``{}`` for the drudge. -'''.format(_DRUDGE_MAGIC) +""".format(_DRUDGE_MAGIC) def main(argv=None): - """The main driver for using drudge as a program. - """ + """The main driver for using drudge as a program.""" - parser = argparse.ArgumentParser(prog='drudge') - parser.add_argument('conf', type=str, metavar='CONF', help=_CONF_HELP) + parser = argparse.ArgumentParser(prog="drudge") + parser.add_argument("conf", type=str, metavar="CONF", help=_CONF_HELP) parser.add_argument( - 'script', type=str, metavar='SCRIPT', - help='The drudge script to execute' + "script", + type=str, + metavar="SCRIPT", + help="The drudge script to execute", ) if argv is not None: args = parser.parse_args(args=argv) else: args = parser.parse_args() - with open(args.conf, 'r') as conf_fp: + with open(args.conf, "r") as conf_fp: conf_src = conf_fp.read() - conf_code = compile(conf_src, args.conf, 'exec') + conf_code = compile(conf_src, args.conf, "exec") - with open(args.script, 'r') as script_fp: + with open(args.script, "r") as script_fp: script_src = script_fp.read() conf_env = {} exec(conf_code, conf_env) if _DRUDGE_MAGIC not in conf_env: - raise ValueError('Drudge is not set to {} by {}'.format( - _DRUDGE_MAGIC, args.conf - )) + raise ValueError( + "Drudge is not set to {} by {}".format(_DRUDGE_MAGIC, args.conf) + ) drudge = conf_env[_DRUDGE_MAGIC] from drudge import Drudge + if not isinstance(drudge, Drudge): - raise ValueError('Invalid drudge is set to {} by {}'.format( - _DRUDGE_MAGIC, args.conf - )) + raise ValueError( + "Invalid drudge is set to {} by {}".format( + _DRUDGE_MAGIC, args.conf + ) + ) env = drudge.exec_drs(script_src, args.script) return 0 if argv is None else env diff --git a/drudge/drudge.py b/drudge/drudge.py index 42d371f9..ee2fa337 100644 --- a/drudge/drudge.py +++ b/drudge/drudge.py @@ -15,7 +15,15 @@ from IPython.display import Math, display from pyspark import RDD, SparkContext from sympy import ( - IndexedBase, Symbol, Indexed, Wild, sympify, Expr, Add, Matrix, Mul + Indexed, + IndexedBase, + Symbol, + Wild, + Expr, + Add, + Mul, + Matrix, + sympify, ) from sympy.concrete.summations import eval_sum_symbolic @@ -23,17 +31,27 @@ from .drs import compile_drs, DrsEnv, DrsSymbol from .report import Report, ScalarLatexPrinter from .term import ( - Range, sum_term, Term, Vec, subst_factor_term, subst_vec_term, parse_terms, - einst_term, diff_term, try_resolve_range, rewrite_term, Sum_expander, - expand_sums_term, ATerms, simplify_amp_sums_term -) -from .utils import ( - ensure_symb, BCastVar, nest_bind, sympy_key, SymbResolver + Range, + Sum_expander, + ATerms, + Term, + Vec, + try_resolve_range, + sum_term, + subst_factor_term, + subst_vec_term, + parse_terms, + einst_term, + diff_term, + rewrite_term, + expand_sums_term, + simplify_amp_sums_term, ) +from .utils import ensure_symb, BCastVar, nest_bind, sympy_key, SymbResolver # To be used by Tensor.subst and Tensor.subst_all -_DECR_SUFFIX = '_InternalProxy' +_DECR_SUFFIX = "_InternalProxy" class Tensor: @@ -48,21 +66,26 @@ class Tensor: """ __slots__ = [ - '_drudge', - '_terms', - '_local_terms', - '_free_vars', - '_expanded', - '_repartitioned' + "_drudge", + "_terms", + "_local_terms", + "_free_vars", + "_expanded", + "_repartitioned", ] # # Term creation # - def __init__(self, drudge: 'Drudge', terms: RDD, - free_vars: typing.Set[Symbol] = None, - expanded=False, repartitioned=False): + def __init__( + self, + drudge: "Drudge", + terms: RDD, + free_vars: typing.Set[Symbol] = None, + expanded=False, + repartitioned=False, + ): """Initialize the tensor. This function is not designed to be called by users directly. Tensor @@ -85,9 +108,9 @@ def __init__(self, drudge: 'Drudge', terms: RDD, # To be used by the apply method. _INIT_ARGS = { - 'free_vars': '_free_vars', - 'expanded': '_expanded', - 'repartitioned': '_repartitioned' + "free_vars": "_free_vars", + "expanded": "_expanded", + "repartitioned": "_repartitioned", } # @@ -173,13 +196,13 @@ def repartition(self, num_partitions=None, cache=False): """ if not self._repartitioned: - num_partitions = ( - self._drudge.num_partitions if num_partitions is None else - num_partitions + self._drudge.num_partitions + if num_partitions is None + else num_partitions ) if num_partitions is None: - raise ValueError('No default number of partitions available') + raise ValueError("No default number of partitions available") self._terms = self._terms.repartition(num_partitions) self._repartitioned = True @@ -199,14 +222,11 @@ def is_scalar(self): self.cache() # Work around a pyspark bug by doing the reduction locally. - return all( - self._terms.map(lambda x: x.is_scalar).collect() - ) + return all(self._terms.map(lambda x: x.is_scalar).collect()) @property def free_vars(self) -> typing.Set[Symbol]: - """The free variables in the tensor. - """ + """The free variables in the tensor.""" if self._free_vars is None: self._free_vars = self._get_free_vars(self._terms) @@ -219,9 +239,9 @@ def _get_free_vars(terms) -> typing.Set[Symbol]: # The terms are definitely going to be used for other purposes. terms.cache() - return terms.map( - lambda term: term.free_vars - ).aggregate(set(), _union, _union) + return terms.map(lambda term: term.free_vars).aggregate( + set(), _union, _union + ) # TODO: investigate performance characteristic with treeAggregate. @property @@ -252,8 +272,9 @@ def has_base(self, base: typing.Union[IndexedBase, Symbol, Vec]) -> bool: # Work around a possible pyspark bug in reduce. return any( - self._terms.map(functools.partial(Term.has_base, base=base)) - .collect() + self._terms.map( + functools.partial(Term.has_base, base=base) + ).collect() ) # @@ -280,9 +301,9 @@ def __str__(self): """ if self.n_terms == 0: - return '0' + return "0" else: - return '\n + '.join(str(i) for i in self.local_terms) + return "\n + ".join(str(i) for i in self.local_terms) def latex(self, **kwargs): r"""Get the latex form for the tensor. @@ -343,8 +364,8 @@ def __setstate__(self, state): drudge = current_drudge if drudge is None: raise ValueError( - 'Tensor objects cannot be unpickled, ' - 'need to be inside Drudge.pickle_env' + "Tensor objects cannot be unpickled, " + "need to be inside Drudge.pickle_env" ) assert isinstance(drudge, Drudge) @@ -445,10 +466,9 @@ def simplify_amps(self, **kwargs): # Some free variables might be canceled. return self.apply( - functools.partial( - self._simplify_amps, **kwargs - ), - free_vars=None, repartitioned=False + functools.partial(self._simplify_amps, **kwargs), + free_vars=None, + repartitioned=False, ) @staticmethod @@ -456,8 +476,9 @@ def _simplify_amps(terms, **kwargs): """Get the terms with amplitude simplified by SymPy.""" simplified_terms = terms.map( - lambda term: term.map(lambda x: x.simplify(**kwargs), - skip_vecs=True) + lambda term: term.map( + lambda x: x.simplify(**kwargs), skip_vecs=True + ) ).filter(_is_nonzero) return simplified_terms @@ -486,9 +507,9 @@ def _simplify_deltas(self, terms, expanded): resolvers = self._drudge.resolvers - return terms.map( - lambda x: x.simplify_deltas(resolvers.value) - ).filter(_is_nonzero) + return terms.map(lambda x: x.simplify_deltas(resolvers.value)).filter( + _is_nonzero + ) def simplify_sums(self, simplifiers=True, excl_bases=True): """Simplify the summations within the amplitude in the tensor. @@ -536,13 +557,14 @@ def simplify_sums(self, simplifiers=True, excl_bases=True): """ - return Tensor(self._drudge, self._simplify_sums( - self._terms, simplifiers=simplifiers, excl_bases=excl_bases - )) + return Tensor( + self._drudge, + self._simplify_sums( + self._terms, simplifiers=simplifiers, excl_bases=excl_bases + ), + ) - def _simplify_sums( - self, terms: RDD, simplifiers=True, excl_bases=True - ): + def _simplify_sums(self, terms: RDD, simplifiers=True, excl_bases=True): """Simplify the summations in the given terms.""" if simplifiers is True: @@ -552,11 +574,14 @@ def _simplify_sums( terms = terms.map(lambda x: x.simplify_trivial_sums()) if simplifiers: - terms = terms.map(functools.partial( - simplify_amp_sums_term, - simplifiers=simplifiers, excl_bases=excl_bases, - resolvers=self._drudge.resolvers - )) + terms = terms.map( + functools.partial( + simplify_amp_sums_term, + simplifiers=simplifiers, + excl_bases=excl_bases, + resolvers=self._drudge.resolvers, + ) + ) return terms @@ -633,9 +658,7 @@ def merge(self, consts=None, gens=None): """ # All the traits could be invalidated by merging. - return Tensor( - self._drudge, self._merge(self._terms, consts, gens) - ) + return Tensor(self._drudge, self._merge(self._terms, consts, gens)) def _merge(self, terms, consts, gens): """Get the term when they are attempted to be merged.""" @@ -644,9 +667,11 @@ def _merge(self, terms, consts, gens): else: specials = _DecomposeSpecials(consts, gens) - return terms.map( - functools.partial(_decompose_term, specials=specials) - ).reduceByKey(operator.add).map(_recover_term) + return ( + terms.map(functools.partial(_decompose_term, specials=specials)) + .reduceByKey(operator.add) + .map(_recover_term) + ) # # Canonicalization @@ -661,7 +686,8 @@ def canon(self): """ return self.apply( functools.partial(self._canon, expanded=self._expanded), - expanded=True, repartitioned=self._expanded and self._repartitioned + expanded=True, + repartitioned=self._expanded and self._repartitioned, ) def _canon(self, terms, expanded): @@ -690,9 +716,7 @@ def normal_order(self): """ # Free variables, expanded, and repartitioned can all be invalidated. - return Tensor( - self._drudge, self._drudge.normal_order(self.terms) - ) + return Tensor(self._drudge, self._drudge.normal_order(self.terms)) # # The driver simplification. @@ -819,14 +843,14 @@ def _add(self, other): free_vars = None return Tensor( - self._drudge, self._terms.union(other.terms), + self._drudge, + self._terms.union(other.terms), free_vars=free_vars, - expanded=self._expanded and other.expanded + expanded=self._expanded and other.expanded, ) def __sub__(self, other): - """Subtract another tensor from this tensor. - """ + """Subtract another tensor from this tensor.""" return self._add(-other) def __rsub__(self, other): @@ -838,11 +862,9 @@ def __neg__(self): The result will be equivalent to multiplication with :math:`-1`. """ - return self.apply( - lambda terms: terms.map(lambda x: x.scale(-1)) - ) + return self.apply(lambda terms: terms.map(lambda x: x.scale(-1))) - def __mul__(self, other) -> 'Tensor': + def __mul__(self, other) -> "Tensor": """Multiply the tensor. This multiplication operation is done completely within the framework of @@ -856,8 +878,7 @@ def __mul__(self, other) -> 'Tensor': return self._mul(other) def __rmul__(self, other): - """Multiply the tensor on the right. - """ + """Multiply the tensor on the right.""" return self._mul(other, right=True) def _mul(self, other, right=False): @@ -865,9 +886,16 @@ def _mul(self, other, right=False): prod, free_vars, expanded = self._cartesian_terms(other, right) dumms = self._drudge.dumms - return Tensor(self._drudge, prod.map( - lambda x: x[0].mul_term(x[1], dumms=dumms.value, excl=free_vars) - ), free_vars=free_vars, expanded=expanded) + return Tensor( + self._drudge, + prod.map( + lambda x: x[0].mul_term( + x[1], dumms=dumms.value, excl=free_vars + ) + ), + free_vars=free_vars, + expanded=expanded, + ) def __or__(self, other): """Compute the commutator with another tensor. @@ -885,7 +913,7 @@ def _comm(self, other, right=False): """Compute the commutator.""" if isinstance(other, Expr): - msg = 'Taking commutator with commutative expression `{}`'.format( + msg = "Taking commutator with commutative expression `{}`".format( other ) warnings.warn(msg) @@ -893,9 +921,16 @@ def _comm(self, other, right=False): prod, free_vars, expanded = self._cartesian_terms(other, right) dumms = self._drudge.dumms - return Tensor(self._drudge, prod.flatMap( - lambda x: x[0].comm_term(x[1], dumms=dumms.value, excl=free_vars) - ), free_vars=free_vars, expanded=expanded) + return Tensor( + self._drudge, + prod.flatMap( + lambda x: x[0].comm_term( + x[1], dumms=dumms.value, excl=free_vars + ) + ), + free_vars=free_vars, + expanded=expanded, + ) def _cartesian_terms(self, other, right): """Cartesian the terms with the terms in another tensor. @@ -906,7 +941,6 @@ def _cartesian_terms(self, other, right): """ if isinstance(other, Tensor): - if right: prod = other.terms.cartesian(self._terms) else: @@ -920,21 +954,21 @@ def _cartesian_terms(self, other, right): other_terms = parse_terms(other) if len(other_terms) > 1: - prod = self._terms.flatMap(lambda term: [ - (i, term) if right else (term, i) - for i in other_terms - ]) + prod = self._terms.flatMap( + lambda term: [ + (i, term) if right else (term, i) for i in other_terms + ] + ) else: # Special optimization when we just have one term. other_term = other_terms[0] prod = self._terms.map( - lambda term: - (other_term, term) if right else (term, other_term) + lambda term: (other_term, term) + if right + else (term, other_term) ) - free_vars = set.union(*[ - i.free_vars for i in other_terms - ]) + free_vars = set.union(*[i.free_vars for i in other_terms]) free_vars |= self.free_vars expanded = False @@ -946,12 +980,12 @@ def __truediv__(self, other): other = sympify(other) return self.apply( lambda terms: terms.map(lambda x: x.scale(1 / other)), - free_vars=None + free_vars=None, ) def __rtruediv__(self, other): """Make division over a tensor.""" - raise NotImplementedError('General tensors cannot be divided over.') + raise NotImplementedError("General tensors cannot be divided over.") # # Substitution @@ -966,9 +1000,10 @@ def _decr_vecs(vecs: typing.Tuple[Vec]): @staticmethod def _restore(term: Term, decr_vars=None): - if decr_vars is not None: - restore_vars = {decr_var: var for var, decr_var in decr_vars.items()} + restore_vars = { + decr_var: var for var, decr_var in decr_vars.items() + } else: suffix_index = -len(_DECR_SUFFIX) restore_vars = {} @@ -980,7 +1015,7 @@ def _restore(term: Term, decr_vars=None): name = var.label.name Ref = IndexedBase else: - raise TypeError('Expecting Symbol or IndexedBase') + raise TypeError("Expecting Symbol or IndexedBase") if name.endswith(_DECR_SUFFIX): restore_vars[var] = Ref( @@ -992,8 +1027,9 @@ def func(x): new_vecs = tuple( Vec(label=vec.label[0], indices=vec.indices) - if isinstance(vec.label, tuple) and len(vec.label) == 2 - and isinstance(vec.label[1], _Decred) + if isinstance(vec.label, tuple) + and len(vec.label) == 2 + and isinstance(vec.label[1], _Decred) else vec for vec in term.vecs ) @@ -1001,8 +1037,14 @@ def func(x): return term.map(func, vecs=new_vecs, skip_vecs=True) def subst( - self, lhs, rhs, wilds=None, full_balance=False, excl=None, - simult=True, keep_decorated=False + self, + lhs, + rhs, + wilds=None, + full_balance=False, + excl=None, + simult=True, + keep_decorated=False, ): """Substitute the all appearance of the defined tensor. @@ -1069,11 +1111,11 @@ def subst( >>> from sympy import symbols >>> dr = Drudge(SparkContext()) - >>> r = Range('R') - >>> a, b = dr.set_dumms(r, symbols('a b c d e f'))[:2] + >>> r = Range("R") + >>> a, b = dr.set_dumms(r, symbols("a b c d e f"))[:2] >>> dr.add_default_resolver(r) - >>> x = IndexedBase('x') - >>> v = Vec('v') + >>> x = IndexedBase("x") + >>> v = Vec("v") >>> tensor = dr.einst(x[a] * x[b] * v[a] * v[b]) >>> str(tensor) 'sum_{a, b} x[a]*x[b] * v[a] * v[b]' @@ -1083,8 +1125,8 @@ def subst( .. doctest:: - >>> o = IndexedBase('o') - >>> y = IndexedBase('y') + >>> o = IndexedBase("o") + >>> y = IndexedBase("y") >>> res = tensor.subst(x[a], dr.einst(o[a, b] * y[b])) >>> str(res) 'sum_{a, b, c, d} y[c]*y[d]*o[a, c]*o[b, d] * v[a] * v[b]' @@ -1093,7 +1135,7 @@ def subst( .. doctest:: - >>> w = Vec('w') + >>> w = Vec("w") >>> res = tensor.subst(v[a], dr.einst(o[a, b] * w[b])) >>> str(res) 'sum_{a, b, c, d} x[a]*x[b]*o[a, c]*o[b, d] * w[c] * w[d]' @@ -1133,10 +1175,10 @@ def subst( if_indexed = True if len(lhs.terms) != 1: - raise ValueError('Invalid LHS to substitute', lhs.terms) + raise ValueError("Invalid LHS to substitute", lhs.terms) term = lhs.terms[0] if len(term.sums) != 0 or term.amp != 1: - raise ValueError('Invalid LHS to substitute', term) + raise ValueError("Invalid LHS to substitute", term) vecs = term.vecs bases = {vec.base for vec in vecs} @@ -1145,8 +1187,9 @@ def subst( lhs = vecs else: raise TypeError( - 'Invalid LHS for substitution', lhs, - 'expecting vector, indexed, or symbol' + "Invalid LHS for substitution", + lhs, + "expecting vector, indexed, or symbol", ) if not all(self.has_base(base) for base in bases): @@ -1163,10 +1206,8 @@ def subst( rhs_terms = parse_terms(rhs) free_vars = set.union(*[term.free_vars for term in rhs_terms]) - if if_scalar and not all( - term.is_scalar for term in rhs_terms - ): - raise ValueError('Invalid RHS for substituting a scalar', rhs) + if if_scalar and not all(term.is_scalar for term in rhs_terms): + raise ValueError("Invalid RHS for substituting a scalar", rhs) # Handling of the wilds if wilds is None: @@ -1179,29 +1220,29 @@ def subst( for indices in index_bunches: wilds.update( (index, Wild(index.name)) - for index in indices if isinstance(index, Symbol) + for index in indices + if isinstance(index, Symbol) ) if if_scalar: lhs = lhs.xreplace(wilds) else: - lhs = tuple( - vec.map(lambda x: x.xreplace(wilds)) for vec in lhs - ) + lhs = tuple(vec.map(lambda x: x.xreplace(wilds)) for vec in lhs) # XXX: Why is it necessary to expand the terms? # Expansion is probably only necessary for complex matching patterns, # which has not been implemented for now. rhs_terms = [ expanded_term.subst(wilds) - for term in rhs_terms for expanded_term in term.expand() + for term in rhs_terms + for expanded_term in term.expand() ] # "Decorate" the RHS to ensure simultaneous substitution decr_vars = {} if simult: # for symbols and indexedBases - # (Note that free_vars have been defined before the handling of the + # (Note that free_vars have been defined before the handling of the # wilds for var in free_vars: for var in free_vars: if isinstance(var, Symbol): @@ -1213,7 +1254,7 @@ def subst( var.label.name + _DECR_SUFFIX, **var._assumptions ) else: - raise TypeError('Expecting Symbol or IndexedBase') + raise TypeError("Expecting Symbol or IndexedBase") rhs_terms = [term.subst(decr_vars) for term in rhs_terms] @@ -1234,8 +1275,11 @@ def subst( return res.map(restore) def _subst( - self, lhs: typing.Union[typing.Tuple[Vec], Indexed, Symbol], - rhs_terms, full_balance, excl=None + self, + lhs: typing.Union[typing.Tuple[Vec], Indexed, Symbol], + rhs_terms, + full_balance, + excl=None, ): """Core substitution function. @@ -1250,7 +1294,7 @@ def _subst( else: rhs_free_vars = set() - free_vars_local = (self.free_vars | rhs_free_vars) + free_vars_local = self.free_vars | rhs_free_vars if excl is not None: free_vars_local |= excl @@ -1261,23 +1305,39 @@ def _subst( # We keep the dummbegs dictionary for each term and substitute all # appearances of the lhs one-by-one. - subs_states = self._terms.map(lambda x: x.reset_dumms( - dumms=dumms.value, excl=free_vars.value - )) + subs_states = self._terms.map( + lambda x: x.reset_dumms(dumms=dumms.value, excl=free_vars.value) + ) rhs_terms = self._drudge.ctx.broadcast(rhs_terms) if isinstance(lhs, (Indexed, Symbol)): - res = nest_bind(subs_states, lambda x: subst_factor_term( - x[0], lhs, rhs_terms.value, - dumms=dumms.value, dummbegs=x[1], excl=free_vars.value, - full_simplify=full_simplify - ), full_balance=full_balance) + res = nest_bind( + subs_states, + lambda x: subst_factor_term( + x[0], + lhs, + rhs_terms.value, + dumms=dumms.value, + dummbegs=x[1], + excl=free_vars.value, + full_simplify=full_simplify, + ), + full_balance=full_balance, + ) else: - res = nest_bind(subs_states, lambda x: subst_vec_term( - x[0], lhs, rhs_terms.value, - dumms=dumms.value, dummbegs=x[1], excl=free_vars.value - ), full_balance=full_balance) + res = nest_bind( + subs_states, + lambda x: subst_vec_term( + x[0], + lhs, + rhs_terms.value, + dumms=dumms.value, + dummbegs=x[1], + excl=free_vars.value, + ), + full_balance=full_balance, + ) res_terms = res.map(operator.itemgetter(0)) return Tensor( @@ -1285,8 +1345,13 @@ def _subst( ) def subst_all( - self, defs, simplify=False, full_balance=False, excl=None, - simult=True, simult_all=False + self, + defs, + simplify=False, + full_balance=False, + excl=None, + simult=True, + simult_all=False, ): """Substitute all given definitions. @@ -1314,13 +1379,18 @@ def subst_all( lhs, rhs = i else: raise TypeError( - 'Invalid substitution', i, - 'expecting definition or LHS/RHS pair' + "Invalid substitution", + i, + "expecting definition or LHS/RHS pair", ) res = res.subst( - lhs, rhs, full_balance=full_balance, excl=excl, - simult=simult, keep_decorated=simult_all + lhs, + rhs, + full_balance=full_balance, + excl=excl, + simult=simult, + keep_decorated=simult_all, ) if sequentially_simplify: res = res.simplify().repartition() @@ -1371,8 +1441,7 @@ def rewrite(self, vecs, new_amp): vecs_terms = parse_terms(vecs) invalid_vecs = ValueError( - 'Invalid vectors to rewrite', vecs, - 'expecting just vectors' + "Invalid vectors to rewrite", vecs, "expecting just vectors" ) if len(vecs_terms) != 1: raise invalid_vecs @@ -1384,14 +1453,12 @@ def rewrite(self, vecs, new_amp): rewritten = self._terms.map( lambda term: rewrite_term(term, vecs, new_amp) ).cache() - new_terms = [ - i for i in rewritten.countByKey().keys() if i is not None - ] + new_terms = [i for i in rewritten.countByKey().keys() if i is not None] get_term = operator.itemgetter(1) - untouched_terms = rewritten.filter( - lambda x: x[0] is None - ).map(get_term) + untouched_terms = rewritten.filter(lambda x: x[0] is None).map( + get_term + ) new_defs = {} for i in new_terms: def_terms = rewritten.filter(lambda x: x[0] == i).map(get_term) @@ -1399,15 +1466,14 @@ def rewrite(self, vecs, new_amp): def_terms.cache() def_terms.count() new_defs[i.amp] = Tensor(self._drudge, def_terms) - continue - return Tensor(self._drudge, untouched_terms.union( - self._drudge.ctx.parallelize(new_terms) - )), new_defs + return Tensor( + self._drudge, + untouched_terms.union(self._drudge.ctx.parallelize(new_terms)), + ), new_defs def expand_sums( - self, range_: Range, expander: Sum_expander, - exts=None, conv_accs=None + self, range_: Range, expander: Sum_expander, exts=None, conv_accs=None ): """Expand some symbolic summations. @@ -1449,10 +1515,15 @@ def expand_sums( where we just strip one (some) component(s) from a symbolic bundle. """ - return self.map(functools.partial( - expand_sums_term, range_=range_, expander=expander, - exts=exts, conv_accs=conv_accs - )) + return self.map( + functools.partial( + expand_sums_term, + range_=range_, + expander=expander, + exts=exts, + conv_accs=conv_accs, + ) + ) # # Analytic gradient @@ -1502,20 +1573,19 @@ def diff(self, variable, real=False, wirtinger_conj=False): if real and wirtinger_conj: raise ValueError( - 'Wittinger conjugate derivative vanishes for real variables' + "Wittinger conjugate derivative vanishes for real variables" ) if isinstance(variable, Indexed): - symms = self._drudge.symms.value if_symm = ( - variable.base in symms or - (variable.base, len(variable.indices)) in symms + variable.base in symms + or (variable.base, len(variable.indices)) in symms ) if if_symm: warnings.warn( - 'Gradient wrt to symmetric tensor {} '.format(variable) + - 'might need further symmetrization' + "Gradient wrt to symmetric tensor {} ".format(variable) + + "might need further symmetrization" ) # We need a copy. @@ -1524,26 +1594,30 @@ def diff(self, variable, real=False, wirtinger_conj=False): for i in variable.indices: if not isinstance(i, Symbol): raise ValueError( - 'Invalid index', i, 'expecting plain symbol' + "Invalid index", i, "expecting plain symbol" ) if i in excl: raise ValueError( - 'Invalid index', i, - 'clashing with existing free symbols' + "Invalid index", + i, + "clashing with existing free symbols", ) excl.add(i) - continue terms = self._reset_dumms(self._terms, excl=excl) elif isinstance(variable, Symbol): terms = self._terms else: - raise TypeError('Invalid variable to differentiate', variable) + raise TypeError("Invalid variable to differentiate", variable) - return Tensor(self._drudge, self._diff( - terms, variable, real=real, wirtinger_conj=wirtinger_conj - ), expanded=True) + return Tensor( + self._drudge, + self._diff( + terms, variable, real=real, wirtinger_conj=wirtinger_conj + ), + expanded=True, + ) def _diff(self, terms, variable, real, wirtinger_conj): """Differentiate the terms.""" @@ -1567,7 +1641,8 @@ def filter(self, crit): """ return self.apply( lambda terms: terms.filter(crit), - free_vars=None, repartitioned=False + free_vars=None, + repartitioned=False, ) def map(self, func): @@ -1619,9 +1694,14 @@ def map2scalars(self, action, skip_vecs=False, skip_ranges=True): """ - return Tensor(self._drudge, self._terms.map(lambda x: x.map( - action, skip_vecs=skip_vecs, skip_ranges=skip_ranges - ))) + return Tensor( + self._drudge, + self._terms.map( + lambda x: x.map( + action, skip_vecs=skip_vecs, skip_ranges=skip_ranges + ) + ), + ) def map2amps(self, action): """Map the given action to the amplitudes in the tensor. @@ -1646,7 +1726,7 @@ def __getattr__(self, item): try: meth = self._drudge.get_tensor_method(item) except KeyError: - raise AttributeError('Invalid operation name on tensor', item) + raise AttributeError("Invalid operation name on tensor", item) return functools.partial(meth, self) @@ -1739,28 +1819,29 @@ def __init__(self, base, exts, tensor: Tensor): super().__init__(tensor.drudge, tensor.terms) else: raise TypeError( - 'Invalid LHS for tensor definition', tensor, - 'expecting a tensor instance' + "Invalid LHS for tensor definition", + tensor, + "expecting a tensor instance", ) self._exts = [] for i in exts: explicit_ext = ( - isinstance(i, Sequence) and len(i) == 2 and - isinstance(i[0], Symbol) and isinstance(i[1], Range) + isinstance(i, Sequence) + and len(i) == 2 + and isinstance(i[0], Symbol) + and isinstance(i[1], Range) ) if explicit_ext: self._exts.append(tuple(i)) elif isinstance(i, Expr): - self._exts.append(( - i, None - )) + self._exts.append((i, None)) else: raise TypeError( - 'Invalid external index', i, - 'expecting dummy/range pair or a dummy.' + "Invalid external index", + i, + "expecting dummy/range pair or a dummy.", ) - continue # Normalize the base. base_name = str(base) @@ -1816,8 +1897,7 @@ def exts(self): # def simplify(self): - """Simplify the tensor in the definition. - """ + """Simplify the tensor in the definition.""" reset = self.reset_dumms() return TensorDef(reset.base, reset.exts, Tensor.simplify(reset)) @@ -1844,10 +1924,14 @@ def reset_dumms(self, excl=None): tensor = Tensor( self.drudge, - self.terms.map(lambda x: x.reset_dumms( - dumms=dumms.value, excl=excl, - dummbegs=dict(dummbegs), add_substs=ext_substs - )[0]) + self.terms.map( + lambda x: x.reset_dumms( + dumms=dumms.value, + excl=excl, + dummbegs=dict(dummbegs), + add_substs=ext_substs, + )[0] + ), ) return TensorDef(self._base, exts, tensor) @@ -1872,10 +1956,9 @@ def __eq__(self, other): # def __str__(self): - """Form simple readable string for a definition. - """ + """Form simple readable string for a definition.""" - return ' = '.join([str(self.lhs), super().__str__()]) + return " = ".join([str(self.lhs), super().__str__()]) def latex(self, **kwargs): r"""Get the latex form for the tensor definition. @@ -1928,17 +2011,14 @@ def act(self, tensor, wilds=None, full_balance=False): ) def __getitem__(self, item): - """Get the tensor when the definition is indexed. - """ + """Get the tensor when the definition is indexed.""" if not isinstance(item, Sequence): item = (item,) n_exts = len(self._exts) if len(item) != n_exts: - raise ValueError( - 'Invalid subscripts', item, 'expecting', n_exts - ) + raise ValueError("Invalid subscripts", item, "expecting", n_exts) return self.act(self._base[item]) @@ -1947,13 +2027,11 @@ def __getitem__(self, item): # def __getstate__(self): - """Get the current state of the definition. - """ + """Get the current state of the definition.""" return self._base, self._exts, self.local_terms def __setstate__(self, state): - """Set the state for the new definition. - """ + """Set the state for the new definition.""" super().__setstate__(state[2]) self.__init__(state[0], state[1], self) return @@ -2000,7 +2078,7 @@ def __init__(self, ctx: SparkContext, num_partitions=True): elif isinstance(num_partitions, int) or num_partitions is None: self._num_partitions = num_partitions else: - raise TypeError('Invalid default partition', num_partitions) + raise TypeError("Invalid default partition", num_partitions) self._full_simplify = True self._simple_merge = False @@ -2023,14 +2101,13 @@ def __init__(self, ctx: SparkContext, num_partitions=True): self._inside_drs = False # Default simplification of summation. - self.sum_simplifiers = BCastVar(self._ctx, { - 1: [_simplify_symbolic_sum] - }) + self.sum_simplifiers = BCastVar( + self._ctx, {1: [_simplify_symbolic_sum]} + ) @property def ctx(self): - """The Spark context of the drudge. - """ + """The Spark context of the drudge.""" return self._ctx # @@ -2039,20 +2116,19 @@ def ctx(self): @property def num_partitions(self): - """The preferred number of partitions for data. - """ + """The preferred number of partitions for data.""" return self._num_partitions @num_partitions.setter def num_partitions(self, value): - """Set the preferred number of partitions for data. - """ + """Set the preferred number of partitions for data.""" if isinstance(value, int) or value is None: self._num_partitions = value else: raise TypeError( - 'Invalid default number of partitions', value, - 'expecting integer or None' + "Invalid default number of partitions", + value, + "expecting integer or None", ) @property @@ -2067,12 +2143,12 @@ def full_simplify(self): @full_simplify.setter def full_simplify(self, value): - """Set if full simplification is going to be carried out. - """ + """Set if full simplification is going to be carried out.""" if value is not True and value is not False: raise TypeError( - 'Invalid full simplification option', value, - 'expecting boolean' + "Invalid full simplification option", + value, + "expecting boolean", ) self._full_simplify = value @@ -2096,13 +2172,13 @@ def simple_merge(self): @simple_merge.setter def simple_merge(self, value): - """Set if simple merge is going to be carried out. - """ + """Set if simple merge is going to be carried out.""" if value is not True and value is not False: raise ValueError( - 'Invalid simple merge setting', value, - 'expecting plain boolean' + "Invalid simple merge setting", + value, + "expecting plain boolean", ) self._simple_merge = value @@ -2118,13 +2194,13 @@ def default_einst(self): @default_einst.setter def default_einst(self, value): - """Set if Einstein convention definition is default for def_. - """ + """Set if Einstein convention definition is default for def_.""" if value is not True and value is not False: raise ValueError( - 'Invalid default Einstein convention', value, - 'expecting plain boolean' + "Invalid default Einstein convention", + value, + "expecting plain boolean", ) self._default_einst = value @@ -2145,9 +2221,9 @@ def form_base_name(self, tensor_def: TensorDef) -> typing.Optional[str]: """ if self is not tensor_def.drudge: - raise ValueError('Unable to add definition from another drudge.') + raise ValueError("Unable to add definition from another drudge.") - return '_' + str(tensor_def.base) + return "_" + str(tensor_def.base) def form_def_name(self, tensor_def: TensorDef) -> typing.Optional[str]: """Form the name for a tensor definition in name archive. @@ -2158,7 +2234,7 @@ def form_def_name(self, tensor_def: TensorDef) -> typing.Optional[str]: """ if self is not tensor_def.drudge: - raise ValueError('Unable to add definition from another drudge.') + raise ValueError("Unable to add definition from another drudge.") return str(tensor_def.base) def set_name(self, *args, **kwargs): @@ -2175,7 +2251,6 @@ def set_name(self, *args, **kwargs): for label, obj in self._get_name_obj_pairs(args, kwargs): setattr(self._names, label, obj) - continue return def unset_name(self, *args, **kwargs): @@ -2190,7 +2265,6 @@ def unset_name(self, *args, **kwargs): for label, obj in self._get_name_obj_pairs(args, kwargs): if hasattr(self.names, label): delattr(self._names, label) - continue return def _get_name_obj_pairs(self, args, kwargs): @@ -2203,13 +2277,12 @@ def _get_name_obj_pairs(self, args, kwargs): if isinstance(i, TensorDef): for j, k in [ (self.form_base_name(i), i.base), - (self.form_def_name(i), i) + (self.form_def_name(i), i), ]: if j is not None: yield j, k else: yield str(i), i - continue yield from kwargs.items() @@ -2223,7 +2296,7 @@ def names(self): """ return self._names - def inject_names(self, prefix='', suffix=''): + def inject_names(self, prefix="", suffix=""): """Inject the names in the name archive into the current global scope. This function is for the convenience of users, especially interactive @@ -2242,7 +2315,7 @@ def inject_names(self, prefix='', suffix=''): del stack for k, v in self._names.__dict__.items(): - globals_[''.join([prefix, k, suffix])] = v + globals_["".join([prefix, k, suffix])] = v return @@ -2254,9 +2327,14 @@ def inject_names(self, prefix='', suffix=''): # be overridden. # - def set_dumms(self, range_: Range, dumms, - set_range_name=True, dumms_suffix='_dumms', - set_dumm_names=True): + def set_dumms( + self, + range_: Range, + dumms, + set_range_name=True, + dumms_suffix="_dumms", + set_dumm_names=True, + ): """Set the dummies for a range. Note that this function overwrites the existing dummies if the range has @@ -2278,8 +2356,7 @@ def set_dumms(self, range_: Range, dumms, @property def dumms(self): - """The broadcast form of the dummies dictionary. - """ + """The broadcast form of the dummies dictionary.""" return self._dumms.bcast def set_symm(self, base, *symms, valence=None, set_base_name=True): @@ -2310,7 +2387,7 @@ def set_symm(self, base, *symms, valence=None, set_base_name=True): """ if len(symms) == 0: - raise ValueError('Invalid empty symmetry, expecting generators!') + raise ValueError("Invalid empty symmetry, expecting generators!") elif len(symms) == 1 and symms[0] is None: group = None else: @@ -2321,9 +2398,11 @@ def set_symm(self, base, *symms, valence=None, set_base_name=True): elif isinstance(i, Iterable): gens.extend(i) else: - raise TypeError('Invalid generator: ', i, - 'expecting Perm or iterable of Perms') - continue + raise TypeError( + "Invalid generator: ", + i, + "expecting Perm or iterable of Perms", + ) if len(gens) > 0: group = Group(gens) @@ -2336,16 +2415,14 @@ def set_symm(self, base, *symms, valence=None, set_base_name=True): valence = int(valence) except ValueError: raise ValueError( - 'Invalid valence', valence, 'expecting integer' + "Invalid valence", valence, "expecting integer" ) if valence < 1: raise ValueError( - 'Invalid valence', valence, 'expecting positive integer' + "Invalid valence", valence, "expecting positive integer" ) - self._symms.var[ - base if valence is None else (base, valence) - ] = group + self._symms.var[base if valence is None else (base, valence)] = group if set_base_name: self.set_name(**{str(base): base}) @@ -2354,8 +2431,7 @@ def set_symm(self, base, *symms, valence=None, set_base_name=True): @property def symms(self): - """The broadcast form of the symmetries. - """ + """The broadcast form of the symmetries.""" return self._symms.bcast def add_resolver(self, resolver): @@ -2406,10 +2482,9 @@ def add_resolver_for_dumms(self, ranges=None, strict=False): for i in ranges: if i not in curr_dumms: raise ValueError( - 'Unexpected range, dummies not yet set', i + "Unexpected range, dummies not yet set", i ) to_proc.append((i, curr_dumms[i])) - continue self.add_resolver(SymbResolver(to_proc, strict)) @@ -2420,9 +2495,9 @@ def add_default_resolver(self, range_): Note that all later resolvers will not be invoked at all after this resolver is added. """ - self.add_resolver(functools.partial( - _resolve_default_range, range_=range_ - )) + self.add_resolver( + functools.partial(_resolve_default_range, range_=range_) + ) @property def resolvers(self): @@ -2481,7 +2556,7 @@ def normal_order(self, terms, **kwargs): if len(kwargs) != 0: raise ValueError( - 'Invalid arguments to free algebra normal order', kwargs + "Invalid arguments to free algebra normal order", kwargs ) return terms @@ -2526,11 +2601,11 @@ def sum(self, *args, predicate=None) -> Tensor: .. doctest:: >>> dr = Drudge(SparkContext()) - >>> r = Range('R') - >>> a = Symbol('a') - >>> b = Symbol('b') - >>> x = IndexedBase('x') - >>> v = Vec('v') + >>> r = Range("R") + >>> a = Symbol("a") + >>> b = Symbol("b") + >>> x = IndexedBase("x") + >>> v = Vec("v") >>> tensor = dr.sum((a, r), (b, r), x[a, b] * v[a] * v[b]) >>> str(tensor) 'sum_{a, b} x[a, b] * v[a] * v[b]' @@ -2540,7 +2615,7 @@ def sum(self, *args, predicate=None) -> Tensor: .. doctest:: - >>> s = Range('S') + >>> s = Range("S") >>> tensor = dr.sum((a, r, s), x[a] * v[a]) >>> print(str(tensor)) sum_{a} x[a] * v[a] @@ -2587,21 +2662,26 @@ def sum(self, *args, predicate=None) -> Tensor: """ if len(args) == 0: - raise ValueError('Expecting summand!') + raise ValueError("Expecting summand!") summand = args[-1] sum_args = args[:-1] if isinstance(summand, Tensor): - return Tensor(self, summand.terms.flatMap( - lambda x: sum_term(sum_args, x, predicate=predicate) - )) + return Tensor( + self, + summand.terms.flatMap( + lambda x: sum_term(sum_args, x, predicate=predicate) + ), + ) else: - return self.create_tensor(sum_term( - sum_args, summand, predicate=predicate - )) + return self.create_tensor( + sum_term(sum_args, summand, predicate=predicate) + ) - def einst(self, summand, auto_exts: bool = False) -> typing.Union[ + def einst( + self, summand, auto_exts: bool = False + ) -> typing.Union[ Tensor, typing.Tuple[Tensor, typing.AbstractSet[Symbol]] ]: """Create a tensor from Einstein summation convention. @@ -2621,10 +2701,10 @@ def einst(self, summand, auto_exts: bool = False) -> typing.Union[ .. doctest:: >>> dr = Drudge(SparkContext()) - >>> r = Range('R') - >>> a, b, c = dr.set_dumms(r, symbols('a b c')) + >>> r = Range("R") + >>> a, b, c = dr.set_dumms(r, symbols("a b c")) >>> dr.add_resolver_for_dumms() - >>> x = IndexedBase('x') + >>> x = IndexedBase("x") >>> tensor = dr.einst(x[a, b] * x[b, c]) >>> str(tensor) 'sum_{b} x[a, b]*x[b, c]' @@ -2658,10 +2738,11 @@ def einst(self, summand, auto_exts: bool = False) -> typing.Union[ # Separate the cases for local and distributed terms for optimization. if isinstance(summand, Tensor): - - einst_res = summand.expand().terms.map( - lambda x: einst_term(x, resolvers.value) - ).cache() + einst_res = ( + summand.expand() + .terms.map(lambda x: einst_term(x, resolvers.value)) + .cache() + ) tensor = Tensor( self, einst_res.flatMap(operator.itemgetter(0)), expanded=True ) @@ -2699,8 +2780,7 @@ def comb_op(curr, new): res_terms.extend(terms) exts_union |= exts exts_inters = _inters(exts_inters, exts) - continue - continue + tensor = self.create_tensor(res_terms) # End splitting between distributed and local input. @@ -2711,8 +2791,9 @@ def comb_op(curr, new): if exts_union != exts_inters: diff = exts_union - exts_inters raise ValueError( - 'Invalid external indices for Einstein convention', - diff, 'appeared only in some terms' + "Invalid external indices for Einstein convention", + diff, + "appeared only in some terms", ) return tensor, exts_inters @@ -2752,7 +2833,7 @@ def define(self, *args) -> TensorDef: """ if len(args) == 0: - raise ValueError('Expecting arguments for definition.') + raise ValueError("Expecting arguments for definition.") base, exts = self._parse_def_lhs(args[:-1]) content = args[-1] @@ -2773,12 +2854,12 @@ def define_einst(self, *args, auto_exts=False) -> TensorDef: """ if len(args) == 0: - raise ValueError('Expecting arguments for definition.') + raise ValueError("Expecting arguments for definition.") if auto_exts: if len(args) != 2: raise TypeError( - 'Invalid number of arguments, base and rhs expected!' + "Invalid number of arguments, base and rhs expected!" ) tensor, exts = self.einst(args[-1], auto_exts=True) exts = self._form_exts(exts) @@ -2798,7 +2879,7 @@ def _parse_def_lhs(self, args): """ if len(args) == 0: - raise ValueError('No LHS given for tensor definition.') + raise ValueError("No LHS given for tensor definition.") elif len(args) == 1: arg = args[0] if isinstance(arg, (Indexed, Vec)): @@ -2824,7 +2905,7 @@ def _form_exts(self, indices): range_ = try_resolve_range(i, {}, self.resolvers.value) if range_ is None: raise ValueError( - 'Invalid index', i, 'range cannot be resolved' + "Invalid index", i, "range cannot be resolved" ) if isinstance(range_, Sequence): exts.append(i) @@ -2832,7 +2913,7 @@ def _form_exts(self, indices): exts.append((i, range_)) else: exts.append(i) - continue + return exts def def_(self, *args) -> TensorDef: @@ -2857,8 +2938,14 @@ def def_(self, *args) -> TensorDef: # def format_latex( - self, inp, sep_lines=False, align_terms=False, proc=None, - no_sum=False, bounds=False, scalar_mul='' + self, + inp, + sep_lines=False, + align_terms=False, + proc=None, + no_sum=False, + bounds=False, + scalar_mul="", ): r"""Get the LaTeX form of a given tensor or tensor definition. @@ -2918,18 +3005,21 @@ def format_latex( """ if isinstance(inp, TensorDef): - prefix = (self._latex_vec(inp.lhs) if isinstance(inp.lhs, Vec) else - self._latex_sympy(inp.lhs)) + ' = ' + prefix = ( + self._latex_vec(inp.lhs) + if isinstance(inp.lhs, Vec) + else self._latex_sympy(inp.lhs) + ) + " = " elif isinstance(inp, Tensor): - prefix = '' + prefix = "" else: - raise TypeError('Invalid object to form into LaTeX.') + raise TypeError("Invalid object to form into LaTeX.") n_terms = inp.n_terms inp_terms = inp.local_terms if n_terms == 0: - return prefix + '0' + return prefix + "0" terms = [] for i, v in enumerate(inp_terms): @@ -2940,18 +3030,17 @@ def format_latex( if proc is not None: term = proc(term, term=v, idx=i) - if i != 0 and term[0] not in {'+', '-'}: - term = ' + ' + term + if i != 0 and term[0] not in {"+", "-"}: + term = " + " + term if align_terms: - term = ' & ' + term + term = " & " + term terms.append(term) - continue - term_sep = r' \\ ' if sep_lines else ' ' + term_sep = r" \\ " if sep_lines else " " return prefix + term_sep.join(terms) - def _latex_term(self, term, no_sum=False, bounds=False, scalar_mul=''): + def _latex_term(self, term, no_sum=False, bounds=False, scalar_mul=""): """Format a term into LaTeX form. This method does not generally need to be overridden. @@ -2960,7 +3049,7 @@ def _latex_term(self, term, no_sum=False, bounds=False, scalar_mul=''): # Small utility. def parenth(content: str): """Parenthesize the string.""" - return ''.join([r'\left(', content, r'\right)']) + return "".join([r"\left(", content, r"\right)"]) parts = [] @@ -2971,8 +3060,8 @@ def parenth(content: str): if isinstance(term.amp, Add): # In this case, we need a big parenthesis for the amplitude. first_try = self._latex_sympy(term.amp) - if first_try[0] == '-': - parts.append('-') + if first_try[0] == "-": + parts.append("-") amp_latex = self._latex_sympy(-term.amp) else: amp_latex = first_try @@ -2985,11 +3074,11 @@ def parenth(content: str): if coeff == 1 and not if_pure_coeff: pass elif coeff == -1 and not if_pure_coeff: - parts.append('-') + parts.append("-") else: coeff_latex = self._latex_sympy(coeff) - if coeff_latex[0] == '-': - parts.append('-') + if coeff_latex[0] == "-": + parts.append("-") coeff_latex = coeff_latex[1:] if isinstance(coeff, Add): @@ -2997,13 +3086,16 @@ def parenth(content: str): amp_parts.append(coeff_latex) if len(factors) > 0: - scalar_mul = ''.join([' ', scalar_mul, ' ']) - - amp_parts.append(scalar_mul.join( - parenth(self._latex_sympy(i)) if isinstance(i, Add) - else self._latex_sympy(i) - for i in factors - )) + scalar_mul = "".join([" ", scalar_mul, " "]) + + amp_parts.append( + scalar_mul.join( + parenth(self._latex_sympy(i)) + if isinstance(i, Add) + else self._latex_sympy(i) + for i in factors + ) + ) if not term.is_scalar: amp_parts.append(scalar_mul) @@ -3012,22 +3104,21 @@ def parenth(content: str): for i, j in term.sums: dumm = self._latex_sympy(i) if bounds and j.bounded: - form = r'\sum_{{{} = {}}}^{{{}}}'.format( - dumm, self._latex_sympy(j.lower), - self._latex_sympy(j.upper - 1) # Math notation. + form = r"\sum_{{{} = {}}}^{{{}}}".format( + dumm, + self._latex_sympy(j.lower), + self._latex_sympy(j.upper - 1), # Math notation. ) else: - form = r'\sum_{{{} \in {}}}'.format(dumm, j.label) + form = r"\sum_{{{} \in {}}}".format(dumm, j.label) parts.append(form) - parts.append(' '.join(amp_parts)) + parts.append(" ".join(amp_parts)) - vecs = self._latex_vec_mul.join( - self._latex_vec(i) for i in term.vecs - ) + vecs = self._latex_vec_mul.join(self._latex_vec(i) for i in term.vecs) parts.append(vecs) - return ' '.join(parts) + return " ".join(parts) @staticmethod def _latex_sympy(expr): @@ -3046,14 +3137,14 @@ def _latex_vec(self, vec): indices are put into the subscripts. """ - head = r'\mathbf{{{}}}'.format(vec.label) + head = r"\mathbf{{{}}}".format(vec.label) if len(vec.indices) > 0: - indices = ', '.join(self._latex_sympy(i) for i in vec.indices) - return r'{}_{{{}}}'.format(head, indices) + indices = ", ".join(self._latex_sympy(i) for i in vec.indices) + return r"{}_{{{}}}".format(head, indices) else: return head - _latex_vec_mul = r' \otimes ' + _latex_vec_mul = r" \otimes " @contextlib.contextmanager def report(self, filename, title): @@ -3087,9 +3178,9 @@ def report(self, filename, title): :options: +SKIP >>> dr = Drudge(SparkContext()) - >>> tensor = dr.sum(IndexedBase('x')[Symbol('a')]) - >>> with dr.report('report.html', 'A simple tensor') as report: - ... report.add('Simple tensor', tensor) + >>> tensor = dr.sum(IndexedBase("x")[Symbol("a")]) + >>> with dr.report("report.html", "A simple tensor") as report: + ... report.add("Simple tensor", tensor) """ @@ -3127,7 +3218,7 @@ def pickle_env(self): .. doctest:: >>> dr = Drudge(SparkContext()) - >>> tensor = dr.sum(IndexedBase('x')[Symbol('a')]) + >>> tensor = dr.sum(IndexedBase("x")[Symbol("a")]) >>> import pickle >>> serialized = pickle.dumps(tensor) >>> with dr.pickle_env(): @@ -3143,7 +3234,7 @@ def pickle_env(self): yield None current_drudge = prev_drudge - def memoize(self, comput, filename, log=None, log_header='Memoize:'): + def memoize(self, comput, filename, log=None, log_header="Memoize:"): """Preserve/lookup result of computation into/from pickle file. When the file with the given name exists, it will be opened and @@ -3188,10 +3279,10 @@ def memoize(self, comput, filename, log=None, log_header='Memoize:'): :options: +SKIP >>> dr = Drudge(SparkContext()) - >>> res = dr.memoize(lambda: 10, 'intermediate.pickle') + >>> res = dr.memoize(lambda: 10, "intermediate.pickle") >>> res 10 - >>> dr.memoize(lambda: 10, 'intermediate.pickle') + >>> dr.memoize(lambda: 10, "intermediate.pickle") 10 Note that in the second execution, the number 10 should be read from the @@ -3206,23 +3297,25 @@ def memoize(self, comput, filename, log=None, log_header='Memoize:'): if log is None: log_args = {} else: - log_args = {'file': log} + log_args = {"file": log} try: - - with self.pickle_env(), open(filename, 'rb') as fp: + with self.pickle_env(), open(filename, "rb") as fp: res = pickle.load(fp) - print(log_header, 'read data from {}'.format(filename), **log_args) + print(log_header, "read data from {}".format(filename), **log_args) except (OSError, pickle.PickleError) as exc: - - print(log_header, 'computing, failed to read from {}: {!s}'.format( - filename, exc - ), **log_args) + print( + log_header, + "computing, failed to read from {}: {!s}".format( + filename, exc + ), + **log_args, + ) res = comput() - with open(filename, 'wb') as fp: + with open(filename, "wb") as fp: pickle.dump(res, fp) return res @@ -3236,7 +3329,7 @@ def inside_drs(self): """If we are currently inside a drudge script.""" return self._inside_drs - def exec_drs(self, src, filename=''): + def exec_drs(self, src, filename=""): """Execute the drudge script. Drudge script are Python scripts tweaked to be executed in special @@ -3322,7 +3415,7 @@ def simplify(self, arg, **kwargs): @staticmethod def lvt_defs2mat( - defs: typing.Iterable[TensorDef], rhs_vecs=None, ret_rhs=False + defs: typing.Iterable[TensorDef], rhs_vecs=None, ret_rhs=False ): r"""Turn a linear vector transformation into matrix form. @@ -3368,24 +3461,19 @@ def lvt_defs2mat( if not isinstance(lhs, Vec): lhs = 1 if lhs in coeffs: - raise ValueError( - 'Duplicate definition', def_.lhs - ) + raise ValueError("Duplicate definition", def_.lhs) curr_coeffs = collections.defaultdict(lambda: 0) coeffs[lhs] = curr_coeffs for term in def_.local_terms: - if len(term.sums) > 0: raise NotImplementedError( - 'RHS for', lhs, 'too complicated', term + "RHS for", lhs, "too complicated", term ) vecs = term.vecs if len(vecs) > 1: - raise ValueError( - 'Nonlinear term for ', lhs, 'in', term - ) + raise ValueError("Nonlinear term for ", lhs, "in", term) elif len(vecs) == 1: curr_coeffs[vecs[0]] += term.amp else: @@ -3399,7 +3487,6 @@ def lvt_defs2mat( rhs_vecs = set() for i in coeffs.values(): rhs_vecs.update(i.keys()) - continue rhs_vecs = list(rhs_vecs) res_coeffs = [] @@ -3410,13 +3497,11 @@ def lvt_defs2mat( row.append(rhs.pop(i)) else: row.append(0) - continue if len(rhs) != 0: raise ValueError( - 'Terms with vectors not given as RHS', list(rhs.keys()) + "Terms with vectors not given as RHS", list(rhs.keys()) ) res_coeffs.append(row) - continue res = Matrix(res_coeffs) if ret_rhs: @@ -3425,8 +3510,10 @@ def lvt_defs2mat( return res def lvt_mat2defs( - self, mat: Matrix, lhs_vecs: typing.Iterable[Vec], - rhs_vecs: typing.Iterable[Vec] + self, + mat: Matrix, + lhs_vecs: typing.Iterable[Vec], + rhs_vecs: typing.Iterable[Vec], ): """Form definitions from a linear transformation matrix. @@ -3440,20 +3527,20 @@ def lvt_mat2defs( if n_rows != len(lhs_vecs): raise ValueError( - 'Expecting', n_rows, 'LHS vectors', len(lhs_vecs), 'given' + "Expecting", n_rows, "LHS vectors", len(lhs_vecs), "given" ) if n_cols != len(rhs_vecs): raise ValueError( - 'Expecting', n_cols, 'RHS vectors', len(rhs_vecs), 'given' + "Expecting", n_cols, "RHS vectors", len(rhs_vecs), "given" ) defs = [] for idx in range(n_rows): - def_ = self.define(lhs_vecs[idx], sum( - i * j for i, j in zip(mat.row(idx), rhs_vecs) - )) + def_ = self.define( + lhs_vecs[idx], + sum(i * j for i, j in zip(mat.row(idx), rhs_vecs)), + ) defs.append(def_) - continue return defs @@ -3519,10 +3606,7 @@ class _DecomposeSpecials: In default mode, no symbol is considered special. """ - __slots__ = [ - '_consts', - '_gens' - ] + __slots__ = ["_consts", "_gens"] def __init__(self, consts=None, gens=None): """Initialize the container.""" @@ -3561,9 +3645,7 @@ def _decompose_term(term, specials): """ # To distinguish ranges with the same label but different bounds. - sums = tuple( - (dumm, range_.args) for dumm, range_ in term.sums - ) + sums = tuple((dumm, range_.args) for dumm, range_ in term.sums) amp = term.amp if specials is None: @@ -3577,26 +3659,23 @@ def _decompose_term(term, specials): symbs = i.atoms(Symbol) if len(symbs) == 0: coeff *= i - elif isinstance(i, Indexed) or i in specials or any( - j in specials for j in symbs + elif ( + isinstance(i, Indexed) + or i in specials + or any(j in specials for j in symbs) ): factor *= i else: coeff *= i - continue - return ( - (sums, term.vecs, factor), - coeff - ) + + return ((sums, term.vecs, factor), coeff) def _recover_term(state): """Recover a term from a merging state.""" key, coeff = state - sums = tuple( - (dumm, Range(*range_args)) for dumm, range_args in key[0] - ) + sums = tuple((dumm, Range(*range_args)) for dumm, range_args in key[0]) return Term(sums, coeff * key[2], key[1]) @@ -3618,6 +3697,7 @@ class _Decred(int): that it can be used in places where ordering and equality comparison is needed. """ + __slots__ = [] @@ -3629,6 +3709,4 @@ def _simplify_symbolic_sum(expr, **_): assert len(expr.args) == 2 - return eval_sum_symbolic( - expr.args[0].simplify(), expr.args[1] - ) + return eval_sum_symbolic(expr.args[0].simplify(), expr.args[1]) diff --git a/drudge/fock.py b/drudge/fock.py index b5fd040f..dd57096c 100644 --- a/drudge/fock.py +++ b/drudge/fock.py @@ -11,8 +11,14 @@ from pyspark import RDD from sympy import ( - KroneckerDelta, IndexedBase, Expr, Symbol, Rational, symbols, conjugate, - factorial + KroneckerDelta, + IndexedBase, + Expr, + Symbol, + Rational, + symbols, + conjugate, + factorial, ) from ._tceparser import parse_tce_out @@ -38,10 +44,7 @@ class CranChar(EnumSymbs): representing creation and annihilation operators. """ - _symbs_ = [ - ('CR', r'\dagger'), - ('AN', '') - ] + _symbs_ = [("CR", r"\dagger"), ("AN", "")] CR = CranChar.CR @@ -83,11 +86,13 @@ def __init__(self, *args, exch=FERMI, **kwargs): if exch == FERMI or exch == BOSE: self._exch = exch else: - raise ValueError('Invalid exchange', exch, 'expecting plus/minus 1') + raise ValueError( + "Invalid exchange", exch, "expecting plus/minus 1" + ) - self.set_tensor_method('eval_vev', self.eval_vev) - self.set_tensor_method('eval_phys_vev', self.eval_phys_vev) - self.set_tensor_method('dagger', self.dagger) + self.set_tensor_method("eval_vev", self.eval_vev) + self.set_tensor_method("eval_phys_vev", self.eval_phys_vev) + self.set_tensor_method("dagger", self.dagger) @property def contractor(self): @@ -101,8 +106,9 @@ def contractor(self): op_parser = self.op_parser return functools.partial( - _contr_field_ops, ancr_contractor=ancr_contractor, - op_parser=op_parser + _contr_field_ops, + ancr_contractor=ancr_contractor, + op_parser=op_parser, ) @property @@ -143,7 +149,7 @@ def op_parser(self) -> OP_PARSER: ANCR_CONTRACTOR = typing.Callable[ [typing.Any, typing.Sequence[Expr], typing.Any, typing.Sequence[Expr]], - Expr + Expr, ] @property @@ -170,9 +176,12 @@ def eval_vev(self, tensor: Tensor, contractor): And this function is also set as a tensor method by the same name. """ - return Tensor(self, self.normal_order( - tensor.terms, comparator=None, contractor=contractor - )) + return Tensor( + self, + self.normal_order( + tensor.terms, comparator=None, contractor=contractor + ), + ) def eval_phys_vev(self, tensor: Tensor): """Evaluate expectation value with respect to the physical vacuum. @@ -181,9 +190,7 @@ def eval_phys_vev(self, tensor: Tensor): function is also set as a tensor method by the same name. """ - return Tensor( - self, self.normal_order(tensor.terms, comparator=None) - ) + return Tensor(self, self.normal_order(tensor.terms, comparator=None)) def normal_order(self, terms: RDD, **kwargs): """Normal order the field operators. @@ -281,21 +288,25 @@ def set_dbbar_base(self, base: IndexedBase, n_body: int, n_body2=None): if n_body > 1: second_half = list(range(n_body, n_slots)) - gens.append(Perm( - self._form_cycl(0, n_body) + second_half, cycl_accs[0] - )) - gens.append(Perm( - self._form_transp(0, n_body) + second_half, transp_acc - )) + gens.append( + Perm(self._form_cycl(0, n_body) + second_half, cycl_accs[0]) + ) + gens.append( + Perm(self._form_transp(0, n_body) + second_half, transp_acc) + ) if n_body2 > 1: first_half = list(range(0, n_body)) - gens.append(Perm( - first_half + self._form_cycl(n_body, n_slots), cycl_accs[1] - )) - gens.append(Perm( - first_half + self._form_transp(n_body, n_slots), transp_acc - )) + gens.append( + Perm( + first_half + self._form_cycl(n_body, n_slots), cycl_accs[1] + ) + ) + gens.append( + Perm( + first_half + self._form_transp(n_body, n_slots), transp_acc + ) + ) self.set_symm(base, gens, valence=n_slots) @@ -317,14 +328,15 @@ def _form_transp(begin, end): return res def _latex_vec(self, vec): - """Get the LaTeX form of field operators. - """ + """Get the LaTeX form of field operators.""" - head = r'{}^{{{}}}'.format(vec.label, self._latex_sympy(vec.indices[0])) - indices = ', '.join(self._latex_sympy(i) for i in vec.indices[1:]) - return r'{}_{{{}}}'.format(head, indices) + head = r"{}^{{{}}}".format( + vec.label, self._latex_sympy(vec.indices[0]) + ) + indices = ", ".join(self._latex_sympy(i) for i in vec.indices[1:]) + return r"{}_{{{}}}".format(head, indices) - _latex_vec_mul = ' ' + _latex_vec_mul = " " def parse_field_op(op: Vec, _: Term): @@ -336,15 +348,15 @@ def parse_field_op(op: Vec, _: Term): indices = op.indices if len(indices) < 1 or (indices[0] != CR and indices[0] != AN): - raise ValueError('Invalid field operator', op, - 'expecting operator character') + raise ValueError( + "Invalid field operator", op, "expecting operator character" + ) return op.label, indices[0], indices[1:] def _compare_field_ops( - op1: Vec, op2: Vec, term: Term, - op_parser: FockDrudge.OP_PARSER + op1: Vec, op2: Vec, term: Term, op_parser: FockDrudge.OP_PARSER ): """Compare the given field operators. @@ -370,9 +382,13 @@ def _compare_field_ops( return key1 >= key2 -def _contr_field_ops(op1: Vec, op2: Vec, term: Term, - ancr_contractor: FockDrudge.ANCR_CONTRACTOR, - op_parser: FockDrudge.OP_PARSER): +def _contr_field_ops( + op1: Vec, + op2: Vec, + term: Term, + ancr_contractor: FockDrudge.ANCR_CONTRACTOR, + op_parser: FockDrudge.OP_PARSER, +): """Contract two field operators. Here we work by the fermion-boson commutation rules. The contractor is only @@ -396,24 +412,27 @@ def _contr_ancr_by_delta(label1, indices1, label2, indices2): # For the delta contraction, some additional checking is needed for it to # make sense. - err_header = 'Invalid field operators to contract by delta' + err_header = "Invalid field operators to contract by delta" # When the operators are on different base, it is likely that delta is not # what is intended. if label1 != label2: - raise ValueError(err_header, (label1, label2), - 'expecting the same base') + raise ValueError( + err_header, (label1, label2), "expecting the same base" + ) if len(indices1) != len(indices2): - raise ValueError(err_header, (indices1, indices2), - 'expecting same number of indices') + raise ValueError( + err_header, + (indices1, indices2), + "expecting same number of indices", + ) res = 1 for i, j in zip(indices1, indices2): # TODO: Maybe support continuous indices here. res *= KroneckerDelta(i, j) - continue return res @@ -443,28 +462,23 @@ def _get_dagger(term: Term, real: bool): new_char = CR else: raise ValueError( - 'Invalid vector to take Hermitian adjoint', vec, - 'expecting CR/AN character in first index' + "Invalid vector to take Hermitian adjoint", + vec, + "expecting CR/AN character in first index", ) - new_vecs.append( - base[(new_char,) + indices[1:]] - ) - continue + new_vecs.append(base[(new_char,) + indices[1:]]) return term.map( lambda x: x if real else conjugate(x), - vecs=tuple(new_vecs), skip_vecs=True + vecs=tuple(new_vecs), + skip_vecs=True, ) def _is_not_zero_by_nilp(term: Term): - """Test if a term is not zero by nilpotency of the operators. - """ + """Test if a term is not zero by nilpotency of the operators.""" vecs = term.vecs - return all( - vecs[i] != vecs[i + 1] - for i in range(0, len(vecs) - 1) - ) + return all(vecs[i] != vecs[i + 1] for i in range(0, len(vecs) - 1)) # @@ -483,8 +497,11 @@ def conserve_spin(*spin_symbs): n_symbs = len(spin_symbs) if n_symbs % 2 == 1: - raise ValueError('Invalid spin symbols', spin_symbs, - 'expecting a even number of them') + raise ValueError( + "Invalid spin symbols", + spin_symbs, + "expecting a even number of them", + ) n_particles = n_symbs // 2 outs = spin_symbs[0:n_particles] @@ -492,10 +509,7 @@ def conserve_spin(*spin_symbs): def test_conserve(symbs_dict): """Test if the spin values from the dictionary is conserved.""" - return all( - symbs_dict[i] == symbs_dict[j] - for i, j in zip(ins, outs) - ) + return all(symbs_dict[i] == symbs_dict[j] for i, j in zip(ins, outs)) return test_conserve @@ -551,10 +565,18 @@ class GenMBDrudge(FockDrudge): """ - def __init__(self, *args, exch=FERMI, op_label='c', - orb=((Range('L'), 'abcdefghijklmnopq'),), spin=(), - one_body=IndexedBase('t'), two_body=IndexedBase('u'), - dbbar=False, **kwargs): + def __init__( + self, + *args, + exch=FERMI, + op_label="c", + orb=((Range("L"), "abcdefghijklmnopq"),), + spin=(), + one_body=IndexedBase("t"), + two_body=IndexedBase("u"), + dbbar=False, + **kwargs, + ): """Initialize the drudge object. Parameters @@ -616,11 +638,9 @@ def __init__(self, *args, exch=FERMI, op_label='c', self.cr = cr self.an = an - self.set_name(**{ - str(op) + '_': an, - str(op) + '_dag': cr, - str(op) + 'dag_': cr - }) + self.set_name( + **{str(op) + "_": an, str(op) + "_dag": cr, str(op) + "dag_": cr} + ) # # Ranges, dummies, and spins. @@ -630,7 +650,6 @@ def __init__(self, *args, exch=FERMI, op_label='c', for range_, dumms in orb: self.set_dumms(range_, dumms) orb_ranges.append(range_) - continue self.orb_ranges = orb_ranges spin = list(spin) @@ -645,8 +664,9 @@ def __init__(self, *args, exch=FERMI, op_label='c', has_spin = True if len(spin) != 2: raise ValueError( - 'Invalid spin specification', spin, - 'expecting range/dummies pair.' + "Invalid spin specification", + spin, + "expecting range/dummies pair.", ) self.set_dumms(spin[0], spin[1]) spin_range = spin[0] @@ -659,8 +679,8 @@ def __init__(self, *args, exch=FERMI, op_label='c', spin_vals = [ensure_expr(i) for i in spin] if len(spin_vals) == 1: warnings.warn( - 'Just one spin value is given: ' - 'consider dropping it for better performance' + "Just one spin value is given: " + "consider dropping it for better performance" ) spin_range = spin_vals @@ -677,12 +697,10 @@ def __init__(self, *args, exch=FERMI, op_label='c', # indexing. orb_dumms = tuple( - Symbol('internalOrbitPlaceholder{}'.format(i)) - for i in range(4) + Symbol("internalOrbitPlaceholder{}".format(i)) for i in range(4) ) spin_dumms = tuple( - Symbol('internalSpinPlaceholder{}'.format(i)) - for i in range(2) + Symbol("internalSpinPlaceholder{}".format(i)) for i in range(2) ) orb_sums = [(i, orb_ranges) for i in orb_dumms] @@ -707,8 +725,8 @@ def __init__(self, *args, exch=FERMI, op_label='c', if has_spin: one_body_ops = ( - cr[orb_dumms[0], spin_dumms[0]] * - an[orb_dumms[1], spin_dumms[0]] + cr[orb_dumms[0], spin_dumms[0]] + * an[orb_dumms[1], spin_dumms[0]] ) else: one_body_ops = cr[orb_dumms[0]] * an[orb_dumms[1]] @@ -731,15 +749,17 @@ def __init__(self, *args, exch=FERMI, op_label='c', if has_spin: two_body_ops = ( - cr[orb_dumms[0], spin_dumms[0]] * - cr[orb_dumms[1], spin_dumms[1]] * - an[orb_dumms[3], spin_dumms[1]] * - an[orb_dumms[2], spin_dumms[0]] + cr[orb_dumms[0], spin_dumms[0]] + * cr[orb_dumms[1], spin_dumms[1]] + * an[orb_dumms[3], spin_dumms[1]] + * an[orb_dumms[2], spin_dumms[0]] ) else: two_body_ops = ( - cr[orb_dumms[0]] * cr[orb_dumms[1]] * - an[orb_dumms[3]] * an[orb_dumms[2]] + cr[orb_dumms[0]] + * cr[orb_dumms[1]] + * an[orb_dumms[3]] + * an[orb_dumms[2]] ) two_body_ham = self.sum( @@ -788,38 +808,52 @@ class PartHoleDrudge(GenMBDrudge): """ - DEFAULT_PART_DUMMS = tuple(Symbol(i) for i in 'abcd') + tuple( - Symbol('a{}'.format(i)) for i in range(50) + DEFAULT_PART_DUMMS = tuple(Symbol(i) for i in "abcd") + tuple( + Symbol("a{}".format(i)) for i in range(50) ) - DEFAULT_HOLE_DUMMS = tuple(Symbol(i) for i in 'ijkl') + tuple( - Symbol('i{}'.format(i)) for i in range(50) + DEFAULT_HOLE_DUMMS = tuple(Symbol(i) for i in "ijkl") + tuple( + Symbol("i{}".format(i)) for i in range(50) ) - DEFAULT_ORB_DUMMS = tuple(Symbol(i) for i in 'pqrs') + tuple( - Symbol('p{}'.format(i)) for i in range(50) + DEFAULT_ORB_DUMMS = tuple(Symbol(i) for i in "pqrs") + tuple( + Symbol("p{}".format(i)) for i in range(50) ) - def __init__(self, *args, op_label='c', - part_orb=(Range('V', 0, Symbol('nv')), DEFAULT_PART_DUMMS), - hole_orb=(Range('O', 0, Symbol('no')), DEFAULT_HOLE_DUMMS), - all_orb_dumms=DEFAULT_ORB_DUMMS, spin=(), - one_body=IndexedBase('t'), two_body=IndexedBase('u'), - fock=IndexedBase('f'), - dbbar=True, **kwargs): + def __init__( + self, + *args, + op_label="c", + part_orb=(Range("V", 0, Symbol("nv")), DEFAULT_PART_DUMMS), + hole_orb=(Range("O", 0, Symbol("no")), DEFAULT_HOLE_DUMMS), + all_orb_dumms=DEFAULT_ORB_DUMMS, + spin=(), + one_body=IndexedBase("t"), + two_body=IndexedBase("u"), + fock=IndexedBase("f"), + dbbar=True, + **kwargs, + ): """Initialize the particle-hole drudge.""" self.part_range = part_orb[0] self.hole_range = hole_orb[0] - super().__init__(*args, exch=FERMI, op_label=op_label, - orb=(part_orb, hole_orb), spin=spin, - one_body=one_body, two_body=two_body, dbbar=dbbar, - **kwargs) + super().__init__( + *args, + exch=FERMI, + op_label=op_label, + orb=(part_orb, hole_orb), + spin=spin, + one_body=one_body, + two_body=two_body, + dbbar=dbbar, + **kwargs, + ) self.all_orb_dumms = tuple(all_orb_dumms) self.set_name(*self.all_orb_dumms) - self.add_resolver({ - i: (self.part_range, self.hole_range) for i in all_orb_dumms - }) + self.add_resolver( + {i: (self.part_range, self.hole_range) for i in all_orb_dumms} + ) full_ham = self.ham full_ham.cache() @@ -827,9 +861,7 @@ def __init__(self, *args, op_label='c', self.ham_energy = full_ham.filter(lambda term: term.is_scalar) - self.one_body_ham = full_ham.filter( - lambda term: len(term.vecs) == 2 - ) + self.one_body_ham = full_ham.filter(lambda term: len(term.vecs) == 2) two_body_ham = full_ham.filter(lambda term: len(term.vecs) == 4) # We need to rewrite the one-body part in terms of Fock matrices. @@ -838,14 +870,13 @@ def __init__(self, *args, op_label='c', for i in self.one_body_ham.local_terms: if i.amp.has(one_body): one_body_terms.append(i.subst({one_body: fock})) - continue rewritten_one_body_ham = self.create_tensor(one_body_terms) ham = rewritten_one_body_ham + two_body_ham ham.cache() self.ham = ham - self.set_tensor_method('eval_fermi_vev', self.eval_fermi_vev) + self.set_tensor_method("eval_fermi_vev", self.eval_fermi_vev) self.set_name(no=self.hole_range.size) self.set_name(nv=self.part_range.size) @@ -869,8 +900,11 @@ def parse_parthole_ops(op: Vec, term: Term): indices[0], dict(term.sums), resolvers.value ) if orb_range is None: - raise ValueError('Invalid orbit value', indices[0], - 'expecting particle or hole') + raise ValueError( + "Invalid orbit value", + indices[0], + "expecting particle or hole", + ) if orb_range == hole_range: char = AN if char == CR else CR return label, char, indices @@ -886,8 +920,9 @@ def eval_fermi_vev(self, tensor: Tensor): """ return self.eval_phys_vev(tensor) - def parse_tce(self, tce_out: str, - cc_bases: typing.Mapping[int, IndexedBase]): + def parse_tce( + self, tce_out: str, cc_bases: typing.Mapping[int, IndexedBase] + ): """Parse TCE output into a tensor. The CC amplitude bases should be given as a dictionary mapping from the @@ -896,18 +931,18 @@ def parse_tce(self, tce_out: str, def range_cb(label): """The range call-back.""" - return self.part_range if label[0] == 'p' else self.hole_range + return self.part_range if label[0] == "p" else self.hole_range def base_cb(name, indices): """Get the indexed base for a name in TCE output.""" - if name == 'f': + if name == "f": return self.fock - elif name == 'v': + elif name == "v": return self.two_body - elif name == 't': + elif name == "t": return cc_bases[len(indices) // 2] else: - raise ValueError('Invalid base', name, 'in TCE output.') + raise ValueError("Invalid base", name, "in TCE output.") terms, free_vars = parse_tce_out(tce_out, range_cb, base_cb) @@ -916,12 +951,10 @@ def base_cb(name, indices): substs = {} for range_, symbs in free_vars.items(): for i, j in zip( - sorted(symbs, key=lambda x: int(x.name[1:])), - self.dumms.value[range_] + sorted(symbs, key=lambda x: int(x.name[1:])), + self.dumms.value[range_], ): substs[i] = j - continue - continue return self.create_tensor([i.subst(substs) for i in terms]) @@ -935,10 +968,7 @@ class SpinOneHalf(EnumSymbs): """ - _symbs_ = [ - ('UP', r'\uparrow'), - ('DOWN', r'\downarrow') - ] + _symbs_ = [("UP", r"\uparrow"), ("DOWN", r"\downarrow")] UP = SpinOneHalf.UP @@ -954,8 +984,7 @@ class SpinOneHalfGenDrudge(GenMBDrudge): """ def __init__(self, *args, **kwargs): - """Initialize the drudge object. - """ + """Initialize the drudge object.""" super().__init__(*args, exch=FERMI, spin=[UP, DOWN], **kwargs) @@ -972,22 +1001,28 @@ class SpinOneHalfPartHoleDrudge(PartHoleDrudge): """ def __init__( - self, *args, - part_orb=( - Range('V', 0, Symbol('nv')), - PartHoleDrudge.DEFAULT_PART_DUMMS + symbols('beta gamma') - ), - hole_orb=( - Range('O', 0, Symbol('no')), - PartHoleDrudge.DEFAULT_HOLE_DUMMS + symbols('u v') - ), spin=(UP, DOWN), - **kwargs + self, + *args, + part_orb=( + Range("V", 0, Symbol("nv")), + PartHoleDrudge.DEFAULT_PART_DUMMS + symbols("beta gamma"), + ), + hole_orb=( + Range("O", 0, Symbol("no")), + PartHoleDrudge.DEFAULT_HOLE_DUMMS + symbols("u v"), + ), + spin=(UP, DOWN), + **kwargs, ): """Initialize the particle-hole drudge.""" super().__init__( - *args, spin=spin, dbbar=False, - part_orb=part_orb, hole_orb=hole_orb, **kwargs + *args, + spin=spin, + dbbar=False, + part_orb=part_orb, + hole_orb=hole_orb, + **kwargs, ) @@ -1017,30 +1052,30 @@ class RestrictedPartHoleDrudge(SpinOneHalfPartHoleDrudge): """ def __init__( - self, *args, - spin_range=Range(r'\uparrow\downarrow', 0, 2), - spin_dumms=tuple(Symbol('sigma{}'.format(i)) for i in range(50)), - **kwargs + self, + *args, + spin_range=Range(r"\uparrow\downarrow", 0, 2), + spin_dumms=tuple(Symbol("sigma{}".format(i)) for i in range(50)), + **kwargs, ): """Initialize the restricted particle-hole drudge.""" - super().__init__( - *args, spin=(spin_range, spin_dumms), **kwargs - ) - self.add_resolver({ - UP: spin_range, - DOWN: spin_range - }) + super().__init__(*args, spin=(spin_range, spin_dumms), **kwargs) + self.add_resolver({UP: spin_range, DOWN: spin_range}) self.spin_range = spin_range self.spin_dumms = self.dumms.value[spin_range] sigma = self.dumms.value[spin_range][0] - p = Symbol('p') - q = Symbol('q') - self.e_ = TensorDef(Vec('E'), (p, q), self.sum( - (sigma, spin_range), self.cr[p, sigma] * self.an[q, sigma] - )) + p = Symbol("p") + q = Symbol("q") + self.e_ = TensorDef( + Vec("E"), + (p, q), + self.sum( + (sigma, spin_range), self.cr[p, sigma] * self.an[q, sigma] + ), + ) self.set_name(e_=self.e_) @@ -1107,27 +1142,35 @@ class BogoliubovDrudge(GenMBDrudge): """ - DEFAULT_P_DUMMS = tuple( - Symbol('l{}'.format(i)) for i in range(1, 100) - ) - DEFAULT_QP_DUMMS = tuple( - Symbol('k{}'.format(i)) for i in range(1, 100) - ) + DEFAULT_P_DUMMS = tuple(Symbol("l{}".format(i)) for i in range(1, 100)) + DEFAULT_QP_DUMMS = tuple(Symbol("k{}".format(i)) for i in range(1, 100)) def __init__( - self, ctx, p_range=Range('L'), p_dumms=DEFAULT_P_DUMMS, - qp_range=Range('Q', 0, Symbol('N')), qp_dumms=DEFAULT_QP_DUMMS, - u_base=IndexedBase('u'), v_base=IndexedBase('v'), - one_body=IndexedBase('epsilon'), two_body=IndexedBase('vbar'), - dbbar=True, qp_op_label=r'\beta', ham_me_format='H^{{{}{}}}', - ham_me_name_format='H{}{}', - **kwargs + self, + ctx, + p_range=Range("L"), + p_dumms=DEFAULT_P_DUMMS, + qp_range=Range("Q", 0, Symbol("N")), + qp_dumms=DEFAULT_QP_DUMMS, + u_base=IndexedBase("u"), + v_base=IndexedBase("v"), + one_body=IndexedBase("epsilon"), + two_body=IndexedBase("vbar"), + dbbar=True, + qp_op_label=r"\beta", + ham_me_format="H^{{{}{}}}", + ham_me_name_format="H{}{}", + **kwargs, ): """Initialize the drudge object.""" super().__init__( - ctx, orb=((p_range, p_dumms),), - one_body=one_body, two_body=two_body, dbbar=dbbar, **kwargs + ctx, + orb=((p_range, p_dumms),), + one_body=one_body, + two_body=two_body, + dbbar=dbbar, + **kwargs, ) self.set_dumms(qp_range, qp_dumms) self.add_resolver_for_dumms() @@ -1143,12 +1186,14 @@ def __init__( self.qp_cr = qp_cr self.qp_an = qp_an - qp_op_str = str(qp_op).replace('\\', "") - self.set_name(**{ - qp_op_str + '_': qp_an, - qp_op_str + '_dag': qp_cr, - qp_op_str + 'dag_': qp_cr - }) + qp_op_str = str(qp_op).replace("\\", "") + self.set_name( + **{ + qp_op_str + "_": qp_an, + qp_op_str + "_dag": qp_cr, + qp_op_str + "dag_": qp_cr, + } + ) self.u_base = u_base self.v_base = v_base @@ -1158,12 +1203,20 @@ def __init__( l = p_dumms[0] k = qp_dumms[0] self.f_in_qp = [ - self.define(cr[l], self.einst( - conjugate(u_base[l, k]) * qp_cr[k] + v_base[l, k] * qp_an[k] - )), - self.define(an[l], self.einst( - u_base[l, k] * qp_an[k] + conjugate(v_base[l, k]) * qp_cr[k] - )) + self.define( + cr[l], + self.einst( + conjugate(u_base[l, k]) * qp_cr[k] + + v_base[l, k] * qp_an[k] + ), + ), + self.define( + an[l], + self.einst( + u_base[l, k] * qp_an[k] + + conjugate(v_base[l, k]) * qp_cr[k] + ), + ), ] orig_ham = self.ham @@ -1174,12 +1227,10 @@ def __init__( self.ham = rewritten self.ham_mes = ham_mes - self.set_tensor_method( - 'eval_bogoliubov_vev', self.eval_bogoliubov_vev - ) + self.set_tensor_method("eval_bogoliubov_vev", self.eval_bogoliubov_vev) def write_in_qp( - self, tensor: Tensor, format_: str, name_format=None, set_symms=True + self, tensor: Tensor, format_: str, name_format=None, set_symms=True ): """Write the given expression in terms of quasi-particle operators. @@ -1234,7 +1285,7 @@ def write_in_qp( for i in term.vecs: if len(i.indices) != 2: raise ValueError( - 'Invalid operator to rewrite, one index expected', i + "Invalid operator to rewrite, one index expected", i ) char, index = i.indices if char == CR: @@ -1246,7 +1297,6 @@ def write_in_qp( assert False indices.append(index) - continue norm = factorial(cr_order) * factorial(an_order) order = (cr_order, an_order) @@ -1271,7 +1321,6 @@ def write_in_qp( new_sums.append(i) else: wrapped_sums.append(i) - continue def_term = Term( sums=tuple(wrapped_sums), amp=orig_amp * norm, vecs=() @@ -1283,14 +1332,16 @@ def write_in_qp( entry[1].append(def_term) else: transf[order] = (new_amp, [def_term]) - rewritten_terms.append(Term( - sums=tuple(new_sums), amp=new_amp / norm, vecs=term.vecs - )) + rewritten_terms.append( + Term( + sums=tuple(new_sums), + amp=new_amp / norm, + vecs=term.vecs, + ) + ) if set_symms and (cr_order > 1 or an_order > 1): self.set_dbbar_base(base, cr_order, an_order) - continue - defs = [ self.define(lhs, self.create_tensor(rhs_terms)) for lhs, rhs_terms in transf.values() diff --git a/drudge/genquad.py b/drudge/genquad.py index c19f7be8..8d1be9a3 100644 --- a/drudge/genquad.py +++ b/drudge/genquad.py @@ -46,8 +46,7 @@ def __init__(self, ctx, full_balance=False, **kwargs): @property def full_balance(self) -> bool: - """If full load-balancing is to be performed during normal-ordering. - """ + """If full load-balancing is to be performed during normal-ordering.""" return self._full_balance @full_balance.setter @@ -56,7 +55,7 @@ def full_balance(self, val: bool): if not isinstance(val, bool): raise TypeError( - 'Invalid option for full balancing', val, 'expecting boolean' + "Invalid option for full balancing", val, "expecting boolean" ) self._full_balance = val @@ -83,19 +82,23 @@ def normal_order(self, terms: RDD, **kwargs): """Normal order the terms in the RDD.""" if len(kwargs) > 0: - raise ValueError('Invalid keyword arguments', kwargs) + raise ValueError("Invalid keyword arguments", kwargs) symms = self.symms swapper = self.swapper resolvers = self.resolvers - init = terms.map(lambda term: _NOState( - pivot=1, front=2, term=term.canon4normal(symms.value) - )) + init = terms.map( + lambda term: _NOState( + pivot=1, front=2, term=term.canon4normal(symms.value) + ) + ) - res = nest_bind(init, lambda x: _sort_vec( - x, swapper=swapper, resolvers=resolvers.value - ), full_balance=self.full_balance) + res = nest_bind( + init, + lambda x: _sort_vec(x, swapper=swapper, resolvers=resolvers.value), + full_balance=self.full_balance, + ) return res.map(lambda x: x.term) @@ -107,11 +110,7 @@ def normal_order(self, terms: RDD, **kwargs): # the vector to swap, possibly. Front is the index for the next pivot. # -_NOState = collections.namedtuple('_NOState', [ - 'pivot', - 'front', - 'term' -]) +_NOState = collections.namedtuple("_NOState", ["pivot", "front", "term"]) def _sort_vec(no_state: _NOState, swapper: GenQuadDrudge.Swapper, resolvers): @@ -130,9 +129,11 @@ def _sort_vec(no_state: _NOState, swapper: GenQuadDrudge.Swapper, resolvers): return None # To be used by the end of the inner loop. - move2front = [_NOState( - pivot=no_state.front, front=no_state.front + 1, term=no_state.term - )] + move2front = [ + _NOState( + pivot=no_state.front, front=no_state.front + 1, term=no_state.term + ) + ] if pivot == 0: return move2front @@ -149,27 +150,27 @@ def _sort_vec(no_state: _NOState, swapper: GenQuadDrudge.Swapper, resolvers): # Now we need to do a swap. head = vecs[:prev] - tail = vecs[pivot + 1:] + tail = vecs[pivot + 1 :] res_states = [] swapped_vecs = head + (vecs[pivot], vecs[prev]) + tail swapped_amp = phase * orig_term.amp if swapped_amp != 0: - swapped_term = Term( - orig_term.sums, swapped_amp, swapped_vecs + swapped_term = Term(orig_term.sums, swapped_amp, swapped_vecs) + res_states.append( + _NOState(pivot=prev, front=no_state.front, term=swapped_term) ) - res_states.append(_NOState( - pivot=prev, front=no_state.front, term=swapped_term - )) for comm_term in comm_terms: if comm_term.amp == 0: continue comm_vecs = comm_term.vecs - res_term = Term(orig_term.sums, comm_term.amp * orig_term.amp, tuple( - itertools.chain(head, comm_vecs, tail) - )).simplify_deltas(resolvers) + res_term = Term( + orig_term.sums, + comm_term.amp * orig_term.amp, + tuple(itertools.chain(head, comm_vecs, tail)), + ).simplify_deltas(resolvers) if res_term.amp == 0: continue @@ -180,9 +181,9 @@ def _sort_vec(no_state: _NOState, swapper: GenQuadDrudge.Swapper, resolvers): # Index of the first newly inserted vector. res_pivot = prev - res_states.append(_NOState( - pivot=res_pivot, front=res_pivot + 1, term=res_term - )) + res_states.append( + _NOState(pivot=res_pivot, front=res_pivot + 1, term=res_term) + ) continue return res_states @@ -192,6 +193,7 @@ def _sort_vec(no_state: _NOState, swapper: GenQuadDrudge.Swapper, resolvers): # Utility class for common problems. # + class GenQuadLatticeDrudge(GenQuadDrudge): r"""Drudge for general quadratic algebra with concentration on the bases. @@ -249,10 +251,16 @@ class GenQuadLatticeDrudge(GenQuadDrudge): """ def __init__( - self, ctx, order: typing.Iterable[Vec], - comms: typing.Mapping[typing.Tuple[Vec, Vec], typing.Union[ - ATerms, typing.Tuple[ATerms, Expr] - ]], assume_comm=False, **kwargs): + self, + ctx, + order: typing.Iterable[Vec], + comms: typing.Mapping[ + typing.Tuple[Vec, Vec], + typing.Union[ATerms, typing.Tuple[ATerms, Expr]], + ], + assume_comm=False, + **kwargs, + ): """Initialize the drudge object.""" super().__init__(ctx, **kwargs) self._swapper = self._form_swapper(order, comms, assume_comm) @@ -272,27 +280,26 @@ def _form_swapper(self, order, comms_inp, assume_comm): base_ranks = {} for i, v in enumerate(order): if v in base_ranks: - raise ValueError( - 'Duplicated generator in the normal order', v - ) + raise ValueError("Duplicated generator in the normal order", v) base_ranks[v] = i continue comms = {} for k, v in comms_inp.items(): invalid_key = ( - not isinstance(k, typing.Sequence) or len(k) != 2 - or any(not isinstance(i, Vec) for i in k) + not isinstance(k, typing.Sequence) + or len(k) != 2 + or any(not isinstance(i, Vec) for i in k) ) if invalid_key: raise ValueError( - 'Invalid bases to commute, expecting two vectors', k + "Invalid bases to commute, expecting two vectors", k ) if isinstance(v, typing.Sequence): if len(v) != 2: raise ValueError( - 'Invalid commutator, commutator and phase expected', v + "Invalid commutator, commutator and phase expected", v ) comm, phase = v else: @@ -303,15 +310,13 @@ def _form_swapper(self, order, comms_inp, assume_comm): phase = sympify(phase) except SympifyError as exc: raise ValueError( - 'Nonsympifiable phase of commutation', phase, exc + "Nonsympifiable phase of commutation", phase, exc ) try: comm = parse_terms(comm) except Exception as exc: - raise ValueError( - 'Invalid commutator result', comm, exc - ) + raise ValueError("Invalid commutator result", comm, exc) if len(k[0].indices) == 0 and len(k[1].indices) == 0: key = (k[0], k[1]) @@ -321,7 +326,7 @@ def _form_swapper(self, order, comms_inp, assume_comm): else: if k[0].indices != k[1].indices: raise ValueError( - 'Unmatching indices for lattice operators.' + "Unmatching indices for lattice operators." ) comms[k[0].base, k[1].base] = (k[0].indices, comm, phase) @@ -338,11 +343,9 @@ def _form_swapper(self, order, comms_inp, assume_comm): ) -_SwapInfo = collections.namedtuple('_SwapInfo', [ - 'base_ranks', - 'comms', - 'assume_comm' -]) +_SwapInfo = collections.namedtuple( + "_SwapInfo", ["base_ranks", "comms", "assume_comm"] +) def _swap_lattice_gens(vec1: Vec, vec2: Vec, bcast_swap_info): @@ -355,16 +358,14 @@ def _swap_lattice_gens(vec1: Vec, vec2: Vec, bcast_swap_info): indices1, indices2 = [i.indices for i in vecs] if len(indices1) != len(indices2): - raise ValueError('Unmatching lattice indices for', vec1, vec2) + raise ValueError("Unmatching lattice indices for", vec1, vec2) base1, base2 = [vec.base for vec in vecs] try: rank1 = base_ranks[base1] rank2 = base_ranks[base2] except KeyError as exc: - raise ValueError( - 'Vector with unspecified normal order', exc.args - ) + raise ValueError("Vector with unspecified normal order", exc.args) if rank1 < rank2: return None @@ -395,19 +396,23 @@ def _swap_lattice_gens(vec1: Vec, vec2: Vec, bcast_swap_info): phase = _UNITY comm_factor = _UNITY else: - raise ValueError( - 'Commutation rules unspecified', vec1, vec2 - ) + raise ValueError("Commutation rules unspecified", vec1, vec2) - delta = functools.reduce(operator.mul, ( - KroneckerDelta(i, j) for i, j in zip(indices1, indices2) - ), _UNITY) + delta = functools.reduce( + operator.mul, + (KroneckerDelta(i, j) for i, j in zip(indices1, indices2)), + _UNITY, + ) terms = Terms( - Term(term.sums, delta * comm_factor * term.amp, tuple( - i[indices1] if len(i.indices) == 0 else i - for i in term.vecs - )) + Term( + term.sums, + delta * comm_factor * term.amp, + tuple( + i[indices1] if len(i.indices) == 0 else i + for i in term.vecs + ), + ) for term in comm ) return phase, terms @@ -425,15 +430,15 @@ def _get_comm_phase(comms, vecs, indices): dumms, comm, phase = entry if len(indices) != len(dumms): raise ValueError( - 'Indices in vectors', indices, - 'cannot be matched for the rules of commuting', vecs + "Indices in vectors", + indices, + "cannot be matched for the rules of commuting", + vecs, ) - substs = { - i: j for i, j in zip(dumms, indices) - } + substs = {i: j for i, j in zip(dumms, indices)} return ( tuple(i.map(lambda x: x.xreplace(substs)) for i in comm), - phase.xreplace(substs) + phase.xreplace(substs), ) else: assert False diff --git a/drudge/nuclear.py b/drudge/nuclear.py index 00b43203..09fae025 100644 --- a/drudge/nuclear.py +++ b/drudge/nuclear.py @@ -7,8 +7,20 @@ import collections from sympy import ( - Symbol, Function, Sum, symbols, Wild, KroneckerDelta, IndexedBase, Integer, - sqrt, factor, Mul, Expr, Matrix, Pow + Symbol, + Function, + Sum, + symbols, + Wild, + KroneckerDelta, + IndexedBase, + Integer, + sqrt, + factor, + Mul, + Expr, + Matrix, + Pow, ) from sympy.physics.quantum.cg import CG, Wigner3j, Wigner6j, Wigner9j from sympy.concrete.summations import eval_sum_symbolic @@ -25,8 +37,7 @@ class _QNOf(Function): - """Base class for quantum number access symbolic functions. - """ + """Base class for quantum number access symbolic functions.""" # To be override by subclasses. _latex_header = None @@ -37,47 +48,54 @@ def _latex(self, printer): The printing will be the header given in the subclasses followed by the printing of the orbit wrapped in braces. """ - return ''.join([ - self._latex_header, '{', printer.doprint(self.args[0]), '}' - ]) + return "".join( + [self._latex_header, "{", printer.doprint(self.args[0]), "}"] + ) class JOf(_QNOf): """Symbolic access of j quantum number of an orbit.""" - _latex_header = 'j_' + + _latex_header = "j_" class TildeOf(_QNOf): """Symbolic access of the tilde part of an orbit.""" - _latex_header = r'\tilde' + + _latex_header = r"\tilde" class MOf(_QNOf): """Symbolic access of the m quantum number of an orbit.""" - _latex_header = 'm_' + + _latex_header = "m_" class NOf(_QNOf): """Symbolic access of the n quantum number of an orbit.""" - _latex_header = 'n_' + + _latex_header = "n_" class LOf(_QNOf): """Symbolic access of the l quantum number in an orbit.""" - _latex_header = 'l_' + + _latex_header = "l_" class PiOf(_QNOf): """Symbolic access of the parity of an orbit.""" - _latex_header = r'\pi_' + + _latex_header = r"\pi_" class TOf(_QNOf): """Symbolic access to the t quantum number of an orbit.""" - _latex_header = 't_' + + _latex_header = "t_" -_SUFFIXED = re.compile(r'^([a-zA-Z]+)([0-9]+)$') +_SUFFIXED = re.compile(r"^([a-zA-Z]+)([0-9]+)$") def _decor_base(symb: Symbol, op, **kwargs): @@ -91,22 +109,20 @@ def _decor_base(symb: Symbol, op, **kwargs): """ m = _SUFFIXED.match(symb.name) if not m: - raise ValueError('Invalid symbol name to parse', symb) + raise ValueError("Invalid symbol name to parse", symb) name, suffix = m.groups() return Symbol(op(name) + suffix, **kwargs) def form_tilde(orig: Symbol): - """Form the tilde symbol for a given orbit symbol. - """ - return _decor_base(orig, lambda x: x + 'tilde') + """Form the tilde symbol for a given orbit symbol.""" + return _decor_base(orig, lambda x: x + "tilde") def form_m(orig: Symbol): - """Form the symbol for m quantum number for a given orbit symbol. - """ - return _decor_base(orig, lambda _: 'm') + """Form the symbol for m quantum number for a given orbit symbol.""" + return _decor_base(orig, lambda _: "m") class NuclearBogoliubovDrudge(BogoliubovDrudge): @@ -138,17 +154,17 @@ class NuclearBogoliubovDrudge(BogoliubovDrudge): """ def __init__( - self, ctx, coll_j_range=Range('J', 0, Symbol('Jmax') + 1), - coll_m_range=Range('M'), - coll_j_dumms=tuple( - Symbol('J{}'.format(i)) for i in range(1, 30) - ), - coll_m_dumms=tuple( - Symbol('M{}'.format(i)) for i in range(1, 30) - ), - tilde_range=Range(r'\tilde{Q}', 0, Symbol('Ntilde')), - form_tilde=form_tilde, - m_range=Range('m'), form_m=form_m, **kwargs + self, + ctx, + coll_j_range=Range("J", 0, Symbol("Jmax") + 1), + coll_m_range=Range("M"), + coll_j_dumms=tuple(Symbol("J{}".format(i)) for i in range(1, 30)), + coll_m_dumms=tuple(Symbol("M{}".format(i)) for i in range(1, 30)), + tilde_range=Range(r"\tilde{Q}", 0, Symbol("Ntilde")), + form_tilde=form_tilde, + m_range=Range("m"), + form_m=form_m, + **kwargs, ): """Initialize the drudge object.""" super().__init__(ctx, **kwargs) @@ -156,9 +172,18 @@ def __init__( # Convenient names for quantum number access functions inside drudge # scripts. self.set_name( - n_=NOf, NOf=NOf, l_=LOf, LOf=LOf, j_=JOf, JOf=JOf, - tilde_=TildeOf, TildeOf=TildeOf, m_=MOf, MOf=MOf, - pi_=PiOf, PiOf=PiOf + n_=NOf, + NOf=NOf, + l_=LOf, + LOf=LOf, + j_=JOf, + JOf=JOf, + tilde_=TildeOf, + TildeOf=TildeOf, + m_=MOf, + MOf=MOf, + pi_=PiOf, + PiOf=PiOf, ) self.coll_j_range = coll_j_range @@ -185,37 +210,45 @@ def __init__( CG=CG, Wigner3j=Wigner3j, Wigner6j=Wigner6j, Wigner9j=Wigner9j ) - self.sum_simplifiers = BCastVar(self._ctx, { - 1: [_simplify_symbolic_sum_nodoit] - }) - self._am_sum_simplifiers = BCastVar(self.ctx, { - # TODO: Add more simplifications here. - 2: [_sum_2_3j_to_delta], - 5: [_sum_4_3j_to_6j] - }) - self.set_tensor_method('simplify_am', self.simplify_am) + self.sum_simplifiers = BCastVar( + self._ctx, {1: [_simplify_symbolic_sum_nodoit]} + ) + self._am_sum_simplifiers = BCastVar( + self.ctx, + { + # TODO: Add more simplifications here. + 2: [_sum_2_3j_to_delta], + 5: [_sum_4_3j_to_6j], + }, + ) + self.set_tensor_method("simplify_am", self.simplify_am) # All expressions for J/j, for merging of simple terms with factors in # J/j-hat style. - self._j_exprs = frozenset(itertools.chain(self.coll_j_dumms, ( - JOf(i) for i in self.tilde_dumms - ))) + self._j_exprs = frozenset( + itertools.chain( + self.coll_j_dumms, (JOf(i) for i in self.tilde_dumms) + ) + ) # For angular momentum coupling. - self.set_tensor_method('do_amc', self.do_amc) + self.set_tensor_method("do_amc", self.do_amc) # Special simplification routines. - self.set_tensor_method('simplify_pono', self.simplify_pono) - self.set_tensor_method('deep_simplify', self.deep_simplify) - self.set_tensor_method('merge_j', self.merge_j) + self.set_tensor_method("simplify_pono", self.simplify_pono) + self.set_tensor_method("deep_simplify", self.deep_simplify) + self.set_tensor_method("merge_j", self.merge_j) # # Angular momentum coupling utilities # def form_amc_def( - self, base: IndexedBase, cr_order: int, an_order: int, - res_base: IndexedBase = None + self, + base: IndexedBase, + cr_order: int, + an_order: int, + res_base: IndexedBase = None, ): """Form the tensor definition for angular momentum coupled form. @@ -261,12 +294,11 @@ def form_amc_def( return self._form_amc_def_2(base, cr_order, an_order, res_base) else: raise NotImplementedError( - 'AMC has not been implemented for total order', total_order + "AMC has not been implemented for total order", total_order ) def _form_amc_def_1(self, base, cr_order, an_order, res_base): - """Form AMC for 1-body tensors. - """ + """Form AMC for 1-body tensors.""" assert cr_order + an_order == 2 k1, k2 = self.qp_dumms[:2] @@ -274,7 +306,7 @@ def _form_amc_def_1(self, base, cr_order, an_order, res_base): phase = _UNITY if cr_order == 2: - phase = _NEG_UNITY ** (JOf(k2) + mk2), + phase = (_NEG_UNITY ** (JOf(k2) + mk2),) mk2 = -mk2 elif cr_order == 1: pass @@ -284,18 +316,21 @@ def _form_amc_def_1(self, base, cr_order, an_order, res_base): else: assert 0 - res = self.define(base[k1, k2], self.sum( - phase * KroneckerDelta(PiOf(k1), PiOf(k2)) - * KroneckerDelta(JOf(k1), JOf(k2)) - * KroneckerDelta(TOf(k1), TOf(k2)) - * KroneckerDelta(mk1, mk2) - * res_base[LOf(k1), JOf(k1), TOf(k1), NOf(k1), NOf(k2)] - )) + res = self.define( + base[k1, k2], + self.sum( + phase + * KroneckerDelta(PiOf(k1), PiOf(k2)) + * KroneckerDelta(JOf(k1), JOf(k2)) + * KroneckerDelta(TOf(k1), TOf(k2)) + * KroneckerDelta(mk1, mk2) + * res_base[LOf(k1), JOf(k1), TOf(k1), NOf(k1), NOf(k2)] + ), + ) return res def _form_amc_def_2(self, base, cr_order, an_order, res_base): - """Form AMC for 2-body tensors. - """ + """Form AMC for 2-body tensors.""" assert cr_order + an_order == 4 ks = self.qp_dumms[:4] @@ -323,13 +358,19 @@ def _form_amc_def_2(self, base, cr_order, an_order, res_base): mk3 = -mk3 mk4 = -mk4 - res = self.define(base[k1, k2, k3, k4], self.sum( - (cj, self.coll_j_range), (cm, self.coll_m_range[-cj, cj + 1]), - phase - * res_base[cj, TildeOf(k1), TildeOf(k2), TildeOf(k3), TildeOf(k4)] - * CG(jk1, mk1, jk2, mk2, cj, cm) - * CG(jk3, mk3, jk4, mk4, cj, cm) - )) + res = self.define( + base[k1, k2, k3, k4], + self.sum( + (cj, self.coll_j_range), + (cm, self.coll_m_range[-cj, cj + 1]), + phase + * res_base[ + cj, TildeOf(k1), TildeOf(k2), TildeOf(k3), TildeOf(k4) + ] + * CG(jk1, mk1, jk2, mk2, cj, cm) + * CG(jk3, mk3, jk4, mk4, cj, cm), + ), + ) return res def do_amc(self, tensor: Tensor, defs, exts=None): @@ -370,7 +411,7 @@ def expand(dumm: Symbol): jtilde = JOf(tilde) return [ (form_tilde(dumm), tilde_range, tilde), - (form_m(dumm), m_range[-jtilde, jtilde + 1], MOf(dumm)) + (form_m(dumm), m_range[-jtilde, jtilde + 1], MOf(dumm)), ] return substed.expand_sums( @@ -419,12 +460,9 @@ def merge_j(self, tensor: Tensor): return tensor.merge(consts=self._j_exprs).map2amps(factor) def simplify_pono(self, tensor: Tensor): - """Simplify the powers of negative ones in the amplitudes of the tensor. - """ + """Simplify the powers of negative ones in the amplitudes of the tensor.""" resolvers = self.resolvers - return tensor.map( - lambda term: _simpl_pono_term(term, resolvers.value) - ) + return tensor.map(lambda term: _simpl_pono_term(term, resolvers.value)) @staticmethod def deep_simplify(tensor: Tensor): @@ -463,6 +501,7 @@ def deep_simplify(tensor: Tensor): # their special treatment. # + class _JM: """A pair of j and m quantum numbers. @@ -477,12 +516,7 @@ class _JM: """ - __slots__ = [ - 'j', - '_m', - '_m_symb', - '_m_phase' - ] + __slots__ = ["j", "_m", "_m_symb", "_m_phase"] def __init__(self, j: Expr, m: Expr): """Initialize the pair.""" @@ -515,33 +549,30 @@ def m(self, new_val): @property def m_symb(self): - """The only symbol in the m part when it is a bare symbol. - """ + """The only symbol in the m part when it is a bare symbol.""" return self._m_symb @property def m_phase(self): - """The phase for the bare symbol in the m part, when applicable. - """ + """The phase for the bare symbol in the m part, when applicable.""" return self._m_phase def inv_m(self): - """Invert the sign of the m part. - """ + """Invert the sign of the m part.""" self.m = -self.m def __repr__(self): - """Get a simple string form for debugging. - """ - return '{!s}, {!s}'.format(self.j, self.m) + """Get a simple string form for debugging.""" + return "{!s}, {!s}".format(self.j, self.m) # # Special simplifications of general scalar quantities. # + def _simpl_pono( - expr: Expr, resolvers, sums_dict, jms=None, rels=None, sums_only=True + expr: Expr, resolvers, sums_dict, jms=None, rels=None, sums_only=True ): """Simplify powers of negative one (pono) in the given expression. @@ -595,9 +626,7 @@ def _simpl_pono( # Preparatory steps. # Mapping from m symbols to the corresponding j symbols. - j_of = { - i.m: i.j for i in jms - } if jms else {} + j_of = {i.m: i.j for i in jms} if jms else {} # m symbols considered in the relations. A mapping from the symbol to its # index number, which is going to be used for coefficient vectors. @@ -623,7 +652,6 @@ def _simpl_pono( else: rel_dicts.append(rel) - continue # Cast the relations into vectors. raw_rel_vecs = [] @@ -632,9 +660,7 @@ def _simpl_pono( coeffs = [0] * n_symbs for k, v in i.items(): coeffs[symb2idx[k]] = v - continue raw_rel_vecs.append(Matrix(coeffs)) - continue # Gram-Schmidt procedure to make the relations orthogonal. rel_vecs = [] @@ -649,15 +675,13 @@ def _simpl_pono( lambda x: isinstance(x, Pow) and x.args[0] == -1, lambda x: _simpl_one_pono( x, resolvers, sums_dict, j_of, symb2idx, rel_vecs - ) + ), ) return expr.powsimp().simplify() -def _simpl_one_pono( - expr: Pow, resolvers, sums_dict, j_of, symb2idx, rel_vecs -): +def _simpl_one_pono(expr: Pow, resolvers, sums_dict, j_of, symb2idx, rel_vecs): """Simplify a power of negative one. Current strategy: first the linear factors over j/m symbols will be given @@ -686,40 +710,34 @@ def _simpl_one_pono( other.append(i) else: coeffs[symb2idx[symb]] += coeff - continue projed_coeffs = _proj_out(rel_vecs, Matrix(coeffs)) addends = other for i, j in zip(symb2idx.keys(), projed_coeffs): if j != 0: addends.append(i * j) - continue # Finally, canonicalize the coefficients again. expr = _NEG_UNITY ** sum(addends) if not isinstance(expr, Pow): return expr - expr = _simpl_pono_jm( - expr, resolvers, sums_dict, j_of - ) + expr = _simpl_pono_jm(expr, resolvers, sums_dict, j_of) return expr def _simpl_pono_jm(expr: Pow, resolvers, sums_dict, j_of): - """Simplify expression based on integer/half-integer properties of j/m. - """ + """Simplify expression based on integer/half-integer properties of j/m.""" addends = _parse_pono(expr) res = _UNITY # The result. def add_to_res(expon): - """Add one exponent of -1 to the result. - """ + """Add one exponent of -1 to the result.""" nonlocal res - res *= (_NEG_UNITY ** expon).simplify() + res *= (_NEG_UNITY**expon).simplify() return phase = 1 # The overall +- 1 phase, separated out for performance. @@ -756,7 +774,6 @@ def add_to_res(expon): phase *= _NEG_UNITY add_to_res(canon_numer / denom * symb) - continue return res.powsimp().simplify() * phase @@ -786,8 +803,6 @@ def _find_if_half_int(indics, sums_dict, resolvers): elif (2 * lower).is_integer: return True - continue - # After all indicators have been tried. return None @@ -805,8 +820,7 @@ def _parse_pono(expr: Pow): def _simpl_pono_term(term: Term, resolvers) -> Term: - """Try to simplify powers of negative unity in a term. - """ + """Try to simplify powers of negative unity in a term.""" sums_dict = dict(term.sums) other, wigner_3js = _parse_3js(term.amp) @@ -816,9 +830,7 @@ def _simpl_pono_term(term: Term, resolvers) -> Term: other, resolvers, sums_dict, jms, rels, sums_only=False ) - new_amp = new_other * prod_( - i.expr for i in wigner_3js - ) + new_amp = new_other * prod_(i.expr for i in wigner_3js) return Term(term.sums, new_amp, term.vecs) @@ -827,6 +839,7 @@ def _simpl_pono_term(term: Term, resolvers) -> Term: # General utilities # + def _parse_sum(expr: Sum): """Parse a SymPy summation into the summand and the summations. @@ -834,9 +847,7 @@ def _parse_sum(expr: Sum): """ assert isinstance(expr, Sum) args = expr.args - return args[0], { - i: (j, k) for i, j, k in args[1:] - } + return args[0], {i: (j, k) for i, j, k in args[1:]} class _UnexpectedForm(ValueError): @@ -848,6 +859,7 @@ class _UnexpectedForm(ValueError): can have a central handling for noncompliance. """ + pass @@ -903,31 +915,23 @@ def _decomp_phase(phase: Expr, sums): inv = _UNITY other = _UNITY - for i in ( - expanded.args if isinstance(expanded, Mul) else (expanded,) - ): + for i in expanded.args if isinstance(expanded, Mul) else (expanded,): if i.atoms(Symbol).isdisjoint(dumms): other *= i else: inv *= i - continue - return tuple( - i.powsimp().simplify() for i in (other, inv) - ) + return tuple(i.powsimp().simplify() for i in (other, inv)) def _rewrite_cg(expr): - """Rewrite CG coefficients in terms of the Wigner 3j symbols. - """ - j1, m1, j2, m2, j3, m3 = symbols( - 'j1 m1 j2 m2 j3 m3', cls=Wild - ) + """Rewrite CG coefficients in terms of the Wigner 3j symbols.""" + j1, m1, j2, m2, j3, m3 = symbols("j1 m1 j2 m2 j3 m3", cls=Wild) return expr.replace( CG(j1, m1, j2, m2, j3, m3), - _NEG_UNITY ** (-j1 + j2 - m3) * sqrt(2 * j3 + 1) * Wigner3j( - j1, m1, j2, m2, j3, -m3 - ) + _NEG_UNITY ** (-j1 + j2 - m3) + * sqrt(2 * j3 + 1) + * Wigner3j(j1, m1, j2, m2, j3, -m3), ) @@ -935,6 +939,7 @@ def _rewrite_cg(expr): # Special simplifications # + class _Wigner3j: """Wrapper for a Wigner 3j symbols for easy manipulation. @@ -966,12 +971,12 @@ class _Wigner3j: """ __slots__ = [ - 'indices', - '_slot_decided', - 'phase_decided', - '_uniq_m', - '_total_j', - '_m_dumms' + "indices", + "_slot_decided", + "phase_decided", + "_uniq_m", + "_total_j", + "_m_dumms", ] def __init__(self, expr: Wigner3j, sums=None, uniq_m=True): @@ -979,9 +984,7 @@ def __init__(self, expr: Wigner3j, sums=None, uniq_m=True): assert isinstance(expr, Wigner3j) args = expr.args - indices = [ - _JM(args[i], args[i + 1]) for i in range(0, 6, 2) - ] + indices = [_JM(args[i], args[i + 1]) for i in range(0, 6, 2)] self.indices = indices self._slot_decided = [False for _ in range(3)] self.phase_decided = False @@ -1002,7 +1005,6 @@ def __init__(self, expr: Wigner3j, sums=None, uniq_m=True): m_dumms[m_symb].add(i) else: m_dumms[m_symb] = i if uniq_m else {i} - continue # This does not change after the manipulations. self._total_j = sum(i.j for i in indices) @@ -1029,8 +1031,7 @@ def expr(self): return Wigner3j(*args) def is_decided(self, slot_index): - """If the content for a slot has been decided. - """ + """If the content for a slot has been decided.""" return self._slot_decided[slot_index] def decide(self, slot_index): @@ -1041,8 +1042,7 @@ def decide(self, slot_index): self._slot_decided[slot_index] = True def swap( - self, src, dest, raise_src=False, raise_dest=False, - raise_pred=False + self, src, dest, raise_src=False, raise_dest=False, raise_pred=False ) -> typing.Optional[Expr]: """Try to swap index slots. @@ -1064,8 +1064,6 @@ def swap( for i, v in enumerate(self.indices): if pred(v): src = i if src is None else False - else: - continue if src is None or src is False: return _fail(raise_pred) @@ -1089,7 +1087,7 @@ def swap( # symbol does not need to be changed as well. for m_symb, old_idx, new_idx in [ (src_m, src, dest), - (dest_m, dest, src) + (dest_m, dest, src), ]: if m_symb is None or m_symb not in self._m_dumms: continue @@ -1103,28 +1101,29 @@ def swap( entry.add(new_idx) self.decide(dest) - return _NEG_UNITY ** self._total_j + return _NEG_UNITY**self._total_j def inv_ms(self): - """Invert the sign of all m quantum numbers. - """ + """Invert the sign of all m quantum numbers.""" for i in self.indices: i.inv_m() - continue - return _NEG_UNITY ** self._total_j + return _NEG_UNITY**self._total_j def __repr__(self): - """Form a string representation for easy debugging. - """ - return '_Wigner3j({})'.format(', '.join([ - repr(i) for i in self.indices - ])) + """Form a string representation for easy debugging.""" + return "_Wigner3j({})".format( + ", ".join([repr(i) for i in self.indices]) + ) def _check_m_contr( - factor1: _Wigner3j, factor2: _Wigner3j, decided_ms, normal, inv, - raise_=True + factor1: _Wigner3j, + factor2: _Wigner3j, + decided_ms, + normal, + inv, + raise_=True, ) -> typing.Optional[Expr]: """Check if two Wigner 3j symbols contracts according to the given pattern. @@ -1245,11 +1244,8 @@ def _check_m_contr( return res -def _check_m_contr_fixed_phase( - factor1, factor2, normal, inv, shared_dumms -): - """Check the m contraction of two symbols with fixed phase. - """ +def _check_m_contr_fixed_phase(factor1, factor2, normal, inv, shared_dumms): + """Check the m contraction of two symbols with fixed phase.""" factors = [factor1, factor2] indices1 = factor1.indices @@ -1274,7 +1270,6 @@ def _check_m_contr_fixed_phase( dumms.add(dumm) if not factor1.is_decided(i1) and not factor2.is_decided(i2): frees.add(dumm) - continue if len(normal_dumms) != len(normal) or len(inv_dumms) != len(inv): return None @@ -1282,7 +1277,7 @@ def _check_m_contr_fixed_phase( phase = _UNITY for to_proc, dumms, frees in [ (normal, normal_dumms, free_normal_dumms), - (inv, inv_dumms, free_inv_dumms) + (inv, inv_dumms, free_inv_dumms), ]: for i1, i2 in to_proc: decided1 = factor1.is_decided(i1) @@ -1342,9 +1337,7 @@ def _check_m_contr_fixed_phase( return phase -def _parse_3js(expr, **kwargs) -> typing.Tuple[ - Expr, typing.List[_Wigner3j] -]: +def _parse_3js(expr, **kwargs) -> typing.Tuple[Expr, typing.List[_Wigner3j]]: """Parse an expression of Wigner 3j symbol product. The result is a phase and a list of wrappers of 3j symbols. All keyword @@ -1359,7 +1352,6 @@ def _parse_3js(expr, **kwargs) -> typing.Tuple[ wigner_3js.append(_Wigner3j(i, **kwargs)) else: phase *= i - continue return phase, wigner_3js @@ -1373,7 +1365,7 @@ def _get_jms_rels(wigner_3js: typing.Iterable[_Wigner3j]): return ( [j for i in wigner_3js for j in i.indices], - [i.indices for i in wigner_3js] + [i.indices for i in wigner_3js], ) @@ -1398,9 +1390,9 @@ def _sum_2_3j_to_delta(expr: Sum, resolvers, sums_dict): return None decided_ms = {} - phase *= _check_m_contr(wigner_3js[0], wigner_3js[1], decided_ms, [ - (0, 0), (1, 1) - ], []) + phase *= _check_m_contr( + wigner_3js[0], wigner_3js[1], decided_ms, [(0, 0), (1, 1)], [] + ) except _UnexpectedForm: return None @@ -1419,9 +1411,12 @@ def _sum_2_3j_to_delta(expr: Sum, resolvers, sums_dict): j3, m3 = indices0[2].j, indices0[2].m j4, m4 = indices1[2].j, indices1[2].m - return KroneckerDelta(j3, j4) * KroneckerDelta( - m3, m4 - ) / (2 * j3 + 1) * noinv_phase + return ( + KroneckerDelta(j3, j4) + * KroneckerDelta(m3, m4) + / (2 * j3 + 1) + * noinv_phase + ) def _sum_4_3j_to_6j(expr: Sum, resolvers, sums_dict): @@ -1454,16 +1449,12 @@ def _sum_4_3j_to_6j(expr: Sum, resolvers, sums_dict): ext_3js.append(i) else: return None - continue if len(ext_3js) != 2 or len(int_3js) != 2: return None # Put the external ones in the middle. for ext_3j in ext_3js: - phase *= ext_3j.swap( - lambda x: x.m_symb not in sums, 1 - ) - continue + phase *= ext_3j.swap(lambda x: x.m_symb not in sums, 1) decided_ms = {} @@ -1511,17 +1502,26 @@ def _sum_4_3j_to_6j(expr: Sum, resolvers, sums_dict): noinv_phase, phase = _decomp_phase(phase.xreplace(decided_ms), sums) jms, rels = _get_jms_rels(wigner_3js) simpl_phase = _simpl_pono(phase, resolvers, sums_dict, jms, rels) - expected_phase = _simpl_pono(_NEG_UNITY ** ( - - m1 - m2 - m4 - m5 - m6 - ), resolvers, sums_dict, jms, rels) + expected_phase = _simpl_pono( + _NEG_UNITY ** (-m1 - m2 - m4 - m5 - m6), + resolvers, + sums_dict, + jms, + rels, + ) if (simpl_phase / expected_phase).simplify() != 1: return None - return _NEG_UNITY ** (j3 - m3 - j1 - j2 - j4 - j5 - j6) / (2 * j3 + 1) * ( + return ( + _NEG_UNITY ** (j3 - m3 - j1 - j2 - j4 - j5 - j6) + / (2 * j3 + 1) + * ( KroneckerDelta(j3, jprm3) * KroneckerDelta(m3, mprm3) * Wigner6j(j1, j2, j3, j4, j5, j6) - ) * noinv_phase + ) + * noinv_phase + ) def _proj_out(bases, vec): @@ -1535,8 +1535,7 @@ def _proj_out(bases, vec): def _canon_cg(expr): - """Pose CG coefficients in the expression into canonical form. - """ + """Pose CG coefficients in the expression into canonical form.""" return expr.replace(CG, _canon_cg_core) @@ -1576,7 +1575,7 @@ def _simpl_varsh_872_4(expr: Sum): return None dummies = (expr.args[1][0], expr.args[2][0]) - j1, j2, cj1, cm1, cj2, cm2 = symbols('j1 j2 J1 M1 J2 M2', cls=Wild) + j1, j2, cj1, cm1, cj2, cm2 = symbols("j1 j2 J1 M1 J2 M2", cls=Wild) for m1, m2 in [dummies, reversed(dummies)]: match = expr.args[0].match( @@ -1584,21 +1583,20 @@ def _simpl_varsh_872_4(expr: Sum): ) if not match: continue - return KroneckerDelta( - match[cj1], match[cj2] - ) * KroneckerDelta(match[cm1], match[cm2]) + return KroneckerDelta(match[cj1], match[cj2]) * KroneckerDelta( + match[cm1], match[cm2] + ) return None def _simpl_varsh_872_5(expr: Sum): - """Make CG simplification based on Varsh 8.7.2 Eq (5). - """ + """Make CG simplification based on Varsh 8.7.2 Eq (5).""" if len(expr.args) != 3: return None dummies = (expr.args[1][0], expr.args[2][0]) - j1, j2, m2, j3, m3, cj = symbols('j1 j2 m2 j3 m3 J', cls=Wild) + j1, j2, m2, j3, m3, cj = symbols("j1 j2 m2 j3 m3 J", cls=Wild) for m1, cm in [dummies, reversed(dummies)]: match = expr.args[0].match( CG(j1, m1, j2, m2, cj, cm) * CG(j1, m1, j3, m3, cj, cm) @@ -1610,32 +1608,35 @@ def _simpl_varsh_872_5(expr: Sum): cjhat = 2 * match[cj] + 1 jhat2 = 2 * match[j2] + 1 - return (cjhat / jhat2) * KroneckerDelta( - match[j2], match[j3] - ) * KroneckerDelta(match[m2], match[m3]) + return ( + (cjhat / jhat2) + * KroneckerDelta(match[j2], match[j3]) + * KroneckerDelta(match[m2], match[m3]) + ) return None def _simpl_varsh_911_8(expr: Sum): - """Make CG simplification based on Varsh 9.1.1 Eq (8). - """ + """Make CG simplification based on Varsh 9.1.1 Eq (8).""" if len(expr.args) != 6: return None - j, m, j12, m12, j2, m2 = symbols('j m j12 m12 j2 m2', cls=Wild) - j1, m1 = symbols('j1 m1', cls=Wild) - j_prm, m_prm, j22, m22 = symbols('jprm mprm j22 m22', cls=Wild) - j23, m23, j3, m3 = symbols('j23 m23 j3 m3', cls=Wild) + j, m, j12, m12, j2, m2 = symbols("j m j12 m12 j2 m2", cls=Wild) + j1, m1 = symbols("j1 m1", cls=Wild) + j_prm, m_prm, j22, m22 = symbols("jprm mprm j22 m22", cls=Wild) + j23, m23, j3, m3 = symbols("j23 m23 j3 m3", cls=Wild) match = expr.args[0].match( - CG(j12, m12, j3, m3, j, m) * CG(j1, m1, j2, m2, j12, m12) * - CG(j1, m1, j23, m23, j_prm, m_prm) * CG(j2, m2, j3, m3, j23, m23) + CG(j12, m12, j3, m3, j, m) + * CG(j1, m1, j2, m2, j12, m12) + * CG(j1, m1, j23, m23, j_prm, m_prm) + * CG(j2, m2, j3, m3, j23, m23) ) - if not match or sorted((match[i] for i in ( - m1, m2, m3, m12, m23 - )), key=sympy_key) != sorted((i[0] for i in expr.args[1:]), key=sympy_key): + if not match or sorted( + (match[i] for i in (m1, m2, m3, m12, m23)), key=sympy_key + ) != sorted((i[0] for i in expr.args[1:]), key=sympy_key): return None jhat12 = sqrt(2 * match[j12] + 1) @@ -1643,19 +1644,21 @@ def _simpl_varsh_911_8(expr: Sum): phase = _NEG_UNITY ** (match[j1] + match[j2] + match[j3] + match[j]) - return jhat12 * jhat23 * phase * KroneckerDelta( - match[j], match[j_prm] - ) * KroneckerDelta(match[m], match[m_prm]) * Wigner6j( - match[j1], match[j2], match[j12], match[j3], match[j], match[j23] + return ( + jhat12 + * jhat23 + * phase + * KroneckerDelta(match[j], match[j_prm]) + * KroneckerDelta(match[m], match[m_prm]) + * Wigner6j( + match[j1], match[j2], match[j12], match[j3], match[j], match[j23] + ) ) def _simplify_symbolic_sum_nodoit(expr, **_): - """Try to simplify a symbolic summation of one dummy with `doit=False`. - """ + """Try to simplify a symbolic summation of one dummy with `doit=False`.""" assert len(expr.args) == 2 - return eval_sum_symbolic( - expr.args[0].simplify(doit=False), expr.args[1] - ) + return eval_sum_symbolic(expr.args[0].simplify(doit=False), expr.args[1]) diff --git a/drudge/report.py b/drudge/report.py index a839096e..830cc838 100644 --- a/drudge/report.py +++ b/drudge/report.py @@ -25,26 +25,22 @@ def __init__(self, filename: str, title: str, drudge: str): self._filename = filename self._drudge = drudge - filename_parts = filename.split('.') + filename_parts = filename.split(".") if len(filename_parts) < 2: raise ValueError( - 'Invalid filename, unable to determine type', filename + "Invalid filename, unable to determine type", filename ) ext = filename_parts[-1].lower() - if ext not in {'html', 'tex', 'pdf'}: - raise ValueError('Invalid extension', ext, 'in', filename) + if ext not in {"html", "tex", "pdf"}: + raise ValueError("Invalid extension", ext, "in", filename) self._ext = ext - self._basename = '.'.join(filename_parts[:-1]) + self._basename = ".".join(filename_parts[:-1]) self._sects = [] - self._ctx = { - 'title': title, - 'sects': self._sects - } + self._ctx = {"title": title, "sects": self._sects} def add( - self, title=None, content=None, description=None, - env='[', **kwargs + self, title=None, content=None, description=None, env="[", **kwargs ): r"""Add a section to the result. @@ -90,17 +86,16 @@ def add( """ - if env == '[': - opening, closing = r'\[', r'\]' + if env == "[": + opening, closing = r"\[", r"\]" else: opening, closing = [ - r'\{}{{{}}}'.format(i, env) - for i in ['begin', 'end'] + r"\{}{{{}}}".format(i, env) for i in ["begin", "end"] ] if content is None: expr = None - elif hasattr(content, 'latex'): + elif hasattr(content, "latex"): expr = content.latex(**kwargs) elif isinstance(content, ATerms): expr = self._drudge.sum(content).latex(**kwargs) @@ -108,13 +103,15 @@ def add( # Try to use raw SymPy LaTeX printing. expr = ScalarLatexPrinter().doprint(content) - self._sects.append({ - 'title': title, - 'description': description, - 'expr': expr, - 'opening': opening, - 'closing': closing - }) + self._sects.append( + { + "title": title, + "description": description, + "expr": expr, + "opening": opening, + "closing": closing, + } + ) def write(self): """Write the report. @@ -123,41 +120,43 @@ def write(self): """ env = Environment( - loader=PackageLoader('drudge'), - lstrip_blocks=True, trim_blocks=True + loader=PackageLoader("drudge"), + lstrip_blocks=True, + trim_blocks=True, ) - if self._ext == 'html': - templ_name = 'report.html' + if self._ext == "html": + templ_name = "report.html" filename = self._filename - elif self._ext == 'tex' or self._ext == 'pdf': - templ_name = 'report.tex' - filename = self._basename + '.tex' + elif self._ext == "tex" or self._ext == "pdf": + templ_name = "report.tex" + filename = self._basename + ".tex" else: assert False templ = env.get_template(templ_name) - with open(filename, 'w') as fp: + with open(filename, "w") as fp: templ.stream(self._ctx).dump(fp) - if self._ext == 'pdf': + if self._ext == "pdf": if shutil.which(_PDFLATEX) is not None: stat = subprocess.run( [_PDFLATEX, filename], - stdout=subprocess.PIPE, stderr=subprocess.PIPE + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) # Do not crash program only because LaTeX does not compile. if stat.returncode != 0: - err_msg = '{} failed for {}. Error: \n{}\n{}'.format( + err_msg = "{} failed for {}. Error: \n{}\n{}".format( _PDFLATEX, filename, stat.stdout, stat.stderr ) warnings.warn(err_msg) else: - warnings.warn('{} cannot be found.'.format(_PDFLATEX)) + warnings.warn("{} cannot be found.".format(_PDFLATEX)) -_PDFLATEX = 'pdflatex' +_PDFLATEX = "pdflatex" class ScalarLatexPrinter(LatexPrinter): @@ -172,15 +171,11 @@ class ScalarLatexPrinter(LatexPrinter): def _print_Indexed(self, expr): base = self._print(expr.base) - match = re.match(r'(.*)_\{(.*)\}', base) + match = re.match(r"(.*)_\{(.*)\}", base) if match and len(match.group(2)) > 0: - base = ''.join([ - match.group(1), '^{(', match.group(2), ')}' - ]) - if base.startswith('_'): + base = "".join([match.group(1), "^{(", match.group(2), ")}"]) + if base.startswith("_"): base = base[1:] - indices = ','.join(self._print(i) for i in expr.indices) - return ''.join([ - base, '_{', indices, '}' - ]) + indices = ",".join(self._print(i) for i in expr.indices) + return "".join([base, "_{", indices, "}"]) diff --git a/drudge/su2.py b/drudge/su2.py index 44d20ddf..49714bcb 100644 --- a/drudge/su2.py +++ b/drudge/su2.py @@ -71,21 +71,26 @@ class SU2LatticeDrudge(GenQuadLatticeDrudge): """ - DEFAULT_CARTAN = Vec('J^z') - DEFAULT_RAISE = Vec('J^+') - DEFAULT_LOWER = Vec('J^-') + DEFAULT_CARTAN = Vec("J^z") + DEFAULT_RAISE = Vec("J^+") + DEFAULT_LOWER = Vec("J^-") def __init__( - self, ctx, cartan=DEFAULT_CARTAN, raise_=DEFAULT_RAISE, - lower=DEFAULT_LOWER, root=Integer(1), norm=Integer(2), shift=0, - order=None, specials=None, **kwargs + self, + ctx, + cartan=DEFAULT_CARTAN, + raise_=DEFAULT_RAISE, + lower=DEFAULT_LOWER, + root=Integer(1), + norm=Integer(2), + shift=0, + order=None, + specials=None, + **kwargs, ): - r"""Initialize the drudge. - """ + r"""Initialize the drudge.""" - order = order if order is not None else ( - raise_, cartan, lower - ) + order = order if order is not None else (raise_, cartan, lower) raise_lower_comm = norm * cartan if shift != 0: @@ -94,7 +99,7 @@ def __init__( comms = { (cartan, raise_): root * raise_, (cartan, lower): -root * lower, - (raise_, lower): raise_lower_comm + (raise_, lower): raise_lower_comm, } if specials is not None: @@ -105,10 +110,12 @@ def __init__( self.cartan = cartan self.raise_ = raise_ self.lower = lower - self.set_name(**{ - cartan.label[0] + '_': cartan, - raise_.label[0] + '_p': raise_, - lower.label[0] + '_m': lower - }) + self.set_name( + **{ + cartan.label[0] + "_": cartan, + raise_.label[0] + "_p": raise_, + lower.label[0] + "_m": lower, + } + ) - _latex_vec_mul = ' ' + _latex_vec_mul = " " diff --git a/drudge/term.py b/drudge/term.py index 6603a7bd..b85bf89b 100644 --- a/drudge/term.py +++ b/drudge/term.py @@ -11,15 +11,39 @@ from collections.abc import Iterable, Mapping, Callable, Sequence from sympy import ( - sympify, Symbol, KroneckerDelta, Eq, solveset, S, Integer, Add, Mul, Number, - Indexed, IndexedBase, Expr, Basic, Pow, Wild, conjugate, Sum, Piecewise, - Intersection, expand_power_base, expand_power_exp + sympify, + Symbol, + KroneckerDelta, + Eq, + solveset, + S, + Integer, + Add, + Mul, + Number, + Indexed, + IndexedBase, + Expr, + Basic, + Pow, + Wild, + conjugate, + Sum, + Piecewise, + Intersection, + expand_power_base, + expand_power_exp, ) from sympy.core.sympify import CantSympify from .canon import canon_factors from .utils import ( - ensure_symb, ensure_expr, sympy_key, is_higher, NonsympifiableFunc, prod_ + ensure_symb, + ensure_expr, + sympy_key, + is_higher, + NonsympifiableFunc, + prod_, ) # @@ -64,30 +88,25 @@ class Range: """ - __slots__ = [ - '_label', - '_lower', - '_upper' - ] + __slots__ = ["_label", "_lower", "_upper"] def __init__(self, label, lower=None, upper=None): - """Initialize the symbolic range. - """ + """Initialize the symbolic range.""" self._label = label self._lower = ( - ensure_expr(lower, 'lower bound') if lower is not None else lower + ensure_expr(lower, "lower bound") if lower is not None else lower ) if self._lower is None: if upper is not None: - raise ValueError('lower range has not been given.') + raise ValueError("lower range has not been given.") else: self._upper = None else: if upper is None: - raise ValueError('upper range has not been given.') + raise ValueError("upper range has not been given.") else: - self._upper = ensure_expr(upper, 'upper bound') + self._upper = ensure_expr(upper, "upper bound") @property def label(self): @@ -133,30 +152,22 @@ def args(self): if self.bounded: return self._label, self._lower, self._upper else: - return self._label, + return (self._label,) def __hash__(self): - """Hash the symbolic range. - """ + """Hash the symbolic range.""" return hash(self._label) def __eq__(self, other): - """Compare equality of two ranges. - """ - return isinstance(other, type(self)) and ( - self._label == other.label - ) + """Compare equality of two ranges.""" + return isinstance(other, type(self)) and (self._label == other.label) def __repr__(self): - """Form the representative string. - """ - return ''.join([ - 'Range(', ', '.join(repr(i) for i in self.args), ')' - ]) + """Form the representative string.""" + return "".join(["Range(", ", ".join(repr(i) for i in self.args), ")"]) def __str__(self): - """Form readable string representation. - """ + """Form readable string representation.""" return str(self._label) @property @@ -183,7 +194,7 @@ def __lt__(self, other): """ if not isinstance(other, Range): - raise TypeError('Invalid range to compare', other) + raise TypeError("Invalid range to compare", other) return self.sort_key < other.sort_key @@ -195,8 +206,8 @@ def __getitem__(self, item): """ if not isinstance(item, tuple) or len(item) != 2: raise TypeError( - 'Invalid bounds for range, expecting upper and lower range', - item + "Invalid bounds for range, expecting upper and lower range", + item, ) lower, upper = [sympify(i) for i in item] @@ -223,9 +234,8 @@ class ATerms(abc.ABC): @property @abc.abstractmethod - def terms(self) -> typing.List['Term']: - """Get an list for the terms. - """ + def terms(self) -> typing.List["Term"]: + """Get an list for the terms.""" pass # @@ -266,7 +276,6 @@ def _mul(left_terms, right_terms): vecs = i.vecs + j.vecs prod_terms.append(Term(sums, amp, vecs)) - continue return Terms(prod_terms) @@ -306,35 +315,28 @@ def __neg__(self): @staticmethod def _add(left_terms, right_terms): - """Add the terms together. - """ + """Add the terms together.""" return Terms(itertools.chain(left_terms, right_terms)) @staticmethod - def _neg_terms(terms: typing.Iterable['Term']): + def _neg_terms(terms: typing.Iterable["Term"]): """Negate the given terms. The resulted terms are lazily evaluated. """ - return ( - Term(i.sums, i.amp * _NEG_UNITY, i.vecs) - for i in terms - ) + return (Term(i.sums, i.amp * _NEG_UNITY, i.vecs) for i in terms) def __truediv__(self, other): """Make division with another object.""" other = sympify(other) - return Terms([ - i.scale(1 / other) for i in self.terms - ]) + return Terms([i.scale(1 / other) for i in self.terms]) def __rtruediv__(self, other): """Being divided over by other object.""" - raise NotImplementedError('General tensors cannot inversed') + raise NotImplementedError("General tensors cannot inversed") def __or__(self, other): - """Compute the commutator with another object. - """ + """Compute the commutator with another object.""" if is_higher(other, self._op_priority): return NotImplemented return self * other - other * self @@ -353,9 +355,9 @@ class Terms(ATerms): the abstract terms objects will be elevated to instances of this class. """ - __slots__ = ['_terms'] + __slots__ = ["_terms"] - def __init__(self, terms: typing.Iterable['Term']): + def __init__(self, terms: typing.Iterable["Term"]): """Initialize the terms object. The possibly lazy iterable of terms will be instantiated here. And zero @@ -369,7 +371,7 @@ def terms(self): return self._terms -def parse_terms(obj) -> typing.List['Term']: +def parse_terms(obj) -> typing.List["Term"]: """Parse the object into a list of terms.""" if isinstance(obj, ATerms): @@ -401,7 +403,7 @@ class Vec(ATerms, CantSympify): """ - __slots__ = ['_label', '_indices'] + __slots__ = ["_label", "_indices"] def __init__(self, label, indices=()): """Initialize a vector. @@ -412,12 +414,11 @@ def __init__(self, label, indices=()): self._label = label if not isinstance(indices, Iterable): indices = (indices,) - self._indices = tuple(ensure_expr(i, 'vector index') for i in indices) + self._indices = tuple(ensure_expr(i, "vector index") for i in indices) @property def label(self): - """The label for the base of the vector. - """ + """The label for the base of the vector.""" return self._label @property @@ -430,8 +431,7 @@ def base(self): @property def indices(self): - """The indices to the vector. - """ + """The indices to the vector.""" return self._indices def __getitem__(self, item): @@ -449,22 +449,27 @@ def __getitem__(self, item): def __repr__(self): """Form repr string form the vector.""" - return ''.join([ - type(self).__name__, '(', repr(self._label), ', (', - ', '.join(repr(i) for i in self._indices), - '))' - ]) + return "".join( + [ + type(self).__name__, + "(", + repr(self._label), + ", (", + ", ".join(repr(i) for i in self._indices), + "))", + ] + ) def __str__(self): """Form a more readable string representation.""" label = str(self._label) if len(self._indices) > 0: - indices = ''.join([ - '[', ', '.join(str(i) for i in self._indices), ']' - ]) + indices = "".join( + ["[", ", ".join(str(i) for i in self._indices), "]"] + ) else: - indices = '' + indices = "" return label + indices @@ -475,9 +480,9 @@ def __hash__(self): def __eq__(self, other): """Compares the equality of two vectors.""" return ( - (isinstance(self, type(other)) or - isinstance(other, type(self))) and - self._label == other.label and self._indices == other.indices + (isinstance(self, type(other)) or isinstance(other, type(self))) + and self._label == other.label + and self._indices == other.indices ) @property @@ -521,19 +526,15 @@ class Term(ATerms): vectors. """ - __slots__ = [ - '_sums', - '_amp', - '_vecs', - '_free_vars', - '_dumms' - ] + __slots__ = ["_sums", "_amp", "_vecs", "_free_vars", "_dumms"] def __init__( - self, sums: typing.Tuple[typing.Tuple[Symbol, Range], ...], - amp: Expr, vecs: typing.Tuple[Vec, ...], - free_vars: typing.FrozenSet[Symbol] = None, - dumms: typing.Mapping[Symbol, Range] = None, + self, + sums: typing.Tuple[typing.Tuple[Symbol, Range], ...], + amp: Expr, + vecs: typing.Tuple[Vec, ...], + free_vars: typing.FrozenSet[Symbol] = None, + dumms: typing.Mapping[Symbol, Range] = None, ): """Initialize the tensor term. @@ -601,22 +602,23 @@ def __eq__(self, other): def __repr__(self): """Form the representative string of a term.""" - return 'Term(sums=[{}], amp={}, vecs=[{}])'.format( - ', '.join(repr(i) for i in self._sums), + return "Term(sums=[{}], amp={}, vecs=[{}])".format( + ", ".join(repr(i) for i in self._sums), repr(self._amp), - ', '.join(repr(i) for i in self._vecs) + ", ".join(repr(i) for i in self._vecs), ) def __str__(self): """Form the readable string representation of a term.""" if len(self._sums) > 0: - header = 'sum_{{{}}} '.format( - ', '.join(str(i[0]) for i in self._sums)) + header = "sum_{{{}}} ".format( + ", ".join(str(i[0]) for i in self._sums) + ) else: - header = '' + header = "" factors = [str(self._amp)] factors.extend(str(i) for i in self._vecs) - return header + ' * '.join(factors) + return header + " * ".join(factors) @property def sort_key(self): @@ -635,9 +637,11 @@ def sort_key(self): sum_keys = [(i[1].sort_key, sympy_key(i[0])) for i in self._sums] return ( - len(vec_keys), vec_keys, - len(sum_keys), sum_keys, - sympy_key(self._amp) + len(vec_keys), + vec_keys, + len(sum_keys), + sum_keys, + sympy_key(self._amp), ) @property @@ -650,8 +654,7 @@ def terms(self): return [self] def scale(self, factor): - """Scale the term by a factor. - """ + """Scale the term by a factor.""" return Term(self._sums, self._amp * factor, self._vecs) def mul_term(self, other, dumms=None, excl=None): @@ -676,7 +679,7 @@ def comm_term(self, other, dumms=None, excl=None): amp0 = lhs.amp * rhs.amp return [ Term(sums, amp0, lhs.vecs + rhs.vecs), - Term(sums, -amp0, rhs.vecs + lhs.vecs) + Term(sums, -amp0, rhs.vecs + lhs.vecs), ] def reconcile_dumms(self, other, dumms, excl): @@ -699,31 +702,29 @@ def exprs(self): if range_.bounded: yield range_.lower yield range_.upper - continue yield self._amp for vec in self._vecs: yield from vec.indices - continue @property def free_vars(self): - """The free symbols used in the term. - """ + """The free symbols used in the term.""" if self._free_vars is None: dumms = self.dumms self._free_vars = set( - i for expr in self.exprs for i in expr.atoms(Symbol) + i + for expr in self.exprs + for i in expr.atoms(Symbol) if i not in dumms ) return self._free_vars @property def dumms(self): - """Get the mapping from dummies to their range. - """ + """Get the mapping from dummies to their range.""" if self._dumms is None: self._dumms = dict(self._sums) @@ -753,7 +754,7 @@ def get_amp_factors(self, *special_symbs, monom_only=True): amp = self._amp if monom_only and isinstance(amp, Add): - raise ValueError('Invalid amplitude: ', amp, 'expecting monomial') + raise ValueError("Invalid amplitude: ", amp, "expecting monomial") if isinstance(amp, Mul): all_factors = amp.args @@ -773,13 +774,17 @@ def get_amp_factors(self, *special_symbs, monom_only=True): factors.append(factor) else: coeff *= factor - continue return factors, coeff def map( - self, func=lambda x: x, sums=None, amp=None, vecs=None, - skip_vecs=False, skip_ranges=False + self, + func=lambda x: x, + sums=None, + amp=None, + vecs=None, + skip_vecs=False, + skip_ranges=False, ): """Map the given function to the SymPy expressions in the term. @@ -823,8 +828,11 @@ def subst(self, substs, sums=None, amp=None, vecs=None, purge_sums=False): sums = tuple(sum_ for sum_ in sums if sum_[0] not in substs) return self.map( - lambda x: x.xreplace(substs), sums=sums, amp=amp, vecs=vecs, - skip_ranges=False + lambda x: x.xreplace(substs), + sums=sums, + amp=amp, + vecs=vecs, + skip_ranges=False, ) def reset_dumms(self, dumms, dummbegs=None, excl=None, add_substs=None): @@ -859,35 +867,32 @@ def reset_sums(sums, dumms, dummbegs=None, excl=None): new_sums = [] substs = {} for dumm_i, range_i in sums: - # For linter. new_dumm = None new_beg = None beg = dummbegs[range_i] if range_i in dummbegs else 0 for i in itertools.count(beg): - try: tentative = dumms[range_i][i] except KeyError: - raise ValueError('Dummies for range', range_i, - 'is not given') + raise ValueError( + "Dummies for range", range_i, "is not given" + ) except IndexError: - raise ValueError('Dummies for range', range_i, 'is used up') + raise ValueError( + "Dummies for range", range_i, "is used up" + ) if excl is None or tentative not in excl: new_dumm = tentative new_beg = i + 1 break - else: - continue new_sums.append((new_dumm, range_i)) substs[dumm_i] = new_dumm dummbegs[range_i] = new_beg - continue - return tuple(new_sums), substs, dummbegs # @@ -911,9 +916,7 @@ def simplify_trivial_sums(self): involvement at all. """ - involved = { - i for expr in self.exprs for i in expr.atoms(Symbol) - } + involved = {i for expr in self.exprs for i in expr.atoms(Symbol)} new_sums = [] factor = _UNITY @@ -925,7 +928,6 @@ def simplify_trivial_sums(self): factor *= range_.size else: new_sums.append((symb, range_)) - continue if dirty: return Term(tuple(new_sums), factor * self._amp, self._vecs) @@ -1003,9 +1005,14 @@ def replace_to_treats(expr: Expr): if expr.func in symms or (expr.func, len(expr.args)) in symms: if_treat = True else: - if_treat = sum(1 for arg in expr.args if any( - arg.has(dumm) for dumm, _ in self.sums - )) > 1 + if_treat = ( + sum( + 1 + for arg in expr.args + if any(arg.has(dumm) for dumm, _ in self.sums) + ) + > 1 + ) if if_treat: to_treats.append(expr) @@ -1015,55 +1022,49 @@ def replace_to_treats(expr: Expr): amp_factors, coeff = self.amp_factors for i in amp_factors: - amp_no_treated = i.replace( lambda _: True, NonsympifiableFunc(replace_to_treats) ) n_to_treats = len(to_treats) if n_to_treats > 1: - raise ValueError( - 'Overly complex factor', i - ) + raise ValueError("Overly complex factor", i) elif n_to_treats == 1: to_treat = to_treats[0] to_treats.clear() # Clean the container for the next factor. - factors.append(( - to_treat, ( - _COMMUTATIVE, - sympy_key(to_treat.base.label) - if isinstance(to_treat, Indexed) - else sympy_key(to_treat.func), - sympy_key(amp_no_treated) + factors.append( + ( + to_treat, + ( + _COMMUTATIVE, + sympy_key(to_treat.base.label) + if isinstance(to_treat, Indexed) + else sympy_key(to_treat.func), + sympy_key(amp_no_treated), + ), ) - )) + ) factors_info.append(amp_no_treated) else: # No part needing explicit treatment. - # When the factor never has an indexed base, we treat it as # indexing a uni-valence internal indexed base. - factors.append(( - wrapper_base[i], (_COMMUTATIVE,) - )) + factors.append((wrapper_base[i], (_COMMUTATIVE,))) factors_info.append(unindexed_factor) - continue - # # Get the factors in the vectors. # for i, v in enumerate(self._vecs): - colour = i if vec_colour is None else vec_colour( - idx=i, vec=v, term=self + colour = ( + i + if vec_colour is None + else vec_colour(idx=i, vec=v, term=self) ) - factors.append(( - v, (_NON_COMMUTATIVE, colour) - )) + factors.append((v, (_NON_COMMUTATIVE, colour))) factors_info.append(vec_factor) - continue # # Invoke the core simplification. @@ -1080,7 +1081,6 @@ def replace_to_treats(expr: Expr): res_amp = coeff * canon_coeff res_vecs = [] for i, j in zip(canoned_factors, factors_info): - if j == vec_factor: # When we have a vector. res_vecs.append(i) @@ -1088,7 +1088,6 @@ def replace_to_treats(expr: Expr): res_amp *= i.indices[0] else: res_amp *= j.xreplace({treated_placeholder: i}) - continue return Term(tuple(res_sums), res_amp, tuple(res_vecs)) @@ -1109,10 +1108,9 @@ def canon4normal(self, symms): # normal ordering. i.sort(key=sympy_key) - canon_term = ( - self.canon(symms=symms, vec_colour=lambda idx, vec, term: 0) - .reset_dumms(dumms)[0] - ) + canon_term = self.canon( + symms=symms, vec_colour=lambda idx, vec, term: 0 + ).reset_dumms(dumms)[0] return canon_term @@ -1123,17 +1121,13 @@ def has_base(self, base): return self._amp.has(base) elif isinstance(base, Vec): label = base.label - return any( - i.label == label for i in self._vecs - ) + return any(i.label == label for i in self._vecs) else: - raise TypeError('Invalid base to test presence', base) + raise TypeError("Invalid base to test presence", base) -_WRAPPER_BASE = IndexedBase( - 'internalWrapper', shape=('internalShape',) -) -_TREATED_PLACEHOLDER = Symbol('internalTreatedPlaceholder') +_WRAPPER_BASE = IndexedBase("internalWrapper", shape=("internalShape",)) +_TREATED_PLACEHOLDER = Symbol("internalTreatedPlaceholder") # For colour of factors in a term. @@ -1146,12 +1140,16 @@ def has_base(self, base): # --------------------------------- # + def subst_vec_term( - term: Term, lhs: typing.Tuple[Vec], rhs_terms: typing.List[Term], - dumms, dummbegs, excl + term: Term, + lhs: typing.Tuple[Vec], + rhs_terms: typing.List[Term], + dumms, + dummbegs, + excl, ): - """Substitute a matching vector in the given term. - """ + """Substitute a matching vector in the given term.""" sums = term.sums vecs = term.vecs @@ -1167,13 +1165,9 @@ def subst_vec_term( new = _match_indices(target, pattern) if new is None or not _update_substs(substs, new): break - else: - continue else: start_idx = i break - - continue else: return None # Based on nest bind protocol. @@ -1184,18 +1178,20 @@ def subst_vec_term( res = [] for i, j in subst_states: new_vecs = list(vecs) - new_vecs[start_idx:start_idx + n_new_vecs] = i.vecs - res.append(( - Term(sums + i.sums, amp * i.amp, tuple(new_vecs)), j - )) - continue + new_vecs[start_idx : start_idx + n_new_vecs] = i.vecs + res.append((Term(sums + i.sums, amp * i.amp, tuple(new_vecs)), j)) return res def subst_factor_term( - term: Term, lhs, rhs_terms: typing.List[Term], dumms, dummbegs, excl, - full_simplify=True + term: Term, + lhs, + rhs_terms: typing.List[Term], + dumms, + dummbegs, + excl, + full_simplify=True, ): """Substitute a scalar factor in the term. @@ -1207,8 +1203,8 @@ def subst_factor_term( amp = term.amp - placeholder1 = Symbol('internalSubstPlaceholder1') - placeholder2 = Symbol('internalSubstPlaceholder2') + placeholder1 = Symbol("internalSubstPlaceholder1") + placeholder2 = Symbol("internalSubstPlaceholder2") found = [False] substs = {} @@ -1246,12 +1242,13 @@ def replace_func(expr): else: raise TypeError( - 'Invalid LHS for substitution', lhs, - 'expecting symbol or indexed quantity' + "Invalid LHS for substitution", + lhs, + "expecting symbol or indexed quantity", ) # Some special treatment is needed for powers. - pow_placeholder = Symbol('internalSubstPowPlaceholder') + pow_placeholder = Symbol("internalSubstPowPlaceholder") pow_val = [None] def decouple_pow(base, e): @@ -1270,14 +1267,12 @@ def decouple_pow(base, e): if pow_val[0] is not None: amp = amp.xreplace({pow_placeholder: pow_val[0]}) - amp = ( - amp.simplify() if full_simplify else amp - ).expand() + amp = (amp.simplify() if full_simplify else amp).expand() # It is called nonlinear error, but some nonlinear forms, like conjugation, # can be handled. nonlinear_err = ValueError( - 'Invalid amplitude', term.amp, 'not expandable in', lhs + "Invalid amplitude", term.amp, "not expandable in", lhs ) if not isinstance(amp, Add) or len(amp.args) != 2: @@ -1301,10 +1296,9 @@ def decouple_pow(base, e): vecs = term.vecs res = [] for i, j in subst_states: - res.append(( - Term(sums + i.sums, amp.xreplace({placeholder1: i.amp}), vecs), j - )) - continue + res.append( + (Term(sums + i.sums, amp.xreplace({placeholder1: i.amp}), vecs), j) + ) return res @@ -1327,7 +1321,6 @@ def _match_indices(target, expr): else: if not _update_substs(substs, res): return None - continue return substs @@ -1344,7 +1337,6 @@ def _update_substs(substs, new): substs[k] = v elif v != substs[k]: return False - continue return True @@ -1362,7 +1354,6 @@ def _prepare_subst_states(rhs_terms, substs, dumms, dummbegs, excl): subst_states = [] for i, v in enumerate(rhs_terms): - # Reuse existing dummy begins only for the first term. if i == 0: curr_dummbegs = dummbegs @@ -1370,16 +1361,13 @@ def _prepare_subst_states(rhs_terms, substs, dumms, dummbegs, excl): curr_dummbegs = dict(dummbegs) curr_term, curr_dummbegs = v.reset_dumms(dumms, curr_dummbegs, excl) - subst_states.append(( - curr_term.subst(substs), curr_dummbegs - )) - continue + subst_states.append((curr_term.subst(substs), curr_dummbegs)) return subst_states def rewrite_term( - term: Term, vecs: typing.Sequence[Vec], new_amp: Expr + term: Term, vecs: typing.Sequence[Vec], new_amp: Expr ) -> typing.Tuple[typing.Optional[Term], Term]: """Rewrite the given term. @@ -1408,24 +1396,24 @@ def rewrite_term( res_symbs = res_amp.atoms(Symbol) res_sums = tuple(i for i in term.sums if i[0] in res_symbs) def_sums = tuple(i for i in term.sums if i[0] not in res_symbs) - return Term(res_sums, res_amp, term.vecs), Term( - def_sums, term.amp, () - ) + return Term(res_sums, res_amp, term.vecs), Term(def_sums, term.amp, ()) return None, term -Sum_expander = typing.Callable[[Symbol], typing.Iterable[typing.Tuple[ - Symbol, Range, Expr -]]] +Sum_expander = typing.Callable[ + [Symbol], typing.Iterable[typing.Tuple[Symbol, Range, Expr]] +] def expand_sums_term( - term: Term, range_: Range, expander: Sum_expander, - exts=None, conv_accs=None + term: Term, + range_: Range, + expander: Sum_expander, + exts=None, + conv_accs=None, ): - """Expand the given summations in the term. - """ + """Expand the given summations in the term.""" res_sums = [] @@ -1439,7 +1427,6 @@ def expand_sums_term( dumms_to_expand.append((i[0], True)) else: res_sums.append(i) - continue repl = {} first_new = {} @@ -1449,16 +1436,16 @@ def expand_sums_term( # Cleanse results from user callback. if not isinstance(new_dumm, Symbol): raise TypeError( - 'Invalid dummy for the new summation', new_dumm + "Invalid dummy for the new summation", new_dumm ) if not isinstance(new_range, Range): raise TypeError( - 'Invalid range for the new summation', new_range + "Invalid range for the new summation", new_range ) if not isinstance(prev_form, Expr): raise TypeError( - 'Invalid previous form of the new summation dummy', - prev_form + "Invalid previous form of the new summation dummy", + prev_form, ) if is_sum: @@ -1468,15 +1455,11 @@ def expand_sums_term( if not first_new_added: first_new[dumm] = new_dumm first_new_added = True - continue - continue if conv_accs: for k, v in first_new.items(): for i in conv_accs: repl[i(k)] = i(v) - continue - continue res_term = term.map( lambda x: x.xreplace(repl), sums=tuple(res_sums), skip_ranges=False @@ -1486,10 +1469,7 @@ def check_expr(expr: Expr): """Check if the given expression still has the expanded dummies.""" for i in dumms_to_expand: if expr.has(i): - raise ValueError( - 'Scalar', expr, 'with original dummy', i - ) - continue + raise ValueError("Scalar", expr, "with original dummy", i) return expr res_term.map(check_expr) # Discard result. @@ -1528,7 +1508,6 @@ def sum_term(sum_args, summand, predicate=None) -> typing.List[Term]: res = [] for sum_i in itertools.product(*sums): for subst_i in itertools.product(*substs): - subst_dict = dict(subst_i) # We always assemble the call sequence here, since this part should @@ -1544,15 +1523,13 @@ def sum_term(sum_args, summand, predicate=None) -> typing.List[Term]: else: curr_inp_terms = parse_terms(inp_func(call_seq)) - curr_terms = [i.subst( - subst_dict, sums=_cat_sums(i.sums, sum_i) - ) for i in curr_inp_terms] + curr_terms = [ + i.subst(subst_dict, sums=_cat_sums(i.sums, sum_i)) + for i in curr_inp_terms + ] res.extend(curr_terms) - continue - continue - return res @@ -1568,14 +1545,14 @@ def _parse_sums(args): substs = [] for arg in args: - if not isinstance(arg, Sequence): - raise TypeError('Invalid summation', arg, 'expecting a sequence') + raise TypeError("Invalid summation", arg, "expecting a sequence") if len(arg) < 2: - raise ValueError('Invalid summation', arg, - 'expecting dummy and range') + raise ValueError( + "Invalid summation", arg, "expecting dummy and range" + ) - dumm = ensure_symb(arg[0], 'dummy') + dumm = ensure_symb(arg[0], "dummy") flattened = [] for i in arg[1:]: @@ -1583,7 +1560,6 @@ def _parse_sums(args): flattened.extend(i) else: flattened.append(i) - continue contents = [] expecting_range = None @@ -1592,15 +1568,17 @@ def _parse_sums(args): if expecting_range is None: expecting_range = True elif not expecting_range: - raise ValueError('Invalid summation on', i, - 'expecting expression') + raise ValueError( + "Invalid summation on", i, "expecting expression" + ) contents.append((dumm, i)) else: if expecting_range is None: expecting_range = False elif expecting_range: - raise ValueError('Invalid summation on', i, - 'expecting a range') + raise ValueError( + "Invalid summation on", i, "expecting a range" + ) expr = ensure_expr(i) contents.append((dumm, expr)) @@ -1628,16 +1606,17 @@ def _cat_sums(sums1, sums2): dumm_counts.update(i[0] for i in sums) if any(i > 1 for i in dumm_counts.values()): raise ValueError( - 'Invalid summations to be concatenated', (sums1, sums2), - 'expecting no conflict in dummies' + "Invalid summations to be concatenated", + (sums1, sums2), + "expecting no conflict in dummies", ) return sums -def einst_term(term: Term, resolvers) -> typing.Tuple[ - typing.List[Term], typing.AbstractSet[Symbol] -]: +def einst_term( + term: Term, resolvers +) -> typing.Tuple[typing.List[Term], typing.AbstractSet[Symbol]]: """Add summations according to the Einstein convention to a term. The likely external indices for the term is also returned. @@ -1665,14 +1644,11 @@ def proc_indexed(*args): else: for i in index.atoms(Symbol): use_tally[i][1] += 1 - continue - continue existing_dumms = term.dumms new_sums = [] exts = set() for symb, use in use_tally.items(): - if symb in existing_dumms: continue @@ -1688,23 +1664,24 @@ def proc_indexed(*args): range_ = try_resolve_range(symb, {}, resolvers) if range_ is None: warnings.warn( - 'Symbol {} is not summed for the incapability to resolve ' - 'range' - .format(symb) + "Symbol {} is not summed for the incapability to resolve " + "range".format(symb) ) continue # Now we have an Einstein summation. new_sums.append((symb, range_)) - continue # Make summation from Einstein convention deterministic. - new_sums.sort(key=lambda x: ( - tuple(i.sort_key for i in ( - [x[1]] if isinstance(x[1], Range) else x[1] - )), - x[0].name - )) + new_sums.sort( + key=lambda x: ( + tuple( + i.sort_key + for i in ([x[1]] if isinstance(x[1], Range) else x[1]) + ), + x[0].name, + ) + ) return sum_term(new_sums, term), exts @@ -1748,17 +1725,20 @@ def simplify_deltas_in_expr(sums_dict, amp, resolvers): return amp, substs # Preprocess some expressions equivalent to deltas into explicit delta form. - arg0 = Wild('arg0') - arg1 = Wild('arg1') - value = Wild('value') + arg0 = Wild("arg0") + arg1 = Wild("arg1") + value = Wild("value") amp = amp.replace( Piecewise((value, Eq(arg0, arg1)), (0, True)), - KroneckerDelta(arg0, arg1) * value + KroneckerDelta(arg0, arg1) * value, ) - new_amp = amp.replace(KroneckerDelta, NonsympifiableFunc(functools.partial( - _proc_delta_in_amp, sums_dict, resolvers, substs - ))) + new_amp = amp.replace( + KroneckerDelta, + NonsympifiableFunc( + functools.partial(_proc_delta_in_amp, sums_dict, resolvers, substs) + ), + ) # Attempt some simple simplifications on simple unresolved deltas. new_amp = _try_simpl_unresolved_deltas(new_amp) @@ -1812,8 +1792,6 @@ def compose_simplified_delta(amp, new_substs, substs, sums_dict, resolvers): substs[i] = substs[i].xreplace(to_add) substs.update(to_add) - continue - return amp, substs @@ -1827,7 +1805,8 @@ def proc_delta(arg1, arg2, sums_dict, resolvers): """ dumms = [ - i for i in set.union(arg1.atoms(Symbol), arg2.atoms(Symbol)) + i + for i in set.union(arg1.atoms(Symbol), arg2.atoms(Symbol)) if i in sums_dict ] @@ -1863,7 +1842,7 @@ def proc_delta(arg1, arg2, sums_dict, resolvers): if sol == domain: # Now we can be sure that we got an identity. return _UNITY, None - elif hasattr(sol, '__len__'): + elif hasattr(sol, "__len__"): # Concrete solutions. if len(sol) > 0: for i in sol: @@ -2033,13 +2012,10 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): res_amp *= factor continue factors.append((factor, symbs)) - continue for vec in term.vecs: for i in vec.indices: imposs_symbs |= i.atoms(Symbol) - continue - continue # Summations in the result to be incrementally built. res_sums = [] @@ -2057,9 +2033,7 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): res_sums.append(sum_) continue - involving_factors = [ - i for i in factors if dumm in i[1] - ] + involving_factors = [i for i in factors if dumm in i[1]] # Trivial summations leaked here must have involvement in other sum # bounds. @@ -2067,8 +2041,9 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): res_sums.append(sum_) else: to_proc[dumm] = types.SimpleNamespace( - factors=involving_factors, range=range_, - triple=(dumm, range_.lower, range_.upper - 1) + factors=involving_factors, + range=range_, + triple=(dumm, range_.lower, range_.upper - 1), ) # TODO: Make simplification considering dummies' involvement in the @@ -2078,7 +2053,6 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): # Main loop, apply the rules until none of them can be applied. has_simplified = True while has_simplified: - has_simplified = False # Toppled to true only after simplification. # Apply the rules in increasing order of their complexity. Simpler @@ -2093,22 +2067,21 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): curr_sums = [i.triple for i in curr_infos] # Factors come and go, here they are tracked by their address. curr_factors = { - id(j): j - for i in curr_infos for j in i.factors + id(j): j for i in curr_infos for j in i.factors } curr_expr = prod_(i[0] for i in curr_factors.values()) orig = Sum(curr_expr, *curr_sums) for simplify in simplifiers[n_sums]: - # Call user-provided simplifier. simplified = simplify( orig, resolvers=resolvers, sums_dict=sums_dict ) if_simplified = ( - simplified is not None and simplified != orig and - not isinstance(simplified, Sum) + simplified is not None + and simplified != orig + and not isinstance(simplified, Sum) ) if not if_simplified: continue @@ -2118,21 +2091,17 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): i for i in factors if id(i) not in curr_factors ] for i in ( - simplified.args if isinstance(simplified, Mul) - else (simplified,) + simplified.args + if isinstance(simplified, Mul) + else (simplified,) ): - new_factors.append(( - i, i.atoms(Symbol) - )) - continue + new_factors.append((i, i.atoms(Symbol))) factors = new_factors for i in sums: del to_proc[i] for k, v in to_proc.items(): - v.factors = [ - i for i in factors if k in i[1] - ] + v.factors = [i for i in factors if k in i[1]] has_simplified = True break @@ -2145,7 +2114,6 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): # Place the unprocessed factors back. for i in factors: res_amp *= i[0] - continue for k, v in to_proc.items(): res_sums.append((k, v.range)) @@ -2157,19 +2125,17 @@ def simplify_amp_sums_term(term: Term, simplifiers, excl_bases, resolvers): # -------------------- # + def diff_term(term: Term, variable, real, wirtinger_conj): - """Differentiate a term. - """ + """Differentiate a term.""" symb = _GRAD_REAL_SYMB if real else _GRAD_SYMB if isinstance(variable, Symbol): - lhs = variable rhs = lhs + symb elif isinstance(variable, Indexed): - indices = variable.indices wilds = tuple( Wild(_GRAD_WILD_FMT.format(i)) for i, _ in enumerate(indices) @@ -2178,11 +2144,12 @@ def diff_term(term: Term, variable, real, wirtinger_conj): lhs = variable.base[wilds] rhs = lhs + functools.reduce( operator.mul, - (KroneckerDelta(i, j) for i, j in zip(wilds, indices)), symb + (KroneckerDelta(i, j) for i, j in zip(wilds, indices)), + symb, ) else: - raise ValueError('Invalid differentiation variable', variable) + raise ValueError("Invalid differentiation variable", variable) if real: orig_amp = term.amp.replace(conjugate(lhs), lhs) @@ -2193,9 +2160,7 @@ def diff_term(term: Term, variable, real, wirtinger_conj): if real: eval_substs = {symb: 0} else: - replaced_amp = replaced_amp.replace( - conjugate(symb), _GRAD_CONJ_SYMB - ) + replaced_amp = replaced_amp.replace(conjugate(symb), _GRAD_CONJ_SYMB) eval_substs = {_GRAD_CONJ_SYMB: 0, symb: 0} if wirtinger_conj: @@ -2211,14 +2176,12 @@ def diff_term(term: Term, variable, real, wirtinger_conj): # Internal symbols for gradients. -_GRAD_SYMB_FMT = 'internalGradient{tag}Placeholder' -_GRAD_SYMB = Symbol(_GRAD_SYMB_FMT.format(tag='')) -_GRAD_CONJ_SYMB = Symbol(_GRAD_SYMB_FMT.format(tag='Conj')) -_GRAD_REAL_SYMB = Symbol( - _GRAD_SYMB_FMT.format(tag='Real'), real=True -) +_GRAD_SYMB_FMT = "internalGradient{tag}Placeholder" +_GRAD_SYMB = Symbol(_GRAD_SYMB_FMT.format(tag="")) +_GRAD_CONJ_SYMB = Symbol(_GRAD_SYMB_FMT.format(tag="Conj")) +_GRAD_REAL_SYMB = Symbol(_GRAD_SYMB_FMT.format(tag="Real"), real=True) -_GRAD_WILD_FMT = 'InternalWildSymbol{}' +_GRAD_WILD_FMT = "InternalWildSymbol{}" # @@ -2226,6 +2189,7 @@ def diff_term(term: Term, variable, real, wirtinger_conj): # --------------------- # + def try_resolve_range(i, sums_dict, resolvers): """Attempt to resolve the range of an expression. @@ -2233,7 +2197,6 @@ def try_resolve_range(i, sums_dict, resolvers): """ for resolver in itertools.chain([sums_dict], resolvers): - if isinstance(resolver, Mapping): if i in resolver: return resolver[i] @@ -2247,12 +2210,17 @@ def try_resolve_range(i, sums_dict, resolvers): if isinstance(range_, Range): return range_ else: - raise TypeError('Invalid range: ', range_, - 'from resolver', resolver, - 'expecting range or None') + raise TypeError( + "Invalid range: ", + range_, + "from resolver", + resolver, + "expecting range or None", + ) else: - raise TypeError('Invalid resolver: ', resolver, - 'expecting callable or mapping') + raise TypeError( + "Invalid resolver: ", resolver, "expecting callable or mapping" + ) # Never resolved nor error found. return None diff --git a/drudge/utils.py b/drudge/utils.py index bf1c1292..297da6f3 100644 --- a/drudge/utils.py +++ b/drudge/utils.py @@ -8,8 +8,15 @@ from pyspark import RDD, SparkContext from sympy import ( - sympify, Symbol, Expr, SympifyError, count_ops, default_sort_key, - AtomicExpr, Integer, S + sympify, + Symbol, + Expr, + SympifyError, + count_ops, + default_sort_key, + AtomicExpr, + Integer, + S, ) from sympy.core.sympify import CantSympify @@ -19,32 +26,33 @@ # --------------- # -def ensure_sympify(obj, role='', expected_type=None): + +def ensure_sympify(obj, role="", expected_type=None): """Sympify the given object with checking and error reporting. This is a shallow wrapper over SymPy sympify function to have error reporting in consistent style and an optional type checking. """ - header = 'Invalid {}: '.format(role) + header = "Invalid {}: ".format(role) try: sympified = sympify(obj) except SympifyError as exc: - raise TypeError(header, obj, 'failed to be simplified', exc.args) + raise TypeError(header, obj, "failed to be simplified", exc.args) if expected_type is None or isinstance(sympified, expected_type): return sympified else: - raise TypeError(header, sympified, 'expecting', expected_type) + raise TypeError(header, sympified, "expecting", expected_type) -def ensure_symb(obj, role=''): +def ensure_symb(obj, role=""): """Sympify the given object into a symbol.""" return ensure_sympify(obj, role, Symbol) -def ensure_expr(obj, role=''): +def ensure_expr(obj, role=""): """Sympify the given object into an expression.""" return ensure_sympify(obj, role, Expr) @@ -65,7 +73,7 @@ def is_higher(obj, priority): lower. """ - return getattr(obj, '_op_priority', priority - 1) > priority + return getattr(obj, "_op_priority", priority - 1) > priority class NonsympifiableFunc(CantSympify): @@ -77,7 +85,7 @@ class NonsympifiableFunc(CantSympify): """ - __slots__ = ['_func'] + __slots__ = ["_func"] def __init__(self, func): """Initialize the object.""" @@ -95,7 +103,7 @@ class _EnumSymbsMeta(type): values from the enumerated symbols set in the class body. """ - SYMBS_INPUT = '_symbs_' + SYMBS_INPUT = "_symbs_" def __new__(mcs, name, bases, attrs): """Create the new concrete symbols class.""" @@ -103,7 +111,7 @@ def __new__(mcs, name, bases, attrs): cls = super().__new__(mcs, name, bases, attrs) if not hasattr(cls, mcs.SYMBS_INPUT): - raise AttributeError('Cannot find attribute ' + mcs.SYMBS_INPUT) + raise AttributeError("Cannot find attribute " + mcs.SYMBS_INPUT) symbs = getattr(cls, mcs.SYMBS_INPUT) if symbs is None: @@ -111,25 +119,27 @@ def __new__(mcs, name, bases, attrs): return cls if not isinstance(symbs, Sequence): - raise ValueError('Invalid symbols', symbs, 'expecting a sequence') + raise ValueError("Invalid symbols", symbs, "expecting a sequence") for i in symbs: - invalid = not isinstance(i, Sequence) or len(i) != 2 or any( - not isinstance(j, str) for j in i + invalid = ( + not isinstance(i, Sequence) + or len(i) != 2 + or any(not isinstance(j, str) for j in i) ) if invalid: raise ValueError( - 'Invalid symbol', i, - 'expecting pairs of identifier and LaTeX form.' + "Invalid symbol", + i, + "expecting pairs of identifier and LaTeX form.", ) if len(symbs) < 2: raise ValueError( - 'Invalid symbols ', symbs, 'expecting multiple of them' + "Invalid symbols ", symbs, "expecting multiple of them" ) for i, v in enumerate(symbs): obj = cls(i) setattr(cls, v[0], obj) - continue return cls @@ -148,20 +158,19 @@ class EnumSymbs(AtomicExpr, metaclass=_EnumSymbsMeta): _symbs_ = None - _VAL_FIELD = '_val_index' + _VAL_FIELD = "_val_index" __slots__ = [_VAL_FIELD] def __init__(self, val_index): - """Initialize the concrete symbol object. - """ + """Initialize the concrete symbol object.""" if self._symbs_ is None: - raise ValueError('Base EnumSymbs class cannot be instantiated') + raise ValueError("Base EnumSymbs class cannot be instantiated") setattr(self, self._VAL_FIELD, val_index) @property def args(self): """The argument for SymPy.""" - return Integer(getattr(self, self._VAL_FIELD)), + return (Integer(getattr(self, self._VAL_FIELD)),) def __str__(self): """Get the string representation of the symbol.""" @@ -169,7 +178,7 @@ def __str__(self): def __repr__(self): """Get the machine readable string representation.""" - return '.'.join([type(self).__name__, str(self)]) + return ".".join([type(self).__name__, str(self)]) _op_priority = 20.0 @@ -205,8 +214,9 @@ def __sub__(self, other: Expr): return self.args[0] - other.args[0] elif len(other.atoms(Symbol)) == 0: raise ValueError( - 'Invalid operation for ', (self, other), - 'concrete symbols can only be subtracted for the same type' + "Invalid operation for ", + (self, other), + "concrete symbols can only be subtracted for the same type", ) else: # We are having a symbolic value at the other expression. We just @@ -234,7 +244,8 @@ def sort_key(self, order=None): return ( self.class_key(), (1, tuple(i.sort_key() for i in self.args)), - S.One.sort_key(), S.One + S.One.sort_key(), + S.One, ) def _latex(self, _): @@ -257,11 +268,7 @@ class BCastVar: """ - __slots__ = [ - '_ctx', - '_var', - '_bcast' - ] + __slots__ = ["_ctx", "_var", "_bcast"] def __init__(self, ctx: SparkContext, var): """Initialize the broadcast variable.""" @@ -307,8 +314,7 @@ def nest_bind(rdd: RDD, func, full_balance=True): def _nest_bind_full_balance(rdd: RDD, func): - """Nest the flat map of the given function with full load balancing. - """ + """Nest the flat map of the given function with full load balancing.""" ctx = rdd.context @@ -331,14 +337,12 @@ def wrapped(obj): res.append(new_entries) curr = step_res.filter(lambda x: x[0]).map(lambda x: x[1]) curr.cache() - continue return ctx.union(res) def _nest_bind_no_balance(rdd: RDD, func): - """Nest the flat map of the given function without load balancing. - """ + """Nest the flat map of the given function without load balancing.""" def wrapped(obj): """Wrapped function for nest bind.""" @@ -352,9 +356,7 @@ def wrapped(obj): res.append(i) else: new_curr.extend(step_res) - continue curr = new_curr - continue return res @@ -366,18 +368,15 @@ def wrapped(obj): # -------------- # + def ensure_pair(obj, role): """Ensures that the given object is a pair.""" if not (isinstance(obj, Sequence) and len(obj) == 2): - raise TypeError('Invalid {}: '.format(role), obj, 'expecting pair') + raise TypeError("Invalid {}: ".format(role), obj, "expecting pair") return obj -_ALNUM = frozenset( - j - for i in [string.ascii_letters, string.digits] - for j in i -) +_ALNUM = frozenset(j for i in [string.ascii_letters, string.digits] for j in i) def extract_alnum(inp: str): @@ -386,7 +385,7 @@ def extract_alnum(inp: str): This function is mostly for generating valid identifiers for objects with a mathematically formatted name. """ - return ''.join(i for i in inp if i in _ALNUM) + return "".join(i for i in inp if i in _ALNUM) # @@ -394,6 +393,7 @@ def extract_alnum(inp: str): # -------------------- # + def sum_(obj): """Sum the values in the given iterable. @@ -487,16 +487,16 @@ def tock(self, label, tensor=None): if tensor is not None: tensor.cache() - n_terms = '{} terms, '.format(tensor.n_terms) + n_terms = "{} terms, ".format(tensor.n_terms) else: - n_terms = '' + n_terms = "" now = time.perf_counter() elapse = now - self._prev self._prev = now self._print( - '{} done, {}wall time: {:.2f} s'.format(label, n_terms, elapse) + "{} done, {}wall time: {:.2f} s".format(label, n_terms, elapse) ) def tock_total(self): @@ -507,9 +507,7 @@ def tock_total(self): """ now = time.perf_counter() - self._print( - 'Total wall time: {:.2f} s'.format(now - self._begin) - ) + self._print("Total wall time: {:.2f} s".format(now - self._begin)) class CallByIndex: @@ -521,7 +519,7 @@ class CallByIndex: """ - __slots__ = ['_callable'] + __slots__ = ["_callable"] def __init__(self, callable): """Initialize the object.""" @@ -564,10 +562,7 @@ class SymbResolver: """ - __slots__ = [ - '_known', - '_strict' - ] + __slots__ = ["_known", "_strict"] def __init__(self, range_symbs, strict): """Initialize the resolver.""" @@ -577,8 +572,6 @@ def __init__(self, range_symbs, strict): for range_, dumms in range_symbs: for i in dumms: known[i] = range_ - continue - continue self._strict = strict @@ -593,6 +586,5 @@ def __call__(self, expr: Expr): for i in expr.atoms(Symbol): if i in known: return known[i] - continue return None diff --git a/drudge/wick.py b/drudge/wick.py index ea78f04f..d077ba91 100644 --- a/drudge/wick.py +++ b/drudge/wick.py @@ -53,7 +53,7 @@ def wick_parallel(self, level): if level not in {0, 1, 2}: raise ValueError( - 'Invalid parallel level for Wick expansion', level + "Invalid parallel level for Wick expansion", level ) self._wick_parallel = level @@ -99,12 +99,10 @@ def normal_order(self, terms: RDD, **kwargs): by the abstract properties. """ - comparator = kwargs.pop('comparator', self.comparator) - contractor = kwargs.pop('contractor', self.contractor) + comparator = kwargs.pop("comparator", self.comparator) + contractor = kwargs.pop("contractor", self.contractor) if len(kwargs) != 0: - raise ValueError( - 'Invalid arguments to Wick normal order', kwargs - ) + raise ValueError("Invalid arguments to Wick normal order", kwargs) phase = self.phase symms = self.symms @@ -119,31 +117,34 @@ def normal_order(self, terms: RDD, **kwargs): return terms_to_keep # Triples: term, contractions, schemes. - wick_terms = terms_to_proc.map(lambda x: _prepare_wick( - x, comparator, contractor, symms.value, resolvers.value - )) + wick_terms = terms_to_proc.map( + lambda x: _prepare_wick( + x, comparator, contractor, symms.value, resolvers.value + ) + ) if self._wick_parallel == 0: - - normal_ordered = wick_terms.flatMap(lambda x: [ - _form_term_from_wick(x[0], x[1], phase, resolvers.value, i) - for i in x[2] - ]) + normal_ordered = wick_terms.flatMap( + lambda x: [ + _form_term_from_wick(x[0], x[1], phase, resolvers.value, i) + for i in x[2] + ] + ) elif self._wick_parallel == 1: - flattened = wick_terms.flatMap( lambda x: [(x[0], x[1], i) for i in x[2]] ) if self._num_partitions is not None: flattened = flattened.repartition(self._num_partitions) - normal_ordered = flattened.map(lambda x: _form_term_from_wick( - x[0], x[1], phase, resolvers.value, x[2] - )) + normal_ordered = flattened.map( + lambda x: _form_term_from_wick( + x[0], x[1], phase, resolvers.value, x[2] + ) + ) elif self._wick_parallel == 2: - # This level of parallelism is reserved for really hard problems. expanded = [] for term, contrs, schemes in wick_terms.collect(): @@ -155,13 +156,12 @@ def normal_order(self, terms: RDD, **kwargs): curr = self._ctx.parallelize(schemes).map(form_term) expanded.append(curr) - continue normal_ordered = self._ctx.union(expanded) else: raise ValueError( - 'Invalid Wick expansion parallel level', self._wick_parallel + "Invalid Wick expansion parallel level", self._wick_parallel ) return terms_to_keep.union(normal_ordered) @@ -214,7 +214,6 @@ def _sort_vecs(term, comparator, contractor, resolvers): front = 2 pivot = 1 while pivot < n_vecs: - pivot_i = vec_order[pivot] pivot_vec = vecs[pivot_i] prev = pivot - 1 @@ -222,7 +221,6 @@ def _sort_vecs(term, comparator, contractor, resolvers): if pivot == 0 or comparator(vecs[vec_order[prev]], pivot_vec, term): pivot, front = front, front + 1 else: - prev_i = vec_order[prev] prev_vec = vecs[prev_i] vec_order[prev], vec_order[pivot] = pivot_i, prev_i @@ -232,12 +230,11 @@ def _sort_vecs(term, comparator, contractor, resolvers): ) if contr_amp != 0: contrs[prev_i][pivot_i] = ( - contr_amp, tuple(contr_substs.items()) + contr_amp, + tuple(contr_substs.items()), ) pivot -= 1 - continue - return vec_order, contrs @@ -264,9 +261,7 @@ def _get_all_contrs(term, contractor, resolvers): ) if contr_amp != 0: curr_contrs[j] = (contr_amp, tuple(contr_substs.items())) - continue contrs.append(curr_contrs) - continue return contrs @@ -308,9 +303,7 @@ def _add_wick(schemes, avail, pivot, contred, vec_order, contrs): vec_perm = list(contred) if not contr_all: vec_perm.extend(i for i in vec_order if avail[i]) - schemes.append(( - vec_perm, len(contred) - )) + schemes.append((vec_perm, len(contred))) return pivot_contrs = contrs[pivot] @@ -325,21 +318,17 @@ def _add_wick(schemes, avail, pivot, contred, vec_order, contrs): if avail[vec_idx] and vec_idx in pivot_contrs: avail[vec_idx] = False contred.extend([pivot, vec_idx]) - _add_wick( - schemes, avail, pivot + 1, contred, vec_order, contrs - ) + _add_wick(schemes, avail, pivot + 1, contred, vec_order, contrs) avail[vec_idx] = True contred.pop() contred.pop() - continue avail[pivot] = True return def _form_term_from_wick(term, contrs, phase, resolvers, wick_scheme): - """Generate a full Term from a Wick expansion scheme. - """ + """Generate a full Term from a Wick expansion scheme.""" sums_dict = term.dumms @@ -351,15 +340,15 @@ def _form_term_from_wick(term, contrs, phase, resolvers, wick_scheme): for contr_i in range(0, n_contred, 2): contr_amp, contr_substs = contrs[perm[contr_i]][perm[contr_i + 1]] amp, _ = compose_simplified_delta( - amp * contr_amp, contr_substs, - substs, sums_dict=sums_dict, resolvers=resolvers + amp * contr_amp, + contr_substs, + substs, + sums_dict=sums_dict, + resolvers=resolvers, ) - continue vecs = tuple(term.vecs[i] for i in perm[n_contred:]) - return term.subst( - substs, amp=amp * term.amp, vecs=vecs, purge_sums=True - ) + return term.subst(substs, amp=amp * term.amp, vecs=vecs, purge_sums=True) def _form_term_from_wick_bcast(term, contrs, phase, resolvers, wick_scheme): @@ -377,6 +366,8 @@ def _get_perm_phase(order, phase): """Get the phase of the given permutation of points.""" n_points = len(order) return phase ** sum( - 1 for i in range(n_points) for j in range(i + 1, n_points) + 1 + for i in range(n_points) + for j in range(i + 1, n_points) if order[i] > order[j] ) From 8457ef1a58519ccff3d7d28811ed8e6fa3daedfb Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 21:20:19 -0600 Subject: [PATCH 05/14] Format all the python files --- docs/conf.py | 80 ++-- docs/examples/ccsd.ipynb | 28 +- docs/examples/conf_ph_spin.py | 3 +- docs/examples/gencc.py | 67 ++-- docs/examples/rccsd.py | 32 +- tests/basic_wick_test.py | 15 +- tests/bcs_test.py | 2 +- tests/bogoliubov_test.py | 43 ++- tests/clifford_test.py | 5 +- tests/conftest.py | 11 +- tests/drs_test.py | 117 +++--- tests/free_algebra_test.py | 674 +++++++++++++++++----------------- tests/genmb_test.py | 111 +++--- tests/genquad_test.py | 9 +- tests/name_injection_test.py | 8 +- tests/nuclear_test.py | 182 ++++----- tests/parthole_test.py | 66 ++-- tests/perm_test.py | 23 +- tests/range_test.py | 32 +- tests/spin_one_half_test.py | 82 +++-- tests/su2_test.py | 55 +-- tests/term_test.py | 45 ++- tests/utils_test.py | 49 ++- tests/vec_test.py | 12 +- 24 files changed, 908 insertions(+), 843 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0bf53d2d..6f769440 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,38 +31,40 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx.ext.napoleon', - 'sphinx.ext.imgconverter', - 'sphinx.ext.githubpages' - ] +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx.ext.imgconverter", + "sphinx.ext.githubpages", +] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'drudge' -copyright = '2017, Jinmo Zhao and Gustavo E Scuseria' -author = 'Jinmo Zhao and Gustavo E Scuseria' +project = "drudge" +copyright = "2017, Jinmo Zhao and Gustavo E Scuseria" +author = "Jinmo Zhao and Gustavo E Scuseria" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -from drudge import __version__ # noqa: E402 +from drudge import __version__ # noqa: E402 + version = __version__ # The full version, including alpha/beta/rc tags. release = __version__ @@ -77,10 +79,10 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -91,7 +93,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -102,13 +104,13 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'drudgedoc' +htmlhelp_basename = "drudgedoc" # -- Options for LaTeX output --------------------------------------------- @@ -117,15 +119,15 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - + # # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - + # # Additional stuff for the LaTeX preamble. # # 'preamble': '', - + # # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -135,8 +137,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'drudge.tex', 'drudge Documentation', - 'Jinmo Zhao and Gustavo E Scuseria', 'manual'), + ( + master_doc, + "drudge.tex", + "drudge Documentation", + "Jinmo Zhao and Gustavo E Scuseria", + "manual", + ), ] @@ -144,10 +151,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'drudge', 'drudge Documentation', - [author], 1) -] +man_pages = [(master_doc, "drudge", "drudge Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -156,19 +160,25 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'drudge', 'drudge Documentation', - author, 'drudge', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "drudge", + "drudge Documentation", + author, + "drudge", + "One line description of project.", + "Miscellaneous", + ), ] -autodoc_member_order = 'bysource' +autodoc_member_order = "bysource" -doctest_global_setup = ''' +doctest_global_setup = """ import os from dummy_spark import SparkContext from sympy import * from drudge import * -''' +""" diff --git a/docs/examples/ccsd.ipynb b/docs/examples/ccsd.ipynb index 8fb370c0..1c39adb3 100644 --- a/docs/examples/ccsd.ipynb +++ b/docs/examples/ccsd.ipynb @@ -29,7 +29,8 @@ "outputs": [], "source": [ "from pyspark import SparkContext\n", - "ctx = SparkContext('local[*]', 'ccsd')" + "\n", + "ctx = SparkContext(\"local[*]\", \"ccsd\")" ] }, { @@ -49,6 +50,7 @@ "outputs": [], "source": [ "from dummy_spark import SparkContext\n", + "\n", "ctx = SparkContext()" ] }, @@ -99,11 +101,11 @@ }, "outputs": [], "source": [ - "t = IndexedBase('t')\n", + "t = IndexedBase(\"t\")\n", "\n", "clusters = dr.einst(\n", - " t[a, i] * c_dag[a] * c_[i] +\n", - " t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4\n", + " t[a, i] * c_dag[a] * c_[i]\n", + " + t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4\n", ")" ] }, @@ -165,12 +167,7 @@ } ], "source": [ - "dr.set_symm(\n", - " t,\n", - " Perm([1, 0, 2, 3], NEG),\n", - " Perm([0, 1, 3, 2], NEG),\n", - " valence=4\n", - ")" + "dr.set_symm(t, Perm([1, 0, 2, 3], NEG), Perm([0, 1, 3, 2], NEG), valence=4)" ] }, { @@ -444,9 +441,9 @@ ")\n", "\n", "working_eqn = [\n", - " dr.define(Symbol('e'), en_eqn), \n", - " dr.define(r1[a, i], t1_eqn), \n", - " dr.define(r2[a, b, i, j], t2_eqn)\n", + " dr.define(Symbol(\"e\"), en_eqn),\n", + " dr.define(r1[a, i], t1_eqn),\n", + " dr.define(r2[a, b, i, j], t2_eqn),\n", "]" ] }, @@ -511,8 +508,9 @@ "%%time\n", "\n", "eval_seq = optimize(\n", - " working_eqn, substs={p.nv: 5000, p.no: 1000}, \n", - " contr_strat=ContrStrat.EXHAUST\n", + " working_eqn,\n", + " substs={p.nv: 5000, p.no: 1000},\n", + " contr_strat=ContrStrat.EXHAUST,\n", ")" ] }, diff --git a/docs/examples/conf_ph_spin.py b/docs/examples/conf_ph_spin.py index 7e77d6d9..728b16f5 100644 --- a/docs/examples/conf_ph_spin.py +++ b/docs/examples/conf_ph_spin.py @@ -1,5 +1,4 @@ -"""Configuration for particle-hole problem with explicit spin. -""" +"""Configuration for particle-hole problem with explicit spin.""" from pyspark import SparkContext from drudge import RestrictedPartHoleDrudge diff --git a/docs/examples/gencc.py b/docs/examples/gencc.py index bea39bd1..04991874 100644 --- a/docs/examples/gencc.py +++ b/docs/examples/gencc.py @@ -21,13 +21,14 @@ parser = argparse.ArgumentParser() parser.add_argument( - 'theory', choices=['ccd', 'ccsd', 'ccsdt', 'ccsdtq'], - help='The CC theory to derive.' + "theory", + choices=["ccd", "ccsd", "ccsdt", "ccsdtq"], + help="The CC theory to derive.", ) args = parser.parse_args() theory = args.theory -conf = SparkConf().setAppName('{}-derivation'.format(theory)) +conf = SparkConf().setAppName("{}-derivation".format(theory)) ctx = SparkContext(conf=conf) # @@ -37,9 +38,11 @@ dr = PartHoleDrudge(ctx) dr.full_simplify = False -print('Derive {} theory, default partition {}'.format( - theory.upper(), dr.num_partitions -)) +print( + "Derive {} theory, default partition {}".format( + theory.upper(), dr.num_partitions + ) +) p = dr.names c_ = p.c_ @@ -47,9 +50,9 @@ v_dumms = p.V_dumms o_dumms = p.O_dumms -ORDER_OF = {'s': 1, 'd': 2, 't': 3, 'q': 4} +ORDER_OF = {"s": 1, "d": 2, "t": 3, "q": 4} -t = IndexedBase('t') +t = IndexedBase("t") orders = [] for i in theory[2:]: order = ORDER_OF[i] @@ -57,15 +60,17 @@ if order > 1: dr.set_dbbar_base(t, order) -corr = dr.einst(sum_( - Rational(1, factorial(i) ** 2) * - t[tuple(v_dumms[:i]) + tuple(o_dumms[:i])] * - prod_(c_dag[j] for j in v_dumms[:i]) * - prod_(c_[j] for j in reversed(o_dumms[:i])) - for i in orders -)) +corr = dr.einst( + sum_( + Rational(1, factorial(i) ** 2) + * t[tuple(v_dumms[:i]) + tuple(o_dumms[:i])] + * prod_(c_dag[j] for j in v_dumms[:i]) + * prod_(c_[j] for j in reversed(o_dumms[:i])) + for i in orders + ) +) -print('Problem setting up done.') +print("Problem setting up done.") # # Similarity transform the Hamiltonian @@ -77,7 +82,7 @@ h_bar = dr.ham for i in range(4): curr = (curr | corr).simplify() / (i + 1) - stopwatch.tock('Commutator order {}'.format(i + 1), curr) + stopwatch.tock("Commutator order {}".format(i + 1), curr) h_bar += curr continue @@ -85,23 +90,21 @@ h_bar.repartition(cache=True) n_terms = h_bar.n_terms -stopwatch.tock('H-bar assembly', h_bar) +stopwatch.tock("H-bar assembly", h_bar) en_eqn = h_bar.eval_fermi_vev().simplify() -stopwatch.tock('Energy equation', en_eqn) +stopwatch.tock("Energy equation", en_eqn) dr.wick_parallel = 1 amp_eqns = collections.OrderedDict() for order in orders: - proj = prod_( - c_dag[j] for j in o_dumms[:order] - ) * prod_( + proj = prod_(c_dag[j] for j in o_dumms[:order]) * prod_( c_[j] for j in reversed(v_dumms[:order]) ) eqn = (proj * h_bar).eval_fermi_vev().simplify() - stopwatch.tock('T{} equation'.format(order), eqn) + stopwatch.tock("T{} equation".format(order), eqn) amp_eqns[order] = eqn continue @@ -109,21 +112,21 @@ stopwatch.tock_total() # Check with the result from TCE. -TCE_BASE_URL = 'http://www.scs.illinois.edu/~sohirata/' -tce_labels = ['e'] -tce_labels.extend('t{}'.format(i) for i in orders) -tce_files = ('{}_{}.out'.format(theory, i) for i in tce_labels) +TCE_BASE_URL = "http://www.scs.illinois.edu/~sohirata/" +tce_labels = ["e"] +tce_labels.extend("t{}".format(i) for i in orders) +tce_files = ("{}_{}.out".format(theory, i) for i in tce_labels) tce_res = [ dr.parse_tce( urllib.request.urlopen(TCE_BASE_URL + i).read().decode(), - {i: t for i in orders} + {i: t for i in orders}, ).simplify() for i in tce_files - ] +] -print('Checking with TCE result: ') -print('Energy: ', en_eqn == tce_res[0]) +print("Checking with TCE result: ") +print("Energy: ", en_eqn == tce_res[0]) for i, order in enumerate(amp_eqns.keys()): diff = (amp_eqns[order] - tce_res[i + 1]).simplify() - print('T{} amplitude: '.format(order), diff == 0) + print("T{} amplitude: ".format(order), diff == 0) diff --git a/docs/examples/rccsd.py b/docs/examples/rccsd.py index b083d20e..ef66a70a 100644 --- a/docs/examples/rccsd.py +++ b/docs/examples/rccsd.py @@ -13,7 +13,7 @@ # Environment setting up. -conf = SparkConf().setAppName('rccsd') +conf = SparkConf().setAppName("rccsd") ctx = SparkContext(conf=conf) dr = RestrictedPartHoleDrudge(ctx) dr.full_simplify = False @@ -25,17 +25,16 @@ # # Cluster excitation operator -# +# # Here, we first write the cluster excitation operator in terms of the # unitary group generator. Then they will be substituted by their fermion # operator definition. # -t = IndexedBase('t') +t = IndexedBase("t") cluster = dr.einst( - t[a, i] * e_[a, i] + - Rational(1, 2) * t[a, b, i, j] * e_[a, i] * e_[b, j] + t[a, i] * e_[a, i] + Rational(1, 2) * t[a, b, i, j] * e_[a, i] * e_[b, j] ) dr.set_n_body_base(t, 2) @@ -44,7 +43,7 @@ # # Similarity transform of the Hamiltonian -# +# stopwatch = Stopwatch() @@ -52,24 +51,21 @@ h_bar = dr.ham for order in range(4): curr = (curr | cluster).simplify() * Rational(1, order + 1) - stopwatch.tock('Commutator order {}'.format(order + 1), curr) + stopwatch.tock("Commutator order {}".format(order + 1), curr) h_bar += curr continue h_bar = h_bar.simplify() h_bar.repartition(cache=True) -stopwatch.tock('H-bar assembly', h_bar) +stopwatch.tock("H-bar assembly", h_bar) en_eqn = h_bar.eval_fermi_vev().simplify() -stopwatch.tock('Energy equation', en_eqn) +stopwatch.tock("Energy equation", en_eqn) dr.wick_parallel = 1 -beta, gamma, u, v = symbols('beta gamma u v') -projs = [ - e_[u, beta], - e_[u, beta] * e_[v, gamma] -] +beta, gamma, u, v = symbols("beta gamma u v") +projs = [e_[u, beta], e_[u, beta] * e_[v, gamma]] # # Dump the result to a simple report. @@ -78,14 +74,14 @@ amp_eqns = [] for order, proj in enumerate(projs): eqn = (proj * h_bar).eval_fermi_vev().simplify() - stopwatch.tock('T{} equation'.format(order + 1), eqn) + stopwatch.tock("T{} equation".format(order + 1), eqn) amp_eqns.append(eqn) continue stopwatch.tock_total() -with dr.report('rCCSD.html', 'restricted CCSD theory') as rep: - rep.add('Energy equation', en_eqn) +with dr.report("rCCSD.html", "restricted CCSD theory") as rep: + rep.add("Energy equation", en_eqn) for i, v in enumerate(amp_eqns): - rep.add(r'\(T^{}\) amplitude equation'.format(i + 1), v) + rep.add(r"\(T^{}\) amplitude equation".format(i + 1), v) continue diff --git a/tests/basic_wick_test.py b/tests/basic_wick_test.py index 38dc658f..6d18a24f 100644 --- a/tests/basic_wick_test.py +++ b/tests/basic_wick_test.py @@ -1,5 +1,4 @@ -"""Test basic Wick expansion of simple things. -""" +"""Test basic Wick expansion of simple things.""" import pickle @@ -22,12 +21,12 @@ def test_ancr_character_has_basic_properties(): # We test both the original value and the deserialized values. for cr, an in [(CR, AN), (n_cr, n_an)]: # Printing, all kinds of printing. - assert str(cr) == 'CR' - assert str(an) == 'AN' - assert repr(cr) == 'CranChar.CR' - assert repr(an) == 'CranChar.AN' - assert latex(cr) == r'\dagger' - assert latex(an) == '' + assert str(cr) == "CR" + assert str(an) == "AN" + assert repr(cr) == "CranChar.CR" + assert repr(an) == "CranChar.AN" + assert latex(cr) == r"\dagger" + assert latex(an) == "" # Ordering, in its original form and as SymPy key. assert cr == cr diff --git a/tests/bcs_test.py b/tests/bcs_test.py index dd055884..48a5f006 100644 --- a/tests/bcs_test.py +++ b/tests/bcs_test.py @@ -6,7 +6,7 @@ from drudge import ReducedBCSDrudge -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def rbcs(spark_ctx): """Initialize the environment for a reduced BCS problem.""" return ReducedBCSDrudge(spark_ctx) diff --git a/tests/bogoliubov_test.py b/tests/bogoliubov_test.py index 0e67e3ed..a41b47db 100644 --- a/tests/bogoliubov_test.py +++ b/tests/bogoliubov_test.py @@ -9,7 +9,7 @@ from drudge import BogoliubovDrudge, CR, AN -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def bogoliubov(spark_ctx): """Initialize the environment for a free algebra.""" @@ -44,9 +44,7 @@ def test_bogoliubov_has_hamiltonian(bogoliubov: BogoliubovDrudge): indices = tuple(itertools.chain(cr_indices, an_indices)) order = (len(cr_indices), len(an_indices)) - assert dict(term.sums) == { - i: qp_range for i in indices - } + assert dict(term.sums) == {i: qp_range for i in indices} # Here we use Python facility to test against the SymPy factorial in the # code. @@ -72,7 +70,7 @@ def test_bogoliubov_has_hamiltonian(bogoliubov: BogoliubovDrudge): (0, 4), (3, 1), (1, 3), - (2, 2) + (2, 2), } @@ -86,10 +84,10 @@ def test_bogoliubov_has_correct_matrix_elements(bogoliubov: BogoliubovDrudge): def_40 = None def_00 = None for i in mes: - if i.base == IndexedBase('H^{40}'): + if i.base == IndexedBase("H^{40}"): assert def_40 is None def_40 = i - elif i.base == Symbol('H^{00}'): + elif i.base == Symbol("H^{00}"): assert def_00 is None def_00 = i continue @@ -103,17 +101,28 @@ def test_bogoliubov_has_correct_matrix_elements(bogoliubov: BogoliubovDrudge): # still potentially fail this test in principle. ext_symbs = [i for i, _ in def_40.exts] k1, k2, k3, k4 = ext_symbs - l1, l2, l3, l4 = symbols('l1 l2 l3 l4') - assert dr.simplify(def_40.rhs - dr.sum( - (l1, p_range), (l2, p_range), (l3, p_range), (l4, p_range), - -6 * dr.two_body[l1, l2, l3, l4] * conjugate(dr.u_base[l1, k1]) - * conjugate(dr.u_base[l2, k2]) - * conjugate(dr.v_base[l4, k4]) - * conjugate(dr.v_base[l3, k3]) - )) == 0 + l1, l2, l3, l4 = symbols("l1 l2 l3 l4") + assert ( + dr.simplify( + def_40.rhs + - dr.sum( + (l1, p_range), + (l2, p_range), + (l3, p_range), + (l4, p_range), + -6 + * dr.two_body[l1, l2, l3, l4] + * conjugate(dr.u_base[l1, k1]) + * conjugate(dr.u_base[l2, k2]) + * conjugate(dr.v_base[l4, k4]) + * conjugate(dr.v_base[l3, k3]), + ) + ) + == 0 + ) # Test the registration of the matrix element names. - assert hasattr(dr.names, 'H00') + assert hasattr(dr.names, "H00") assert isinstance(dr.names.H00, IndexedBase) @@ -121,4 +130,4 @@ def test_bogoliubov_vev(bogoliubov: BogoliubovDrudge): """Test the correctness of Bogoliubov VEV evaluation.""" dr = bogoliubov res = dr.ham.eval_bogoliubov_vev() - assert res == dr.sum(Symbol(r'H^{00}')) + assert res == dr.sum(Symbol(r"H^{00}")) diff --git a/tests/clifford_test.py b/tests/clifford_test.py index 321e1534..16836015 100644 --- a/tests/clifford_test.py +++ b/tests/clifford_test.py @@ -4,13 +4,12 @@ def test_clifford_drudge_by_quaternions(spark_ctx): - """Test basic functionality of Clifford drudge by quaternions. - """ + """Test basic functionality of Clifford drudge by quaternions.""" dr = CliffordDrudge( spark_ctx, inner=lambda v1, v2: -inner_by_delta(v1, v2) ) - e_ = Vec('e') + e_ = Vec("e") i_ = dr.sum(e_[2] * e_[3]).simplify() j_ = dr.sum(e_[3] * e_[1]).simplify() diff --git a/tests/conftest.py b/tests/conftest.py index 0ea90ac9..51fa250b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,19 +4,22 @@ import pytest -IF_DUMMY_SPARK = 'DUMMY_SPARK' in os.environ +IF_DUMMY_SPARK = "DUMMY_SPARK" in os.environ -@pytest.fixture(scope='session', autouse=True) + +@pytest.fixture(scope="session", autouse=True) def spark_ctx(): """A simple spark context.""" if IF_DUMMY_SPARK: from dummy_spark import SparkConf, SparkContext + conf = SparkConf() - ctx = SparkContext(master='', conf=conf) + ctx = SparkContext(master="", conf=conf) else: from pyspark import SparkConf, SparkContext - conf = SparkConf().setMaster('local[2]').setAppName('drudge-unittest') + + conf = SparkConf().setMaster("local[2]").setAppName("drudge-unittest") ctx = SparkContext(conf=conf) return ctx diff --git a/tests/drs_test.py b/tests/drs_test.py index 11760fd2..57d4f626 100644 --- a/tests/drs_test.py +++ b/tests/drs_test.py @@ -8,7 +8,12 @@ from drudge import Drudge, Range, Vec, Term from drudge.drs import ( - DrsSymbol, compile_drs, _DEF_METH_NAME, DrsEnv, _DRUDGE_MAGIC, main + DrsSymbol, + DrsEnv, + compile_drs, + _DEF_METH_NAME, + _DRUDGE_MAGIC, + main, ) from drudge.utils import sympy_key @@ -20,17 +25,13 @@ def test_basic_drs_symb(): - """Test the symbol class for basic operations. - """ + """Test the symbol class for basic operations.""" - name = 'a' + name = "a" ref = Symbol(name) dict_ = {ref: 1} - symbs = [ - DrsSymbol(None, name), - DrsSymbol([], name) - ] + symbs = [DrsSymbol(None, name), DrsSymbol([], name)] for i in symbs: assert isinstance(i, DrsSymbol) assert ref == i @@ -38,9 +39,9 @@ def test_basic_drs_symb(): assert hash(ref) == hash(i) assert dict_[i] == 1 assert sympy_key(ref) == sympy_key(i) - assert not hasattr(i, '__dict__') + assert not hasattr(i, "__dict__") - ref = Symbol(name + 'x') + ref = Symbol(name + "x") for i in symbs: assert ref != i assert i != ref @@ -51,16 +52,16 @@ def test_basic_drs_symb(): def test_basic_drs_indexed(): """Test basic properties of drudge script indexed object.""" - base_name = 'a' + base_name = "a" orig_base = IndexedBase(base_name) for drudge in [None, []]: matching_indices = [ - (Symbol('x'), DrsSymbol(drudge, 'x')), + (Symbol("x"), DrsSymbol(drudge, "x")), ( - (Symbol('x'), Symbol('y')), - (DrsSymbol(drudge, 'x'), DrsSymbol(drudge, 'y')) - ) + (Symbol("x"), Symbol("y")), + (DrsSymbol(drudge, "x"), DrsSymbol(drudge, "y")), + ), ] drs_base = DrsSymbol(drudge, base_name) for orig_indices, drs_indices in matching_indices: @@ -68,7 +69,7 @@ def test_basic_drs_indexed(): for i in [ orig_base[drs_indices], drs_base[orig_indices], - drs_base[drs_indices] + drs_base[drs_indices], ]: assert ref == i assert hash(ref) == hash(i) @@ -80,27 +81,27 @@ def test_drs_symb_call(spark_ctx): class TestCls: def meth(self): - return 'meth' + return "meth" @property def prop(self): - return 'prop' + return "prop" obj = TestCls() - meth = DrsSymbol(None, 'meth') - assert meth(obj) == 'meth' - prop = DrsSymbol(None, 'prop') - assert prop(obj) == 'prop' - invalid = DrsSymbol(None, 'invalid') + meth = DrsSymbol(None, "meth") + assert meth(obj) == "meth" + prop = DrsSymbol(None, "prop") + assert prop(obj) == "prop" + invalid = DrsSymbol(None, "invalid") with pytest.raises(NameError): invalid(obj) with pytest.raises(AttributeError) as exc: prop.lhs - assert exc.value.args[0].find('prop') > 0 + assert exc.value.args[0].find("prop") > 0 # Test automatic raising to tensors. - v = Vec('v') - tensor_meth = 'local_terms' + v = Vec("v") + tensor_meth = "local_terms" assert not hasattr(v, tensor_meth) # Or the test just will not work. assert DrsSymbol(Drudge(spark_ctx), tensor_meth)(v) == [ Term(sums=(), amp=Integer(1), vecs=(v,)) @@ -113,54 +114,54 @@ def test_drs_tensor_def_dispatch(spark_ctx): dr = Drudge(spark_ctx) names = dr.names - i_symb = Symbol('i') - x = IndexedBase('x') + i_symb = Symbol("i") + x = IndexedBase("x") rhs = x[i_symb] - dr.add_default_resolver(Range('R')) + dr.add_default_resolver(Range("R")) - a = DrsSymbol(dr, 'a') - i = DrsSymbol(dr, 'i') + a = DrsSymbol(dr, "a") + i = DrsSymbol(dr, "i") for lhs in [a, a[i]]: expected = dr.define(lhs, rhs) def_ = lhs <= rhs assert def_ == expected - assert not hasattr(names, 'a') - assert not hasattr(names, '_a') + assert not hasattr(names, "a") + assert not hasattr(names, "_a") def_ = lhs.def_as(rhs) assert def_ == expected assert names.a == expected if isinstance(lhs, DrsSymbol): - assert names._a == Symbol('a') + assert names._a == Symbol("a") else: - assert names._a == IndexedBase('a') + assert names._a == IndexedBase("a") dr.unset_name(def_) def test_drs_integers(): """Test fixers for integer literals in drudge scripts.""" - body = 'a = 1 / (1 + (1 + 2))' - code = compile_drs(body, '') - ctx = {'Integer': Integer} + body = "a = 1 / (1 + (1 + 2))" + code = compile_drs(body, "") + ctx = {"Integer": Integer} exec(code, ctx) - assert ctx['a'] == Rational(1, 4) + assert ctx["a"] == Rational(1, 4) def test_drs_global_def(): """Test global definition operation in drudge scripts.""" body = 'a[0] <<= "x"' - code = compile_drs(body, '') + code = compile_drs(body, "") a = [Mock()] def_mock = Mock(return_value=10) setattr(a[0], _DEF_METH_NAME, def_mock) - ctx = {'a': a, 'Integer': Integer} + ctx = {"a": a, "Integer": Integer} exec(code, ctx) # Test a is no longer rebound. - assert ctx['a'] is a - def_mock.assert_called_with('x') + assert ctx["a"] is a + def_mock.assert_called_with("x") def test_drs_env(): @@ -168,25 +169,25 @@ def test_drs_env(): dr = types.SimpleNamespace() dr.names = types.SimpleNamespace() - dr.names.archived = 'archived' + dr.names.archived = "archived" specials = types.SimpleNamespace() - specials.special = 'special' + specials.special = "special" env = DrsEnv(dr, specials=specials) with pytest.raises(KeyError): - env['__tracebackhide__'] + env["__tracebackhide__"] - assert env['archived'] == 'archived' - assert env['special'] == 'special' - assert env['names'] is dr.names - assert env['Range'] is Range - assert env['Symbol'] is Symbol - assert env['range'] is range + assert env["archived"] == "archived" + assert env["special"] == "special" + assert env["names"] is dr.names + assert env["Range"] is Range + assert env["Symbol"] is Symbol + assert env["range"] is range # Specially excluded items from some path entries. - assert isinstance(env['N'], DrsSymbol) + assert isinstance(env["N"], DrsSymbol) CONF_SCRIPT = """ @@ -204,14 +205,14 @@ def test_drs_env(): def test_drs_main(tmpdir): """Test drudge main function.""" olddir = tmpdir.chdir() - with open('conf.py', 'w') as fp: + with open("conf.py", "w") as fp: fp.write(CONF_SCRIPT) - with open('run.drs', 'w') as fp: + with open("run.drs", "w") as fp: fp.write(DRUDGE_SCRIPT) - env = main(['conf.py', 'run.drs']) - assert 'def_' in env - def_ = env['def_'] + env = main(["conf.py", "run.drs"]) + assert "def_" in env + def_ = env["def_"] assert def_.n_terms == 1 assert def_.rhs_terms[0].amp == Rational(1, 5) diff --git a/tests/free_algebra_test.py b/tests/free_algebra_test.py index 13a7b079..ed283294 100644 --- a/tests/free_algebra_test.py +++ b/tests/free_algebra_test.py @@ -8,12 +8,31 @@ import pytest from sympy import ( - sympify, IndexedBase, sin, cos, KroneckerDelta, symbols, conjugate, Wild, - Rational, Symbol, Function + sympify, + IndexedBase, + sin, + cos, + KroneckerDelta, + symbols, + conjugate, + Wild, + Rational, + Symbol, + Function, ) from drudge import ( - Drudge, Range, Vec, Term, Perm, NEG, CONJ, TensorDef, CR, UP, DOWN + Drudge, + Range, + Vec, + Term, + Perm, + TensorDef, + NEG, + CONJ, + CR, + UP, + DOWN, ) from conftest import skip_in_spark @@ -25,36 +44,34 @@ def free_alg(spark_ctx): dr = Drudge(spark_ctx) - r = Range('R') - dumms = sympify('i, j, k, l, m, n') + r = Range("R") + dumms = sympify("i, j, k, l, m, n") dr.set_dumms(r, dumms) - s = Range('S') - s_dumms = symbols('alpha beta') + s = Range("S") + s_dumms = symbols("alpha beta") dr.set_dumms(s, s_dumms) dr.add_resolver_for_dumms() # For testing the Einstein over multiple ranges. - a1, a2 = symbols('a1 a2') - dr.add_resolver({ - a1: (r, s), a2: (r, s) - }) + a1, a2 = symbols("a1 a2") + dr.add_resolver({a1: (r, s), a2: (r, s)}) dr.set_name(a1, a2) - v = Vec('v') + v = Vec("v") dr.set_name(v) - m = IndexedBase('m') + m = IndexedBase("m") dr.set_symm(m, Perm([1, 0], NEG)) - h = IndexedBase('h') + h = IndexedBase("h") dr.set_symm(h, Perm([1, 0], NEG | CONJ)) - rho = IndexedBase('rho') + rho = IndexedBase("rho") dr.set_symm(rho, Perm([1, 0, 3, 2]), valence=4) - dr.set_tensor_method('get_one', lambda x: 1) + dr.set_tensor_method("get_one", lambda x: 1) return dr @@ -68,16 +85,16 @@ def test_drudge_has_names(free_alg): p = free_alg.names # Range and dummy related. - assert p.R == Range('R') + assert p.R == Range("R") assert len(p.R_dumms) == 6 assert p.R_dumms[0] == p.i assert p.R_dumms[-1] == p.n # Vector bases. - assert p.v == Vec('v') + assert p.v == Vec("v") # Scalar bases. - assert p.m == IndexedBase('m') + assert p.m == IndexedBase("m") def test_tensor_can_be_created(free_alg): @@ -86,13 +103,10 @@ def test_tensor_can_be_created(free_alg): dr = free_alg p = dr.names i, v, r = p.i, p.v, p.R - x = IndexedBase('x') + x = IndexedBase("x") # Create the tensor by two user creation functions. - for tensor in [ - dr.sum((i, r), x[i] * v[i]), - dr.einst(x[i] * v[i]) - ]: + for tensor in [dr.sum((i, r), x[i] * v[i]), dr.einst(x[i] * v[i])]: assert tensor.n_terms == 1 terms = tensor.local_terms @@ -107,7 +121,7 @@ def test_complex_tensor_creation(free_alg): dr = free_alg p = dr.names i, v, r = p.i, p.v, p.R - x = IndexedBase('x') + x = IndexedBase("x") for summand in [(x[i] / 2) * v[i], x[i] * (v[i] / 2)]: tensor = dr.einst(summand) assert tensor.n_terms == 1 @@ -136,13 +150,10 @@ def test_tensor_has_basic_operations(free_alg): dr = free_alg p = dr.names i, j, k, l, m = p.R_dumms[:5] - x = IndexedBase('x') + x = IndexedBase("x") r = p.R v = p.v - tensor = ( - dr.sum((l, r), x[i, l] * v[l]) + - dr.sum((m, r), x[j, m] * v[m]) - ) + tensor = dr.sum((l, r), x[i, l] * v[l]) + dr.sum((m, r), x[j, m] * v[m]) # Without dummy resetting, they cannot be merged. assert tensor.n_terms == 2 @@ -154,10 +165,7 @@ def test_tensor_has_basic_operations(free_alg): # Reset dummy. reset = tensor.reset_dumms() - expected = ( - dr.sum((k, r), x[i, k] * v[k]) + - dr.sum((k, r), x[j, k] * v[k]) - ) + expected = dr.sum((k, r), x[i, k] * v[k]) + dr.sum((k, r), x[j, k] * v[k]) assert reset == expected assert reset.local_terms == expected.local_terms @@ -168,7 +176,7 @@ def test_tensor_has_basic_operations(free_alg): assert term == Term(((k, r),), x[i, k] + x[j, k], (v[k],)) # Slightly separate test for expansion. - c, d = symbols('c d') + c, d = symbols("c d") tensor = dr.sum((i, r), x[i] * (c + d) * v[i]) assert tensor.n_terms == 1 expanded = tensor.expand() @@ -178,7 +186,7 @@ def test_tensor_has_basic_operations(free_alg): assert shallowly_expanded.n_terms == 1 # Make sure shallow expansion does the job on the top-level. - y = IndexedBase('y') + y = IndexedBase("y") tensor = dr.sum((i, r), (x[i] * (c + d) + y[i]) * v[i]) assert tensor.n_terms == 1 expanded = tensor.expand() @@ -187,16 +195,14 @@ def test_tensor_has_basic_operations(free_alg): assert shallowly_expanded.n_terms == 2 # Here we also test concrete summation facility. - expected = dr.sum( - (i, r), (j, [c, d]), x[i] * j * v[i] + expected = dr.sum((i, r), (j, [c, d]), x[i] * j * v[i]) + assert ( + expected == dr.sum((i, r), x[i] * c * v[i] + x[i] * d * v[i]).expand() ) - assert expected == dr.sum( - (i, r), x[i] * c * v[i] + x[i] * d * v[i] - ).expand() # Test mapping to scalars. tensor = dr.sum((i, r), x[i] * v[i, j]) - y = IndexedBase('y') + y = IndexedBase("y") substs = {x: y, j: c} res = tensor.map2scalars(lambda x: x.xreplace(substs)) assert res == dr.sum((i, r), y[i] * v[i, c]) @@ -208,8 +214,8 @@ def test_tensor_has_basic_operations(free_alg): tensor = dr.einst(x[i] * v[i]) assert tensor.has_base(x) assert tensor.has_base(v) - assert not tensor.has_base(IndexedBase('y')) - assert not tensor.has_base(Vec('w')) + assert not tensor.has_base(IndexedBase("y")) + assert not tensor.has_base(Vec("w")) # Test Einstein summation over multiple ranges. a1, a2 = p.a1, p.a2 @@ -230,30 +236,30 @@ def test_basic_handling_range_with_variable_bounds(spark_ctx): dr = Drudge(spark_ctx) - j1, j2 = symbols('j1 j2') - m1, m2 = symbols('m1, m2') - j_max = symbols('j_max') - j = Range('j', 0, j_max) - m = Range('m') + j1, j2 = symbols("j1 j2") + m1, m2 = symbols("m1, m2") + j_max = symbols("j_max") + j = Range("j", 0, j_max) + m = Range("m") dr.set_dumms(j, [j1, j2]) dr.set_dumms(m, [m1, m2]) - v = Vec('v') - x = IndexedBase('x') + v = Vec("v") + x = IndexedBase("x") tensor = dr.sum((j2, j), (m2, m[0, j2]), x[j2, m2] * v[j2, m2]) reset = tensor.reset_dumms() assert reset.n_terms == 1 term = reset.local_terms[0] assert len(term.sums) == 2 - if term.sums[0][1].label == 'j': + if term.sums[0][1].label == "j": j_sum, m_sum = term.sums else: m_sum, j_sum = term.sums assert j_sum[0] == j1 assert j_sum[1].args == j.args assert m_sum[0] == m1 - assert m_sum[1].label == 'm' + assert m_sum[1].label == "m" assert m_sum[1].lower == 0 assert m_sum[1].upper == j1 # Important! assert term.amp == x[j1, m1] @@ -267,7 +273,7 @@ def test_basic_handling_range_with_variable_bounds(spark_ctx): term = repled.local_terms[0] checked = False for _, i in term.sums: - if i.label == 'j': + if i.label == "j": assert i.lower == 0 assert i.upper == 10 checked = True @@ -276,13 +282,12 @@ def test_basic_handling_range_with_variable_bounds(spark_ctx): def test_handling_of_variable_bound_sums_in_merge(free_alg): - """A regression test for handling bounds with different variable bounds. - """ + """A regression test for handling bounds with different variable bounds.""" dr = free_alg p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") v = p.v i = p.i r = p.R @@ -290,19 +295,19 @@ def test_handling_of_variable_bound_sums_in_merge(free_alg): first = dr.sum((i, r), x[i] * v[i]) # First trial, when the ranges are really the same. - assert dr.simplify( - first - dr.sum((i, r), x[i] * v[i]) - ) == 0 + assert dr.simplify(first - dr.sum((i, r), x[i] * v[i])) == 0 # This time, they should not be merged. - assert dr.simplify( - first - dr.sum((i, r[0, Symbol('n')]), x[i] * v[i]) - ).n_terms == 2 + assert ( + dr.simplify( + first - dr.sum((i, r[0, Symbol("n")]), x[i] * v[i]) + ).n_terms + == 2 + ) def test_handling_of_variable_bound_sums_in_trivial_summation(free_alg): - """A regression test for handling bounds with different variable bounds. - """ + """A regression test for handling bounds with different variable bounds.""" dr = free_alg p = dr.names @@ -312,27 +317,23 @@ def test_handling_of_variable_bound_sums_in_trivial_summation(free_alg): i = p.i alpha = p.alpha s = p.S - n = Symbol('N') + n = Symbol("N") first = dr.sum((i, r[0, n]), (alpha, s[0, n]), v[alpha]) # First trial, when the dummy is not actually used. - assert dr.simplify( - first - ) == dr.sum((alpha, s[0, n]), n * v[alpha]) + assert dr.simplify(first) == dr.sum((alpha, s[0, n]), n * v[alpha]) # When i is used in the bounds of summation over alpha, it should be kept. second = dr.sum((i, r[0, n]), (alpha, s[0, i]), v[alpha]) - assert dr.simplify( - second - ) == second + assert dr.simplify(second) == second def test_adv_merging(free_alg): """Test advanced merging options.""" dr = free_alg - m, n, a, b, c = symbols('m n a b c') + m, n, a, b, c = symbols("m n a b c") orig = m * a * b + n * a * c factored = (m * b + n * c) * a tensor = dr.sum(orig).expand() @@ -378,17 +379,18 @@ def test_tensor_can_be_simplified_amp(free_alg): i, j = p.R_dumms[:2] alpha = p.alpha - x = IndexedBase('x') - y = IndexedBase('y') - theta = sympify('theta') + x = IndexedBase("x") + y = IndexedBase("y") + theta = sympify("theta") tensor = ( - dr.sum((i, r), sin(theta) ** 2 * x[i] * v[i]) + - dr.sum( - (i, r), (j, r), - cos(theta) ** 2 * x[j] * KroneckerDelta(i, j) * v[i] - ) + - dr.sum((i, r), (alpha, s), KroneckerDelta(i, alpha) * y[i] * v[i]) + dr.sum((i, r), sin(theta) ** 2 * x[i] * v[i]) + + dr.sum( + (i, r), + (j, r), + cos(theta) ** 2 * x[j] * KroneckerDelta(i, j) * v[i], + ) + + dr.sum((i, r), (alpha, s), KroneckerDelta(i, alpha) * y[i] * v[i]) ) assert tensor.n_terms == 3 @@ -424,10 +426,8 @@ def test_simplify_delta_of_unsolvable_functions(free_alg): dr = free_alg p = dr.names - f = Function('f') - tensor = dr.sum( - (p.i, p.R), KroneckerDelta(f(p.i), p.alpha) * p.v - ) + f = Function("f") + tensor = dr.sum((p.i, p.R), KroneckerDelta(f(p.i), p.alpha) * p.v) assert tensor.n_terms == 1 assert tensor.simplify_deltas() == tensor assert tensor.simplify() == tensor @@ -448,10 +448,11 @@ def test_tensor_can_be_canonicalized(free_alg): h = p.h v = p.v + # fmt: off # Anti-symmetric real matrix. tensor = ( - dr.sum((i, r), (j, r), m[i, j] * v[i] * v[j]) + - dr.sum((i, r), (j, r), m[j, i] * v[i] * v[j]) + dr.sum((i, r), (j, r), m[i, j] * v[i] * v[j]) + + dr.sum((i, r), (j, r), m[j, i] * v[i] * v[j]) ) assert tensor.n_terms == 2 res = tensor.simplify() @@ -459,8 +460,8 @@ def test_tensor_can_be_canonicalized(free_alg): # With wrapping under an even function. tensor = ( - dr.sum((i, r), (j, r), m[i, j] ** 2 * v[i] * v[j]) + - dr.sum((i, r), (j, r), m[j, i] ** 2 * v[i] * v[j]) + dr.sum((i, r), (j, r), m[i, j] ** 2 * v[i] * v[j]) + + dr.sum((i, r), (j, r), m[j, i] ** 2 * v[i] * v[j]) ) assert tensor.n_terms == 2 res = tensor.simplify() @@ -472,17 +473,16 @@ def test_tensor_can_be_canonicalized(free_alg): # With wrapping under an odd function. tensor = ( - dr.sum((i, r), (j, r), m[i, j] ** 3 * v[i] * v[j]) + - dr.sum((i, r), (j, r), m[j, i] ** 3 * v[i] * v[j]) + dr.sum((i, r), (j, r), m[i, j] ** 3 * v[i] * v[j]) + + dr.sum((i, r), (j, r), m[j, i] ** 3 * v[i] * v[j]) ) + # fmt: on assert tensor.n_terms == 2 res = tensor.simplify() assert res.n_terms == 0 # Hermitian matrix. - tensor = dr.einst( - h[i, j] * v[i] * v[j] + conjugate(h[j, i]) * v[i] * v[j] - ) + tensor = dr.einst(h[i, j] * v[i] * v[j] + conjugate(h[j, i]) * v[i] * v[j]) assert tensor.n_terms == 2 res = tensor.simplify() assert res == 0 @@ -490,6 +490,7 @@ def test_tensor_can_be_canonicalized(free_alg): class SymmFunc(Function): """A symmetric function.""" + pass @@ -514,16 +515,15 @@ def test_tensors_w_functions_can_be_canonicalized(free_alg): def test_canonicalization_of_vectors_w_symm(free_alg): - """Test the canonicalization when vectors are given (anti-)symmetries. - """ + """Test the canonicalization when vectors are given (anti-)symmetries.""" dr = free_alg p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") r = p.R i, j = p.i, p.j - vs = Vec('vs') + vs = Vec("vs") dr.set_symm(vs, Perm([1, 0]), valence=2) tensor = dr.sum((i, r), (j, r), x[i, j] * vs[j, i]) res = tensor.simplify() @@ -533,7 +533,7 @@ def test_canonicalization_of_vectors_w_symm(free_alg): assert term.amp == x[i, j] assert term.vecs == (vs[i, j],) - va = Vec('va') + va = Vec("va") dr.set_symm(va, Perm([1, 0], NEG), valence=2) tensor = dr.sum((i, r), (j, r), x[i, j] * va[j, i]) res = tensor.simplify() @@ -549,12 +549,15 @@ def test_canonicalization_connected_summations(free_alg): dr = free_alg p = dr.names i, j, k, l = p.R_dumms[:4] - a, b = symbols('a b') - t = IndexedBase('t') + a, b = symbols("a b") + t = IndexedBase("t") tensor = dr.sum( - (i, p.R), (j, p.R[0, i]), (k, p.R[0, a]), (l, p.R[0, b]), - t[i] * t[j] * t[k] * t[l] + (i, p.R), + (j, p.R[0, i]), + (k, p.R[0, a]), + (l, p.R[0, b]), + t[i] * t[j] * t[k] * t[l], ) res = tensor.simplify() sums = res.local_terms[0].sums @@ -576,10 +579,10 @@ def test_tensor_math_ops(free_alg): p = dr.names r = p.R v = p.v - w = Vec('w') - x = IndexedBase('x') + w = Vec("w") + x = IndexedBase("x") i, j, k = p.R_dumms[:3] - a = sympify('a') + a = sympify("a") v1 = dr.sum((i, r), x[i] * v[i]) w1 = dr.sum((i, r), x[i] * w[i]) @@ -600,8 +603,10 @@ def test_tensor_math_ops(free_alg): prod = v1_1 * w1_1 # Test scalar multiplication here as well. expected = ( - 2 * a + a * v1 + 2 * w1 + - dr.sum((i, r), (j, r), x[i] * x[j] * v[i] * w[j]) + 2 * a + + a * v1 + + 2 * w1 + + dr.sum((i, r), (j, r), x[i] * x[j] * v[i] * w[j]) ) assert prod.simplify() == expected.simplify() @@ -610,13 +615,15 @@ def test_tensor_math_ops(free_alg): assert comm_v1v1.simplify() == 0 # Here the tensor subtraction can also be tested. comm_v1w1 = v1 | w1 + # fmt: off expected = ( - dr.sum((i, r), (j, r), x[i] * x[j] * v[i] * w[j]) - - dr.sum((i, r), (j, r), x[j] * x[i] * w[i] * v[j]) + dr.sum((i, r), (j, r), x[i] * x[j] * v[i] * w[j]) + - dr.sum((i, r), (j, r), x[j] * x[i] * w[i] * v[j]) ) + # fmt: on assert comm_v1w1.simplify() == expected.simplify() - alpha = symbols('alpha') + alpha = symbols("alpha") assert alpha not in v1.free_vars tensor = v1 / alpha assert tensor.n_terms == 1 @@ -632,9 +639,9 @@ def test_tensor_math_ops(free_alg): def test_trivial_sums_can_be_simplified(free_alg): """Test the simplification facility for trivial sums.""" dr = free_alg - r = Range('D', 0, 2) + r = Range("D", 0, 2) - a, b = symbols('a b') + a, b = symbols("a b") tensor = dr.sum(1) + dr.sum((a, r), 1) + dr.sum((a, r), (b, r), 1) res = tensor.simplify() assert res == dr.sum(7) @@ -644,15 +651,13 @@ def test_amp_sums_can_be_simplified(free_alg): """Test the simplification facility for more complex amplitude sums.""" dr = free_alg v = dr.names.v - n, i, j = symbols('n i j') - x = IndexedBase('x') - r = Range('D', 0, n) + n, i, j = symbols("n i j") + x = IndexedBase("x") + r = Range("D", 0, n) - tensor = dr.sum((i, r), (j, r), i ** 2 * x[j] * v[j]) + tensor = dr.sum((i, r), (j, r), i**2 * x[j] * v[j]) res = tensor.simplify_sums() - assert res == dr.sum((j, r), ( - n ** 3 / 3 - n ** 2 / 2 + n / 6 - ) * x[j] * v[j]) + assert res == dr.sum((j, r), (n**3 / 3 - n**2 / 2 + n / 6) * x[j] * v[j]) def test_tensors_can_be_differentiated(free_alg): @@ -661,34 +666,25 @@ def test_tensors_can_be_differentiated(free_alg): dr = free_alg p = dr.names - a = IndexedBase('a') - b = IndexedBase('b') + a = IndexedBase("a") + b = IndexedBase("b") i, j, k, l, m, n = p.R_dumms[:6] - tensor = dr.einst( - a[i, j, k, l] * b[i, j] * conjugate(b[k, l]) - ) + tensor = dr.einst(a[i, j, k, l] * b[i, j] * conjugate(b[k, l])) # Test real analytic gradient. res = tensor.diff(b[i, j], real=True) - expected = dr.einst( - b[k, l] * (a[k, l, i, j] + a[i, j, k, l]) - ) + expected = dr.einst(b[k, l] * (a[k, l, i, j] + a[i, j, k, l])) assert (res - expected).simplify() == 0 # Test Wirtinger complex derivative. res, res_conj = [ - tensor.diff(b[m, n], wirtinger_conj=conj) - for conj in [False, True] + tensor.diff(b[m, n], wirtinger_conj=conj) for conj in [False, True] ] - expected = dr.einst( - conjugate(b[i, j]) * a[m, n, i, j] - ) - expect_conj = dr.einst( - a[i, j, m, n] * b[i, j] - ) + expected = dr.einst(conjugate(b[i, j]) * a[m, n, i, j]) + expect_conj = dr.einst(a[i, j, m, n] * b[i, j]) for res_i, expected_i in [(res, expected), (res_conj, expect_conj)]: assert (res_i - expected_i).simplify() == 0 @@ -700,28 +696,25 @@ def test_tensors_can_be_differentiated(free_alg): assert (grad - 2 * b[j, i]).simplify() == 0 -@pytest.mark.parametrize('full_balance', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) def test_tensors_can_substitute_scalars(free_alg, full_balance): """Test scalar substitution facility for tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') - y = IndexedBase('y') - z = IndexedBase('z') + x = IndexedBase("x") + y = IndexedBase("y") + z = IndexedBase("z") r = p.R i, j, k, l, m = p.R_dumms[:5] - x_def = dr.define( - x[i], dr.sum((j, r), y[j] * z[i]) - ) + x_def = dr.define(x[i], dr.sum((j, r), y[j] * z[i])) orig = dr.sum((i, r), x[i] ** 2 * x[k]) # k is free. expected = dr.sum( - (i, r), (j, r), (l, r), (m, r), - z[i] ** 2 * y[j] * y[l] * y[m] * z[k] + (i, r), (j, r), (l, r), (m, r), z[i] ** 2 * y[j] * y[l] * y[m] * z[k] ) # Test different ways to perform the substitution. @@ -729,27 +722,25 @@ def test_tensors_can_substitute_scalars(free_alg, full_balance): orig.subst(x[i], x_def.rhs, full_balance=full_balance), orig.subst_all([x_def], full_balance=full_balance), orig.subst_all([(x[i], x_def.rhs)], full_balance=full_balance), - x_def.act(orig, full_balance=full_balance) + x_def.act(orig, full_balance=full_balance), ]: assert res.simplify() == expected.simplify() -@pytest.mark.parametrize('full_balance', [True, False]) -@pytest.mark.parametrize('full_simplify', [True, False]) -def test_tensors_can_substitute_vectors( - free_alg, full_balance, full_simplify -): +@pytest.mark.parametrize("full_balance", [True, False]) +@pytest.mark.parametrize("full_simplify", [True, False]) +def test_tensors_can_substitute_vectors(free_alg, full_balance, full_simplify): """Test vector substitution facility for tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') - t = IndexedBase('t') - u = IndexedBase('u') + x = IndexedBase("x") + t = IndexedBase("t") + u = IndexedBase("u") i, j = p.i, p.j v = p.v - w = Vec('w') + w = Vec("w") orig = dr.einst(x[i] * v[i]) v_def = dr.einst(t[i, j] * w[j] + u[i, j] * w[j]) @@ -764,17 +755,17 @@ def test_tensors_can_substitute_vectors( assert res == expected -@pytest.mark.parametrize('full_balance', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) def test_numbers_can_substitute_scalars(free_alg, full_balance): """Test substituting scalars with numbers.""" dr = free_alg p = dr.names - x = IndexedBase('x') - y = IndexedBase('y') - r = Range('D', 0, 2) - i, j, k, l = symbols('i j k l') + x = IndexedBase("x") + y = IndexedBase("y") + r = Range("D", 0, 2) + i, j, k, l = symbols("i j k l") dr.set_dumms(r, [i, j, k, l]) v = p.v @@ -788,21 +779,23 @@ def test_numbers_can_substitute_scalars(free_alg, full_balance): assert res == dr.sum(16 * y[k] * v[l]) -@pytest.mark.parametrize('full_balance', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) def test_numbers_can_substitute_vectors(free_alg, full_balance): """Test substituting vectors with numbers.""" dr = free_alg p = dr.names - x = IndexedBase('x') - y = IndexedBase('y') + x = IndexedBase("x") + y = IndexedBase("y") r = p.R - i, j, k, l = symbols('i j k l') + i, j, k, l = symbols("i j k l") v = p.v - w = Vec('w') + w = Vec("w") - orig = dr.sum((i, r), (j, r), x[i, j] * v[i] * w[j] + y[i, j] * v[i] * v[j]) + orig = dr.sum( + (i, r), (j, r), x[i, j] * v[i] * w[j] + y[i, j] * v[i] * v[j] + ) res = orig.subst(v[k], 0, full_balance=full_balance).simplify() assert res == 0 @@ -810,16 +803,14 @@ def test_numbers_can_substitute_vectors(free_alg, full_balance): assert res == dr.sum((i, r), (j, r), x[j, i] * w[i] + y[i, j]) -@pytest.mark.parametrize('full_balance', [True, False]) -def test_tensors_can_substitute_scalars_simultaneously( - free_alg, full_balance -): +@pytest.mark.parametrize("full_balance", [True, False]) +def test_tensors_can_substitute_scalars_simultaneously(free_alg, full_balance): """Test scalar substitution facility for tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") r = p.R i, j = p.R_dumms[:2] @@ -828,29 +819,29 @@ def test_tensors_can_substitute_scalars_simultaneously( orig = dr.sum((i, r), summand) # k is free. - expected = dr.sum((i, r), summand * 2 ** 3) + expected = dr.sum((i, r), summand * 2**3) # Test different ways to perform the substitution. for res in [ orig.subst(x[i], x_def.rhs, full_balance=full_balance), orig.subst_all([x_def], full_balance=full_balance), orig.subst_all([(x[i], x_def.rhs)], full_balance=full_balance), - x_def.act(orig, full_balance=full_balance) + x_def.act(orig, full_balance=full_balance), ]: assert res.simplify() == expected.simplify() -@pytest.mark.parametrize('full_balance', [True, False]) -@pytest.mark.parametrize('full_simplify', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) +@pytest.mark.parametrize("full_simplify", [True, False]) def test_tensors_can_substitute_vectors_simultaneously( - free_alg, full_balance, full_simplify + free_alg, full_balance, full_simplify ): """Test vector substitution facility for tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") i, j = p.i, p.j v = p.v @@ -865,23 +856,23 @@ def test_tensors_can_substitute_vectors_simultaneously( assert res == expected -@pytest.mark.parametrize('full_balance', [True, False]) -@pytest.mark.parametrize('full_simplify', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) +@pytest.mark.parametrize("full_simplify", [True, False]) def test_tensors_can_substitute_symbols_simultaneously( - free_alg, full_balance, full_simplify + free_alg, full_balance, full_simplify ): """Test vector substitution facility for tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') - alpha = Symbol('alpha') - beta = IndexedBase('beta') + x = IndexedBase("x") + alpha = Symbol("alpha") + beta = IndexedBase("beta") i, j, k = p.i, p.j, p.k v = p.v - orig = dr.einst(alpha ** 2 * x[i] * v[i]) + orig = dr.einst(alpha**2 * x[i] * v[i]) alpha_def = dr.einst(alpha * beta[i, i]) assert alpha_def.n_terms == 1 assert len(alpha_def.local_terms[0].sums) == 1 @@ -891,27 +882,27 @@ def test_tensors_can_substitute_symbols_simultaneously( dr.full_simplify = True expected = dr.einst( - alpha ** 2 * beta[i, i] * beta[j, j] * x[k] * v[k] + alpha**2 * beta[i, i] * beta[j, j] * x[k] * v[k] ).simplify() assert res == expected -@pytest.mark.parametrize('full_balance', [True, False]) -@pytest.mark.parametrize('full_simplify', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) +@pytest.mark.parametrize("full_simplify", [True, False]) def test_tensors_can_substitute_strings_of_vectors( - free_alg, full_balance, full_simplify + free_alg, full_balance, full_simplify ): """Test vector substitution facility for strings of tensors.""" dr = free_alg p = dr.names - x = IndexedBase('x') - t = IndexedBase('t') - u = IndexedBase('u') + x = IndexedBase("x") + t = IndexedBase("t") + u = IndexedBase("u") i, j = p.i, p.j v = p.v - w = Vec('w') + w = Vec("w") orig = dr.sum((i, p.R), x[i] * v[i] * v[i]) vivi_def = dr.einst(t[i, j] * w[j] + u[i, j] * w[j]) @@ -934,32 +925,27 @@ def test_tensors_can_substitute_strings_of_vectors( assert res == orig -@pytest.mark.parametrize('full_balance', [True, False]) -@pytest.mark.parametrize('simplify', [True, False]) -def test_batch_vector_substitutions( - free_alg, full_balance, simplify -): - """Test the batch substitutions using the subst_all method - """ +@pytest.mark.parametrize("full_balance", [True, False]) +@pytest.mark.parametrize("simplify", [True, False]) +def test_batch_vector_substitutions(free_alg, full_balance, simplify): + """Test the batch substitutions using the subst_all method""" dr = free_alg p = dr.names - a = IndexedBase('a') - x = IndexedBase('x') - y = IndexedBase('y') + a = IndexedBase("a") + x = IndexedBase("x") + y = IndexedBase("y") i, j = p.i, p.j v = p.v - v_dag = Vec('v', indices=(CR,)) + v_dag = Vec("v", indices=(CR,)) # # Spin flipping # orig1 = dr.sum((i, p.R), (j, p.R), a[i, j] * v[i, UP] * v[j, DOWN]) - defs1 = [ - dr.define(v[i, UP], v[i, DOWN]), dr.define(v[i, DOWN], v[i, UP]) - ] + defs1 = [dr.define(v[i, UP], v[i, DOWN]), dr.define(v[i, DOWN], v[i, UP])] # Sequentially apply the definitions of the substitutions expected_sequential = dr.sum( @@ -984,8 +970,8 @@ def test_batch_vector_substitutions( # orig2 = dr.einst( - a[i, j] * v_dag[i, UP] * v[j, UP] + - a[i, j] * v_dag[i, DOWN] * v[j, DOWN] + a[i, j] * v_dag[i, UP] * v[j, UP] + + a[i, j] * v_dag[i, DOWN] * v[j, DOWN] ) defs2 = [ dr.define(v_dag[i, UP], x[i] * v_dag[i, UP] - y[i] * v[i, DOWN]), @@ -1006,12 +992,15 @@ def test_batch_vector_substitutions( # Simultaneously apply the definitions of the substitutions expected_simultaneous = dr.sum( - (i, p.R), (j, p.R), a[i, j] * ( + (i, p.R), + (j, p.R), + a[i, j] + * ( (x[i] * v_dag[i, UP] - y[i] * v[i, DOWN]) * (x[j] * v[j, UP] - y[j] * v_dag[j, DOWN]) + (x[i] * v_dag[i, DOWN] + y[i] * v[i, UP]) * (x[j] * v[j, DOWN] + y[j] * v_dag[j, UP]) - ) + ), ).simplify() res = orig2.subst_all( defs2, simult_all=True, full_balance=full_balance, simplify=simplify @@ -1019,25 +1008,21 @@ def test_batch_vector_substitutions( assert res == expected_simultaneous -@pytest.mark.parametrize('full_balance', [True, False]) +@pytest.mark.parametrize("full_balance", [True, False]) def test_batch_amp_substitutions(free_alg, full_balance): - """Test the batch amplitude substitutions using the subst_all method - """ + """Test the batch amplitude substitutions using the subst_all method""" dr = free_alg p = dr.names - a = IndexedBase('a') - b = Symbol('b') + a = IndexedBase("a") + b = Symbol("b") i = p.i r = p.R v = p.v orig = dr.einst(b * a[i] * v[i]) - defs = [ - dr.define(a[i], a[i] + b), - dr.define(b, sin(b)) - ] + defs = [dr.define(a[i], a[i] + b), dr.define(b, sin(b))] # Sequentially apply the definitions of the substitutions expected_sequential = dr.sum( @@ -1059,27 +1044,30 @@ def test_batch_amp_substitutions(free_alg, full_balance): def test_special_substitution_of_identity(free_alg): - """Test the special substitution of integer one standing for identity. - """ + """Test the special substitution of integer one standing for identity.""" dr = free_alg p = dr.names - x = IndexedBase('x') - t = IndexedBase('y') - a = IndexedBase('a') + x = IndexedBase("x") + t = IndexedBase("y") + a = IndexedBase("a") i, j = p.i, p.j v = p.v - w = Vec('w') + w = Vec("w") orig = dr.sum((i, p.R), x[i] * v[i] + a[i]) ident_def = dr.define(1, dr.einst(t[i] * w[i])) res = orig.subst_all([ident_def]) - assert dr.simplify( - res - dr.einst(x[i] * v[i]) - - dr.sum((i, p.R), (j, p.R), a[i] * t[j] * w[j]) - ) == 0 + assert ( + dr.simplify( + res + - dr.einst(x[i] * v[i]) + - dr.sum((i, p.R), (j, p.R), a[i] * t[j] * w[j]) + ) + == 0 + ) def test_tensors_can_be_rewritten(free_alg): @@ -1087,21 +1075,23 @@ def test_tensors_can_be_rewritten(free_alg): dr = free_alg p = dr.names - v = Vec('v') + v = Vec("v") a, b = p.R_dumms[:2] - x = IndexedBase('x') - o = IndexedBase('o') - y = IndexedBase('y') - z = IndexedBase('z') + x = IndexedBase("x") + o = IndexedBase("o") + y = IndexedBase("y") + z = IndexedBase("z") tensor = dr.einst( - x[a] * v[a] + o[a, b] * y[b] * v[a] + z[b] * v[b] # Terms to rewrite. + x[a] * v[a] + + o[a, b] * y[b] * v[a] + + z[b] * v[b] # Terms to rewrite. + z[a, b] * v[a] * v[b] # Terms to keep. ) - w = Wild('w') - r = IndexedBase('r') + w = Wild("w") + r = IndexedBase("r") rewritten, defs = tensor.rewrite(v[w], r[w]) assert rewritten == dr.einst( @@ -1116,11 +1106,13 @@ def test_tensors_can_be_rewritten(free_alg): class x(Function): """Get the x-component symbolically.""" + pass class y(Function): """Get the y-component symbolically.""" + pass @@ -1134,40 +1126,48 @@ def test_sums_can_be_expanded(spark_ctx): dr = Drudge(spark_ctx) - comp = Range('P') - r1, r2 = symbols('r1, r2') + comp = Range("P") + r1, r2 = symbols("r1, r2") dr.set_dumms(comp, [r1, r2]) - a = IndexedBase('a') - v = Vec('v') + a = IndexedBase("a") + v = Vec("v") # A simple thing written in terms of composite indices. orig = dr.sum((r1, comp), (r2, comp), a[r1] * a[r2] * v[r1] * v[r2]) # Rewrite the expression in terms of components. Here, r1 should be # construed as a simple Wild. - rewritten = orig.subst_all([ - (a[r1], a[x(r1), y(r1)]), - (v[r1], v[x(r1), y(r1)]) - ]) + rewritten = orig.subst_all( + [(a[r1], a[x(r1), y(r1)]), (v[r1], v[x(r1), y(r1)])] + ) # Expand the summation over r. - x_dim = Range('X') - y_dim = Range('Y') - x1, x2 = symbols('x1 x2') + x_dim = Range("X") + y_dim = Range("Y") + x1, x2 = symbols("x1 x2") dr.set_dumms(x_dim, [x1, x2]) - y1, y2 = symbols('y1 y2') + y1, y2 = symbols("y1 y2") dr.set_dumms(y_dim, [y1, y2]) - res = rewritten.expand_sums(comp, lambda r: [ - (Symbol(str(r).replace('r', 'x')), x_dim, x(r)), - (Symbol(str(r).replace('r', 'y')), y_dim, y(r)) - ]) + res = rewritten.expand_sums( + comp, + lambda r: [ + (Symbol(str(r).replace("r", "x")), x_dim, x(r)), + (Symbol(str(r).replace("r", "y")), y_dim, y(r)), + ], + ) - assert (res - dr.sum( - (x1, x_dim), (y1, y_dim), (x2, x_dim), (y2, y_dim), - a[x1, y1] * a[x2, y2] * v[x1, y1] * v[x2, y2] - )).simplify() == 0 + assert ( + res + - dr.sum( + (x1, x_dim), + (y1, y_dim), + (x2, x_dim), + (y2, y_dim), + a[x1, y1] * a[x2, y2] * v[x1, y1] * v[x2, y2], + ) + ).simplify() == 0 def test_advanced_manipulations(free_alg): @@ -1176,9 +1176,9 @@ def test_advanced_manipulations(free_alg): p = dr.names i, j, k = p.i, p.j, p.k - u = IndexedBase('u') - v = IndexedBase('v') - f = Vec('f') + u = IndexedBase("u") + v = IndexedBase("v") + f = Vec("f") tensor = dr.einst(u[i, j] * f[j] + v[i, j] * f[j]) assert tensor.n_terms == 2 @@ -1190,7 +1190,7 @@ def has_u(term): expect = dr.sum((j, p.R), u[i, j] * f[j]) for res in [ tensor.filter(has_u), - tensor.bind(lambda x: [x] if has_u(x) else []) + tensor.bind(lambda x: [x] if has_u(x) else []), ]: assert res.n_terms == 1 assert res == expect @@ -1203,19 +1203,19 @@ def subst_i(term): for res in [ tensor.map(subst_i), tensor.bind(lambda x: [subst_i(x)]), - tensor.map2scalars(lambda x: x.xreplace({i: k})) + tensor.map2scalars(lambda x: x.xreplace({i: k})), ]: assert res.n_terms == 2 assert res == expect - alpha, beta = symbols('alpha beta') + alpha, beta = symbols("alpha beta") assert tensor.bind( lambda x: [Term(x.sums, x.amp * i_, x.vecs) for i_ in [alpha, beta]] ) == (tensor * alpha + tensor * beta) - assert tensor.map2scalars( - lambda x: x.xreplace({j: k}) - ) == dr.sum((j, p.R), u[i, k] * f[k] + v[i, k] * f[k]) + assert tensor.map2scalars(lambda x: x.xreplace({j: k})) == dr.sum( + (j, p.R), u[i, k] * f[k] + v[i, k] * f[k] + ) assert tensor.map2scalars( lambda x: x.xreplace({j: k}), skip_vecs=True @@ -1236,7 +1236,7 @@ def test_creating_empty_tensor_def(free_alg): """Test the creation of empty tensor definition.""" dr = free_alg - def_ = TensorDef(symbols('a'), (), dr.create_tensor([])) + def_ = TensorDef(symbols("a"), (), dr.create_tensor([])) assert def_.rhs == 0 @@ -1251,9 +1251,9 @@ def test_tensor_def_creation_and_basic_properties(free_alg): p = dr.names i, j, k = p.R_dumms[:3] - x = IndexedBase('x') - o = IndexedBase('o') - y = IndexedBase('y') + x = IndexedBase("x") + o = IndexedBase("o") + y = IndexedBase("y") rhs = o[i, j] * x[j] @@ -1265,8 +1265,8 @@ def test_tensor_def_creation_and_basic_properties(free_alg): assert y_def.base == y assert y_def.exts == [(i, p.R)] - assert str(y_def) == 'y[i] = sum_{j} o[i, j]*x[j]' - assert y_def.latex().strip() == r'y_{i} = \sum_{j \in R} x_{j} o_{i,j}' + assert str(y_def) == "y[i] = sum_{j} o[i, j]*x[j]" + assert y_def.latex().strip() == r"y_{i} = \sum_{j \in R} x_{j} o_{i,j}" y_def1 = dr.define(y[i], dr.sum((j, p.R), rhs)) y_def2 = dr.define_einst(y[i], rhs) @@ -1289,8 +1289,8 @@ def test_tensor_def_creation_and_basic_properties(free_alg): assert p._y == y assert p.y == y_def4 dr.unset_name(y_def4) - assert not hasattr(p, '_y') - assert not hasattr(p, 'y') + assert not hasattr(p, "_y") + assert not hasattr(p, "y") # This tests the `act` method as well. assert y_def[1].simplify() == dr.einst(o[1, j] * x[j]).simplify() @@ -1306,9 +1306,9 @@ def test_einstein_convention(free_alg): dr = free_alg p = dr.names - o = IndexedBase('o') - v = IndexedBase('v') - w = IndexedBase('w') + o = IndexedBase("o") + v = IndexedBase("v") + w = IndexedBase("w") i, j, k = p.R_dumms[:3] raw_amp_1 = o[i, k] * v[k, j] @@ -1330,30 +1330,30 @@ def test_einstein_convention(free_alg): continue # Test the automatic definition formation. - tensor_def = dr.define_einst('r', raw_amp, auto_exts=True) + tensor_def = dr.define_einst("r", raw_amp, auto_exts=True) assert len(tensor_def.exts) == 2 assert tensor_def.exts[0] == (i, p.R) assert tensor_def.exts[1] == (j, p.R) - assert tensor_def.base == IndexedBase('r') + assert tensor_def.base == IndexedBase("r") assert tensor_def.rhs == dr.einst(raw_amp) def test_tensor_def_simplification(free_alg): - """Test basic tensor definition simplification and dummy manipulation. - """ + """Test basic tensor definition simplification and dummy manipulation.""" dr = free_alg p = dr.names i, j = p.R_dumms[:2] - x = IndexedBase('x') - o = IndexedBase('o') - y = IndexedBase('y') + x = IndexedBase("x") + o = IndexedBase("o") + y = IndexedBase("y") y_def = dr.define( - y, (j, p.R), - dr.sum((i, p.R), o[j, i] * x[i]) - dr.einst(o[j, i] * x[i]) + y, + (j, p.R), + dr.sum((i, p.R), o[j, i] * x[i]) - dr.einst(o[j, i] * x[i]), ) reset = y_def.reset_dumms() @@ -1374,79 +1374,83 @@ def test_tensors_has_string_and_latex_form(free_alg, tmpdir): v = p.v i = p.i - x = IndexedBase('x') + x = IndexedBase("x") tensor = dr.einst(x[i] * v[i] - x[i] * v[i]) zero = tensor.simplify() # The basic string form. orig = str(tensor) - assert orig == 'sum_{i} x[i] * v[i]\n + sum_{i} -x[i] * v[i]' - assert str(zero) == '0' + assert orig == "sum_{i} x[i] * v[i]\n + sum_{i} -x[i] * v[i]" + assert str(zero) == "0" # The LaTeX form. expected_terms = [ - r'\sum_{i \in R} x_{i} \mathbf{v}_{i}', - r'- \sum_{i \in R} x_{i} \mathbf{v}_{i}' + r"\sum_{i \in R} x_{i} \mathbf{v}_{i}", + r"- \sum_{i \in R} x_{i} \mathbf{v}_{i}", ] - expected = ' '.join(expected_terms) + expected = " ".join(expected_terms) assert tensor.latex() == expected assert tensor.latex(sep_lines=True) != expected - assert tensor.latex(sep_lines=True).replace(r'\\ ', '') == expected + assert tensor.latex(sep_lines=True).replace(r"\\ ", "") == expected assert tensor.latex(align_terms=True) != expected - assert tensor.latex(align_terms=True).replace(' & ', '') == expected + assert tensor.latex(align_terms=True).replace(" & ", "") == expected def proc(form, term, idx): """Process the terms in the LaTeX formatting.""" assert term == tensor.local_terms[idx] assert form == expected_terms[idx] - return 'N' + return "N" - assert tensor.latex(proc=proc).replace(' ', '') == 'N + N'.replace(' ', '') + assert tensor.latex(proc=proc).replace(" ", "") == "N + N".replace(" ", "") # Test the reporting facility. with tmpdir.as_cwd(): - title = 'Simple report test' - sect = 'A simple tensor' - descr = 'Nothing' + title = "Simple report test" + sect = "A simple tensor" + descr = "Nothing" - filename = 'freealg.html' + filename = "freealg.html" with dr.report(filename, title) as rep: rep.add(sect, tensor, description=descr) # Here we just simply test the existence of the file. assert os.path.isfile(filename) - filename = 'freealg.pdf' - with dr.report(filename, 'Simple report test') as rep: + filename = "freealg.pdf" + with dr.report(filename, "Simple report test") as rep: rep.add( - sect, tensor, description=descr, env='dmath', sep_lines=False + sect, tensor, description=descr, env="dmath", sep_lines=False ) rep.add( - sect, tensor, description=descr, env='dmath', - no_sum=True, scalar_mul=r'\invismult' + sect, + tensor, + description=descr, + env="dmath", + no_sum=True, + scalar_mul=r"\invismult", ) - assert os.path.isfile('freealg.tex') - if shutil.which('pdflatex') is not None: + assert os.path.isfile("freealg.tex") + if shutil.which("pdflatex") is not None: assert os.path.isfile(filename) # Test the printing of pure zero. - assert zero.latex() == '0' - assert zero.latex(sep_lines=True) == '0' + assert zero.latex() == "0" + assert zero.latex(sep_lines=True) == "0" # Test printing of very special tensors with terms being pure plus/minus # unity. special = dr.sum(1) + dr.sum(-1) assert special.n_terms == 2 res = special.latex() - assert res.replace(' ', '') == '1-1' + assert res.replace(" ", "") == "1-1" # Testing printing of vectors without subscripts. special = dr.sum(2 * v) res = special.latex() - assert res.replace(' ', '') == r'2 \mathbf{v}'.replace(' ', '') + assert res.replace(" ", "") == r"2 \mathbf{v}".replace(" ", "") def test_drudge_has_default_properties(free_alg): @@ -1463,15 +1467,12 @@ def test_tensor_can_be_added_summation(free_alg): dr = free_alg p = dr.names i, j = p.R_dumms[:2] - x = IndexedBase('x') - y = IndexedBase('y') + x = IndexedBase("x") + y = IndexedBase("y") tensor = dr.sum((i, p.R), x[i, j] * y[j, i]) - for res in [ - dr.einst(tensor), - dr.sum((j, p.R), tensor) - ]: + for res in [dr.einst(tensor), dr.sum((j, p.R), tensor)]: assert res == dr.einst(x[i, j] * y[j, i]) @@ -1480,9 +1481,9 @@ def test_pickling_tensors(free_alg): dr = free_alg p = dr.names - x = IndexedBase('x') - v = Vec('v') - b = Vec('b') + x = IndexedBase("x") + v = Vec("v") + b = Vec("b") tensor = dr.einst(x[p.i] * v[p.i]) def_ = dr.define(b, tensor) @@ -1503,7 +1504,7 @@ def test_memoise(free_alg, tmpdir): dr = free_alg n_calls = [0] - filename = 'tmp.pickle' + filename = "tmp.pickle" log = io.StringIO() def get_zero(): @@ -1532,18 +1533,18 @@ def test_simple_drs(free_alg): p = dr.names env = dr.exec_drs(TEST_SIMPLE_DRS) - x = Vec('x') + x = Vec("x") i = p.i def_ = dr.define_einst(x[i], Rational(1, 2) * p.m[i] * p.v[i]) - assert env['x'] == def_ - assert env['_x'] == x - assert env['y'] == 45 - assert env['n'] == 1 + assert env["x"] == def_ + assert env["_x"] == x + assert env["y"] == 45 + assert env["n"] == 1 dr.unset_name(def_) # Test some drudge script specials about the free algebra environment. - assert env['DRUDGE'] is dr - assert env['sum_'] is sum + assert env["DRUDGE"] is dr + assert env["sum_"] is sum TEST_PICKLE_DRS = """ @@ -1567,9 +1568,9 @@ def test_pickle_within_drs(free_alg): dr = free_alg env = dr.exec_drs(TEST_PICKLE_DRS) - assert env['good_symb'] - assert env['good_indexed'] - assert env['def_'] == env['def_back'] + assert env["good_symb"] + assert env["good_indexed"] + assert env["def_"] == env["def_back"] def test_inverse_of_linear_vector_transforms(free_alg: Drudge): @@ -1583,13 +1584,10 @@ def test_inverse_of_linear_vector_transforms(free_alg: Drudge): p = dr.names v = p.v - a = Vec('a') - b = Vec('b') + a = Vec("a") + b = Vec("b") - defs = [ - dr.define(a, v + 1), - dr.define(b, v - 1) - ] + defs = [dr.define(a, v + 1), dr.define(b, v - 1)] res = dr.lvt_inv(defs) assert len(res) == 2 diff --git a/tests/genmb_test.py b/tests/genmb_test.py index 37226197..5c46f01f 100644 --- a/tests/genmb_test.py +++ b/tests/genmb_test.py @@ -10,7 +10,7 @@ from drudge import GenMBDrudge, CR, AN, Range -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def genmb(spark_ctx): """Initialize the environment for a free algebra.""" @@ -25,8 +25,8 @@ def test_genmb_has_basic_properties(genmb): assert len(dr.orb_ranges) == 1 assert dr.spin_vals is None - assert dr.one_body == dr.names.t == IndexedBase('t') - assert dr.two_body == dr.names.u == IndexedBase('u') + assert dr.one_body == dr.names.t == IndexedBase("t") + assert dr.two_body == dr.names.u == IndexedBase("u") # The Hamiltonian should already be simplified for this simple model. assert dr.ham.n_terms == 2 @@ -40,8 +40,8 @@ def test_einstein_summation(genmb): p = dr.names l = p.L a, b, c = p.L_dumms[:3] - o = IndexedBase('o') - v = IndexedBase('v') + o = IndexedBase("o") + v = IndexedBase("v") c_dag = p.c_dag summand = o[a, b] * v[b] * c_dag[a] @@ -53,11 +53,11 @@ def test_einstein_summation(genmb): assert tensor == dr.sum((a, l), (b, l), summand) -@pytest.mark.parametrize('par_level', [0, 1, 2]) -@pytest.mark.parametrize('full_simplify', [True, False]) -@pytest.mark.parametrize('simple_merge', [True, False]) +@pytest.mark.parametrize("par_level", [0, 1, 2]) +@pytest.mark.parametrize("full_simplify", [True, False]) +@pytest.mark.parametrize("simple_merge", [True, False]) def test_genmb_simplify_simple_expressions( - genmb, par_level, full_simplify, simple_merge + genmb, par_level, full_simplify, simple_merge ): """Test the basic Wick expansion facility on a single Fermion expression.""" @@ -68,12 +68,15 @@ def test_genmb_simplify_simple_expressions( r = dr.names.L a, b, c, d = dr.names.L_dumms[:4] - t = IndexedBase('t') - u = IndexedBase('u') + t = IndexedBase("t") + u = IndexedBase("u") inp = dr.sum( - (a, r), (b, r), (c, r), (d, r), - t[a, b] * u[c, d] * c_dag[a] * c_[b] * c_dag[c] * c_[d] + (a, r), + (b, r), + (c, r), + (d, r), + t[a, b] * u[c, d] * c_dag[a] * c_[b] * c_dag[c] * c_[d], ) dr.wick_parallel = par_level @@ -95,8 +98,8 @@ def test_genmb_simplify_simple_expressions( assert res.n_terms == 2 expected = dr.einst( - t[a, c] * u[b, d] * c_dag[a] * c_dag[b] * c_[d] * c_[c] + - t[a, c] * u[c, b] * c_dag[a] * c_[b] + t[a, c] * u[b, d] * c_dag[a] * c_dag[b] * c_[d] * c_[c] + + t[a, c] * u[c, b] * c_dag[a] * c_[b] ).simplify() assert res == expected @@ -117,8 +120,7 @@ def test_genmb_simplifies_nilpotent_operators(genmb): def test_genmb_gives_conventional_dummies(genmb): - """Test dummy placement in canonicalization facility on many-body drudge. - """ + """Test dummy placement in canonicalization facility on many-body drudge.""" dr = genmb p = dr.names @@ -126,15 +128,14 @@ def test_genmb_gives_conventional_dummies(genmb): c_ = p.c_ a, b, c, d = p.a, p.b, p.c, p.d - x = IndexedBase('x') + x = IndexedBase("x") tensor = dr.einst(x[a, b, c, d] * c_dag[a] * c_dag[b] * c_[d] * c_[c]) res = tensor.simplify() assert res == tensor def test_genmb_derives_spin_orbit_hartree_fock(genmb): - """Test general many-body model can derive HF theory in spin-orbital basis. - """ + """Test general many-body model can derive HF theory in spin-orbital basis.""" dr = genmb p = genmb.names @@ -147,24 +148,31 @@ def test_genmb_derives_spin_orbit_hartree_fock(genmb): comm = (dr.ham | rot).simplify() assert comm.n_terms == 4 - rho = IndexedBase('rho') + rho = IndexedBase("rho") # Following Ring and Schuck, here all creation comes before the # annihilation. - res = comm.eval_vev(lambda op1, op2, _: ( - rho[op2.indices[1], op1.indices[1]] - if op1.indices[0] == CR and op2.indices[0] == AN - else 0 - )).simplify() + res = comm.eval_vev( + lambda op1, op2, _: ( + rho[op2.indices[1], op1.indices[1]] + if op1.indices[0] == CR and op2.indices[0] == AN + else 0 + ) + ).simplify() assert res.n_terms == 6 # The correct result: [\rho, f]^b_a - f = IndexedBase('f') + f = IndexedBase("f") expected = dr.sum((c, r), rho[b, c] * f[c, a] - f[b, c] * rho[c, a]) - expected = expected.subst(f[a, b], p.t[a, b] + dr.sum( - (c, r), (d, r), - p.u[a, c, b, d] * rho[d, c] - p.u[a, c, d, b] * rho[d, c] - )) + expected = expected.subst( + f[a, b], + p.t[a, b] + + dr.sum( + (c, r), + (d, r), + p.u[a, c, b, d] * rho[d, c] - p.u[a, c, d, b] * rho[d, c], + ), + ) expected = expected.simplify() assert res == expected @@ -180,12 +188,12 @@ def test_fock_drudge_prints_operators(genmb): dr = genmb p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") a, b = p.L_dumms[:2] - tensor = dr.einst(- x[a, b] * p.c_dag[a] * p.c_[b]) + tensor = dr.einst(-x[a, b] * p.c_dag[a] * p.c_[b]) assert tensor.latex() == ( - r'- \sum_{a \in L} \sum_{b \in L} x_{a,b} c^{\dagger}_{a} c^{}_{b}' + r"- \sum_{a \in L} \sum_{b \in L} x_{a,b} c^{\dagger}_{a} c^{}_{b}" ) @@ -194,7 +202,7 @@ def test_dagger_of_field_operators(genmb): dr = genmb p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") c_dag = p.c_dag c_ = p.c_ a, b = p.L_dumms[:2] @@ -215,18 +223,19 @@ def test_diag_tight_binding_hamiltonian(spark_ctx): summations. """ - n = Symbol('N', integer=True) - dr = GenMBDrudge(spark_ctx, orb=( - (Range('L', 0, n), symbols('x y z x1 x2', integer=True)), - )) + n = Symbol("N", integer=True) + dr = GenMBDrudge( + spark_ctx, + orb=((Range("L", 0, n), symbols("x y z x1 x2", integer=True)),), + ) # The reciprocal space range and dummies. - k, q = symbols('k q', integer=True) - dr.set_dumms(Range('R', 0, n), [k, q]) + k, q = symbols("k q", integer=True) + dr.set_dumms(Range("R", 0, n), [k, q]) p = dr.names - h = Symbol('h') # Hopping neighbours. - delta = Symbol('Delta') + h = Symbol("h") # Hopping neighbours. + delta = Symbol("Delta") c_dag = p.c_dag c_ = p.c_ a = p.L_dumms[0] @@ -238,12 +247,16 @@ def test_diag_tight_binding_hamiltonian(spark_ctx): assert real_ham.n_terms == 2 # Unitary fourier transform. - cr_def = (c_dag[a], dr.sum( - (k, p.R), (1 / sqrt(n)) * exp(-I * 2 * pi * k * a / n) * c_dag[k] - )) - an_def = (c_[a], dr.sum( - (k, p.R), (1 / sqrt(n)) * exp(I * 2 * pi * k * a / n) * c_[k] - )) + cr_def = ( + c_dag[a], + dr.sum( + (k, p.R), (1 / sqrt(n)) * exp(-I * 2 * pi * k * a / n) * c_dag[k] + ), + ) + an_def = ( + c_[a], + dr.sum((k, p.R), (1 / sqrt(n)) * exp(I * 2 * pi * k * a / n) * c_[k]), + ) rec_ham = real_ham.subst_all([cr_def, an_def]) res = rec_ham.simplify() diff --git a/tests/genquad_test.py b/tests/genquad_test.py index 2d21fe92..c8a5199b 100644 --- a/tests/genquad_test.py +++ b/tests/genquad_test.py @@ -10,11 +10,12 @@ def test_assume_comm(spark_ctx): is not specified. """ - v1 = Vec(r'v_1') - v2 = Vec(r'v_2') + v1 = Vec(r"v_1") + v2 = Vec(r"v_2") - dr = GenQuadLatticeDrudge(spark_ctx, order=(v1, v2), comms={}, - assume_comm=True) + dr = GenQuadLatticeDrudge( + spark_ctx, order=(v1, v2), comms={}, assume_comm=True + ) tensor = dr.sum(v1 | v2) assert tensor.simplify() == Integer(0) diff --git a/tests/name_injection_test.py b/tests/name_injection_test.py index 06df9721..677b7c3c 100644 --- a/tests/name_injection_test.py +++ b/tests/name_injection_test.py @@ -11,11 +11,11 @@ def test_drudge_injects_names(): # Dummy drudge. dr = Drudge(types.SimpleNamespace(defaultParallelism=1)) - string_name = 'string_name' + string_name = "string_name" dr.set_name(string_name) dr.set_name(one=1) - dr.inject_names(suffix='_') + dr.inject_names(suffix="_") - assert string_name_ == string_name # noqa: F821 - assert one_ == 1 # noqa: F821 + assert string_name_ == string_name # noqa: F821 + assert one_ == 1 # noqa: F821 diff --git a/tests/nuclear_test.py b/tests/nuclear_test.py index 6c887346..67a7440b 100644 --- a/tests/nuclear_test.py +++ b/tests/nuclear_test.py @@ -6,13 +6,12 @@ from sympy import Symbol, symbols, KroneckerDelta, sqrt, IndexedBase from drudge import NuclearBogoliubovDrudge, Range, Term -from drudge.nuclear import ( - JOf, MOf, CG, Wigner6j, Wigner3j, _simpl_pono_term -) +from drudge.nuclear import JOf, MOf, CG, Wigner6j, Wigner3j, _simpl_pono_term from conftest import skip_in_spark -@pytest.fixture(scope='module') + +@pytest.fixture(scope="module") def nuclear(spark_ctx): """Set up the drudge to test.""" return NuclearBogoliubovDrudge(spark_ctx) @@ -22,16 +21,14 @@ def nuclear(spark_ctx): # Test of the core power of negative one simplification. # + def test_jm_acc_as_half_integer(): - """Test j/m access of single-particle k to be half integers. - """ + """Test j/m access of single-particle k to be half integers.""" - k = Symbol('k') + k = Symbol("k") for acc in [JOf, MOf]: e = acc(k) - term = Term( - (), (-1) ** (e * 2), () - ) + term = Term((), (-1) ** (e * 2), ()) res = _simpl_pono_term(term, []) assert len(res.sums) == 0 @@ -40,19 +37,20 @@ def test_jm_acc_as_half_integer(): def test_coll_jm_integer(nuclear: NuclearBogoliubovDrudge): - """Test integrity of collective angular momentum symbols. - """ + """Test integrity of collective angular momentum symbols.""" p = nuclear.names - k = Symbol('k') + k = Symbol("k") wigner = Wigner3j(p.J1, p.M1, p.J2, p.M2, JOf(k), p.m1) for factor, phase in [ - (p.M1, 1), (p.M2, 1), (p.J1, 1), (p.J2, 1), - (JOf(k), -1), (p.m1, -1) + (p.M1, 1), + (p.M2, 1), + (p.J1, 1), + (p.J2, 1), + (JOf(k), -1), + (p.m1, -1), ]: - term = Term( - (), (-1) ** (factor * 2) * wigner, () - ) + term = Term((), (-1) ** (factor * 2) * wigner, ()) res = _simpl_pono_term(term, nuclear.resolvers.value) assert len(res.sums) == 0 @@ -61,17 +59,16 @@ def test_coll_jm_integer(nuclear: NuclearBogoliubovDrudge): def test_wigner_3j_m_rels_simpl(): - """Test simplification based on m-sum rules of Wigner 3j symbols. - """ - j = Symbol('j') - a, b, c, d, e = symbols('a b c d e') + """Test simplification based on m-sum rules of Wigner 3j symbols.""" + j = Symbol("j") + a, b, c, d, e = symbols("a b c d e") wigner_3js = Wigner3j(j, a, j, b, j, c) * Wigner3j(j, c, j, d, j, e) for amp in [ (-1) ** (a + b + c), (-1) ** (c + d + e), (-1) ** (a + b + 2 * c + d + e), - (-1) ** (a + b - d - e) + (-1) ** (a + b - d - e), ]: term = Term((), wigner_3js * amp, ()) res = _simpl_pono_term(term, []) @@ -83,13 +80,11 @@ def test_wigner_3j_m_rels_simpl(): def test_varsh_872_4(nuclear: NuclearBogoliubovDrudge): """Test simplification based on Varshalovich 8.7.2 Eq (4).""" dr = nuclear - c, gamma, c_prm, gamma_prm = symbols('c gamma cprm gammaprm', integer=True) - a, alpha, b, beta = symbols('a alpha b beta', integer=True) + c, gamma, c_prm, gamma_prm = symbols("c gamma cprm gammaprm", integer=True) + a, alpha, b, beta = symbols("a alpha b beta", integer=True) - m_range = Range('m') - sums = [ - (alpha, m_range[-a, a + 1]), (beta, m_range[-b, b + 1]) - ] + m_range = Range("m") + sums = [(alpha, m_range[-a, a + 1]), (beta, m_range[-b, b + 1])] amp = CG(a, alpha, b, beta, c, gamma) * CG( a, alpha, b, beta, c_prm, gamma_prm ) @@ -102,9 +97,9 @@ def test_varsh_872_4(nuclear: NuclearBogoliubovDrudge): assert res.n_terms == 1 term = res.local_terms[0] assert len(term.sums) == 0 - assert term.amp == KroneckerDelta( - c, c_prm - ) * KroneckerDelta(gamma, gamma_prm) + assert term.amp == KroneckerDelta(c, c_prm) * KroneckerDelta( + gamma, gamma_prm + ) @skip_in_spark(reason="Maybe assumptions are not serialized with symbols") @@ -116,20 +111,19 @@ def test_varsh_872_5(nuclear: NuclearBogoliubovDrudge): dr = nuclear a, alpha, b, beta, b_prm, beta_prm = symbols( - 'a alpha b beta bprm betaprm', integer=True + "a alpha b beta bprm betaprm", integer=True ) - c, gamma = symbols('c gamma', integer=True) - sums = [ - (alpha, Range('m', -a, a + 1)), - (gamma, Range('M', -c, c + 1)) - ] + c, gamma = symbols("c gamma", integer=True) + sums = [(alpha, Range("m", -a, a + 1)), (gamma, Range("M", -c, c + 1))] amp = CG(a, alpha, b, beta, c, gamma) * CG( a, alpha, b_prm, beta_prm, c, gamma ) expected = ( - KroneckerDelta(b, b_prm) * KroneckerDelta(beta, beta_prm) - * (2 * c + 1) / (2 * b + 1) + KroneckerDelta(b, b_prm) + * KroneckerDelta(beta, beta_prm) + * (2 * c + 1) + / (2 * b + 1) ) for sums_i in [sums, reversed(sums)]: tensor = dr.sum(*sums_i, amp) @@ -141,27 +135,32 @@ def test_varsh_872_5(nuclear: NuclearBogoliubovDrudge): assert (term.amp - expected).simplify() == 0 -@pytest.mark.skip(reason='Pending improvement in PONO simplification') +@pytest.mark.skip(reason="Pending improvement in PONO simplification") def test_varsh_911_8(nuclear: NuclearBogoliubovDrudge): - """Test simplification based on the rule in Varshalovich 9.1.1 Eq (8). - """ + """Test simplification based on the rule in Varshalovich 9.1.1 Eq (8).""" dr = nuclear j, m, j12, m12, j2, m2, j1, m1, j_prm, m_prm, j23, m23, j3, m3 = symbols( - 'j m j12 m12 j2 m2 j1 m1 jprm mprm j23 m23 j3 m3', integer=True + "j m j12 m12 j2 m2 j1 m1 jprm mprm j23 m23 j3 m3", integer=True + ) + m_range = Range("m") + sums = [ + (m_i, m_range[-j_i, j_i + 1]) + for m_i, j_i in [(m1, j1), (m2, j2), (m3, j3), (m12, j12), (m23, j23)] + ] + amp = ( + CG(j12, m12, j3, m3, j, m) + * CG(j1, m1, j2, m2, j12, m12) + * CG(j1, m1, j23, m23, j_prm, m_prm) + * CG(j2, m2, j3, m3, j23, m23) ) - m_range = Range('m') - sums = [(m_i, m_range[-j_i, j_i + 1]) for m_i, j_i in [ - (m1, j1), (m2, j2), (m3, j3), (m12, j12), (m23, j23) - ]] - amp = CG(j12, m12, j3, m3, j, m) * CG(j1, m1, j2, m2, j12, m12) * CG( - j1, m1, j23, m23, j_prm, m_prm - ) * CG(j2, m2, j3, m3, j23, m23) expected = ( - KroneckerDelta(j, j_prm) * KroneckerDelta(m, m_prm) - * (-1) ** (j1 + j2 + j3 + j) - * sqrt(2 * j12 + 1) * sqrt(2 * j23 + 1) - * Wigner6j(j1, j2, j12, j3, j, j23) + KroneckerDelta(j, j_prm) + * KroneckerDelta(m, m_prm) + * (-1) ** (j1 + j2 + j3 + j) + * sqrt(2 * j12 + 1) + * sqrt(2 * j23 + 1) + * Wigner6j(j1, j2, j12, j3, j, j23) ) # For performance reason, just test a random arrangement of the summations. @@ -184,32 +183,36 @@ def test_wigner3j_sum_to_wigner6j(nuclear: NuclearBogoliubovDrudge): dr = nuclear j1, j2, j3, jprm3, j4, j5, j6 = symbols( - 'j1 j2 j3 jprm3 j4 j5 j6', integer=True + "j1 j2 j3 jprm3 j4 j5 j6", integer=True ) m1, m2, m3, mprm3, m4, m5, m6 = symbols( - 'm1 m2 m3 mprm3 m4 m5 m6', integer=True + "m1 m2 m3 mprm3 m4 m5 m6", integer=True ) - m_range = Range('m') - sums = [(m_i, m_range[-j_i, j_i + 1]) for m_i, j_i in [ - (m1, j1), (m2, j2), (m4, j4), (m5, j5), (m6, j6) - ]] + m_range = Range("m") + sums = [ + (m_i, m_range[-j_i, j_i + 1]) + for m_i, j_i in [(m1, j1), (m2, j2), (m4, j4), (m5, j5), (m6, j6)] + ] - phase = (-1) ** ( - j1 + j2 + j4 + j5 + j6 - m1 - m2 - m4 - m5 - m6 - ) + phase = (-1) ** (j1 + j2 + j4 + j5 + j6 - m1 - m2 - m4 - m5 - m6) amp = ( - Wigner3j(j2, m2, j3, -m3, j1, m1) - * Wigner3j(j1, -m1, j5, m5, j6, m6) - * Wigner3j(j5, -m5, jprm3, mprm3, j4, m4) - * Wigner3j(j4, -m4, j2, -m2, j6, -m6) + Wigner3j(j2, m2, j3, -m3, j1, m1) + * Wigner3j(j1, -m1, j5, m5, j6, m6) + * Wigner3j(j5, -m5, jprm3, mprm3, j4, m4) + * Wigner3j(j4, -m4, j2, -m2, j6, -m6) ) expected = ( + ( ((-1) ** (j3 - m3) / (2 * j3 + 1)) - * KroneckerDelta(j3, jprm3) * KroneckerDelta(m3, mprm3) + * KroneckerDelta(j3, jprm3) + * KroneckerDelta(m3, mprm3) * Wigner6j(j1, j2, j3, j4, j5, j6) - ).expand().simplify(doit=False) + ) + .expand() + .simplify(doit=False) + ) # For performance reason, just test a random arrangement of the summations. random.shuffle(sums) @@ -223,7 +226,7 @@ def test_wigner3j_sum_to_wigner6j(nuclear: NuclearBogoliubovDrudge): assert len(difference.local_terms) == 0 -@pytest.mark.skip(reason='Pending improvement in PONO simplification') +@pytest.mark.skip(reason="Pending improvement in PONO simplification") def test_sum_4_3j_to_6j_in_bccd(nuclear: NuclearBogoliubovDrudge): """Test summation of 4 Wigner 3j symbols in a really BCCD term. @@ -243,11 +246,13 @@ def test_sum_4_3j_to_6j_in_bccd(nuclear: NuclearBogoliubovDrudge): ktilde4, ktilde5, ktilde6 = p.ktilde4, p.ktilde5, p.ktilde6 ktilde7, ktilde8 = p.ktilde7, p.ktilde8 m1, m2, m3, m4 = p.m1, p.m2, p.m3, p.m4 - t = IndexedBase('t') - h04 = IndexedBase('H04') + t = IndexedBase("t") + h04 = IndexedBase("H04") tensor = dr.sum( - (J2, j_range), (J3, j_range), (M2, m_range[-J2, J2 + 1]), + (J2, j_range), + (J3, j_range), + (M2, m_range[-J2, J2 + 1]), (ktilde5, tilde_range), (ktilde6, tilde_range), (ktilde7, tilde_range), @@ -256,14 +261,27 @@ def test_sum_4_3j_to_6j_in_bccd(nuclear: NuclearBogoliubovDrudge): (m2, m_range[-JOf(ktilde2), JOf(ktilde2) + 1]), (m3, m_range[-JOf(ktilde4), JOf(ktilde4) + 1]), (m4, m_range[-JOf(ktilde5), JOf(ktilde5) + 1]), - -(-1) ** J1 * (-1) ** J2 * (-1) ** (6 * J3) * (-1) ** (-M1) - * (-1) ** (-M2) * (-1) ** JOf(ktilde2) * (-1) ** (3 * JOf(ktilde3)) - * (-1) ** (4 * JOf(ktilde4)) * (-1) ** (2 * JOf(ktilde5)) - * (-1) ** (4 * JOf(ktilde7)) * (-1) ** (2 * JOf(ktilde8)) + -((-1) ** J1) + * (-1) ** J2 + * (-1) ** (6 * J3) + * (-1) ** (-M1) + * (-1) ** (-M2) + * (-1) ** JOf(ktilde2) + * (-1) ** (3 * JOf(ktilde3)) + * (-1) ** (4 * JOf(ktilde4)) + * (-1) ** (2 * JOf(ktilde5)) + * (-1) ** (4 * JOf(ktilde7)) + * (-1) ** (2 * JOf(ktilde8)) * ( - 4 * J1 * J2 * J3 + 2 * J1 * J2 + 2 * J1 * J3 + J1 + 2 * J2 * J3 - + J2 + J3 - ) * KroneckerDelta(JOf(ktilde3), JOf(ktilde5)) + 4 * J1 * J2 * J3 + + 2 * J1 * J2 + + 2 * J1 * J3 + + J1 + + 2 * J2 * J3 + + J2 + + J3 + ) + * KroneckerDelta(JOf(ktilde3), JOf(ktilde5)) * h04[J3, ktilde6, ktilde7, ktilde8, ktilde5] * t[J2, ktilde5, ktilde1, ktilde2, ktilde4] * t[J3, ktilde6, ktilde7, ktilde8, ktilde3] @@ -271,7 +289,7 @@ def test_sum_4_3j_to_6j_in_bccd(nuclear: NuclearBogoliubovDrudge): * Wigner3j(JOf(ktilde2), -m2, JOf(ktilde4), -m3, J2, -M2) * Wigner3j(JOf(ktilde3), -m4, JOf(ktilde4), -m3, J1, -M1) * Wigner3j(JOf(ktilde5), m4, JOf(ktilde1), m1, J2, -M2) - / (3 * (2 * JOf(ktilde5) + 1)) + / (3 * (2 * JOf(ktilde5) + 1)), ) res = tensor.deep_simplify() assert res.n_terms == 1 diff --git a/tests/parthole_test.py b/tests/parthole_test.py index d3afa6ed..d059ee83 100644 --- a/tests/parthole_test.py +++ b/tests/parthole_test.py @@ -6,18 +6,18 @@ from drudge import PartHoleDrudge -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def parthole(spark_ctx): """Initialize the environment for a free algebra.""" dr = PartHoleDrudge(spark_ctx) return dr -@pytest.mark.parametrize('par_level', [0, 1, 2]) -@pytest.mark.parametrize('full_simplify', [True, False]) -@pytest.mark.parametrize('simple_merge', [True, False]) +@pytest.mark.parametrize("par_level", [0, 1, 2]) +@pytest.mark.parametrize("full_simplify", [True, False]) +@pytest.mark.parametrize("simple_merge", [True, False]) def test_simple_parthole_normal_order( - parthole, par_level, full_simplify, simple_merge + parthole, par_level, full_simplify, simple_merge ): """Test particle-hole normal ordering on a simple term. @@ -34,9 +34,7 @@ def test_simple_parthole_normal_order( j = p.j t = dr.one_body - inp = dr.einst( - t[i, j] * c_dag[i] * c_[j] - ) + inp = dr.einst(t[i, j] * c_dag[i] * c_[j]) dr.wick_parallel = par_level dr.full_simplify = full_simplify @@ -49,9 +47,7 @@ def test_simple_parthole_normal_order( dr.simple_merge = False assert res.n_terms == 2 - assert res == dr.einst( - -t[i, j] * c_[j] * c_dag[i] + t[i, i] - ).simplify() + assert res == dr.einst(-t[i, j] * c_[j] * c_dag[i] + t[i, i]).simplify() def test_parthole_drudge_has_good_ham(parthole): @@ -64,7 +60,7 @@ def test_parthole_drudge_has_good_ham(parthole): # # TODO: Add inspection of the actual value. - assert dr.orig_ham.n_terms == 2 ** 2 + 2 ** 4 + assert dr.orig_ham.n_terms == 2**2 + 2**4 assert dr.full_ham.n_terms == 2 + 8 + 9 assert dr.ham_energy.n_terms == 2 @@ -76,11 +72,14 @@ def test_parthole_drudge_has_good_ham(parthole): h_range = p.O i, j = p.O_dumms[:2] - expected = (dr.sum( - (i, h_range), dr.one_body[i, i] - ) + dr.sum( - (i, h_range), (j, h_range), dr.two_body[i, j, i, j] * Rational(1, 2) - )).simplify() + expected = ( + dr.sum((i, h_range), dr.one_body[i, i]) + + dr.sum( + (i, h_range), + (j, h_range), + dr.two_body[i, j, i, j] * Rational(1, 2), + ) + ).simplify() assert dr.eval_fermi_vev(dr.orig_ham).simplify() == expected assert dr.ham_energy == expected @@ -100,7 +99,7 @@ def test_tce_parse(parthole): * Sum ( h5 ) * f ( h5 h1 ) * t ( p3 p4 h5 h2 ) """ - t = IndexedBase('t') + t = IndexedBase("t") res = dr.parse_tce(tce_out, {2: t}) @@ -144,8 +143,7 @@ def test_parthole_with_ph_excitations(parthole): def test_parthole_drudge_gives_conventional_dummies(parthole): - """Test dummy naming in canonicalization facility on particle-hole drudge. - """ + """Test dummy naming in canonicalization facility on particle-hole drudge.""" dr = parthole p = dr.names @@ -177,12 +175,14 @@ def test_parthole_drudge_canonicalize_complex_exprs(parthole): dr = parthole p = dr.names - t = IndexedBase('t') - z = IndexedBase('z') + t = IndexedBase("t") + z = IndexedBase("z") tensor = dr.einst( - t[p.c, p.l] * t[p.d, p.k] * p.u[p.k, p.i, p.c, p.a] * - z[p.d, p.b, p.j, p.l] + t[p.c, p.l] + * t[p.d, p.k] + * p.u[p.k, p.i, p.c, p.a] + * z[p.d, p.b, p.j, p.l] ) once = tensor.canon().reset_dumms() @@ -204,12 +204,12 @@ def test_drs_for_parthole_drudge(parthole): dr = parthole p = dr.names - env = dr.exec_drs(DRUDGE_SCRIPT, '') + env = dr.exec_drs(DRUDGE_SCRIPT, "") - x_def = env['x'] - s = env['s'] + x_def = env["x"] + s = env["s"] - t = IndexedBase('t') + t = IndexedBase("t") u = p.u i, j, a, b = p.i, p.j, p.a, p.b @@ -219,20 +219,18 @@ def test_drs_for_parthole_drudge(parthole): assert s == 0 # Different repr form in different environments. - assert repr(s).find('TensorDef object at 0x') > 0 - assert env['s_str'] == 'x = 0' + assert repr(s).find("TensorDef object at 0x") > 0 + assert env["s_str"] == "x = 0" def test_einstein_sum_for_both_particles_and_holes(parthole): """Test Einstein convention over both ranges.""" dr = parthole p = dr.names - x = IndexedBase('x') + x = IndexedBase("x") summand = x[p.p, p.q] * p.c_[p.p, p.q] res = dr.einst(summand).simplify() assert res.n_terms == 4 ranges = (dr.part_range, dr.hole_range) - assert res == dr.sum( - (p.p, ranges), (p.q, ranges), summand - ).simplify() + assert res == dr.sum((p.p, ranges), (p.q, ranges), summand).simplify() diff --git a/tests/perm_test.py b/tests/perm_test.py index 117b0588..3986b1d1 100644 --- a/tests/perm_test.py +++ b/tests/perm_test.py @@ -1,5 +1,4 @@ -"""Tests for the basic permutation facility. -""" +"""Tests for the basic permutation facility.""" import pickle @@ -18,11 +17,11 @@ def test_perm_has_basic_functionality(): pre_images = [1, 2, 0] perm = Perm(pre_images, 1) - assert (len(perm) == len(pre_images)) + assert len(perm) == len(pre_images) for i, v in enumerate(pre_images): - assert (perm[i] == v) + assert perm[i] == v - assert (perm.acc == 1) + assert perm.acc == 1 return @@ -34,9 +33,9 @@ def test_perm_pickles(): perm = Perm(pre_images, 1) new_args = perm.__getnewargs__() - assert (len(new_args) == 2) - assert (new_args[0] == pre_images) - assert (new_args[1] == 1) + assert len(new_args) == 2 + assert new_args[0] == pre_images + assert new_args[1] == 1 new_perm = Perm(*new_args) pickled = pickle.dumps(perm) @@ -44,10 +43,10 @@ def test_perm_pickles(): for form in [new_perm, unpickled_perm]: # Maybe equality comparison should be added to Perms. - assert (len(form) == len(perm)) + assert len(form) == len(perm) for i in range(len(perm)): - assert (form[i] == perm[i]) - assert (form.acc == perm.acc) + assert form[i] == perm[i] + assert form.acc == perm.acc return @@ -62,7 +61,7 @@ def test_perm_reports_error(): Perm([1, 2]) with pytest.raises(TypeError): - Perm('aaa') + Perm("aaa") with pytest.raises(TypeError): Perm([0, 1], 0.5) diff --git a/tests/range_test.py b/tests/range_test.py index e00b804e..47d0ff7b 100644 --- a/tests/range_test.py +++ b/tests/range_test.py @@ -8,13 +8,13 @@ def test_range_has_basic_operations(): """Test the basic operations on ranges.""" - a_symb = sympify('a') - b_symb = sympify('b') + a_symb = sympify("a") + b_symb = sympify("b") - bound0 = Range('B', 'a', 'b') - bound1 = Range('B', a_symb, b_symb) - symb0 = Range('S') - symb1 = Range('S') + bound0 = Range("B", "a", "b") + bound1 = Range("B", a_symb, b_symb) + symb0 = Range("S") + symb1 = Range("S") assert bound0 == bound1 assert hash(bound0) == hash(bound1) @@ -24,14 +24,14 @@ def test_range_has_basic_operations(): assert bound0 != symb0 assert hash(bound0) != hash(symb0) - assert bound0.label == 'B' + assert bound0.label == "B" assert bound0.lower == a_symb assert bound0.upper == b_symb assert bound0.args == (bound1.label, bound1.lower, bound1.upper) assert bound0.size == b_symb - a_symb - assert bound0.replace_label('B1') == Range('B1', a_symb, b_symb) + assert bound0.replace_label("B1") == Range("B1", a_symb, b_symb) - assert symb0.label == 'S' + assert symb0.label == "S" assert symb0.lower is None assert symb0.upper is None assert len(symb0.args) == 1 @@ -39,18 +39,17 @@ def test_range_has_basic_operations(): def test_bounds_operations_for_ranges(): - """Properties about bounds for ranges. - """ + """Properties about bounds for ranges.""" - l, u = sympify('l, u') - r = Range('R') + l, u = sympify("l, u") + r = Range("R") assert not r.bounded magic = 10 d = {r: magic} assert d[r] == magic - assert Range('S') not in d + assert Range("S") not in d # Add bounds should not change the identity of the range. r_lu = r[l, u] @@ -59,10 +58,7 @@ def test_bounds_operations_for_ranges(): assert r_lu.upper == u assert d[r_lu] == 10 - for r_02 in [ - r_lu[0, 2], - r_lu.map(lambda x: x.xreplace({l: 0, u: 2})) - ]: + for r_02 in [r_lu[0, 2], r_lu.map(lambda x: x.xreplace({l: 0, u: 2}))]: assert d[r_02] == 10 assert r_02.bounded assert r_02.lower == 0 diff --git a/tests/spin_one_half_test.py b/tests/spin_one_half_test.py index 9816f7d5..00b5d15d 100644 --- a/tests/spin_one_half_test.py +++ b/tests/spin_one_half_test.py @@ -4,8 +4,13 @@ from sympy import IndexedBase, symbols, Rational, KroneckerDelta, Integer from drudge import ( - CR, AN, UP, DOWN, SpinOneHalfGenDrudge, SpinOneHalfPartHoleDrudge, - RestrictedPartHoleDrudge + CR, + AN, + UP, + DOWN, + SpinOneHalfGenDrudge, + SpinOneHalfPartHoleDrudge, + RestrictedPartHoleDrudge, ) @@ -18,13 +23,13 @@ def test_up_down_enum_symbs(): assert KroneckerDelta(UP, DOWN) == 0 assert KroneckerDelta(DOWN, UP) == 0 - sigma = symbols('sigma') + sigma = symbols("sigma") for i in [UP, DOWN]: assert KroneckerDelta(i, sigma) != 0 assert KroneckerDelta(sigma, i) != 0 -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def genmb(spark_ctx): """The fixture with a general spin one-half drudge.""" return SpinOneHalfGenDrudge(spark_ctx) @@ -49,7 +54,7 @@ def test_restricted_hf_theory(genmb): c_dag = p.c_dag c_ = p.c_ a, b, c, d = p.L_dumms[:4] - alpha = symbols('alpha') + alpha = symbols("alpha") # Concrete summation. rot = dr.sum( @@ -59,30 +64,35 @@ def test_restricted_hf_theory(genmb): comm = (dr.ham | rot).simplify() # Restricted theory has same density for spin up and down. - rho = IndexedBase('rho') - res = comm.eval_vev(lambda op1, op2, _: ( - rho[op2.indices[1], op1.indices[1]] - if op1.indices[0] == CR and op2.indices[0] == AN - and op1.indices[2] == op2.indices[2] - else 0 - )).simplify() + rho = IndexedBase("rho") + res = comm.eval_vev( + lambda op1, op2, _: ( + rho[op2.indices[1], op1.indices[1]] + if op1.indices[0] == CR + and op2.indices[0] == AN + and op1.indices[2] == op2.indices[2] + else 0 + ) + ).simplify() # The expected result. t = dr.one_body u = dr.two_body - f = IndexedBase('f') + f = IndexedBase("f") expected = dr.einst(rho[b, c] * f[c, a] - f[b, c] * rho[c, a]) - expected = expected.subst(f[a, b], dr.einst( - t[a, b] + - 2 * u[a, c, b, d] * rho[d, c] - u[c, a, b, d] * rho[d, c] - )) + expected = expected.subst( + f[a, b], + dr.einst( + t[a, b] + 2 * u[a, c, b, d] * rho[d, c] - u[c, a, b, d] * rho[d, c] + ), + ) expected = expected.simplify() assert res == expected -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def parthole(spark_ctx): """The fixture with a particle-hole spin one-half drudge.""" return SpinOneHalfPartHoleDrudge(spark_ctx) @@ -93,7 +103,7 @@ def test_spin_one_half_particle_hole_drudge_has_basic_properties(parthole): dr = parthole - assert dr.orig_ham.n_terms == 8 + 4 * 2 ** 4 + assert dr.orig_ham.n_terms == 8 + 4 * 2**4 ham_terms = dr.ham.local_terms # Numbers are from the old PySLATA code. @@ -102,7 +112,7 @@ def test_spin_one_half_particle_hole_drudge_has_basic_properties(parthole): assert dr.ham.n_terms == 8 + 36 -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def restricted_parthole(spark_ctx): """The fixture with a restricted particle-hole drudge.""" return RestrictedPartHoleDrudge(spark_ctx) @@ -123,16 +133,20 @@ def test_restricted_parthole_drudge_has_good_hamiltonian(restricted_parthole): v = dr.two_body half = Rational(1, 2) orbs = tuple(dr.orb_ranges) - p, q, r, s = symbols('p q r s') - - expected_ham = (dr.sum( - (p, orbs), (q, orbs), h[p, q] * e_[p, q] - ) + dr.sum( - (p, orbs), (q, orbs), (r, orbs), (s, orbs), - half * v[p, r, q, s] * ( - e_[p, q] * e_[r, s] - KroneckerDelta(q, r) * e_[p, s] + p, q, r, s = symbols("p q r s") + + expected_ham = ( + dr.sum((p, orbs), (q, orbs), h[p, q] * e_[p, q]) + + dr.sum( + (p, orbs), + (q, orbs), + (r, orbs), + (s, orbs), + half + * v[p, r, q, s] + * (e_[p, q] * e_[r, s] - KroneckerDelta(q, r) * e_[p, s]), ) - )).simplify() + ).simplify() assert (dr.orig_ham - expected_ham).simplify() == 0 @@ -172,12 +186,16 @@ def test_restricted_parthole_drudge_on_complex_expression(restricted_parthole): i, j, k, l = p.O_dumms[0:4] e_ = p.e_ - t = IndexedBase('t') + t = IndexedBase("t") u = p.u tensor = dr.einst( - u[i, j, c, d] * e_[i, c] * e_[j, d] * - t[a, b, k, l] * e_[b, l] * e_[a, k] + u[i, j, c, d] + * e_[i, c] + * e_[j, d] + * t[a, b, k, l] + * e_[b, l] + * e_[a, k] ) res = tensor.simplify() frees_vars = res.free_vars diff --git a/tests/su2_test.py b/tests/su2_test.py index c7de3e8d..d5556ada 100644 --- a/tests/su2_test.py +++ b/tests/su2_test.py @@ -15,10 +15,7 @@ def test_su2_without_symbolic_index(spark_ctx): # Test the basic commutation rules without explicit site or on the same # site. - for ops in [ - (p.J_, p.J_p, p.J_m), - (p.J_[0], p.J_p[0], p.J_m[0]) - ]: + for ops in [(p.J_, p.J_p, p.J_m), (p.J_[0], p.J_p[0], p.J_m[0])]: j_z, j_p, j_m = [dr.sum(i) for i in ops] assert (j_z | j_p).simplify() == j_p assert (j_z | j_m).simplify() == -1 * j_m @@ -30,9 +27,7 @@ def test_su2_without_symbolic_index(spark_ctx): assert (j_y | j_z).simplify() == I * j_x assert (j_z | j_x).simplify() == I * j_y - j_sq = dr.sum( - j_z * j_z + half * j_p * j_m + half * j_m * j_p - ) + j_sq = dr.sum(j_z * j_z + half * j_p * j_m + half * j_m * j_p) for i in [j_x, j_y, j_z]: assert (j_sq | i).simplify() == 0 continue @@ -45,8 +40,8 @@ def test_su2_on_1d_heisenberg_model(spark_ctx): """ dr = SU2LatticeDrudge(spark_ctx) - l = Range('L') - dr.set_dumms(l, symbols('i j k l m n')) + l = Range("L") + dr.set_dumms(l, symbols("i j k l m n")) dr.add_default_resolver(l) p = dr.names @@ -56,16 +51,20 @@ def test_su2_on_1d_heisenberg_model(spark_ctx): i = p.i half = Rational(1, 2) - coupling = Symbol('J') - ham = dr.sum( - (i, l), - j_z[i] * j_z[i + 1] + - j_p[i] * j_m[i + 1] / 2 + j_m[i] * j_p[i + 1] / 2 - ) * coupling + coupling = Symbol("J") + ham = ( + dr.sum( + (i, l), + j_z[i] * j_z[i + 1] + + j_p[i] * j_m[i + 1] / 2 + + j_m[i] * j_p[i + 1] / 2, + ) + * coupling + ) s_sq = dr.sum( (i, l), - j_z[i] * j_z[i] + half * j_p[i] * j_m[i] + half * j_m[i] * j_p[i] + j_z[i] * j_z[i] + half * j_p[i] * j_m[i] + half * j_m[i] * j_p[i], ) comm = (ham | s_sq).simplify() @@ -78,20 +77,22 @@ def test_su2_with_deformed_commutation(spark_ctx): raise_ = SU2LatticeDrudge.DEFAULT_RAISE lower = SU2LatticeDrudge.DEFAULT_LOWER cartan = SU2LatticeDrudge.DEFAULT_CARTAN - alpha = IndexedBase('alpha') - a = Symbol('a') + alpha = IndexedBase("alpha") + a = Symbol("a") - dr = SU2LatticeDrudge(spark_ctx, specials={ - (raise_[a], lower[a]): alpha[a] * cartan[a] - 1 - }) + dr = SU2LatticeDrudge( + spark_ctx, specials={(raise_[a], lower[a]): alpha[a] * cartan[a] - 1} + ) assert dr.simplify(cartan[a] | raise_[a]) == dr.sum(raise_[a]) assert dr.simplify(cartan[a] | lower[a]) == dr.sum(-lower[a]) - assert dr.simplify(raise_[a] | lower[a]) == dr.sum( - alpha[a] * cartan[a] - 1 - ).simplify() - assert dr.simplify(lower[a] | raise_[a]) == dr.sum( - 1 - alpha[a] * cartan[a] - ).simplify() + assert ( + dr.simplify(raise_[a] | lower[a]) + == dr.sum(alpha[a] * cartan[a] - 1).simplify() + ) + assert ( + dr.simplify(lower[a] | raise_[a]) + == dr.sum(1 - alpha[a] * cartan[a]).simplify() + ) assert dr.simplify(raise_[1] | lower[2]) == 0 diff --git a/tests/term_test.py b/tests/term_test.py index 352d0ba5..7344be3f 100644 --- a/tests/term_test.py +++ b/tests/term_test.py @@ -18,21 +18,19 @@ def mprod(): This can be used to test some basic operations on terms. """ - i, j, k = sympify('i, j, k') - n = sympify('n') - l = Range('L', 1, n) - a = IndexedBase('a', shape=(n, n)) - b = IndexedBase('b', shape=(n, n)) - v = Vec('v') - - prod = sum_term( - [(i, l), (j, l), (k, l)], - a[i, j] * b[j, k] * v[i] * v[k] - ) + i, j, k = sympify("i, j, k") + n = sympify("n") + l = Range("L", 1, n) + a = IndexedBase("a", shape=(n, n)) + b = IndexedBase("b", shape=(n, n)) + v = Vec("v") + + prod = sum_term([(i, l), (j, l), (k, l)], a[i, j] * b[j, k] * v[i] * v[k]) assert len(prod) == 1 - return prod[0], types.SimpleNamespace(i=i, j=j, k=k, l=l, a=a, b=b, v=v, - n=n) + return prod[0], types.SimpleNamespace( + i=i, j=j, k=k, l=l, a=a, b=b, v=v, n=n + ) def test_terms_has_basic_operations(mprod): @@ -58,7 +56,7 @@ def test_terms_has_basic_operations(mprod): ref_prod = Term( tuple((i, p.l) for i in [p.i, p.j, p.k]), p.a[p.i, p.j] * p.b[p.j, p.k], - (p.v[p.i], p.v[p.k]) + (p.v[p.i], p.v[p.k]), ) assert prod == ref_prod assert hash(prod) == hash(ref_prod) @@ -71,7 +69,7 @@ def test_terms_has_basic_operations(mprod): assert prod != i assert hash(prod) != hash(i) - assert str(prod) == 'sum_{i, j, k} a[i, j]*b[j, k] * v[i] * v[k]' + assert str(prod) == "sum_{i, j, k} a[i, j]*b[j, k] * v[i] * v[k]" assert repr(prod) == ( "Term(sums=" "[(i, Range('L', 1, n)), (j, Range('L', 1, n)), (k, Range('L', 1, n))]," @@ -110,7 +108,7 @@ def test_terms_can_be_reset_dummies(mprod): prod, p = mprod - w = sympify('w') + w = sympify("w") excl = {w} dumms = {p.l: [w, p.i, p.j, p.k]} @@ -128,7 +126,7 @@ def test_terms_can_be_reset_dummies(mprod): res, dummbegs = prod.reset_dumms(dumms) expected = sum_term( [(p.k, p.l), (p.j, p.l), (p.i, p.l)], - p.a[p.k, p.j] * p.b[p.j, p.i] * p.v[p.k] * p.v[p.i] + p.a[p.k, p.j] * p.b[p.j, p.i] * p.v[p.k] * p.v[p.i], )[0] assert res == expected assert len(dummbegs) == 1 @@ -145,8 +143,7 @@ def test_delta_can_be_simplified(mprod): dumms = {l: [i, j, k]} term = sum_term( - [(i, l), (j, l)], - KroneckerDelta(i, j) * KroneckerDelta(j, k) * p.v[i] + [(i, l), (j, l)], KroneckerDelta(i, j) * KroneckerDelta(j, k) * p.v[i] )[0] # If we do not tell which range k belongs, a delta should be kept. @@ -171,9 +168,9 @@ def test_simple_terms_can_be_canonicalized(): that we expect. """ - l = Range('L') - x = IndexedBase('x') - i, j = sympify('i, j') + l = Range("L") + x = IndexedBase("x") + i, j = sympify("i, j") # A term without the vector part, canonicalization without symmetry. term = sum_term([(j, l), (i, l)], x[i, j])[0] @@ -182,7 +179,7 @@ def test_simple_terms_can_be_canonicalized(): assert res == expected # A term without the vector part, canonicalization with symmetry. - m = Range('M') + m = Range("M") term = sum_term([(j, m), (i, l)], x[j, i])[0] for neg, conj in itertools.product([IDENT, NEG], [IDENT, CONJ]): acc = neg | conj @@ -203,7 +200,7 @@ def test_simple_terms_can_be_canonicalized(): assert res == expected # Now we add vectors to the terms. - v = Vec('v') + v = Vec("v") term = sum_term([(i, l), (j, l)], v[i] * v[j])[0] # Without anything added, it should already be in the canonical form. diff --git a/tests/utils_test.py b/tests/utils_test.py index 6967ad1a..e71e9efb 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -8,7 +8,13 @@ from sympy import IndexedBase, symbols, Symbol from drudge import ( - Vec, sum_, prod_, Stopwatch, ScalarLatexPrinter, InvariantIndexable, Range + Vec, + sum_, + prod_, + Stopwatch, + ScalarLatexPrinter, + InvariantIndexable, + Range, ) from drudge.term import parse_terms, try_resolve_range from drudge.utils import extract_alnum, SymbResolver @@ -17,7 +23,7 @@ def test_sum_prod_utility(): """Test the summation and product utility.""" - v = Vec('v') + v = Vec("v") vecs = [v[i] for i in range(3)] v0, v1, v2 = vecs @@ -47,15 +53,15 @@ def print_cb(stamp): stamper = Stopwatch(print_cb) precise_sleep(0.5) - stamper.tock('Nothing') + stamper.tock("Nothing") res = res_holder[0] - assert res.startswith('Nothing done') + assert res.startswith("Nothing done") assert float(res.split()[-2]) - 0.5 < 0.001 precise_sleep(0.5) - stamper.tock('Tensor', tensor) + stamper.tock("Tensor", tensor) res = res_holder[0] - assert res.startswith('Tensor done, 2 terms') + assert res.startswith("Tensor done, 2 terms") assert float(res.split()[-2]) - 0.5 < 0.001 tensor.cache.assert_called_once_with() @@ -67,36 +73,39 @@ def print_cb(stamp): def test_invariant_indexable(): """Test the utility for invariant indexables.""" - val = Symbol('G') + val = Symbol("G") tensor = InvariantIndexable(val) assert tensor[1] == val - assert tensor[1, Symbol('i')] == val + assert tensor[1, Symbol("i")] == val def test_scalar_latex_printing(): """Test the printing of scalars into LaTeX form.""" - x1 = IndexedBase('x1') - i, j = symbols('i j') + x1 = IndexedBase("x1") + i, j = symbols("i j") expr = x1[i, j] - assert ScalarLatexPrinter().doprint(expr) == 'x^{(1)}_{i,j}' + assert ScalarLatexPrinter().doprint(expr) == "x^{(1)}_{i,j}" def test_extracting_alnum_substring(): """Test the utility to extract alphanumeric part of a string.""" - assert extract_alnum('x_{1, 2}') == 'x12' + assert extract_alnum("x_{1, 2}") == "x12" def test_symb_resolvers(): """Test the functionality of symbol resolvers in strict mode.""" - r = Range('R') - a, b = symbols('a b') - - strict, normal = [functools.partial( - try_resolve_range, sums_dict={}, resolvers=[SymbResolver( - [(r, [a])], strict=i - )] - ) for i in [True, False]] + r = Range("R") + a, b = symbols("a b") + + strict, normal = [ + functools.partial( + try_resolve_range, + sums_dict={}, + resolvers=[SymbResolver([(r, [a])], strict=i)], + ) + for i in [True, False] + ] # Strict mode. assert strict(a) == r diff --git a/tests/vec_test.py b/tests/vec_test.py index e3203360..fa6bcecc 100644 --- a/tests/vec_test.py +++ b/tests/vec_test.py @@ -10,14 +10,14 @@ def test_vecs_has_basic_properties(): """Tests the basic properties of vector instances.""" - base = Vec('v') - v_ab = Vec('v', indices=['a', 'b']) - v_ab_1 = base['a', 'b'] - v_ab_2 = (base['a'])['b'] + base = Vec("v") + v_ab = Vec("v", indices=["a", "b"]) + v_ab_1 = base["a", "b"] + v_ab_2 = (base["a"])["b"] - indices_ref = (sympify('a'), sympify('b')) + indices_ref = (sympify("a"), sympify("b")) hash_ref = hash(v_ab) - str_ref = 'v[a, b]' + str_ref = "v[a, b]" repr_ref = "Vec('v', (a, b))" for i in [v_ab, v_ab_1, v_ab_2]: From d0a4b88d705d91caa08e3945271333653e8a78dd Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 21:37:14 -0600 Subject: [PATCH 06/14] Fix more formatting issues --- .ruff.toml | 2 ++ deps/libcanon | 2 +- docs/examples/ccd.drs | 21 +++++++-------------- docs/examples/ccd_adv.drs | 29 +++++++++++++---------------- docs/examples/gencc.py | 3 --- docs/examples/rccsd.drs | 21 +++++++-------------- docs/examples/rccsd.py | 2 -- drudge/_tceparser.py | 3 --- drudge/bcs.py | 2 -- drudge/canon.py | 10 ---------- drudge/clifford.py | 2 -- drudge/drs.py | 3 --- tests/bogoliubov_test.py | 3 --- tests/eldag_canon_test.py | 3 --- tests/free_algebra_test.py | 3 --- tests/su2_test.py | 1 - tests/term_test.py | 1 - 17 files changed, 30 insertions(+), 81 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index 1b506446..c6ecac3d 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,6 +1,7 @@ target-version = "py312" line-length = 79 exclude = ["deps"] +extend-include = ["*.drs"] [lint] ignore = ["E741"] @@ -10,3 +11,4 @@ docstring-code-format = true [lint.per-file-ignores] "*.ipynb" = ["F403", "F405"] +"*.drs" = ["F403", "F405", "F821"] diff --git a/deps/libcanon b/deps/libcanon index 6785c39b..fb82d43a 160000 --- a/deps/libcanon +++ b/deps/libcanon @@ -1 +1 @@ -Subproject commit 6785c39bd506bab875dd5857e9ad4c65368c275b +Subproject commit fb82d43a66516bffb972c1d874e945c11dd57994 diff --git a/docs/examples/ccd.drs b/docs/examples/ccd.drs index 632b6502..54132908 100644 --- a/docs/examples/ccd.drs +++ b/docs/examples/ccd.drs @@ -10,9 +10,7 @@ set_dbbar_base(t, 2) # Einstein summation convention can be used for easy tensor creation. -t2 = einst( - t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4 -) +t2 = einst(t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4) # Get the similarity-transformed Hamiltonian. Note that ``|`` operator # computes the commutator between operators. @@ -21,22 +19,17 @@ c1 = simplify(c0 | t2) c2 = simplify(c1 | t2) c3 = simplify(c2 | t2) c4 = simplify(c3 | t2) -h_bar = simplify( - c0 + c1 + (1/2) * c2 + (1/6) * c3 + (1/24) * c4 -) +h_bar = simplify(c0 + c1 + (1 / 2) * c2 + (1 / 6) * c3 + (1 / 24) * c4) -print('Similarity-transformed Hamiltonian has {} terms'.format( - n_terms(h_bar) -)) +print("Similarity-transformed Hamiltonian has {} terms".format(n_terms(h_bar))) # Derive the working equations by projection. en_eqn = simplify(eval_fermi_vev(h_bar)) proj = c_dag[i] * c_dag[j] * c_[b] * c_[a] t2_eqn = simplify(eval_fermi_vev(proj * h_bar)) -print('Working equation derived!') - -with report('ccd.html', 'CCD theory') as rep: - rep.add('Energy equation', en_eqn) - rep.add('Doubles amplitude equation', t2_eqn) +print("Working equation derived!") +with report("ccd.html", "CCD theory") as rep: + rep.add("Energy equation", en_eqn) + rep.add("Doubles amplitude equation", t2_eqn) diff --git a/docs/examples/ccd_adv.drs b/docs/examples/ccd_adv.drs index 7425b2f2..4bb7c165 100644 --- a/docs/examples/ccd_adv.drs +++ b/docs/examples/ccd_adv.drs @@ -7,9 +7,8 @@ # set_dbbar_base(t, 2) -t2 = einst( - t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4 -) +t2 = einst(t[a, b, i, j] * c_dag[a] * c_dag[b] * c_[j] * c_[i] / 4) + def compute_h_bar(): """Compute the similarity transformed Hamiltonian.""" @@ -21,11 +20,12 @@ def compute_h_bar(): h_bar += curr return simplify(h_bar) + # By using the `memoise` function, the result can be automatically dumped into # the given pickle file, and read from it if it is already available. This can # be convenient for large multi-step jobs. -h_bar = memoize(compute_h_bar, 'h_bar.pickle') -print('H-bar has {} terms'.format(n_terms(h_bar))) +h_bar = memoize(compute_h_bar, "h_bar.pickle") +print("H-bar has {} terms".format(n_terms(h_bar))) # Derive the working equations by projection. Here we make them into tensor # definition with explicit left-hand side, so that they can be used for @@ -34,13 +34,11 @@ e <<= simplify(eval_fermi_vev(h_bar)) proj = c_dag[i] * c_dag[j] * c_[b] * c_[a] r2[a, b, i, j] <<= simplify(eval_fermi_vev(proj * h_bar)) -print('Working equation derived!') +print("Working equation derived!") # When the gristmill package is also installed, the evaluation of the working # equations can also be optimized with it. -eval_seq = optimize( - [e, r2], substs={no: 1000, nv: 10000} -) +eval_seq = optimize([e, r2], substs={no: 1000, nv: 10000}) # In addition to HTML report, we can also have LaTeX report. Note that the # report can be structured into sections with descriptions. For LaTeX output, @@ -53,11 +51,10 @@ The optimization is based on 1000 occupied orbitals and 10000 virtual orbitals, which should be representative of common problems for CCD theory. """ -with report('ccd.tex', 'CCD theory') as rep: - rep.add(title='Working equations') - rep.add(content=e, description='The energy equation') - rep.add(content=r2, description='Doubles amplitude equation', env='dmath') - rep.add(title='Optimized evaluation', description=opt_description) +with report("ccd.tex", "CCD theory") as rep: + rep.add(title="Working equations") + rep.add(content=e, description="The energy equation") + rep.add(content=r2, description="Doubles amplitude equation", env="dmath") + rep.add(title="Optimized evaluation", description=opt_description) for step in eval_seq: - rep.add(content=step, env='dmath') - + rep.add(content=step, env="dmath") diff --git a/docs/examples/gencc.py b/docs/examples/gencc.py index 04991874..2cf8e381 100644 --- a/docs/examples/gencc.py +++ b/docs/examples/gencc.py @@ -84,7 +84,6 @@ curr = (curr | corr).simplify() / (i + 1) stopwatch.tock("Commutator order {}".format(i + 1), curr) h_bar += curr - continue h_bar = h_bar.simplify() h_bar.repartition(cache=True) @@ -107,8 +106,6 @@ stopwatch.tock("T{} equation".format(order), eqn) amp_eqns[order] = eqn - continue - stopwatch.tock_total() # Check with the result from TCE. diff --git a/docs/examples/rccsd.drs b/docs/examples/rccsd.drs index 968e76fd..48cde967 100644 --- a/docs/examples/rccsd.drs +++ b/docs/examples/rccsd.drs @@ -7,8 +7,7 @@ Scuseria et al, J Chem Phys 89 (1988) 7382 (10.1063/1.455269). # Cluster excitation operator cluster = einst( - t[a, i] * e_[a, i] + - (1/2) * t[a, b, i, j] * e_[a, i] * e_[b, j] + t[a, i] * e_[a, i] + (1 / 2) * t[a, b, i, j] * e_[a, i] * e_[b, j] ) set_n_body_base(t, 2) @@ -21,22 +20,16 @@ h_bar = ham for order in range(4): curr = simplify(curr | cluster) / (order + 1) h_bar += curr - continue h_bar = h_bar.simplify() # The working equations. en_eqn = simplify(eval_fermi_vev(h_bar)) -t1_eqn = simplify(eval_fermi_vev( - e_[a, i] * h_bar -)) -t2_eqn = simplify(eval_fermi_vev( - e_[a, i] * e_[b, j] * h_bar -)) - -with report('rCCSD.html', 'restricted CCSD theory') as rep: - rep.add('Energy equation', en_eqn) - rep.add(r'\(T^1\) amplitude equation', t1_eqn) - rep.add(r'\(T^2\) amplitude equation', t2_eqn) +t1_eqn = simplify(eval_fermi_vev(e_[a, i] * h_bar)) +t2_eqn = simplify(eval_fermi_vev(e_[a, i] * e_[b, j] * h_bar)) +with report("rCCSD.html", "restricted CCSD theory") as rep: + rep.add("Energy equation", en_eqn) + rep.add(r"\(T^1\) amplitude equation", t1_eqn) + rep.add(r"\(T^2\) amplitude equation", t2_eqn) diff --git a/docs/examples/rccsd.py b/docs/examples/rccsd.py index ef66a70a..402e3480 100644 --- a/docs/examples/rccsd.py +++ b/docs/examples/rccsd.py @@ -53,7 +53,6 @@ curr = (curr | cluster).simplify() * Rational(1, order + 1) stopwatch.tock("Commutator order {}".format(order + 1), curr) h_bar += curr - continue h_bar = h_bar.simplify() h_bar.repartition(cache=True) @@ -76,7 +75,6 @@ eqn = (proj * h_bar).eval_fermi_vev().simplify() stopwatch.tock("T{} equation".format(order + 1), eqn) amp_eqns.append(eqn) - continue stopwatch.tock_total() diff --git a/drudge/_tceparser.py b/drudge/_tceparser.py index a64b2bc0..b9331cbc 100644 --- a/drudge/_tceparser.py +++ b/drudge/_tceparser.py @@ -33,7 +33,6 @@ def parse_tce_out(tce_out, range_cb, base_cb): stripped = line.strip() if len(stripped) > 0: lines.append(stripped) - continue free_vars = collections.defaultdict(set) return list( @@ -98,11 +97,9 @@ def _parse_term(term_str, range_cb, base_cb, free_vars): for i, j in zip(indices_symbs, indices): if i not in dumms: free_vars[range_cb(j)].add(i) - continue base_symb = base_cb(base, indices_symbs) amp *= base_symb[indices_symbs] - continue return Term(sums=sums, amp=amp, vecs=()) diff --git a/drudge/bcs.py b/drudge/bcs.py index e588264b..eae5c801 100644 --- a/drudge/bcs.py +++ b/drudge/bcs.py @@ -211,6 +211,4 @@ def _nonzero_by_cartan(term: Term, raise_, cartan, lower): if indices in cartan_indices: return False - continue - return True diff --git a/drudge/canon.py b/drudge/canon.py index 4edae9c1..4dd83516 100644 --- a/drudge/canon.py +++ b/drudge/canon.py @@ -70,8 +70,6 @@ def int_colour(self): _, g = v for _, idx in g: int_colour[idx] = i - continue - continue return int_colour @@ -173,7 +171,6 @@ def canon_factors(sums, factors, symms): factor_res = conjugate(factor_res) factors_res.append(factor_res) - continue return sums_res, factors_res, coeff @@ -230,7 +227,6 @@ def _build_eldag(sums, factors, symms): eldag.add_node( edges, None, (_SUM, i.label, bounded, with_dummy, free_var_keys) ) - continue # Real work, factors. # @@ -259,8 +255,6 @@ def _build_eldag(sums, factors, symms): if i in symms: factor_symms = symms[i] break - else: - continue else: factor_symms = None @@ -268,7 +262,6 @@ def _build_eldag(sums, factors, symms): idx = eldag.add_node(index_nodes, factor_symms, (_FACTOR, colour)) factor_idxes.append(idx) - continue return eldag, factor_idxes @@ -297,7 +290,6 @@ def _proc_indices(indices, dumms, eldag): for i in expr.atoms(Symbol): if i in dumms: involved[dumms[i]] = i - continue sum_nodes = list(involved.keys()) @@ -327,7 +319,6 @@ def _proc_indices(indices, dumms, eldag): curr_symms = [] elif form == curr_form: curr_symms.append(_find_perm(curr_edges, edges)) - continue # Now the order of the edges are determined. @@ -338,7 +329,6 @@ def _proc_indices(indices, dumms, eldag): ) nodes.append(idx) - continue return nodes diff --git a/drudge/clifford.py b/drudge/clifford.py index bdc93641..48c3b7bf 100644 --- a/drudge/clifford.py +++ b/drudge/clifford.py @@ -138,6 +138,4 @@ def _collapse4clifford(term: Term, *, inner): if n_rem > 0: vecs.append(k) - continue - return Term(term.sums, amp, tuple(vecs)) diff --git a/drudge/drs.py b/drudge/drs.py index b87740e1..c4df985a 100644 --- a/drudge/drs.py +++ b/drudge/drs.py @@ -304,7 +304,6 @@ def compile_drs(src, filename): for i in _FIXERS: root = i.visit(root) - continue return compile(root, filename, mode="exec") @@ -364,8 +363,6 @@ def __missing__(self, key: str): if hasattr(entry, key) and key not in excl: resolv = getattr(entry, key) break - else: - continue else: resolv = DrsSymbol(self._drudge, key) return resolv diff --git a/tests/bogoliubov_test.py b/tests/bogoliubov_test.py index a41b47db..b9936eeb 100644 --- a/tests/bogoliubov_test.py +++ b/tests/bogoliubov_test.py @@ -38,7 +38,6 @@ def test_bogoliubov_has_hamiltonian(bogoliubov: BogoliubovDrudge): an_indices.append(index) else: assert False - continue an_indices.reverse() indices = tuple(itertools.chain(cr_indices, an_indices)) @@ -59,8 +58,6 @@ def test_bogoliubov_has_hamiltonian(bogoliubov: BogoliubovDrudge): assert amp.indices == indices orders[order] = amp.base - continue - # Right now we do not test the bases. assert set(orders.keys()) == { (1, 1), diff --git a/tests/eldag_canon_test.py b/tests/eldag_canon_test.py index 2610144b..98823549 100644 --- a/tests/eldag_canon_test.py +++ b/tests/eldag_canon_test.py @@ -37,7 +37,6 @@ def test_eldag_can_be_canonicalized(): assert node_order[1] == 1 for i in [0, 2, 3]: assert perms[i] is None - continue # The ordering of the two terminals. if if_same: @@ -56,6 +55,4 @@ def test_eldag_can_be_canonicalized(): assert perm[1] == 0 assert perm.acc == 1 - continue - return diff --git a/tests/free_algebra_test.py b/tests/free_algebra_test.py index ed283294..452926d8 100644 --- a/tests/free_algebra_test.py +++ b/tests/free_algebra_test.py @@ -277,7 +277,6 @@ def test_basic_handling_range_with_variable_bounds(spark_ctx): assert i.lower == 0 assert i.upper == 10 checked = True - continue assert checked @@ -1327,7 +1326,6 @@ def test_einstein_convention(free_alg): elif idx == 1: assert term.amp == raw_amp_2 assert len(term.vecs) == 0 - continue # Test the automatic definition formation. tensor_def = dr.define_einst("r", raw_amp, auto_exts=True) @@ -1603,6 +1601,5 @@ def test_inverse_of_linear_vector_transforms(free_alg: Drudge): v_checked = True else: assert False - continue assert one_checked and v_checked diff --git a/tests/su2_test.py b/tests/su2_test.py index d5556ada..3e8d25f3 100644 --- a/tests/su2_test.py +++ b/tests/su2_test.py @@ -30,7 +30,6 @@ def test_su2_without_symbolic_index(spark_ctx): j_sq = dr.sum(j_z * j_z + half * j_p * j_m + half * j_m * j_p) for i in [j_x, j_y, j_z]: assert (j_sq | i).simplify() == 0 - continue def test_su2_on_1d_heisenberg_model(spark_ctx): diff --git a/tests/term_test.py b/tests/term_test.py index 7344be3f..88ba9cd5 100644 --- a/tests/term_test.py +++ b/tests/term_test.py @@ -192,7 +192,6 @@ def test_simple_terms_can_be_canonicalized(): expected_amp = conjugate(expected_amp) expected = sum_term([(i, l), (j, m)], expected_amp)[0] assert res == expected - continue # In the absence of symmetry, the two indices should not be permuted. res = term.canon() From 28c412a7df4125e8ba08d2be50c103280396c642 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 21:45:57 -0600 Subject: [PATCH 07/14] Rename file --- .github/workflows/{SpellCheck.yml => typos.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{SpellCheck.yml => typos.yml} (100%) diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/typos.yml similarity index 100% rename from .github/workflows/SpellCheck.yml rename to .github/workflows/typos.yml From 382df0d379d6ba2f1eed61ea2767b5b6da3e1806 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 21:46:12 -0600 Subject: [PATCH 08/14] Add ruff GitHub Action --- .github/workflows/ruff.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/ruff.yml diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 00000000..7d6294b8 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,31 @@ +name: Lint and Format + +on: + push: + branches: + - master + - 'release/*' + pull_request: + branches: + - master + workflow_dispatch: + +env: + CLICOLOR: 1 + +jobs: + ruff: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v5 + + - name: Ruff format check + uses: astral-sh/ruff-action@v3 + with: + args: "format --check" + + - name: Ruff lint + uses: astral-sh/ruff-action@v3 + with: + args: "check" From 8f4176ece5b97cd0c32aa4870b36a13b84a0fd58 Mon Sep 17 00:00:00 2001 From: Guo Chen Date: Sun, 16 Nov 2025 21:55:14 -0600 Subject: [PATCH 09/14] Revert changes to the libcanon submodule --- deps/libcanon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/libcanon b/deps/libcanon index fb82d43a..6785c39b 160000 --- a/deps/libcanon +++ b/deps/libcanon @@ -1 +1 @@ -Subproject commit fb82d43a66516bffb972c1d874e945c11dd57994 +Subproject commit 6785c39bd506bab875dd5857e9ad4c65368c275b From 9867fbb77974c4a86ed235d10820e3f16d7caa2b Mon Sep 17 00:00:00 2001 From: "Guo P. Chen" Date: Sun, 16 Nov 2025 22:01:08 -0600 Subject: [PATCH 10/14] Update drudge/wick.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- drudge/wick.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drudge/wick.py b/drudge/wick.py index d077ba91..6fac85b7 100644 --- a/drudge/wick.py +++ b/drudge/wick.py @@ -53,7 +53,7 @@ def wick_parallel(self, level): if level not in {0, 1, 2}: raise ValueError( - "Invalid parallel level for Wick expansion", level + f"Invalid parallel level for Wick expansion: {level}" ) self._wick_parallel = level From 76c29fda615a9678f23512c8ba29d8c064bfb42b Mon Sep 17 00:00:00 2001 From: "Guo P. Chen" Date: Sun, 16 Nov 2025 22:01:30 -0600 Subject: [PATCH 11/14] Update drudge/fock.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- drudge/fock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drudge/fock.py b/drudge/fock.py index dd57096c..2b0e802c 100644 --- a/drudge/fock.py +++ b/drudge/fock.py @@ -87,7 +87,7 @@ def __init__(self, *args, exch=FERMI, **kwargs): self._exch = exch else: raise ValueError( - "Invalid exchange", exch, "expecting plus/minus 1" + f"Invalid exchange: {exch}, expecting plus/minus 1" ) self.set_tensor_method("eval_vev", self.eval_vev) From ad8a81d76fba7a88123133700e004b10d5323966 Mon Sep 17 00:00:00 2001 From: "Guo P. Chen" Date: Sun, 16 Nov 2025 22:01:40 -0600 Subject: [PATCH 12/14] Update drudge/term.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- drudge/term.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drudge/term.py b/drudge/term.py index b85bf89b..411035fa 100644 --- a/drudge/term.py +++ b/drudge/term.py @@ -754,7 +754,7 @@ def get_amp_factors(self, *special_symbs, monom_only=True): amp = self._amp if monom_only and isinstance(amp, Add): - raise ValueError("Invalid amplitude: ", amp, "expecting monomial") + raise ValueError(f"Invalid amplitude: {amp}, expecting monomial") if isinstance(amp, Mul): all_factors = amp.args From 9e5034178cb55526b1682d976e87510539c51107 Mon Sep 17 00:00:00 2001 From: "Guo P. Chen" Date: Sun, 16 Nov 2025 22:01:47 -0600 Subject: [PATCH 13/14] Update drudge/utils.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- drudge/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drudge/utils.py b/drudge/utils.py index 297da6f3..54e9ac59 100644 --- a/drudge/utils.py +++ b/drudge/utils.py @@ -44,7 +44,7 @@ def ensure_sympify(obj, role="", expected_type=None): if expected_type is None or isinstance(sympified, expected_type): return sympified else: - raise TypeError(header, sympified, "expecting", expected_type) + raise TypeError(f"{header}{sympified}, expecting {expected_type}") def ensure_symb(obj, role=""): From 6425bf8c4891a6a2051e140432199245ef5659f4 Mon Sep 17 00:00:00 2001 From: "Guo P. Chen" Date: Sun, 16 Nov 2025 22:01:55 -0600 Subject: [PATCH 14/14] Update drudge/utils.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- drudge/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drudge/utils.py b/drudge/utils.py index 54e9ac59..e7f38791 100644 --- a/drudge/utils.py +++ b/drudge/utils.py @@ -39,7 +39,7 @@ def ensure_sympify(obj, role="", expected_type=None): try: sympified = sympify(obj) except SympifyError as exc: - raise TypeError(header, obj, "failed to be simplified", exc.args) + raise TypeError(f"{header}{obj} failed to be simplified: {exc.args}") if expected_type is None or isinstance(sympified, expected_type): return sympified