diff --git a/poetry.lock b/poetry.lock index 1ce3aa0f83..3ec55ad477 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -738,73 +738,73 @@ test = ["altair", "baytune", "chocolate", "dask", "distributed", "kahypar", "mat [[package]] name = "coverage" -version = "7.6.7" +version = "7.6.8" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, - {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, - {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, - {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, - {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, - {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, - {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, - {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, - {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, - {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, - {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, - {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, - {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, - {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, - {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, - {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed"}, + {file = "coverage-7.6.8-cp310-cp310-win32.whl", hash = "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e"}, + {file = "coverage-7.6.8-cp310-cp310-win_amd64.whl", hash = "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0"}, + {file = "coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801"}, + {file = "coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443"}, + {file = "coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad"}, + {file = "coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b"}, + {file = "coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146"}, + {file = "coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b"}, + {file = "coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71"}, + {file = "coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea"}, + {file = "coverage-7.6.8-cp39-cp39-win32.whl", hash = "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e"}, + {file = "coverage-7.6.8-cp39-cp39-win_amd64.whl", hash = "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076"}, + {file = "coverage-7.6.8-pp39.pp310-none-any.whl", hash = "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce"}, + {file = "coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc"}, ] [package.dependencies] @@ -1112,37 +1112,37 @@ cython = ["cython"] [[package]] name = "debugpy" -version = "1.8.8" +version = "1.8.9" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.8-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:e59b1607c51b71545cb3496876544f7186a7a27c00b436a62f285603cc68d1c6"}, - {file = "debugpy-1.8.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6531d952b565b7cb2fbd1ef5df3d333cf160b44f37547a4e7cf73666aca5d8d"}, - {file = "debugpy-1.8.8-cp310-cp310-win32.whl", hash = "sha256:b01f4a5e5c5fb1d34f4ccba99a20ed01eabc45a4684f4948b5db17a319dfb23f"}, - {file = "debugpy-1.8.8-cp310-cp310-win_amd64.whl", hash = "sha256:535f4fb1c024ddca5913bb0eb17880c8f24ba28aa2c225059db145ee557035e9"}, - {file = "debugpy-1.8.8-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:c399023146e40ae373753a58d1be0a98bf6397fadc737b97ad612886b53df318"}, - {file = "debugpy-1.8.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09cc7b162586ea2171eea055985da2702b0723f6f907a423c9b2da5996ad67ba"}, - {file = "debugpy-1.8.8-cp311-cp311-win32.whl", hash = "sha256:eea8821d998ebeb02f0625dd0d76839ddde8cbf8152ebbe289dd7acf2cdc6b98"}, - {file = "debugpy-1.8.8-cp311-cp311-win_amd64.whl", hash = "sha256:d4483836da2a533f4b1454dffc9f668096ac0433de855f0c22cdce8c9f7e10c4"}, - {file = "debugpy-1.8.8-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:0cc94186340be87b9ac5a707184ec8f36547fb66636d1029ff4f1cc020e53996"}, - {file = "debugpy-1.8.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64674e95916e53c2e9540a056e5f489e0ad4872645399d778f7c598eacb7b7f9"}, - {file = "debugpy-1.8.8-cp312-cp312-win32.whl", hash = "sha256:5c6e885dbf12015aed73770f29dec7023cb310d0dc2ba8bfbeb5c8e43f80edc9"}, - {file = "debugpy-1.8.8-cp312-cp312-win_amd64.whl", hash = "sha256:19ffbd84e757a6ca0113574d1bf5a2298b3947320a3e9d7d8dc3377f02d9f864"}, - {file = "debugpy-1.8.8-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:705cd123a773d184860ed8dae99becd879dfec361098edbefb5fc0d3683eb804"}, - {file = "debugpy-1.8.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890fd16803f50aa9cb1a9b9b25b5ec321656dd6b78157c74283de241993d086f"}, - {file = "debugpy-1.8.8-cp313-cp313-win32.whl", hash = "sha256:90244598214bbe704aa47556ec591d2f9869ff9e042e301a2859c57106649add"}, - {file = "debugpy-1.8.8-cp313-cp313-win_amd64.whl", hash = "sha256:4b93e4832fd4a759a0c465c967214ed0c8a6e8914bced63a28ddb0dd8c5f078b"}, - {file = "debugpy-1.8.8-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:143ef07940aeb8e7316de48f5ed9447644da5203726fca378f3a6952a50a9eae"}, - {file = "debugpy-1.8.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f95651bdcbfd3b27a408869a53fbefcc2bcae13b694daee5f1365b1b83a00113"}, - {file = "debugpy-1.8.8-cp38-cp38-win32.whl", hash = "sha256:26b461123a030e82602a750fb24d7801776aa81cd78404e54ab60e8b5fecdad5"}, - {file = "debugpy-1.8.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3cbf1833e644a3100eadb6120f25be8a532035e8245584c4f7532937edc652a"}, - {file = "debugpy-1.8.8-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:53709d4ec586b525724819dc6af1a7703502f7e06f34ded7157f7b1f963bb854"}, - {file = "debugpy-1.8.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a9c013077a3a0000e83d97cf9cc9328d2b0bbb31f56b0e99ea3662d29d7a6a2"}, - {file = "debugpy-1.8.8-cp39-cp39-win32.whl", hash = "sha256:ffe94dd5e9a6739a75f0b85316dc185560db3e97afa6b215628d1b6a17561cb2"}, - {file = "debugpy-1.8.8-cp39-cp39-win_amd64.whl", hash = "sha256:5c0e5a38c7f9b481bf31277d2f74d2109292179081f11108e668195ef926c0f9"}, - {file = "debugpy-1.8.8-py2.py3-none-any.whl", hash = "sha256:ec684553aba5b4066d4de510859922419febc710df7bba04fe9e7ef3de15d34f"}, - {file = "debugpy-1.8.8.zip", hash = "sha256:e6355385db85cbd666be703a96ab7351bc9e6c61d694893206f8001e22aee091"}, + {file = "debugpy-1.8.9-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:cfe1e6c6ad7178265f74981edf1154ffce97b69005212fbc90ca22ddfe3d017e"}, + {file = "debugpy-1.8.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada7fb65102a4d2c9ab62e8908e9e9f12aed9d76ef44880367bc9308ebe49a0f"}, + {file = "debugpy-1.8.9-cp310-cp310-win32.whl", hash = "sha256:c36856343cbaa448171cba62a721531e10e7ffb0abff838004701454149bc037"}, + {file = "debugpy-1.8.9-cp310-cp310-win_amd64.whl", hash = "sha256:17c5e0297678442511cf00a745c9709e928ea4ca263d764e90d233208889a19e"}, + {file = "debugpy-1.8.9-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040"}, + {file = "debugpy-1.8.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70"}, + {file = "debugpy-1.8.9-cp311-cp311-win32.whl", hash = "sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66"}, + {file = "debugpy-1.8.9-cp311-cp311-win_amd64.whl", hash = "sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d"}, + {file = "debugpy-1.8.9-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2"}, + {file = "debugpy-1.8.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe"}, + {file = "debugpy-1.8.9-cp312-cp312-win32.whl", hash = "sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11"}, + {file = "debugpy-1.8.9-cp312-cp312-win_amd64.whl", hash = "sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53"}, + {file = "debugpy-1.8.9-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:957ecffff80d47cafa9b6545de9e016ae8c9547c98a538ee96ab5947115fb3dd"}, + {file = "debugpy-1.8.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1efbb3ff61487e2c16b3e033bc8595aea578222c08aaf3c4bf0f93fadbd662ee"}, + {file = "debugpy-1.8.9-cp313-cp313-win32.whl", hash = "sha256:7c4d65d03bee875bcb211c76c1d8f10f600c305dbd734beaed4077e902606fee"}, + {file = "debugpy-1.8.9-cp313-cp313-win_amd64.whl", hash = "sha256:e46b420dc1bea64e5bbedd678148be512442bc589b0111bd799367cde051e71a"}, + {file = "debugpy-1.8.9-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:472a3994999fe6c0756945ffa359e9e7e2d690fb55d251639d07208dbc37caea"}, + {file = "debugpy-1.8.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365e556a4772d7d0d151d7eb0e77ec4db03bcd95f26b67b15742b88cacff88e9"}, + {file = "debugpy-1.8.9-cp38-cp38-win32.whl", hash = "sha256:54a7e6d3014c408eb37b0b06021366ee985f1539e12fe49ca2ee0d392d9ceca5"}, + {file = "debugpy-1.8.9-cp38-cp38-win_amd64.whl", hash = "sha256:8e99c0b1cc7bf86d83fb95d5ccdc4ad0586d4432d489d1f54e4055bcc795f693"}, + {file = "debugpy-1.8.9-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:7e8b079323a56f719977fde9d8115590cb5e7a1cba2fcee0986ef8817116e7c1"}, + {file = "debugpy-1.8.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6953b335b804a41f16a192fa2e7851bdcfd92173cbb2f9f777bb934f49baab65"}, + {file = "debugpy-1.8.9-cp39-cp39-win32.whl", hash = "sha256:7e646e62d4602bb8956db88b1e72fe63172148c1e25c041e03b103a25f36673c"}, + {file = "debugpy-1.8.9-cp39-cp39-win_amd64.whl", hash = "sha256:3d9755e77a2d680ce3d2c5394a444cf42be4a592caaf246dbfbdd100ffcf7ae5"}, + {file = "debugpy-1.8.9-py2.py3-none-any.whl", hash = "sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899"}, + {file = "debugpy-1.8.9.zip", hash = "sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e"}, ] [[package]] @@ -1269,13 +1269,13 @@ pyrepl = ">=0.8.2" [[package]] name = "fastjsonschema" -version = "2.20.0" +version = "2.21.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, - {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, + {file = "fastjsonschema-2.21.0-py3-none-any.whl", hash = "sha256:5b23b8e7c9c6adc0ecb91c03a0768cb48cd154d9159378a69c8318532e0b5cbf"}, + {file = "fastjsonschema-2.21.0.tar.gz", hash = "sha256:a02026bbbedc83729da3bfff215564b71902757f33f60089f1abae193daa4771"}, ] [package.extras] @@ -2757,13 +2757,13 @@ files = [ [[package]] name = "nbclient" -version = "0.10.0" +version = "0.10.1" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, - {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, + {file = "nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d"}, + {file = "nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68"}, ] [package.dependencies] @@ -2774,7 +2774,7 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] -docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] @@ -3085,14 +3085,14 @@ files = [ [[package]] name = "nvidia-nvjitlink-cu12" -version = "12.6.77" +version = "12.6.85" description = "Nvidia JIT LTO Library" optional = false python-versions = ">=3" files = [ - {file = "nvidia_nvjitlink_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:3bf10d85bb1801e9c894c6e197e44dd137d2a0a9e43f8450e9ad13f2df0dd52d"}, - {file = "nvidia_nvjitlink_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9ae346d16203ae4ea513be416495167a0101d33d2d14935aa9c1829a3fb45142"}, - {file = "nvidia_nvjitlink_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:410718cd44962bed862a31dd0318620f6f9a8b28a6291967bcfcb446a6516771"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-win_amd64.whl", hash = "sha256:e61120e52ed675747825cdd16febc6a0730537451d867ee58bee3853b1b13d1c"}, ] [[package]] @@ -3488,22 +3488,22 @@ testing = ["google-api-core (>=1.31.5)"] [[package]] name = "protobuf" -version = "5.28.3" +version = "5.29.0" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.28.3-cp310-abi3-win32.whl", hash = "sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24"}, - {file = "protobuf-5.28.3-cp310-abi3-win_amd64.whl", hash = "sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868"}, - {file = "protobuf-5.28.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687"}, - {file = "protobuf-5.28.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584"}, - {file = "protobuf-5.28.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135"}, - {file = "protobuf-5.28.3-cp38-cp38-win32.whl", hash = "sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548"}, - {file = "protobuf-5.28.3-cp38-cp38-win_amd64.whl", hash = "sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b"}, - {file = "protobuf-5.28.3-cp39-cp39-win32.whl", hash = "sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535"}, - {file = "protobuf-5.28.3-cp39-cp39-win_amd64.whl", hash = "sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36"}, - {file = "protobuf-5.28.3-py3-none-any.whl", hash = "sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed"}, - {file = "protobuf-5.28.3.tar.gz", hash = "sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b"}, + {file = "protobuf-5.29.0-cp310-abi3-win32.whl", hash = "sha256:ea7fb379b257911c8c020688d455e8f74efd2f734b72dc1ea4b4d7e9fd1326f2"}, + {file = "protobuf-5.29.0-cp310-abi3-win_amd64.whl", hash = "sha256:34a90cf30c908f47f40ebea7811f743d360e202b6f10d40c02529ebd84afc069"}, + {file = "protobuf-5.29.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c931c61d0cc143a2e756b1e7f8197a508de5365efd40f83c907a9febf36e6b43"}, + {file = "protobuf-5.29.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:85286a47caf63b34fa92fdc1fd98b649a8895db595cfa746c5286eeae890a0b1"}, + {file = "protobuf-5.29.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:0d10091d6d03537c3f902279fcf11e95372bdd36a79556311da0487455791b20"}, + {file = "protobuf-5.29.0-cp38-cp38-win32.whl", hash = "sha256:0cd67a1e5c2d88930aa767f702773b2d054e29957432d7c6a18f8be02a07719a"}, + {file = "protobuf-5.29.0-cp38-cp38-win_amd64.whl", hash = "sha256:e467f81fdd12ded9655cea3e9b83dc319d93b394ce810b556fb0f421d8613e86"}, + {file = "protobuf-5.29.0-cp39-cp39-win32.whl", hash = "sha256:17d128eebbd5d8aee80300aed7a43a48a25170af3337f6f1333d1fac2c6839ac"}, + {file = "protobuf-5.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:6c3009e22717c6cc9e6594bb11ef9f15f669b19957ad4087214d69e08a213368"}, + {file = "protobuf-5.29.0-py3-none-any.whl", hash = "sha256:88c4af76a73183e21061881360240c0cdd3c39d263b4e8fb570aaf83348d608f"}, + {file = "protobuf-5.29.0.tar.gz", hash = "sha256:445a0c02483869ed8513a585d80020d012c6dc60075f96fa0563a724987b1001"}, ] [[package]] @@ -3704,13 +3704,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.10.0" +version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" files = [ - {file = "PyJWT-2.10.0-py3-none-any.whl", hash = "sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15"}, - {file = "pyjwt-2.10.0.tar.gz", hash = "sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c"}, + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, ] [package.extras] @@ -4243,7 +4243,7 @@ develop = false [package.dependencies] numba = ">=0.59.0" psutil = "^5.9.5" -qibo = "^0.2.13" +qibo = {git = "https://github.com/qiboteam/qibo", branch = "backend_refactor"} scipy = "^1.10.1" [package.extras] @@ -4253,8 +4253,8 @@ cuquantum = ["cuquantum-python-cu12 (>=23.10.0,<24.0.0)"] [package.source] type = "git" url = "https://github.com/qiboteam/qibojit.git" -reference = "HEAD" -resolved_reference = "290b1776c2ba272f1c9eb59cba1d31964a239f2a" +reference = "backend_refactor" +resolved_reference = "10f6d8cf3da9971cddc8f41282c0b6e04c96e6c0" [[package]] name = "qiboml" @@ -4269,13 +4269,13 @@ develop = false jax = "^0.4.25" jaxlib = "^0.4.25" numpy = "^1.26.4" -qibo = {git = "https://github.com/qiboteam/qibo"} +qibo = {git = "https://github.com/qiboteam/qibo", branch = "backend_refactor"} [package.source] type = "git" url = "https://github.com/qiboteam/qiboml.git" -reference = "HEAD" -resolved_reference = "3e52004c497ca738730e21aa5a2ca8c2f6044398" +reference = "backend_refactor" +resolved_reference = "49c38f516662e1a396916a0104e3f4e0cd4f74dd" [[package]] name = "qibotn" @@ -4506,30 +4506,40 @@ files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, + {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, + {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, + {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, + {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, + {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, @@ -5157,13 +5167,43 @@ files = [ [[package]] name = "tomli" -version = "2.1.0" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, - {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -5244,40 +5284,40 @@ optree = ["optree (>=0.9.1)"] [[package]] name = "tornado" -version = "6.4.1" +version = "6.4.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.8" files = [ - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, - {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, - {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, - {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"}, + {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"}, + {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"}, + {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"}, ] [[package]] name = "tqdm" -version = "4.67.0" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be"}, - {file = "tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] @@ -5445,81 +5485,76 @@ test = ["pytest"] [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] @@ -5549,4 +5584,4 @@ torch = ["torch"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "731880ba3f30c5c16b15692d782ced337173dac75fc8990bea1cd7baaef7f01b" +content-hash = "81af6b3dcd0dd854722a50e06a1799ac1d47d53444432635af890c6222bf4324" diff --git a/pyproject.toml b/pyproject.toml index 113a087f95..2e9cd0b1a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ ipython = "^8.10.0" qulacs = { version = "^0.6.4", markers = "(sys_platform == 'darwin' and python_version > '3.9') or sys_platform != 'darwin'" } seaborn = "^0.13.2" ipykernel = "^6.29.4" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "backend_refactor" } [tool.poetry.group.tests] optional = true @@ -70,9 +70,9 @@ pytest-cov = "^4.0.0" pylint = "3.1.0" matplotlib = "^3.7.0" torch = "^2.1.1,<2.4" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "backend_refactor"} qibotn = { git = "https://github.com/qiboteam/qibotn.git" } -qiboml = { git = "https://github.com/qiboteam/qiboml.git" } +qiboml = { git = "https://github.com/qiboteam/qiboml.git", branch = "backend_refactor" } stim = "^1.12.0" qulacs = { version = "^0.6.4", markers = "(sys_platform == 'darwin' and python_version > '3.9') or sys_platform != 'darwin'" } @@ -91,7 +91,7 @@ optional = true [tool.poetry.group.cuda11.dependencies] cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "backend_refactor" } qibotn = { git = "https://github.com/qiboteam/qibotn.git" } @@ -101,7 +101,7 @@ optional = true [tool.poetry.group.cuda12.dependencies] cupy-cuda12x = "^12.0.0" cuquantum-python-cu12 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "backend_refactor" } qibotn = { git = "https://github.com/qiboteam/qibotn.git" } [tool.poetry.extras] diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 73b139c5d9..4cd1ab9803 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -342,7 +342,7 @@ def _check_backend_and_local_state(seed, backend): "CupyBackend", "CuQuantumBackend", ]: # pragma: no cover - local_state = backend.np.random.default_rng(seed) + local_state = backend.default_rng(seed) else: local_state = np.random.default_rng(seed) else: diff --git a/src/qibo/backends/abstract.py b/src/qibo/backends/abstract.py index 9cf431016f..8e5367eeba 100644 --- a/src/qibo/backends/abstract.py +++ b/src/qibo/backends/abstract.py @@ -1,7 +1,10 @@ import abc +import collections from typing import Optional, Union -from qibo.config import raise_error +from qibo.backends import einsum_utils +from qibo.config import log, raise_error +from qibo.result import CircuitResult, MeasurementOutcomes, QuantumState class Backend(abc.ABC): @@ -77,20 +80,16 @@ def set_threads(self, nthreads): # pragma: no cover raise_error(NotImplementedError) @abc.abstractmethod - def cast(self, x, copy=False): # pragma: no cover + def cast(self, x, dtype=None, copy=False): # pragma: no cover """Cast an object as the array type of the current backend. Args: x: Object to cast to array. + dtype: native backend array dtype. copy (bool): If ``True`` a copy of the object is created in memory. """ raise_error(NotImplementedError) - @abc.abstractmethod - def is_sparse(self, x): # pragma: no cover - """Determine if a given array is a sparse tensor.""" - raise_error(NotImplementedError) - @abc.abstractmethod def to_numpy(self, x): # pragma: no cover """Cast a given array to numpy.""" @@ -105,329 +104,1261 @@ def compile(self, func): # pragma: no cover raise_error(NotImplementedError) @abc.abstractmethod - def zero_state(self, nqubits): # pragma: no cover - """Generate :math:`|000 \\cdots 0 \\rangle` state vector as an array.""" + def calculate_jacobian_matrix( + self, circuit, parameters, initial_state=None, return_complex: bool = True + ): # pragma: no cover + """Calculate the Jacobian matrix of ``circuit`` with respect to varables ``params``.""" raise_error(NotImplementedError) + def zero_state(self, nqubits): + state = self.zeros(2**nqubits, dtype=self.dtype) + state[0] = 1 + return state + + def zero_density_matrix(self, nqubits): + state = self.zeros(2 * (2**nqubits,), dtype=self.dtype) + state[0, 0] = 1 + return state + + def identity_density_matrix(self, nqubits, normalize: bool = True): + state = self.eye(2**nqubits, dtype=self.dtype) + if normalize is True: + state /= 2**nqubits + return state + + def plus_state(self, nqubits): + state = self.ones(2**nqubits, dtype=self.dtype) + state /= self.sqrt(2**nqubits) + return state + + def plus_density_matrix(self, nqubits): + state = self.ones(2 * (2**nqubits,), dtype=self.dtype) + state /= 2**nqubits + return state + + def matrix(self, gate): + """Convert a gate to its matrix representation in the computational basis.""" + name = gate.__class__.__name__ + _matrix = getattr(self.matrices, name) + if callable(_matrix): + _matrix = _matrix(2 ** len(gate.target_qubits)) + return self.cast(_matrix, dtype=_matrix.dtype) + + def matrix_parametrized(self, gate): + """Convert a parametrized gate to its matrix representation in the computational basis.""" + name = gate.__class__.__name__ + _matrix = getattr(self.matrices, name) + if name == "GeneralizedRBS": + _matrix = _matrix( + qubits_in=gate.init_args[0], + qubits_out=gate.init_args[1], + theta=gate.init_kwargs["theta"], + phi=gate.init_kwargs["phi"], + ) + else: + _matrix = _matrix(*gate.parameters) + return self.cast(_matrix, dtype=_matrix.dtype) + + def matrix_fused(self, fgate): + rank = len(fgate.target_qubits) + matrix = self.sparse_eye(2**rank) + + for gate in fgate.gates: + # transfer gate matrix to numpy as it is more efficient for + # small tensor calculations + # explicit to_numpy see https://github.com/qiboteam/qibo/issues/928 + # --> not sure whether going to numpy is still optimal in every case + gmatrix = self.to_numpy(gate.matrix(self)) + # add controls if controls were instantiated using + # the ``Gate.controlled_by`` method + num_controls = len(gate.control_qubits) + if num_controls > 0: + gmatrix = self.block_diag( + self.eye(2 ** len(gate.qubits) - len(gmatrix)), gmatrix + ) + # Kronecker product with identity is needed to make the + # original matrix have shape (2**rank x 2**rank) + eye = self.eye(2 ** (rank - len(gate.qubits))) + gmatrix = self.kron(gmatrix, eye) + # Transpose the new matrix indices so that it targets the + # target qubits of the original gate + original_shape = gmatrix.shape + gmatrix = self.reshape(gmatrix, 2 * rank * (2,)) + qubits = list(gate.qubits) + indices = qubits + [q for q in fgate.target_qubits if q not in qubits] + indices = self.argsort(indices) + transpose_indices = list(indices) + transpose_indices.extend(indices + rank) + gmatrix = self.transpose(gmatrix, transpose_indices) + gmatrix = self.reshape(gmatrix, original_shape) + # fuse the individual gate matrix to the total ``FusedGate`` matrix + # we are using sparse matrices to improve perfomances + matrix = self.sparse_csr_matrix(gmatrix).dot(matrix) + + return self.cast(self.to_dense(matrix)) + + def apply_gate(self, gate, state, nqubits): + state = self.reshape(state, nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: + matrix = self.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) + ncontrol = len(gate.control_qubits) + nactive = nqubits - ncontrol + order, targets = einsum_utils.control_order(gate, nqubits) + state = self.transpose(state, order) + # Apply `einsum` only to the part of the state where all controls + # are active. This should be `state[-1]` + state = self.reshape(state, (2**ncontrol,) + nactive * (2,)) + opstring = einsum_utils.apply_gate_string(targets, nactive) + updates = self.einsum(opstring, state[-1], matrix) + # Concatenate the updated part of the state `updates` with the + # part of of the state that remained unaffected `state[:-1]`. + state = self.concatenate([state[:-1], updates[None]], axis=0) + state = self.reshape(state, nqubits * (2,)) + # Put qubit indices back to their proper places + state = self.transpose(state, einsum_utils.reverse_order(order)) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + opstring = einsum_utils.apply_gate_string(gate.qubits, nqubits) + state = self.einsum(opstring, state, matrix) + return self.reshape(state, (2**nqubits,)) + + def apply_gate_density_matrix(self, gate, state, nqubits): + state = self.cast(state) + state = self.reshape(state, 2 * nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: + matrix = self.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) + matrixc = self.conj(matrix) + ncontrol = len(gate.control_qubits) + nactive = nqubits - ncontrol + n = 2**ncontrol + + order, targets = einsum_utils.control_order_density_matrix(gate, nqubits) + state = self.transpose(state, order) + state = self.reshape(state, 2 * (n,) + 2 * nactive * (2,)) + + leftc, rightc = einsum_utils.apply_gate_density_matrix_controlled_string( + targets, nactive + ) + state01 = state[: n - 1, n - 1] + state01 = self.einsum(rightc, state01, matrixc) + state10 = state[n - 1, : n - 1] + state10 = self.einsum(leftc, state10, matrix) + + left, right = einsum_utils.apply_gate_density_matrix_string( + targets, nactive + ) + state11 = state[n - 1, n - 1] + state11 = self.einsum(right, state11, matrixc) + state11 = self.einsum(left, state11, matrix) + + state00 = state[range(n - 1)] + state00 = state00[:, range(n - 1)] + state01 = self.concatenate([state00, state01[:, None]], axis=1) + state10 = self.concatenate([state10, state11[None]], axis=0) + state = self.concatenate([state01, state10[None]], axis=0) + state = self.reshape(state, 2 * nqubits * (2,)) + state = self.transpose(state, einsum_utils.reverse_order(order)) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + matrixc = self.conj(matrix) + left, right = einsum_utils.apply_gate_density_matrix_string( + gate.qubits, nqubits + ) + state = self.einsum(right, state, matrixc) + state = self.einsum(left, state, matrix) + return self.reshape(state, 2 * (2**nqubits,)) + + def apply_gate_half_density_matrix(self, gate, state, nqubits): + state = self.cast(state) + state = self.reshape(state, 2 * nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: # pragma: no cover + raise_error( + NotImplementedError, + "Gate density matrix half call is " + "not implemented for ``controlled_by``" + "gates.", + ) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + left, _ = einsum_utils.apply_gate_density_matrix_string( + gate.qubits, nqubits + ) + state = self.einsum(left, state, matrix) + return self.reshape(state, 2 * (2**nqubits,)) + + def apply_channel(self, channel, state, nqubits): + probabilities = channel.coefficients + (1 - self.sum(channel.coefficients),) + index = self.sample_shots(probabilities, 1)[0] + if index != len(channel.gates): + gate = channel.gates[index] + state = self.apply_gate(gate, state, nqubits) + return state + + def apply_channel_density_matrix(self, channel, state, nqubits): + state = self.cast(state) + new_state = (1 - channel.coefficient_sum) * state + for coeff, gate in zip(channel.coefficients, channel.gates): + new_state += coeff * self.apply_gate_density_matrix(gate, state, nqubits) + return new_state + + def _append_zeros(self, state, qubits, results): + """Helper method for collapse.""" + for q, r in zip(qubits, results): + state = self.expand_dims(state, q) + state = ( + self.concatenate([self.zeros(state.shape, dtype=state.dtype), state], q) + if r == 1 + else self.concatenate( + [state, self.zeros(state.shape, dtype=state.dtype)], q + ) + ) + return state + + def collapse_state(self, state, qubits, shot, nqubits, normalize=True): + state = self.cast(state) + shape = state.shape + binshot = self.samples_to_binary(shot, len(qubits))[0] + state = self.reshape(state, nqubits * (2,)) + order = list(qubits) + [q for q in range(nqubits) if q not in qubits] + state = self.transpose(state, order) + subshape = (2 ** len(qubits),) + (nqubits - len(qubits)) * (2,) + state = self.reshape(state, subshape)[int(shot)] + if normalize: + norm = self.sqrt(self.sum(self.abs(state) ** 2)) + state = state / norm + state = self._append_zeros(state, qubits, binshot) + return self.reshape(state, shape) + + def collapse_density_matrix(self, state, qubits, shot, nqubits, normalize=True): + state = self.cast(state) + shape = state.shape + binshot = list(self.samples_to_binary(shot, len(qubits))[0]) + order = list(qubits) + [q + nqubits for q in qubits] + order.extend(q for q in range(nqubits) if q not in qubits) + order.extend(q + nqubits for q in range(nqubits) if q not in qubits) + state = self.reshape(state, 2 * nqubits * (2,)) + state = self.transpose(state, order) + subshape = 2 * (2 ** len(qubits),) + 2 * (nqubits - len(qubits)) * (2,) + state = self.reshape(state, subshape)[int(shot), int(shot)] + n = 2 ** (len(state.shape) // 2) + if normalize: + norm = self.trace(self.reshape(state, (n, n))) + state = state / norm + qubits = qubits + [q + nqubits for q in qubits] + state = self._append_zeros(state, qubits, 2 * binshot) + return self.reshape(state, shape) + + def reset_error_density_matrix(self, gate, state, nqubits): + from qibo.gates import X # pylint: disable=C0415 + from qibo.quantum_info.linalg_operations import ( # pylint: disable=C0415 + partial_trace, + ) + + state = self.cast(state) + shape = state.shape + q = gate.target_qubits[0] + p_0, p_1 = gate.init_kwargs["p_0"], gate.init_kwargs["p_1"] + trace = partial_trace(state, (q,), backend=self) + trace = self.reshape(trace, 2 * (nqubits - 1) * (2,)) + zero = self.zero_density_matrix(1) + zero = self.tensordot(trace, zero, 0) + order = list(range(2 * nqubits - 2)) + order.insert(q, 2 * nqubits - 2) + order.insert(q + nqubits, 2 * nqubits - 1) + zero = self.reshape(self.transpose(zero, order), shape) + state = (1 - p_0 - p_1) * state + p_0 * zero + return state + p_1 * self.apply_gate_density_matrix(X(q), zero, nqubits) + + def thermal_error_density_matrix(self, gate, state, nqubits): + state = self.cast(state) + shape = state.shape + state = self.apply_gate(gate, self.ravel(state), 2 * nqubits) + return self.reshape(state, shape) + + def depolarizing_error_density_matrix(self, gate, state, nqubits): + from qibo.quantum_info.linalg_operations import ( # pylint: disable=C0415 + partial_trace, + ) + + state = self.cast(state) + shape = state.shape + q = gate.target_qubits + lam = gate.init_kwargs["lam"] + trace = partial_trace(state, q, backend=self) + trace = self.reshape(trace, 2 * (nqubits - len(q)) * (2,)) + identity = self.identity_density_matrix(len(q)) + identity = self.reshape(identity, 2 * len(q) * (2,)) + identity = self.tensordot(trace, identity, 0) + qubits = list(range(nqubits)) + for j in q: + qubits.pop(qubits.index(j)) + qubits.sort() + qubits += list(q) + qubit_1 = list(range(nqubits - len(q))) + list( + range(2 * (nqubits - len(q)), 2 * nqubits - len(q)) + ) + qubit_2 = list(range(nqubits - len(q), 2 * (nqubits - len(q)))) + list( + range(2 * nqubits - len(q), 2 * nqubits) + ) + qs = [qubit_1, qubit_2] + order = [] + for qj in qs: + qj = [qj[qubits.index(i)] for i in range(len(qubits))] + order += qj + identity = self.reshape(self.transpose(identity, order), shape) + state = (1 - lam) * state + lam * identity + return state + + def execute_circuit(self, circuit, initial_state=None, nshots=1000): + + if isinstance(initial_state, type(circuit)): + if not initial_state.density_matrix == circuit.density_matrix: + raise_error( + ValueError, + f"""Cannot set circuit with density_matrix {initial_state.density_matrix} as + initial state for circuit with density_matrix {circuit.density_matrix}.""", + ) + elif ( + not initial_state.accelerators == circuit.accelerators + ): # pragma: no cover + raise_error( + ValueError, + f"""Cannot set circuit with accelerators {initial_state.density_matrix} as + initial state for circuit with accelerators {circuit.density_matrix}.""", + ) + else: + return self.execute_circuit(initial_state + circuit, None, nshots) + elif initial_state is not None: + initial_state = self.cast(initial_state) + valid_shape = ( + 2 * (2**circuit.nqubits,) + if circuit.density_matrix + else (2**circuit.nqubits,) + ) + if tuple(initial_state.shape) != valid_shape: + raise_error( + ValueError, + f"Given initial state has shape {initial_state.shape} instead of " + f"the expected {valid_shape}.", + ) + + if circuit.repeated_execution: + if circuit.measurements or circuit.has_collapse: + return self.execute_circuit_repeated(circuit, nshots, initial_state) + else: + raise_error( + RuntimeError, + "Attempting to perform noisy simulation with `density_matrix=False` " + + "and no Measurement gate in the Circuit. If you wish to retrieve the " + + "statistics of the outcomes please include measurements in the circuit, " + + "otherwise set `density_matrix=True` to recover the final state.", + ) + + if circuit.accelerators: # pragma: no cover + return self.execute_distributed_circuit(circuit, initial_state, nshots) + + try: + nqubits = circuit.nqubits + + if circuit.density_matrix: + if initial_state is None: + state = self.zero_density_matrix(nqubits) + else: + state = self.cast(initial_state) + + for gate in circuit.queue: + state = gate.apply_density_matrix(self, state, nqubits) + + else: + if initial_state is None: + state = self.zero_state(nqubits) + else: + state = self.cast(initial_state) + + for gate in circuit.queue: + state = gate.apply(self, state, nqubits) + + if circuit.has_unitary_channel: + # here we necessarily have `density_matrix=True`, otherwise + # execute_circuit_repeated would have been called + if circuit.measurements: + circuit._final_state = CircuitResult( + state, circuit.measurements, backend=self, nshots=nshots + ) + return circuit._final_state + else: + circuit._final_state = QuantumState(state, backend=self) + return circuit._final_state + + else: + if circuit.measurements: + circuit._final_state = CircuitResult( + state, circuit.measurements, backend=self, nshots=nshots + ) + return circuit._final_state + else: + circuit._final_state = QuantumState(state, backend=self) + return circuit._final_state + + except self.oom_error: + raise_error( + RuntimeError, + f"State does not fit in {self.device} memory." + "Please switch the execution device to a " + "different one using ``qibo.set_device``.", + ) + + def execute_circuits( + self, circuits, initial_states=None, nshots=1000, processes=None + ): + from qibo.parallel import parallel_circuits_execution + + return parallel_circuits_execution( + circuits, initial_states, nshots, processes, backend=self + ) + + def execute_circuit_repeated(self, circuit, nshots, initial_state=None): + """ + Execute the circuit `nshots` times to retrieve probabilities, frequencies + and samples. Note that this method is called only if a unitary channel + is present in the circuit (i.e. noisy simulation) and `density_matrix=False`, or + if some collapsing measurement is performed. + """ + + if ( + circuit.has_collapse + and not circuit.measurements + and not circuit.density_matrix + ): + raise_error( + RuntimeError, + "The circuit contains only collapsing measurements (`collapse=True`) but " + + "`density_matrix=False`. Please set `density_matrix=True` to retrieve " + + "the final state after execution.", + ) + + results, final_states = [], [] + nqubits = circuit.nqubits + + if not circuit.density_matrix: + samples = [] + target_qubits = [ + measurement.target_qubits for measurement in circuit.measurements + ] + target_qubits = sum(target_qubits, tuple()) + + for _ in range(nshots): + if circuit.density_matrix: + if initial_state is None: + state = self.zero_density_matrix(nqubits) + else: + state = self.cast(initial_state, copy=True) + + for gate in circuit.queue: + if gate.symbolic_parameters: + gate.substitute_symbols() + state = gate.apply_density_matrix(self, state, nqubits) + else: + if circuit.accelerators: # pragma: no cover + # pylint: disable=E1111 + state = self.execute_distributed_circuit(circuit, initial_state) + else: + if initial_state is None: + state = self.zero_state(nqubits) + else: + state = self.cast(initial_state, copy=True) + + for gate in circuit.queue: + if gate.symbolic_parameters: + gate.substitute_symbols() + state = gate.apply(self, state, nqubits) + + if circuit.density_matrix: + final_states.append(state) + if circuit.measurements: + result = CircuitResult( + state, circuit.measurements, backend=self, nshots=1 + ) + sample = result.samples()[0] + results.append(sample) + if not circuit.density_matrix: + samples.append("".join([str(int(s)) for s in sample])) + for gate in circuit.measurements: + gate.result.reset() + + if circuit.density_matrix: # this implies also it has_collapse + assert circuit.has_collapse + final_state = self.cast(self.mean(self.to_numpy(final_states), 0)) + if circuit.measurements: + final_result = CircuitResult( + final_state, + circuit.measurements, + backend=self, + samples=self.aggregate_shots(results), + nshots=nshots, + ) + else: + final_result = QuantumState(final_state, backend=self) + circuit._final_state = final_result + return final_result + else: + final_result = MeasurementOutcomes( + circuit.measurements, + backend=self, + samples=self.aggregate_shots(results), + nshots=nshots, + ) + final_result._repeated_execution_frequencies = self.calculate_frequencies( + samples + ) + circuit._final_state = final_result + return final_result + @abc.abstractmethod - def zero_density_matrix(self, nqubits): # pragma: no cover - """Generate :math:`|000\\cdots0\\rangle\\langle000\\cdots0|` density matrix as an array.""" + def execute_distributed_circuit(self, circuit, initial_state=None, nshots=None): raise_error(NotImplementedError) - @abc.abstractmethod - def identity_density_matrix( - self, nqubits, normalize: bool = True - ): # pragma: no cover - """Generate density matrix + def calculate_symbolic( + self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 + ): + state = self.to_numpy(state) + terms = [] + for i in self.nonzero(state)[0]: + b = bin(i)[2:].zfill(nqubits) + if self.abs(state[i]) >= cutoff: + x = self.round(state[i], decimals) + terms.append(f"{x}|{b}>") + if len(terms) >= max_terms: + terms.append("...") + return terms + return terms + + def calculate_symbolic_density_matrix( + self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 + ): + state = self.to_numpy(state) + terms = [] + indi, indj = self.nonzero(state) + for i, j in zip(indi, indj): + bi = bin(i)[2:].zfill(nqubits) + bj = bin(j)[2:].zfill(nqubits) + if self.abs(state[i, j]) >= cutoff: + x = self.round(state[i, j], decimals) + terms.append(f"{x}|{bi}><{bj}|") + if len(terms) >= max_terms: + terms.append("...") + return terms + return terms + + def _order_probabilities(self, probs, qubits, nqubits): + """Arrange probabilities according to the given ``qubits`` ordering.""" + unmeasured, reduced = [], {} + for i in range(nqubits): + if i in qubits: + reduced[i] = i - len(unmeasured) + else: + unmeasured.append(i) + return self.transpose(probs, [reduced.get(i) for i in qubits]) + + def calculate_probabilities(self, state, qubits, nqubits): + rtype = self.real(state).dtype + unmeasured_qubits = tuple(i for i in range(nqubits) if i not in qubits) + state = self.reshape(self.abs(state) ** 2, nqubits * (2,)) + probs = self.sum(self.cast(state, dtype=rtype), axis=unmeasured_qubits) + return self.ravel(self._order_probabilities(probs, qubits, nqubits)) + + def calculate_probabilities_density_matrix(self, state, qubits, nqubits): + order = tuple(sorted(qubits)) + order += tuple(i for i in range(nqubits) if i not in qubits) + order = order + tuple(i + nqubits for i in order) + shape = 2 * (2 ** len(qubits), 2 ** (nqubits - len(qubits))) + state = self.reshape(state, 2 * nqubits * (2,)) + state = self.reshape(self.transpose(state, order), shape) + probs = self.abs(self.einsum("abab->a", state)) + probs = self.reshape(probs, len(qubits) * (2,)) + return self.ravel(self._order_probabilities(probs, qubits, nqubits)) + + def set_seed(self, seed): + self.seed(seed) + + def sample_shots(self, probabilities, nshots): + return self.random_choice( + range(len(probabilities)), size=nshots, p=probabilities + ) + + def aggregate_shots(self, shots): + return self.cast(shots, dtype=shots[0].dtype) + + def samples_to_binary(self, samples, nqubits): + qrange = self.arange(nqubits - 1, -1, -1, dtype=self.get_dtype("int32")) + return self.mod(self.right_shift(samples[:, None], qrange), 2) + + def samples_to_decimal(self, samples, nqubits): + ### This is faster just staying @ NumPy. + ## --> should we keep this method abstract then? + qrange = self.arange(nqubits - 1, -1, -1, dtype=self.get_dtype("int32")) + qrange = (2**qrange)[:, None] + samples = self.cast(samples, dtype=self.get_dtype("int32")) + return self.matmul(samples, qrange)[:, 0] + + def calculate_frequencies(self, samples): + # Samples are a list of strings so there is no advantage in using other backends + res, counts = self.unique(samples, return_counts=True) + res = self.to_numpy(res).tolist() + counts = self.to_numpy(counts).tolist() + return collections.Counter(dict(zip(res, counts))) + + def update_frequencies(self, frequencies, probabilities, nsamples): + samples = self.sample_shots(probabilities, nsamples) + res, counts = self.unique(samples, return_counts=True) + frequencies[res] += counts + return frequencies + + def sample_frequencies(self, probabilities, nshots): + from qibo.config import SHOT_BATCH_SIZE + + nprobs = probabilities / self.sum(probabilities) + frequencies = self.zeros(len(nprobs), dtype=self.get_dtype("int64")) + for _ in range(nshots // SHOT_BATCH_SIZE): + frequencies = self.update_frequencies(frequencies, nprobs, SHOT_BATCH_SIZE) + frequencies = self.update_frequencies( + frequencies, nprobs, nshots % SHOT_BATCH_SIZE + ) + return collections.Counter( + {i: int(f) for i, f in enumerate(frequencies) if f > 0} + ) + + def apply_bitflips(self, noiseless_samples, bitflip_probabilities): + noiseless_samples = self.cast(noiseless_samples, dtype=noiseless_samples.dtype) + fprobs = self.cast(bitflip_probabilities, dtype="float64") + sprobs = self.cast(self.rand(*noiseless_samples.shape), dtype="float64") + flip_0 = self.cast(sprobs < fprobs[0], dtype=noiseless_samples.dtype) + flip_1 = self.cast(sprobs < fprobs[1], dtype=noiseless_samples.dtype) + noisy_samples = noiseless_samples + (1 - noiseless_samples) * flip_0 + noisy_samples = noisy_samples - noiseless_samples * flip_1 + return noisy_samples + + def calculate_norm(self, state, order=2): + state = self.cast(state) + return self.linalg_norm(state, order) + + def calculate_norm_density_matrix(self, state, order="nuc"): + state = self.cast(state) + return self.linalg_norm(state, ord=order) + + def calculate_overlap(self, state1, state2): + return self.abs(self.sum(self.conj(self.cast(state1)) * self.cast(state2))) + + def calculate_overlap_density_matrix(self, state1, state2): + return self.trace( + self.matmul(self.conj(self.cast(state1)).T, self.cast(state2)) + ) + + def calculate_eigenvalues(self, matrix, k: int = 6, hermitian: bool = True): + if self.is_sparse(matrix): + log.warning( + "Calculating sparse matrix eigenvectors because " + "sparse modules do not provide ``eigvals`` method." + ) + return self.calculate_eigenvectors(matrix, k=k)[0] + if hermitian: + return self.eigvalsh(matrix) + return self.eigvals(matrix) + + def calculate_eigenvectors(self, matrix, k: int = 6, hermitian: bool = True): + if self.is_sparse(matrix): + if k < matrix.shape[0]: + return self.sparse_eigsh(matrix, k=k, which="SA") + else: # pragma: no cover + matrix = self.to_dense(matrix) + if hermitian: + return self.eigh(matrix) + return self.eig(matrix) + + def calculate_matrix_exp(self, a, matrix, eigenvectors=None, eigenvalues=None): + if eigenvectors is None or self.is_sparse(matrix): + if self.is_sparse(matrix): + return self.sparse_expm(-1j * a * matrix) + return self.expm(-1j * a * matrix) + expd = self.diag(self.exp(-1j * a * eigenvalues)) + ud = self.transpose(self.conj(eigenvectors)) + return self.matmul(eigenvectors, self.matmul(expd, ud)) + + def calculate_matrix_power( + self, + matrix, + power: Union[float, int], + precision_singularity: float = 1e-14, + ): + if not isinstance(power, (float, int)): + raise_error( + TypeError, + f"``power`` must be either float or int, but it is type {type(power)}.", + ) + + if power < 0.0: + # negative powers of singular matrices via SVD + determinant = self.det(matrix) + if abs(determinant) < precision_singularity: + return self._calculate_negative_power_singular_matrix( + matrix, power, precision_singularity + ) + + return self.fractional_matrix_power(matrix, power) + + def _calculate_negative_power_singular_matrix( + self, matrix, power: Union[float, int], precision_singularity: float + ): + """Calculate negative power of singular matrix.""" + U, S, Vh = self.calculate_singular_value_decomposition(matrix) + # cast needed because of different dtypes in `torch` + S = self.cast(S) + S_inv = self.where(self.abs(S) < precision_singularity, 0.0, S**power) + + return self.inverse(Vh) @ self.diag(S_inv) @ self.inverse(U) + + def calculate_expectation_state(self, hamiltonian, state, normalize): + statec = self.conj(state) + hstate = hamiltonian @ state + ev = self.real(self.sum(statec * hstate)) + if normalize: + ev /= self.sum(self.square(self.abs(state))) + return ev + + def calculate_expectation_density_matrix(self, hamiltonian, state, normalize): + ev = self.real(self.trace(self.cast(hamiltonian @ state))) + if normalize: + norm = self.real(self.trace(state)) + ev /= norm + return ev + + def calculate_singular_value_decomposition(self, matrix): + return self.linalg_svd(matrix) + + # TODO: remove this method + def calculate_hamiltonian_matrix_product(self, matrix1, matrix2): + return matrix1 @ matrix2 + + # TODO: remove this method + def calculate_hamiltonian_state_product(self, matrix, state): + if len(tuple(state.shape)) > 2: + raise_error( + ValueError, + f"Cannot multiply Hamiltonian with rank-{len(tuple(state.shape))} tensor.", + ) + return matrix @ state + + def _test_regressions(self, name): + if name == "test_measurementresult_apply_bitflips": + return [ + [0, 0, 0, 0, 2, 3, 0, 0, 0, 0], + [0, 0, 0, 0, 2, 3, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 2, 0, 0, 0, 0, 0], + ] + elif name == "test_probabilistic_measurement": + return {0: 249, 1: 231, 2: 253, 3: 267} + elif name == "test_unbalanced_probabilistic_measurement": + return {0: 171, 1: 148, 2: 161, 3: 520} + elif name == "test_post_measurement_bitflips_on_circuit": + return [ + {5: 30}, + {5: 18, 4: 5, 7: 4, 1: 2, 6: 1}, + {4: 8, 2: 6, 5: 5, 1: 3, 3: 3, 6: 2, 7: 2, 0: 1}, + ] + + def assert_circuitclose(self, circuit, target_circuit, rtol=1e-7, atol=0.0): + value = self.execute_circuit(circuit)._state + target = self.execute_circuit(target_circuit)._state + self.assert_allclose(value, target, rtol=rtol, atol=atol) - .. math:: - \\rho = \\frac{1}{2^\\text{nqubits}} \\, \\sum_{k=0}^{2^\\text{nqubits} - 1} \\, - |k \\rangle \\langle k| + # -------------------------------------------------------------------------------------------- + # New methods introduced by the refactor: + # in my view this might be considered as some sort of the core of the backend, + # i.e. the computation engine that defines how the single small operations + # are performed and it is going to be completely abstract. All the methods defined + # above are possibly going to be combination of the core methods below and, therefore, + # directly implemented in the abstract backend. - if ``normalize=True``. If ``normalize=False``, returns the unnormalized - Identity matrix, which is equivalent to :func:`numpy.eye`. + # array creation and manipulation + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + def array(self, x: Union[list, tuple], **kwargs): + """Construct a native array of the backend starting from a `list` or `tuple`. + + Args: + x (list | tuple): input list or tuple. + kwargs: keyword argument passed to the `Backend.cast` method. """ - raise_error(NotImplementedError) + return self.cast(x, **kwargs) @abc.abstractmethod - def plus_state(self, nqubits): # pragma: no cover - """Generate :math:`|+++\\cdots+\\rangle` state vector as an array.""" + def eye(self, *args, **kwargs): + """Numpy-like eye: https://numpy.org/devdocs/reference/generated/numpy.eye.html""" raise_error(NotImplementedError) @abc.abstractmethod - def plus_density_matrix(self, nqubits): # pragma: no cover - """Generate :math:`|+++\\cdots+\\rangle\\langle+++\\cdots+|` density matrix as an array.""" + def zeros(self, *args, **kwargs): + """Numpy-like zeros: https://numpy.org/devdocs/reference/generated/numpy.zeros.html""" raise_error(NotImplementedError) @abc.abstractmethod - def matrix(self, gate): # pragma: no cover - """Convert a :class:`qibo.gates.Gate` to the corresponding matrix.""" + def ones(self, *args, **kwargs): + """Numpy-like ones: https://numpy.org/devdocs/reference/generated/numpy.ones.html""" raise_error(NotImplementedError) @abc.abstractmethod - def matrix_parametrized(self, gate): # pragma: no cover - """Equivalent to :meth:`qibo.backends.abstract.Backend.matrix` for parametrized gates.""" + def arange(self, *args, **kwargs): + """Numpy-like arange: https://numpy.org/devdocs/reference/generated/numpy.arange.html""" raise_error(NotImplementedError) @abc.abstractmethod - def matrix_fused(self, gate): # pragma: no cover - """Fuse matrices of multiple gates.""" + def copy(self, *args, **kwargs): + """Numpy-like copy: https://numpy.org/devdocs/reference/generated/numpy.copy.html""" raise_error(NotImplementedError) @abc.abstractmethod - def apply_gate(self, gate, state, nqubits): # pragma: no cover - """Apply a gate to state vector.""" + def reshape(self, *args, **kwargs): + """Numpy-like reshape: https://numpy.org/devdocs/reference/generated/numpy.reshape.html""" raise_error(NotImplementedError) @abc.abstractmethod - def apply_gate_density_matrix(self, gate, state, nqubits): # pragma: no cover - """Apply a gate to density matrix.""" + def ravel(self, *args, **kwargs): + """Numpy-like ravel: https://numpy.org/devdocs/reference/generated/numpy.ravel.html""" raise_error(NotImplementedError) @abc.abstractmethod - def apply_gate_half_density_matrix(self, gate, state, nqubits): # pragma: no cover - """Apply a gate to one side of the density matrix.""" + def transpose(self, *args, **kwargs): + """Numpy-like transpose: https://numpy.org/devdocs/reference/generated/numpy.transpose.html""" raise_error(NotImplementedError) @abc.abstractmethod - def apply_channel(self, channel, state, nqubits): # pragma: no cover - """Apply a channel to state vector.""" - raise_error(NotImplementedError) + def concatenate(self, *args, **kwargs): + """Numpy-like concatenate: https://numpy.org/devdocs/reference/generated/numpy.concatenate.html""" + raise NotImplementedError @abc.abstractmethod - def apply_channel_density_matrix(self, channel, state, nqubits): # pragma: no cover - """Apply a channel to density matrix.""" - raise_error(NotImplementedError) + def expand_dims(self, *args, **kwargs): + """Numpy-like expand_dims: https://numpy.org/devdocs/reference/generated/numpy.expand_dims.html""" + raise NotImplementedError @abc.abstractmethod - def collapse_state( - self, state, qubits, shot, nqubits, normalize=True - ): # pragma: no cover - """Collapse state vector according to measurement shot.""" + def squeeze(self, *args, **kwargs): + """Numpy-like squeeze: https://numpy.org/devdocs/reference/generated/numpy.squeeze.html""" raise_error(NotImplementedError) @abc.abstractmethod - def collapse_density_matrix( - self, state, qubits, shot, nqubits, normalize=True - ): # pragma: no cover - """Collapse density matrix according to measurement shot.""" + def stack(self, *args, **kwargs): + """Numpy-like stack: https://numpy.org/devdocs/reference/generated/numpy.stack.html""" + raise NotImplementedError + + @abc.abstractmethod + def vstack(self, *args, **kwargs): + """Numpy-like vstack: https://numpy.org/devdocs/reference/generated/numpy.vstack.html""" raise_error(NotImplementedError) @abc.abstractmethod - def reset_error_density_matrix(self, gate, state, nqubits): # pragma: no cover - """Apply reset error to density matrix.""" + def unique(self, *args, **kwargs): + """Numpy-like unique: https://numpy.org/devdocs/reference/generated/numpy.unique.html""" + raise NotImplementedError + + @abc.abstractmethod + def where(self, *args, **kwargs): + """Numpy-like where: https://numpy.org/doc/stable/reference/generated/numpy.where.html""" raise_error(NotImplementedError) @abc.abstractmethod - def thermal_error_density_matrix(self, gate, state, nqubits): # pragma: no cover - """Apply thermal relaxation error to density matrix.""" + def flip(self, *args, **kwargs): + """Numpy-like flip: https://numpy.org/doc/stable/reference/generated/numpy.flip.html""" raise_error(NotImplementedError) @abc.abstractmethod - def execute_circuit( - self, circuit, initial_state=None, nshots=None - ): # pragma: no cover - """Execute a :class:`qibo.models.circuit.Circuit`.""" + def swapaxes(self, *args, **kwargs): + """Numpy-like swapaxes: https://numpy.org/doc/stable/reference/generated/numpy.swapaxes.html""" raise_error(NotImplementedError) @abc.abstractmethod - def execute_circuits( - self, circuits, initial_states=None, nshots=None - ): # pragma: no cover - """Execute multiple :class:`qibo.models.circuit.Circuit` in parallel.""" + def diagonal(self, *args, **kwargs): + """Numpy-like diagonal: https://numpy.org/doc/stable/reference/generated/numpy.diagonal.html""" raise_error(NotImplementedError) @abc.abstractmethod - def execute_circuit_repeated( - self, circuit, nshots, initial_state=None - ): # pragma: no cover - """Execute a :class:`qibo.models.circuit.Circuit` multiple times. + def nonzero(self, *args, **kwargs): + """Numpy-like nonzero: https://numpy.org/doc/stable/reference/generated/numpy.nonzero.html""" + raise NotImplementedError - Useful for noise simulation using state vectors or for simulating gates - controlled by measurement outcomes. - """ - raise_error(NotImplementedError) + @abc.abstractmethod + def sign(self, *args, **kwargs): + """Numpy-like element-wise sign function: https://numpy.org/doc/stable/reference/generated/numpy.sign.html""" + raise NotImplementedError @abc.abstractmethod - def execute_distributed_circuit( - self, circuit, initial_state=None, nshots=None - ): # pragma: no cover - """Execute a :class:`qibo.models.circuit.Circuit` using multiple GPUs.""" - raise_error(NotImplementedError) + def delete(self, a, obj, axis=None): + """Numpy-like delete function: https://numpy.org/doc/stable/reference/generated/numpy.delete.html""" + raise NotImplementedError + + # linear algebra + # ^^^^^^^^^^^^^^ @abc.abstractmethod - def calculate_symbolic( - self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 - ): # pragma: no cover - """Dirac representation of a state vector.""" - raise_error(NotImplementedError) + def einsum(self, *args, **kwargs): + """Numpy-like einsum: https://numpy.org/devdocs/reference/generated/numpy.einsum.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_symbolic_density_matrix( - self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 - ): # pragma: no cover - """Dirac representation of a density matrix.""" - raise_error(NotImplementedError) + def matmul(self, *args, **kwargs): + """Numpy-like matmul: https://numpy.org/devdocs/reference/generated/numpy.matmul.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_probabilities(self, state, qubits, nqubits): # pragma: no cover - """Calculate probabilities given a state vector.""" - raise_error(NotImplementedError) + def multiply(self, *args, **kwargs): + """Numpy-like multiply: https://numpy.org/doc/stable/reference/generated/numpy.multiply.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_probabilities_density_matrix( - self, state, qubits, nqubits - ): # pragma: no cover - """Calculate probabilities given a density matrix.""" - raise_error(NotImplementedError) + def prod(self, *args, **kwargs): + """Numpy-like prod: https://numpy.org/doc/stable/reference/generated/numpy.prod.html""" + raise NotImplementedError @abc.abstractmethod - def set_seed(self, seed): # pragma: no cover - """Set the seed of the random number generator.""" - raise_error(NotImplementedError) + def tensordot(self, *args, **kwargs): + """Numpy-like tensordot: https://numpy.org/doc/stable/reference/generated/numpy.tensordot.html""" + raise NotImplementedError @abc.abstractmethod - def sample_shots(self, probabilities, nshots): # pragma: no cover - """Sample measurement shots according to a probability distribution.""" - raise_error(NotImplementedError) + def kron(self, *args, **kwargs): + """Numpy-like kron: https://numpy.org/doc/stable/reference/generated/numpy.kron.html""" + raise NotImplementedError @abc.abstractmethod - def aggregate_shots(self, shots): # pragma: no cover - """Collect shots to a single array.""" - raise_error(NotImplementedError) + def outer(self, *args, **kwargs): + """Numpy-like outer: https://numpy.org/doc/stable/reference/generated/numpy.outer.html""" + raise NotImplementedError @abc.abstractmethod - def samples_to_binary(self, samples, nqubits): # pragma: no cover - """Convert samples from decimal representation to binary.""" - raise_error(NotImplementedError) + def diag(self, *args, **kwargs): + """Numpy-like diag: https://numpy.org/devdocs/reference/generated/numpy.diag.html""" + raise NotImplementedError @abc.abstractmethod - def samples_to_decimal(self, samples, nqubits): # pragma: no cover - """Convert samples from binary representation to decimal.""" - raise_error(NotImplementedError) + def trace(self, *args, **kwargs): + """Numpy-like trace: https://numpy.org/devdocs/reference/generated/numpy.trace.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_frequencies(self, samples): # pragma: no cover - """Calculate measurement frequencies from shots.""" - raise_error(NotImplementedError) + def linalg_svd(self, *args, **kwargs): + """Numpy-like linalg.svd: https://numpy.org/devdocs/reference/generated/numpy.linalg.svd.html""" + raise NotImplementedError @abc.abstractmethod - def update_frequencies( - self, frequencies, probabilities, nsamples - ): # pragma: no cover - raise_error(NotImplementedError) + def linalg_norm(self, *args, **kwargs): + """Numpy-like linalg.norm: https://numpy.org/devdocs/reference/generated/numpy.linalg.norm.html""" + raise NotImplementedError @abc.abstractmethod - def sample_frequencies(self, probabilities, nshots): # pragma: no cover - """Sample measurement frequencies according to a probability distribution.""" - raise_error(NotImplementedError) + def det(self, *args, **kwargs): + """Numpy-like matrix determinant: https://numpy.org/doc/stable/reference/generated/numpy.linalg.det.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_norm(self, state, order=2): # pragma: no cover - """Calculate norm of a state vector. + def qr(self, *args, **kwargs): + """Numpy-like linear algebra QR decomposition: https://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html""" + raise NotImplementedError - For specifications on possible values of the parameter ``order`` - for the ``tensorflow`` backend, please refer to - `tensorflow.norm `_. - For all other backends, please refer to - `numpy.linalg.norm `_. - """ - raise_error(NotImplementedError) + @abc.abstractmethod + def inverse(self, *args, **kwargs): + """Numpy-like linear algebra inverse: https://numpy.org/doc/stable/reference/generated/numpy.linalg.inv.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_norm_density_matrix(self, state, order="nuc"): # pragma: no cover - """Calculate norm of a density matrix. Default is the ``nuclear`` norm. + def eigvalsh(self, *args, **kwargs): + """Numpy-like eigvalsh: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigvalsh.html""" + raise NotImplementedError - If ``order="nuc"``, it returns the nuclear norm of ``state``, - assuming ``state`` is Hermitian (also known as trace norm). - For specifications on the other possible values of the - parameter ``order`` for the ``tensorflow`` backend, please refer to - `tensorflow.norm `_. - For all other backends, please refer to - `numpy.linalg.norm `_. - """ - raise_error(NotImplementedError) + @abc.abstractmethod + def eigvals(self, *args, **kwargs): + """Eigenvalues of a matrix: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigvals.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_overlap(self, state1, state2): # pragma: no cover - """Calculate overlap of two state vectors.""" - raise_error(NotImplementedError) + def eigh(self, *args, **kwargs): + """Numpy-like eigvals: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigh.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_overlap_density_matrix(self, state1, state2): # pragma: no cover - """Calculate overlap of two density matrices.""" - raise_error(NotImplementedError) + def eig(self, *args, **kwargs): + """Numpy-like eig: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eig.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_eigenvalues( - self, matrix, k: int = 6, hermitian: bool = True - ): # pragma: no cover - """Calculate eigenvalues of a matrix.""" - raise_error(NotImplementedError) + def expm(self, *args, **kwargs): + """Scipy-like expm: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.expm.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_eigenvectors( - self, matrix, k: int = 6, hermitian: bool = True - ): # pragma: no cover - """Calculate eigenvectors of a matrix.""" - raise_error(NotImplementedError) + def fractional_matrix_power(self, A, t): + """Scipy-like fractional_matrix_power: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.fractional_matrix_power.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_expectation_state( - self, hamiltonian, state, normalize - ): # pragma: no cover - """Calculate expectation value of a state vector given the observable matrix.""" - raise_error(NotImplementedError) + def block_diag(self, *args, **kwargs): + """Scipy-like block_diag: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.block_diag.html""" + raise NotImplementedError + + # sparse + # ^^^^^^ @abc.abstractmethod - def calculate_expectation_density_matrix( - self, hamiltonian, state, normalize - ): # pragma: no cover - """Calculate expectation value of a density matrix given the observable matrix.""" + def is_sparse(self, x): # pragma: no cover + """Scipy-like issparse: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.issparse.html""" raise_error(NotImplementedError) @abc.abstractmethod - def calculate_matrix_exp( - self, a, matrix, eigenvectors=None, eigenvalues=None - ): # pragma: no cover - """Calculate matrix exponential of a matrix. - If the eigenvectors and eigenvalues are given the matrix diagonalization is - used for exponentiation. - """ - raise_error(NotImplementedError) + def sparse_csr_matrix(self, *args, **kwargs): + """Scipy-like sparse csr matrix: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_matrix_power( - self, matrix, power: Union[float, int], precision_singularity: float = 1e-14 - ): # pragma: no cover - """Calculate the (fractional) ``power`` :math:`\\alpha` of ``matrix`` :math:`A`, - i.e. :math:`A^{\\alpha}`. - - .. note:: - For the ``pytorch`` backend, this method relies on a copy of the original tensor. - This may break the gradient flow. For the GPU backends (i.e. ``cupy`` and - ``cuquantum``), this method falls back to CPU whenever ``power`` is not - an integer. - """ - raise_error(NotImplementedError) + def sparse_eye(self, *args, **kwargs): + """Scipy-like sparse eye: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.eye.html""" + raise NotImplementedError + + @abc.abstractmethod + def to_dense(self, *args, **kwargs): + """Scipy-like sparse to dense: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.toarray.html""" + raise NotImplementedError + + @abc.abstractmethod + def sparse_expm(self, A): + """Scipy-like sparse expm: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.expm.html""" + raise NotImplementedError @abc.abstractmethod - def calculate_singular_value_decomposition(self, matrix): # pragma: no cover - """Calculate the Singular Value Decomposition of ``matrix``.""" + def sparse_eigsh(self, *args, **kwargs): + """Scipy-like sparse eigsh: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.eigsh.html""" + raise NotImplementedError + + # randomization + # ^^^^^^^^^^^^^ + + @abc.abstractmethod + def random_choice(self, *args, **kwargs): + """Numpy-like random.choice: https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html""" raise_error(NotImplementedError) @abc.abstractmethod - def calculate_jacobian_matrix( - self, circuit, parameters, initial_state=None, return_complex: bool = True - ): # pragma: no cover - """Calculate the Jacobian matrix of ``circuit`` with respect to varables ``params``.""" + def seed(self, *args, **kwargs): + """Numpy-like random seed: https://numpy.org/devdocs/reference/random/generated/numpy.random.seed.html""" + raise NotImplementedError + + @abc.abstractmethod + def permutation(self, *args, **kwargs): + """Numpy-like random permutation: https://numpy.org/doc/stable/reference/random/generated/numpy.random.permutation.html""" + raise NotImplementedError + + @abc.abstractmethod + def multinomial(self, *args, **kwargs): + """Numpy-like multinomial: https://numpy.org/doc/2.0/reference/random/generated/numpy.random.multinomial.html""" + raise NotImplementedError + + @abc.abstractmethod + def default_rng(self, *args, **kwargs): + """Numpy-like random default_rng: https://numpy.org/doc/stable/reference/random/generator.html""" + raise NotImplementedError + + @abc.abstractmethod + def rand(self, *args, **kwargs): + """Numpy-like random rand: https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html""" + raise NotImplementedError + + # logical operations + # ^^^^^^^^^^^^^^^^^^ + + @abc.abstractmethod + def less(self, *args, **kwargs): + """Numpy-like less: https://numpy.org/doc/stable/reference/generated/numpy.less.html""" + raise NotImplementedError + + @abc.abstractmethod + def any(self, *args, **kwargs): + """Numpy-like any: https://numpy.org/doc/stable/reference/generated/numpy.any.html""" + raise NotImplementedError + + @abc.abstractmethod + def allclose(self, *args, **kwargs): + """Numpy-like allclose: https://numpy.org/doc/stable/reference/generated/numpy.allclose.html""" + raise NotImplementedError + + @abc.abstractmethod + def right_shift(self, *args, **kwargs): + """Numpy-like element-wise right shift: https://numpy.org/doc/stable/reference/generated/numpy.right_shift.html""" + raise NotImplementedError + + # mathematical operations + # ^^^^^^^^^^^^^^^^^^^^^^^ + + @abc.abstractmethod + def sum(self, *args, **kwargs): + """Numpy-like sum: https://numpy.org/devdocs/reference/generated/numpy.sum.html""" + raise NotImplementedError + + @abc.abstractmethod + def conj(self, *args, **kwargs): + """Numpy-like conj: https://numpy.org/devdocs/reference/generated/numpy.conj.html""" raise_error(NotImplementedError) @abc.abstractmethod - def calculate_hamiltonian_matrix_product( - self, matrix1, matrix2 - ): # pragma: no cover - """Multiply two matrices.""" + def exp(self, *args, **kwargs): + """Numpy-like exp: https://numpy.org/devdocs/reference/generated/numpy.exp.html""" raise_error(NotImplementedError) @abc.abstractmethod - def calculate_hamiltonian_state_product(self, matrix, state): # pragma: no cover - """Multiply a matrix to a state vector or density matrix.""" + def log(self, *args, **kwargs): + """Numpy-like log: https://numpy.org/doc/stable/reference/generated/numpy.log.html""" + raise NotImplementedError + + @abc.abstractmethod + def log2(self, *args, **kwargs): + """Numpy-like log2: https://numpy.org/doc/stable/reference/generated/numpy.log2.html""" + raise NotImplementedError + + @abc.abstractmethod + def real(self, *args, **kwargs): + """Numpy-like real: https://numpy.org/devdocs/reference/generated/numpy.real.html""" + raise NotImplementedError + + @abc.abstractmethod + def imag(self, *args, **kwargs): + """Numpy-like imag: https://numpy.org/doc/stable/reference/generated/numpy.imag.html""" + raise NotImplementedError + + @abc.abstractmethod + def abs(self, *args, **kwargs): + """Numpy-like abs: https://numpy.org/devdocs/reference/generated/numpy.abs.html""" + raise NotImplementedError + + @abc.abstractmethod + def pow(self, *args, **kwargs): + """Numpy-like element-wise power: https://numpy.org/doc/stable/reference/generated/numpy.power.html""" + raise NotImplementedError + + @abc.abstractmethod + def square(self, *args, **kwargs): + """Numpy-like element-wise square: https://numpy.org/doc/stable/reference/generated/numpy.square.html""" + raise NotImplementedError + + @abc.abstractmethod + def sqrt(self, *args, **kwargs): + """Numpy-like sqrt: https://numpy.org/devdocs/reference/generated/numpy.sqrt.html""" + raise NotImplementedError + + @abc.abstractmethod + def mean(self, *args, **kwargs): + """Numpy-like mean: https://numpy.org/doc/stable/reference/generated/numpy.mean.html""" + raise NotImplementedError + + @abc.abstractmethod + def std(self, *args, **kwargs): + """Numpy-like standard deviation: https://numpy.org/doc/stable/reference/generated/numpy.std.html""" + raise NotImplementedError + + @abc.abstractmethod + def cos(self, *args, **kwargs): + """Numpy-like cos: https://numpy.org/devdocs/reference/generated/numpy.cos.html""" raise_error(NotImplementedError) @abc.abstractmethod - def assert_allclose(self, value, target, rtol=1e-7, atol=0.0): # pragma: no cover + def sin(self, *args, **kwargs): + """Numpy-like sin: https://numpy.org/devdocs/reference/generated/numpy.sin.html""" raise_error(NotImplementedError) - def assert_circuitclose(self, circuit, target_circuit, rtol=1e-7, atol=0.0): - value = self.execute_circuit(circuit)._state - target = self.execute_circuit(target_circuit)._state - self.assert_allclose(value, target, rtol=rtol, atol=atol) + @abc.abstractmethod + def arccos(self, *args, **kwargs): + """Numpy-like arccos: https://numpy.org/doc/stable/reference/generated/numpy.arccos.html""" + raise NotImplementedError @abc.abstractmethod - def _test_regressions(self, name): # pragma: no cover - """Correct outcomes for tests that involve random numbers. + def arctan2(self, *args, **kwargs): + """Numpy-like arctan2: https://numpy.org/doc/stable/reference/generated/numpy.arctan2.html""" + raise NotImplementedError - The outcomes of such tests depend on the backend. - """ + @abc.abstractmethod + def angle(self, *args, **kwargs): + """Numpy-like angle: https://numpy.org/doc/stable/reference/generated/numpy.angle.html""" + raise NotImplementedError + + @abc.abstractmethod + def mod(self, *args, **kwargs): + """Numpy-like element-wise mod: https://numpy.org/doc/stable/reference/generated/numpy.mod.html""" + raise NotImplementedError + + @abc.abstractmethod + def round(self, *args, **kwargs): + """Numpy-like element-wise round: https://numpy.org/doc/stable/reference/generated/numpy.round.html""" + raise NotImplementedError + + # misc + # ^^^^ + + @abc.abstractmethod + def sort(self, *args, **kwargs): + """Numpy-like sort: https://numpy.org/doc/stable/reference/generated/numpy.sort.html""" + raise NotImplementedError + + @abc.abstractmethod + def argsort(self, *args, **kwargs): + """Numpy-like argsort: https://numpy.org/doc/stable/reference/generated/numpy.argsort.html""" + raise NotImplementedError + + @abc.abstractmethod + def count_nonzero(self, *args, **kwargs): + """Numpy-like count_nonzero: https://numpy.org/doc/stable/reference/generated/numpy.count_nonzero.html""" + raise NotImplementedError + + @abc.abstractmethod + def finfo(self, *args, **kwargs): + """Numpy-like finfo: https://numpy.org/doc/stable/reference/generated/numpy.finfo.html""" + raise NotImplementedError + + @abc.abstractmethod + def __version__( + self, + ): + """Version of the backend engine.""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def get_dtype(self, type_name: str): + """Backend engine dtype""" raise_error(NotImplementedError) + + @abc.abstractmethod + def assert_allclose(self, *args, **kwargs): + """Numpy-like testing.assert_allclose: https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_allclose.html""" + raise NotImplementedError + + # Optimization + # ^^^^^^^^^^^^^ + + @abc.abstractmethod + def jacobian(self, *args, **kwargs): + """Compute the Jacobian matrix""" + raise NotImplementedError + + +# backend methods used for the execution + +# cast +# zero_state/density_matrix +# apply_gate/... +# mean +# reshape +# transpose +# einsum +# concatenate +# conj +# sum +# sample_shots diff --git a/src/qibo/backends/abstract_execution.py b/src/qibo/backends/abstract_execution.py new file mode 100644 index 0000000000..8f2a8df9d9 --- /dev/null +++ b/src/qibo/backends/abstract_execution.py @@ -0,0 +1,617 @@ +import abc +import collections +from typing import Generic, Optional, TypeVar, Union + +from qibo.backends import einsum_utils +from qibo.config import raise_error +from qibo.result import CircuitResult, MeasurementOutcomes, QuantumState + +array = Generic[TypeVar("array")] + + +class Backend(abc.ABC): + def __init__(self): + super().__init__() + self.name = "backend" + self.platform = None + + self.precision = "double" + self.dtype = "complex128" + self.matrices = None + + self.device = "/CPU:0" + self.nthreads = 1 + self.supports_multigpu = False + self.oom_error = MemoryError + + def __reduce__(self): + """Allow pickling backend objects that have references to modules.""" + return self.__class__, tuple() + + def __repr__(self): + if self.platform is None: + return self.name + else: + return f"{self.name} ({self.platform})" + + @property + @abc.abstractmethod + def qubits(self) -> Optional[list[Union[int, str]]]: # pragma: no cover + """Return the qubit names of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + + @property + @abc.abstractmethod + def connectivity( + self, + ) -> Optional[list[tuple[Union[int, str], Union[int, str]]]]: # pragma: no cover + """Return the available qubit pairs of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + + @property + @abc.abstractmethod + def natives(self) -> Optional[list[str]]: # pragma: no cover + """Return the native gates of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def set_precision(self, precision): # pragma: no cover + """Set complex number precision. + + Args: + precision (str): 'single' or 'double'. + """ + raise_error(NotImplementedError) + + @abc.abstractmethod + def set_device(self, device): # pragma: no cover + """Set simulation device. + + Args: + device (str): Device such as '/CPU:0', '/GPU:0', etc. + """ + raise_error(NotImplementedError) + + @abc.abstractmethod + def set_threads(self, nthreads): # pragma: no cover + """Set number of threads for CPU simulation. + + Args: + nthreads (int): Number of threads. + """ + raise_error(NotImplementedError) + + @abc.abstractmethod + def cast(self, x, dtype=None, copy=False): # pragma: no cover + """Cast an object as the array type of the current backend. + + Args: + x: Object to cast to array. + dtype: native backend array dtype. + copy (bool): If ``True`` a copy of the object is created in memory. + """ + raise_error(NotImplementedError) + + @abc.abstractmethod + def to_numpy(self, x: array): # pragma: no cover + """Cast a given array to numpy.""" + raise_error(NotImplementedError) + + # initial state + # ^^^^^^^^^^^^^ + + def zero_state(self, nqubits: int) -> array: + state = self.zeros(2**nqubits, dtype=self.dtype) + state[0] = 1 + return state + + def zero_density_matrix(self, nqubits): + state = self.zeros(2 * (2**nqubits,), dtype=self.dtype) + state[0, 0] = 1 + return state + + # matrix representation + # ^^^^^^^^^^^^^^^^^^^^^ + + def matrix(self, gate): + """Convert a gate to its matrix representation in the computational basis.""" + name = gate.__class__.__name__ + _matrix = getattr(self.matrices, name) + if callable(_matrix): + _matrix = _matrix(2 ** len(gate.target_qubits)) + return self.cast(_matrix, dtype=_matrix.dtype) + + def matrix_parametrized(self, gate): + """Convert a parametrized gate to its matrix representation in the computational basis.""" + name = gate.__class__.__name__ + _matrix = getattr(self.matrices, name) + if name == "GeneralizedRBS": + _matrix = _matrix( + qubits_in=gate.init_args[0], + qubits_out=gate.init_args[1], + theta=gate.init_kwargs["theta"], + phi=gate.init_kwargs["phi"], + ) + else: + _matrix = _matrix(*gate.parameters) + return self.cast(_matrix, dtype=_matrix.dtype) + + def matrix_fused(self, fgate): + rank = len(fgate.target_qubits) + matrix = self.sparse_eye(2**rank) + + for gate in fgate.gates: + # transfer gate matrix to numpy as it is more efficient for + # small tensor calculations + # explicit to_numpy see https://github.com/qiboteam/qibo/issues/928 + # --> not sure whether going to numpy is still optimal in every case + gmatrix = self.to_numpy(gate.matrix(self)) + # add controls if controls were instantiated using + # the ``Gate.controlled_by`` method + num_controls = len(gate.control_qubits) + if num_controls > 0: + gmatrix = self.block_diag( + self.eye(2 ** len(gate.qubits) - len(gmatrix)), gmatrix + ) + # Kronecker product with identity is needed to make the + # original matrix have shape (2**rank x 2**rank) + eye = self.eye(2 ** (rank - len(gate.qubits))) + gmatrix = self.kron(gmatrix, eye) + # Transpose the new matrix indices so that it targets the + # target qubits of the original gate + original_shape = gmatrix.shape + gmatrix = self.reshape(gmatrix, 2 * rank * (2,)) + qubits = list(gate.qubits) + indices = qubits + [q for q in fgate.target_qubits if q not in qubits] + indices = self.argsort(indices) + transpose_indices = list(indices) + transpose_indices.extend(indices + rank) + gmatrix = self.transpose(gmatrix, transpose_indices) + gmatrix = self.reshape(gmatrix, original_shape) + # fuse the individual gate matrix to the total ``FusedGate`` matrix + # we are using sparse matrices to improve perfomances + matrix = self.sparse_csr_matrix(gmatrix).dot(matrix) + + return self.cast(self.to_dense(matrix)) + + # gate application + # ^^^^^^^^^^^^^^^^ + + def apply_gate(self, gate, state, nqubits): + state = self.reshape(state, nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: + matrix = self.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) + ncontrol = len(gate.control_qubits) + nactive = nqubits - ncontrol + order, targets = einsum_utils.control_order(gate, nqubits) + state = self.transpose(state, order) + # Apply `einsum` only to the part of the state where all controls + # are active. This should be `state[-1]` + state = self.reshape(state, (2**ncontrol,) + nactive * (2,)) + opstring = einsum_utils.apply_gate_string(targets, nactive) + updates = self.einsum(opstring, state[-1], matrix) + # Concatenate the updated part of the state `updates` with the + # part of of the state that remained unaffected `state[:-1]`. + state = self.concatenate([state[:-1], updates[None]], axis=0) + state = self.reshape(state, nqubits * (2,)) + # Put qubit indices back to their proper places + state = self.transpose(state, einsum_utils.reverse_order(order)) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + opstring = einsum_utils.apply_gate_string(gate.qubits, nqubits) + state = self.einsum(opstring, state, matrix) + return self.reshape(state, (2**nqubits,)) + + def apply_gate_density_matrix(self, gate, state, nqubits): + state = self.cast(state) + state = self.reshape(state, 2 * nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: + matrix = self.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) + matrixc = self.conj(matrix) + ncontrol = len(gate.control_qubits) + nactive = nqubits - ncontrol + n = 2**ncontrol + + order, targets = einsum_utils.control_order_density_matrix(gate, nqubits) + state = self.transpose(state, order) + state = self.reshape(state, 2 * (n,) + 2 * nactive * (2,)) + + leftc, rightc = einsum_utils.apply_gate_density_matrix_controlled_string( + targets, nactive + ) + state01 = state[: n - 1, n - 1] + state01 = self.einsum(rightc, state01, matrixc) + state10 = state[n - 1, : n - 1] + state10 = self.einsum(leftc, state10, matrix) + + left, right = einsum_utils.apply_gate_density_matrix_string( + targets, nactive + ) + state11 = state[n - 1, n - 1] + state11 = self.einsum(right, state11, matrixc) + state11 = self.einsum(left, state11, matrix) + + state00 = state[range(n - 1)] + state00 = state00[:, range(n - 1)] + state01 = self.concatenate([state00, state01[:, None]], axis=1) + state10 = self.concatenate([state10, state11[None]], axis=0) + state = self.concatenate([state01, state10[None]], axis=0) + state = self.reshape(state, 2 * nqubits * (2,)) + state = self.transpose(state, einsum_utils.reverse_order(order)) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + matrixc = self.conj(matrix) + left, right = einsum_utils.apply_gate_density_matrix_string( + gate.qubits, nqubits + ) + state = self.einsum(right, state, matrixc) + state = self.einsum(left, state, matrix) + return self.reshape(state, 2 * (2**nqubits,)) + + def apply_gate_half_density_matrix(self, gate, state, nqubits): + state = self.cast(state) + state = self.reshape(state, 2 * nqubits * (2,)) + matrix = gate.matrix(self) + if gate.is_controlled_by: # pragma: no cover + raise_error( + NotImplementedError, + "Gate density matrix half call is " + "not implemented for ``controlled_by``" + "gates.", + ) + else: + matrix = self.reshape(matrix, 2 * len(gate.qubits) * (2,)) + left, _ = einsum_utils.apply_gate_density_matrix_string( + gate.qubits, nqubits + ) + state = self.einsum(left, state, matrix) + return self.reshape(state, 2 * (2**nqubits,)) + + def apply_channel(self, channel, state, nqubits): + probabilities = channel.coefficients + (1 - self.sum(channel.coefficients),) + index = self.sample_shots(probabilities, 1)[0] + if index != len(channel.gates): + gate = channel.gates[index] + state = self.apply_gate(gate, state, nqubits) + return state + + def apply_channel_density_matrix(self, channel, state, nqubits): + state = self.cast(state) + new_state = (1 - channel.coefficient_sum) * state + for coeff, gate in zip(channel.coefficients, channel.gates): + new_state += coeff * self.apply_gate_density_matrix(gate, state, nqubits) + return new_state + + # circuit execution + # ^^^^^^^^^^^^^^^^^ + + def execute_circuit(self, circuit, initial_state=None, nshots=1000): + + if isinstance(initial_state, type(circuit)): + if not initial_state.density_matrix == circuit.density_matrix: + raise_error( + ValueError, + f"""Cannot set circuit with density_matrix {initial_state.density_matrix} as + initial state for circuit with density_matrix {circuit.density_matrix}.""", + ) + elif ( + not initial_state.accelerators == circuit.accelerators + ): # pragma: no cover + raise_error( + ValueError, + f"""Cannot set circuit with accelerators {initial_state.density_matrix} as + initial state for circuit with accelerators {circuit.density_matrix}.""", + ) + else: + return self.execute_circuit(initial_state + circuit, None, nshots) + elif initial_state is not None: + initial_state = self.cast(initial_state) + valid_shape = ( + 2 * (2**circuit.nqubits,) + if circuit.density_matrix + else (2**circuit.nqubits,) + ) + if tuple(initial_state.shape) != valid_shape: + raise_error( + ValueError, + f"Given initial state has shape {initial_state.shape} instead of " + f"the expected {valid_shape}.", + ) + + if circuit.repeated_execution: + if circuit.measurements or circuit.has_collapse: + return self.execute_circuit_repeated(circuit, nshots, initial_state) + else: + raise_error( + RuntimeError, + "Attempting to perform noisy simulation with `density_matrix=False` " + + "and no Measurement gate in the Circuit. If you wish to retrieve the " + + "statistics of the outcomes please include measurements in the circuit, " + + "otherwise set `density_matrix=True` to recover the final state.", + ) + + if circuit.accelerators: # pragma: no cover + return self.execute_distributed_circuit(circuit, initial_state, nshots) + + try: + nqubits = circuit.nqubits + + if circuit.density_matrix: + if initial_state is None: + state = self.zero_density_matrix(nqubits) + else: + state = self.cast(initial_state) + + for gate in circuit.queue: + state = gate.apply_density_matrix(self, state, nqubits) + + else: + if initial_state is None: + state = self.zero_state(nqubits) + else: + state = self.cast(initial_state) + + for gate in circuit.queue: + state = gate.apply(self, state, nqubits) + + if circuit.has_unitary_channel: + # here we necessarily have `density_matrix=True`, otherwise + # execute_circuit_repeated would have been called + if circuit.measurements: + circuit._final_state = CircuitResult( + state, circuit.measurements, backend=self, nshots=nshots + ) + return circuit._final_state + else: + circuit._final_state = QuantumState(state, backend=self) + return circuit._final_state + + else: + if circuit.measurements: + circuit._final_state = CircuitResult( + state, circuit.measurements, backend=self, nshots=nshots + ) + return circuit._final_state + else: + circuit._final_state = QuantumState(state, backend=self) + return circuit._final_state + + except self.oom_error: + raise_error( + RuntimeError, + f"State does not fit in {self.device} memory." + "Please switch the execution device to a " + "different one using ``qibo.set_device``.", + ) + + def execute_circuits( + self, circuits, initial_states=None, nshots=1000, processes=None + ): + from qibo.parallel import parallel_circuits_execution + + return parallel_circuits_execution( + circuits, initial_states, nshots, processes, backend=self + ) + + def execute_circuit_repeated(self, circuit, nshots, initial_state=None): + """ + Execute the circuit `nshots` times to retrieve probabilities, frequencies + and samples. Note that this method is called only if a unitary channel + is present in the circuit (i.e. noisy simulation) and `density_matrix=False`, or + if some collapsing measurement is performed. + """ + + if ( + circuit.has_collapse + and not circuit.measurements + and not circuit.density_matrix + ): + raise_error( + RuntimeError, + "The circuit contains only collapsing measurements (`collapse=True`) but " + + "`density_matrix=False`. Please set `density_matrix=True` to retrieve " + + "the final state after execution.", + ) + + results, final_states = [], [] + nqubits = circuit.nqubits + + if not circuit.density_matrix: + samples = [] + target_qubits = [ + measurement.target_qubits for measurement in circuit.measurements + ] + target_qubits = sum(target_qubits, tuple()) + + for _ in range(nshots): + if circuit.density_matrix: + if initial_state is None: + state = self.zero_density_matrix(nqubits) + else: + state = self.cast(initial_state, copy=True) + + for gate in circuit.queue: + if gate.symbolic_parameters: + gate.substitute_symbols() + state = gate.apply_density_matrix(self, state, nqubits) + else: + if circuit.accelerators: # pragma: no cover + # pylint: disable=E1111 + state = self.execute_distributed_circuit(circuit, initial_state) + else: + if initial_state is None: + state = self.zero_state(nqubits) + else: + state = self.cast(initial_state, copy=True) + + for gate in circuit.queue: + if gate.symbolic_parameters: + gate.substitute_symbols() + state = gate.apply(self, state, nqubits) + + if circuit.density_matrix: + final_states.append(state) + if circuit.measurements: + result = CircuitResult( + state, circuit.measurements, backend=self, nshots=1 + ) + sample = result.samples()[0] + results.append(sample) + if not circuit.density_matrix: + samples.append("".join([str(int(s)) for s in sample])) + for gate in circuit.measurements: + gate.result.reset() + + if circuit.density_matrix: # this implies also it has_collapse + assert circuit.has_collapse + final_state = self.mean(final_states, axis=0) + if circuit.measurements: + final_result = CircuitResult( + final_state, + circuit.measurements, + backend=self, + samples=self.concatenate(results, axis=0), + nshots=nshots, + ) + else: + final_result = QuantumState(final_state, backend=self) + circuit._final_state = final_result + return final_result + else: + final_result = MeasurementOutcomes( + circuit.measurements, + backend=self, + samples=self.concatenate(results, axis=0), + nshots=nshots, + ) + final_result._repeated_execution_frequencies = self.calculate_frequencies( + samples + ) + circuit._final_state = final_result + return final_result + + @abc.abstractmethod + def execute_distributed_circuit(self, circuit, initial_state=None, nshots=None): + raise_error(NotImplementedError) + + # shots and freq sampling + # ^^^^^^^^^^^^^^^^^^^^^^^ + + def calculate_frequencies(self, samples): + res, counts = self.unique(samples, return_counts=True) + res = self.to_numpy(res).tolist() + # I would not cast the counts to a list, but rather keep the backend array dtype + counts = self.to_numpy(counts).tolist() + return collections.Counter(dict(zip(res, counts))) + + def sample_shots(self, probabilities, nshots): + return self.random_choice( + range(len(probabilities)), size=nshots, p=probabilities + ) + + # core methods + # ^^^^^^^^^^^^ + + # array creation and manipulation + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + @abc.abstractmethod + def zeros(self, *args, **kwargs): + """Numpy-like zeros: https://numpy.org/devdocs/reference/generated/numpy.zeros.html""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def eye(self, *args, **kwargs): + """Numpy-like eye: https://numpy.org/devdocs/reference/generated/numpy.eye.html""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def reshape(self, *args, **kwargs): + """Numpy-like reshape: https://numpy.org/devdocs/reference/generated/numpy.reshape.html""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def transpose(self, *args, **kwargs): + """Numpy-like transpose: https://numpy.org/devdocs/reference/generated/numpy.transpose.html""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def concatenate(self, *args, **kwargs): + """Numpy-like concatenate: https://numpy.org/devdocs/reference/generated/numpy.concatenate.html""" + raise NotImplementedError + + @abc.abstractmethod + def argsort(self, *args, **kwargs): + """Numpy-like argsort: https://numpy.org/doc/stable/reference/generated/numpy.argsort.html""" + raise NotImplementedError + + @abc.abstractmethod + def unique(self, *args, **kwargs): + """Numpy-like unique: https://numpy.org/devdocs/reference/generated/numpy.unique.html""" + raise NotImplementedError + + # basic math + # ^^^^^^^^^^ + + @abc.abstractmethod + def conj(self, *args, **kwargs): + """Numpy-like conj: https://numpy.org/devdocs/reference/generated/numpy.conj.html""" + raise_error(NotImplementedError) + + @abc.abstractmethod + def sum(self, *args, **kwargs): + """Numpy-like sum: https://numpy.org/devdocs/reference/generated/numpy.sum.html""" + raise NotImplementedError + + @abc.abstractmethod + def mean(self, *args, **kwargs): + """Numpy-like mean: https://numpy.org/doc/stable/reference/generated/numpy.mean.html""" + raise NotImplementedError + + # linear algebra + # ^^^^^^^^^^^^^^ + + # shall we keep only einsum + @abc.abstractmethod + def einsum(self, *args, **kwargs): + """Numpy-like einsum: https://numpy.org/devdocs/reference/generated/numpy.einsum.html""" + raise NotImplementedError + + # this can probably be done through einsum + @abc.abstractmethod + def kron(self, *args, **kwargs): + """Numpy-like kron: https://numpy.org/doc/stable/reference/generated/numpy.kron.html""" + raise NotImplementedError + + @abc.abstractmethod + def block_diag(self, *args, **kwargs): + """Scipy-like block_diag: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.block_diag.html""" + raise NotImplementedError + + # sparse utils + # ^^^^^^^^^^^^ + + @abc.abstractmethod + def sparse_csr_matrix(self, *args, **kwargs): + """Scipy-like sparse csr matrix: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html""" + raise NotImplementedError + + @abc.abstractmethod + def sparse_eye(self, *args, **kwargs): + """Scipy-like sparse eye: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.eye.html""" + raise NotImplementedError + + @abc.abstractmethod + def to_dense(self, *args, **kwargs): + """Scipy-like sparse to dense: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.toarray.html""" + raise NotImplementedError + + # random utils + # ^^^^^^^^^^^^ + + @abc.abstractmethod + def random_choice(self, *args, **kwargs): + """Numpy-like random.choice: https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html""" + raise_error(NotImplementedError) diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index daef2a4606..426aa0733b 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -1,27 +1,22 @@ -import collections -import math -from typing import Union +from functools import cache import numpy as np +import scipy as sp from scipy import sparse -from scipy.linalg import block_diag, fractional_matrix_power from qibo import __version__ -from qibo.backends import einsum_utils from qibo.backends.abstract import Backend from qibo.backends.npmatrices import NumpyMatrices -from qibo.config import log, raise_error -from qibo.result import CircuitResult, MeasurementOutcomes, QuantumState +from qibo.config import raise_error class NumpyBackend(Backend): def __init__(self): super().__init__() - self.np = np self.name = "numpy" self.matrices = NumpyMatrices(self.dtype) self.tensor_types = np.ndarray - self.versions = {"qibo": __version__, "numpy": self.np.__version__} + self.versions = {"qibo": __version__, "numpy": np.__version__} self.numeric_types = ( int, float, @@ -78,797 +73,504 @@ def cast(self, x, dtype=None, copy=False): return x.astype(dtype, copy=copy) return np.array(x, dtype=dtype, copy=copy) - def is_sparse(self, x): - from scipy import sparse - - return sparse.issparse(x) - def to_numpy(self, x): if self.is_sparse(x): - return x.toarray() + return self.to_dense(x) return x def compile(self, func): return func - def zero_state(self, nqubits): - state = self.np.zeros(2**nqubits, dtype=self.dtype) - state[0] = 1 - return state - - def zero_density_matrix(self, nqubits): - state = self.np.zeros(2 * (2**nqubits,), dtype=self.dtype) - state[0, 0] = 1 - return state - - def identity_density_matrix(self, nqubits, normalize: bool = True): - state = self.np.eye(2**nqubits, dtype=self.dtype) - if normalize is True: - state /= 2**nqubits - return state - - def plus_state(self, nqubits): - state = self.np.ones(2**nqubits, dtype=self.dtype) - state /= math.sqrt(2**nqubits) - return state - - def plus_density_matrix(self, nqubits): - state = self.np.ones(2 * (2**nqubits,), dtype=self.dtype) - state /= 2**nqubits - return state - - def matrix(self, gate): - """Convert a gate to its matrix representation in the computational basis.""" - name = gate.__class__.__name__ - _matrix = getattr(self.matrices, name) - if callable(_matrix): - _matrix = _matrix(2 ** len(gate.target_qubits)) - return self.cast(_matrix, dtype=_matrix.dtype) - - def matrix_parametrized(self, gate): - """Convert a parametrized gate to its matrix representation in the computational basis.""" - name = gate.__class__.__name__ - _matrix = getattr(self.matrices, name) - if name == "GeneralizedRBS": - _matrix = _matrix( - qubits_in=gate.init_args[0], - qubits_out=gate.init_args[1], - theta=gate.init_kwargs["theta"], - phi=gate.init_kwargs["phi"], - ) - else: - _matrix = _matrix(*gate.parameters) - return self.cast(_matrix, dtype=_matrix.dtype) - - def matrix_fused(self, fgate): - rank = len(fgate.target_qubits) - matrix = sparse.eye(2**rank) - - for gate in fgate.gates: - # transfer gate matrix to numpy as it is more efficient for - # small tensor calculations - # explicit to_numpy see https://github.com/qiboteam/qibo/issues/928 - gmatrix = self.to_numpy(gate.matrix(self)) - # add controls if controls were instantiated using - # the ``Gate.controlled_by`` method - num_controls = len(gate.control_qubits) - if num_controls > 0: - gmatrix = block_diag( - np.eye(2 ** len(gate.qubits) - len(gmatrix)), gmatrix - ) - # Kronecker product with identity is needed to make the - # original matrix have shape (2**rank x 2**rank) - eye = np.eye(2 ** (rank - len(gate.qubits))) - gmatrix = np.kron(gmatrix, eye) - # Transpose the new matrix indices so that it targets the - # target qubits of the original gate - original_shape = gmatrix.shape - gmatrix = np.reshape(gmatrix, 2 * rank * (2,)) - qubits = list(gate.qubits) - indices = qubits + [q for q in fgate.target_qubits if q not in qubits] - indices = np.argsort(indices) - transpose_indices = list(indices) - transpose_indices.extend(indices + rank) - gmatrix = np.transpose(gmatrix, transpose_indices) - gmatrix = np.reshape(gmatrix, original_shape) - # fuse the individual gate matrix to the total ``FusedGate`` matrix - # we are using sparse matrices to improve perfomances - matrix = sparse.csr_matrix(gmatrix).dot(matrix) - - return self.cast(matrix.toarray()) - - def apply_gate(self, gate, state, nqubits): - state = self.np.reshape(state, nqubits * (2,)) - matrix = gate.matrix(self) - if gate.is_controlled_by: - matrix = self.np.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) - ncontrol = len(gate.control_qubits) - nactive = nqubits - ncontrol - order, targets = einsum_utils.control_order(gate, nqubits) - state = self.np.transpose(state, order) - # Apply `einsum` only to the part of the state where all controls - # are active. This should be `state[-1]` - state = self.np.reshape(state, (2**ncontrol,) + nactive * (2,)) - opstring = einsum_utils.apply_gate_string(targets, nactive) - updates = self.np.einsum(opstring, state[-1], matrix) - # Concatenate the updated part of the state `updates` with the - # part of of the state that remained unaffected `state[:-1]`. - state = self.np.concatenate([state[:-1], updates[None]], axis=0) - state = self.np.reshape(state, nqubits * (2,)) - # Put qubit indices back to their proper places - state = self.np.transpose(state, einsum_utils.reverse_order(order)) - else: - matrix = self.np.reshape(matrix, 2 * len(gate.qubits) * (2,)) - opstring = einsum_utils.apply_gate_string(gate.qubits, nqubits) - state = self.np.einsum(opstring, state, matrix) - return self.np.reshape(state, (2**nqubits,)) - - def apply_gate_density_matrix(self, gate, state, nqubits): - state = self.cast(state) - state = self.np.reshape(state, 2 * nqubits * (2,)) - matrix = gate.matrix(self) - if gate.is_controlled_by: - matrix = self.np.reshape(matrix, 2 * len(gate.target_qubits) * (2,)) - matrixc = self.np.conj(matrix) - ncontrol = len(gate.control_qubits) - nactive = nqubits - ncontrol - n = 2**ncontrol - - order, targets = einsum_utils.control_order_density_matrix(gate, nqubits) - state = self.np.transpose(state, order) - state = self.np.reshape(state, 2 * (n,) + 2 * nactive * (2,)) - - leftc, rightc = einsum_utils.apply_gate_density_matrix_controlled_string( - targets, nactive - ) - state01 = state[: n - 1, n - 1] - state01 = self.np.einsum(rightc, state01, matrixc) - state10 = state[n - 1, : n - 1] - state10 = self.np.einsum(leftc, state10, matrix) - - left, right = einsum_utils.apply_gate_density_matrix_string( - targets, nactive - ) - state11 = state[n - 1, n - 1] - state11 = self.np.einsum(right, state11, matrixc) - state11 = self.np.einsum(left, state11, matrix) - - state00 = state[range(n - 1)] - state00 = state00[:, range(n - 1)] - state01 = self.np.concatenate([state00, state01[:, None]], axis=1) - state10 = self.np.concatenate([state10, state11[None]], axis=0) - state = self.np.concatenate([state01, state10[None]], axis=0) - state = self.np.reshape(state, 2 * nqubits * (2,)) - state = self.np.transpose(state, einsum_utils.reverse_order(order)) - else: - matrix = self.np.reshape(matrix, 2 * len(gate.qubits) * (2,)) - matrixc = self.np.conj(matrix) - left, right = einsum_utils.apply_gate_density_matrix_string( - gate.qubits, nqubits - ) - state = self.np.einsum(right, state, matrixc) - state = self.np.einsum(left, state, matrix) - return self.np.reshape(state, 2 * (2**nqubits,)) - - def apply_gate_half_density_matrix(self, gate, state, nqubits): - state = self.cast(state) - state = self.np.reshape(state, 2 * nqubits * (2,)) - matrix = gate.matrix(self) - if gate.is_controlled_by: # pragma: no cover - raise_error( - NotImplementedError, - "Gate density matrix half call is " - "not implemented for ``controlled_by``" - "gates.", - ) - else: - matrix = self.np.reshape(matrix, 2 * len(gate.qubits) * (2,)) - left, _ = einsum_utils.apply_gate_density_matrix_string( - gate.qubits, nqubits - ) - state = self.np.einsum(left, state, matrix) - return self.np.reshape(state, 2 * (2**nqubits,)) - - def apply_channel(self, channel, state, nqubits): - probabilities = channel.coefficients + (1 - np.sum(channel.coefficients),) - index = self.sample_shots(probabilities, 1)[0] - if index != len(channel.gates): - gate = channel.gates[index] - state = self.apply_gate(gate, state, nqubits) - return state - - def apply_channel_density_matrix(self, channel, state, nqubits): - state = self.cast(state) - new_state = (1 - channel.coefficient_sum) * state - for coeff, gate in zip(channel.coefficients, channel.gates): - new_state += coeff * self.apply_gate_density_matrix(gate, state, nqubits) - return new_state - - def _append_zeros(self, state, qubits, results): - """Helper method for collapse.""" - for q, r in zip(qubits, results): - state = self.np.expand_dims(state, q) - state = ( - self.np.concatenate([self.np.zeros_like(state), state], q) - if r == 1 - else self.np.concatenate([state, self.np.zeros_like(state)], q) - ) - return state - - def collapse_state(self, state, qubits, shot, nqubits, normalize=True): - state = self.cast(state) - shape = state.shape - binshot = self.samples_to_binary(shot, len(qubits))[0] - state = self.np.reshape(state, nqubits * (2,)) - order = list(qubits) + [q for q in range(nqubits) if q not in qubits] - state = self.np.transpose(state, order) - subshape = (2 ** len(qubits),) + (nqubits - len(qubits)) * (2,) - state = self.np.reshape(state, subshape)[int(shot)] - if normalize: - norm = self.np.sqrt(self.np.sum(self.np.abs(state) ** 2)) - state = state / norm - state = self._append_zeros(state, qubits, binshot) - return self.np.reshape(state, shape) - - def collapse_density_matrix(self, state, qubits, shot, nqubits, normalize=True): - state = self.cast(state) - shape = state.shape - binshot = list(self.samples_to_binary(shot, len(qubits))[0]) - order = list(qubits) + [q + nqubits for q in qubits] - order.extend(q for q in range(nqubits) if q not in qubits) - order.extend(q + nqubits for q in range(nqubits) if q not in qubits) - state = self.np.reshape(state, 2 * nqubits * (2,)) - state = self.np.transpose(state, order) - subshape = 2 * (2 ** len(qubits),) + 2 * (nqubits - len(qubits)) * (2,) - state = self.np.reshape(state, subshape)[int(shot), int(shot)] - n = 2 ** (len(state.shape) // 2) - if normalize: - norm = self.np.trace(self.np.reshape(state, (n, n))) - state = state / norm - qubits = qubits + [q + nqubits for q in qubits] - state = self._append_zeros(state, qubits, 2 * binshot) - return self.np.reshape(state, shape) - - def reset_error_density_matrix(self, gate, state, nqubits): - from qibo.gates import X # pylint: disable=C0415 - from qibo.quantum_info.linalg_operations import ( # pylint: disable=C0415 - partial_trace, - ) - - state = self.cast(state) - shape = state.shape - q = gate.target_qubits[0] - p_0, p_1 = gate.init_kwargs["p_0"], gate.init_kwargs["p_1"] - trace = partial_trace(state, (q,), backend=self) - trace = self.np.reshape(trace, 2 * (nqubits - 1) * (2,)) - zero = self.zero_density_matrix(1) - zero = self.np.tensordot(trace, zero, 0) - order = list(range(2 * nqubits - 2)) - order.insert(q, 2 * nqubits - 2) - order.insert(q + nqubits, 2 * nqubits - 1) - zero = self.np.reshape(self.np.transpose(zero, order), shape) - state = (1 - p_0 - p_1) * state + p_0 * zero - return state + p_1 * self.apply_gate_density_matrix(X(q), zero, nqubits) - - def thermal_error_density_matrix(self, gate, state, nqubits): - state = self.cast(state) - shape = state.shape - state = self.apply_gate(gate, state.ravel(), 2 * nqubits) - return self.np.reshape(state, shape) - - def depolarizing_error_density_matrix(self, gate, state, nqubits): - from qibo.quantum_info.linalg_operations import ( # pylint: disable=C0415 - partial_trace, + def execute_distributed_circuit(self, circuit, initial_state=None, nshots=None): + raise_error( + NotImplementedError, f"{self} does not support distributed execution." ) - state = self.cast(state) - shape = state.shape - q = gate.target_qubits - lam = gate.init_kwargs["lam"] - trace = partial_trace(state, q, backend=self) - trace = self.np.reshape(trace, 2 * (nqubits - len(q)) * (2,)) - identity = self.identity_density_matrix(len(q)) - identity = self.np.reshape(identity, 2 * len(q) * (2,)) - identity = self.np.tensordot(trace, identity, 0) - qubits = list(range(nqubits)) - for j in q: - qubits.pop(qubits.index(j)) - qubits.sort() - qubits += list(q) - qubit_1 = list(range(nqubits - len(q))) + list( - range(2 * (nqubits - len(q)), 2 * nqubits - len(q)) - ) - qubit_2 = list(range(nqubits - len(q), 2 * (nqubits - len(q)))) + list( - range(2 * nqubits - len(q), 2 * nqubits) + def calculate_jacobian_matrix( + self, circuit, parameters=None, initial_state=None, return_complex: bool = True + ): + raise_error( + NotImplementedError, + "This method is only implemented in backends that allow automatic differentiation, " + + "e.g. ``PytorchBackend`` and ``TensorflowBackend``.", ) - qs = [qubit_1, qubit_2] - order = [] - for qj in qs: - qj = [qj[qubits.index(i)] for i in range(len(qubits))] - order += qj - identity = self.np.reshape(self.np.transpose(identity, order), shape) - state = (1 - lam) * state + lam * identity - return state - - def execute_circuit(self, circuit, initial_state=None, nshots=1000): - - if isinstance(initial_state, type(circuit)): - if not initial_state.density_matrix == circuit.density_matrix: - raise_error( - ValueError, - f"""Cannot set circuit with density_matrix {initial_state.density_matrix} as - initial state for circuit with density_matrix {circuit.density_matrix}.""", - ) - elif ( - not initial_state.accelerators == circuit.accelerators - ): # pragma: no cover - raise_error( - ValueError, - f"""Cannot set circuit with accelerators {initial_state.density_matrix} as - initial state for circuit with accelerators {circuit.density_matrix}.""", - ) - else: - return self.execute_circuit(initial_state + circuit, None, nshots) - elif initial_state is not None: - initial_state = self.cast(initial_state) - valid_shape = ( - 2 * (2**circuit.nqubits,) - if circuit.density_matrix - else (2**circuit.nqubits,) - ) - if tuple(initial_state.shape) != valid_shape: - raise_error( - ValueError, - f"Given initial state has shape {initial_state.shape} instead of " - f"the expected {valid_shape}.", - ) - - if circuit.repeated_execution: - if circuit.measurements or circuit.has_collapse: - return self.execute_circuit_repeated(circuit, nshots, initial_state) - else: - raise_error( - RuntimeError, - "Attempting to perform noisy simulation with `density_matrix=False` " - + "and no Measurement gate in the Circuit. If you wish to retrieve the " - + "statistics of the outcomes please include measurements in the circuit, " - + "otherwise set `density_matrix=True` to recover the final state.", - ) - if circuit.accelerators: # pragma: no cover - return self.execute_distributed_circuit(circuit, initial_state, nshots) + # core methods + # ^^^^^^^^^^^^ + + # array creation and manipulation + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + @staticmethod + def eye(N, **kwargs): + """Numpy-like eye: https://numpy.org/devdocs/reference/generated/numpy.eye.html""" + return np.eye(N, **kwargs) + + @staticmethod + def zeros(shape, **kwargs): + """Numpy-like zeros: https://numpy.org/devdocs/reference/generated/numpy.zeros.html""" + return np.zeros(shape, **kwargs) + + @staticmethod + def ones(shape, **kwargs): + """Numpy-like ones: https://numpy.org/devdocs/reference/generated/numpy.ones.html""" + return np.ones(shape, **kwargs) + + @staticmethod + def arange(*args, **kwargs): + """Numpy-like arange: https://numpy.org/devdocs/reference/generated/numpy.arange.html""" + return np.arange(*args, **kwargs) + + @staticmethod + def copy(a, **kwargs): + """Numpy-like copy: https://numpy.org/devdocs/reference/generated/numpy.copy.html""" + return np.copy(a, **kwargs) + + @staticmethod + def reshape(a, shape, **kwargs): + """Numpy-like reshape: https://numpy.org/devdocs/reference/generated/numpy.reshape.html""" + return np.reshape(a, shape, **kwargs) + + @staticmethod + def ravel(a, **kwargs): + """Numpy-like reshape: https://numpy.org/devdocs/reference/generated/numpy.reshape.html""" + return np.ravel(a, **kwargs) + + @staticmethod + def transpose(a, axes=None): + """Numpy-like transpose: https://numpy.org/devdocs/reference/generated/numpy.transpose.html""" + return np.transpose(a, axes=axes) + + @staticmethod + def concatenate(*a, **kwargs): + """Numpy-like concatenate: https://numpy.org/devdocs/reference/generated/numpy.concatenate.html""" + return np.concatenate(*a, **kwargs) + + @staticmethod + def expand_dims(a, axis): + """Numpy-like expand_dims: https://numpy.org/devdocs/reference/generated/numpy.expand_dims.html""" + return np.expand_dims(a, axis) + + @staticmethod + def squeeze(a, **kwargs): + """Numpy-like squeeze: https://numpy.org/devdocs/reference/generated/numpy.squeeze.html""" + return np.squeeze(a, **kwargs) + + @staticmethod + def stack(arrays, axis=0, **kwargs): + """Numpy-like stack: https://numpy.org/devdocs/reference/generated/numpy.stack.html""" + return np.stack(arrays, axis=axis, **kwargs) + + @staticmethod + def vstack(tup, **kwargs): + """Numpy-like vstack: https://numpy.org/devdocs/reference/generated/numpy.vstack.html""" + return np.vstack(tup, **kwargs) + + @staticmethod + def unique(ar, **kwargs): + """Numpy-like unique: https://numpy.org/devdocs/reference/generated/numpy.unique.html""" + return np.unique(ar, **kwargs) + + @staticmethod + def where(condition, *args): + """Numpy-like where: https://numpy.org/doc/stable/reference/generated/numpy.where.html""" + return np.where(condition, *args) + + @staticmethod + def flip(m, axis=None): + """Numpy-like flip: https://numpy.org/doc/stable/reference/generated/numpy.flip.html""" + return np.flip(m, axis=axis) + + @staticmethod + def swapaxes(a, axis1, axis2): + """Numpy-like swapaxes: https://numpy.org/doc/stable/reference/generated/numpy.swapaxes.html""" + return np.swapaxes(a, axis1, axis2) + + @staticmethod + def diagonal(a, offset=0, axis1=0, axis2=1): + """Numpy-like diagonal: https://numpy.org/doc/stable/reference/generated/numpy.diagonal.html""" + return np.diagonal(a, offset=offset, axis1=axis1, axis2=axis2) + + @staticmethod + def nonzero(a): + """Numpy-like nonzero: https://numpy.org/doc/stable/reference/generated/numpy.nonzero.html""" + return np.nonzero(a) + + @staticmethod + def sign(a, **kwargs): + """Numpy-like element-wise sign function: https://numpy.org/doc/stable/reference/generated/numpy.sign.html""" + return np.sign(a, **kwargs) + + @staticmethod + def delete(a, obj, axis=None): + """Numpy-like element-wise delete function: https://numpy.org/doc/stable/reference/generated/numpy.delete.html""" + return np.delete(a, obj=obj, axis=axis) + + # linear algebra + # ^^^^^^^^^^^^^^ + + @staticmethod + def einsum(subscripts, *operands, **kwargs): + """Numpy-like einsum: https://numpy.org/devdocs/reference/generated/numpy.einsum.html""" + return np.einsum(subscripts, *operands, **kwargs) + + @staticmethod + def matmul(a, b, **kwargs): + """Numpy-like matmul: https://numpy.org/devdocs/reference/generated/numpy.matmul.html""" + return np.matmul(a, b, **kwargs) + + @staticmethod + def multiply(a, b, **kwargs): + """Numpy-like multiply: https://numpy.org/doc/stable/reference/generated/numpy.multiply.html""" + return np.multiply(a, b, **kwargs) + + @staticmethod + def prod(a, **kwargs): + """Numpy-like prod: https://numpy.org/doc/stable/reference/generated/numpy.prod.html""" + return np.prod(a, **kwargs) + + @staticmethod + def tensordot(a, b, axes=2): + """Numpy-like tensordot: https://numpy.org/doc/stable/reference/generated/numpy.tensordot.html""" + return np.tensordot(a, b, axes=axes) + + @staticmethod + def kron(a, b): + """Numpy-like kron: https://numpy.org/doc/stable/reference/generated/numpy.kron.html""" + return np.kron(a, b) + + @staticmethod + def outer(a, b, out=None): + """Numpy-like outer: https://numpy.org/doc/stable/reference/generated/numpy.outer.html""" + return np.outer(a, b, out=out) + + @staticmethod + def diag(a, k=0): + """Numpy-like diag: https://numpy.org/devdocs/reference/generated/numpy.diag.html""" + return np.diag(a, k=k) + + @staticmethod + def trace(a, **kwargs): + """Numpy-like trace: https://numpy.org/devdocs/reference/generated/numpy.trace.html""" + return np.trace(a, **kwargs) + + @staticmethod + def linalg_svd(a, **kwargs): + """Numpy-like linalg.svd: https://numpy.org/devdocs/reference/generated/numpy.linalg.svd.html""" + return np.linalg.svd(a, **kwargs) + + @staticmethod + def linalg_norm(a, ord=None, axis=None, keepdims=False): + """Numpy-like linalg.norm: https://numpy.org/devdocs/reference/generated/numpy.linalg.norm.html""" + return np.linalg.norm(a, ord=ord, axis=axis, keepdims=keepdims) + + @staticmethod + def det(a): + """Numpy-like matrix determinant: https://numpy.org/doc/stable/reference/generated/numpy.linalg.det.html""" + return np.linalg.det(a) + + @staticmethod + def qr(a, **kwargs): + """Numpy linear algebra QR decomposition: https://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html""" + return np.linalg.qr(a, **kwargs) + + @staticmethod + def inverse(a): + """Numpy linear algebra inverse: https://numpy.org/doc/stable/reference/generated/numpy.linalg.inv.html""" + return np.linalg.inv(a) + + @staticmethod + def eigvalsh(a, **kwargs): + """Numpy-like eigvalsh: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigvalsh.html""" + return np.linalg.eigvalsh(a, **kwargs) + + @staticmethod + def eigvals(a): + """Eigenvalues of a matrix: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigvals.html""" + return np.linalg.eigvals(a) + + @staticmethod + def eigh(a, **kwargs): + """Numpy-like eigvals: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eigh.html""" + return np.linalg.eigh(a, **kwargs) + + @staticmethod + def eig(a): + """Numpy-like eig: https://numpy.org/doc/stable/reference/generated/numpy.linalg.eig.html""" + return np.linalg.eig(a) + + @staticmethod + def expm(a): + """Scipy-like expm: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.expm.html""" + return sp.linalg.expm(a) + + @staticmethod + def fractional_matrix_power(A, t): + """Scipy-like fractional_matrix_power: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.fractional_matrix_power.html""" + return sp.linalg.fractional_matrix_power(A, t) + + @staticmethod + def block_diag(*args, **kwargs): + """Scipy-like block_diag: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.block_diag.html""" + return sp.linalg.block_diag(*args, **kwargs) + + # sparse + # ^^^^^^ + + @staticmethod + def is_sparse(x): + """Scipy-like issparse: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.issparse.html""" + return sparse.issparse(x) - try: - nqubits = circuit.nqubits + @staticmethod + def sparse_csr_matrix(*args, **kwargs): + """Scipy-like sparse csr matrix: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html""" + return sparse.csr_matrix(*args, **kwargs) - if circuit.density_matrix: - if initial_state is None: - state = self.zero_density_matrix(nqubits) - else: - state = self.cast(initial_state) + @staticmethod + def sparse_eye(*args, **kwargs): + """Scipy-like sparse eye: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.eye.html""" + return sparse.eye(*args, **kwargs) - for gate in circuit.queue: - state = gate.apply_density_matrix(self, state, nqubits) + @staticmethod + def to_dense(a): + """Scipy-like sparse to dense: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.toarray.html""" + return a.toarray() - else: - if initial_state is None: - state = self.zero_state(nqubits) - else: - state = self.cast(initial_state) - - for gate in circuit.queue: - state = gate.apply(self, state, nqubits) - - if circuit.has_unitary_channel: - # here we necessarily have `density_matrix=True`, otherwise - # execute_circuit_repeated would have been called - if circuit.measurements: - circuit._final_state = CircuitResult( - state, circuit.measurements, backend=self, nshots=nshots - ) - return circuit._final_state - else: - circuit._final_state = QuantumState(state, backend=self) - return circuit._final_state + @staticmethod + def sparse_expm(A): + """Scipy-like sparse expm: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.expm.html""" + return sparse.linalg.expm(A) - else: - if circuit.measurements: - circuit._final_state = CircuitResult( - state, circuit.measurements, backend=self, nshots=nshots - ) - return circuit._final_state - else: - circuit._final_state = QuantumState(state, backend=self) - return circuit._final_state - - except self.oom_error: - raise_error( - RuntimeError, - f"State does not fit in {self.device} memory." - "Please switch the execution device to a " - "different one using ``qibo.set_device``.", - ) + @staticmethod + def sparse_eigsh(*args, **kwargs): + """Scipy-like sparse eigsh: https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.eigsh.html""" + return sparse.linalg.eigsh(*args, **kwargs) - def execute_circuits( - self, circuits, initial_states=None, nshots=1000, processes=None - ): - from qibo.parallel import parallel_circuits_execution + # randomization + # ^^^^^^^^^^^^^ - return parallel_circuits_execution( - circuits, initial_states, nshots, processes, backend=self - ) - - def execute_circuit_repeated(self, circuit, nshots, initial_state=None): + @staticmethod + def random_choice(a, size=None, replace=True, p=None): """ - Execute the circuit `nshots` times to retrieve probabilities, frequencies - and samples. Note that this method is called only if a unitary channel - is present in the circuit (i.e. noisy simulation) and `density_matrix=False`, or - if some collapsing measurement is performed. + Numpy-like random.choice: https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html """ + return np.random.choice(a, size=size, replace=replace, p=p) - if ( - circuit.has_collapse - and not circuit.measurements - and not circuit.density_matrix - ): - raise_error( - RuntimeError, - "The circuit contains only collapsing measurements (`collapse=True`) but " - + "`density_matrix=False`. Please set `density_matrix=True` to retrieve " - + "the final state after execution.", - ) - - results, final_states = [], [] - nqubits = circuit.nqubits - - if not circuit.density_matrix: - samples = [] - target_qubits = [ - measurement.target_qubits for measurement in circuit.measurements - ] - target_qubits = sum(target_qubits, tuple()) - - for _ in range(nshots): - if circuit.density_matrix: - if initial_state is None: - state = self.zero_density_matrix(nqubits) - else: - state = self.cast(initial_state, copy=True) - - for gate in circuit.queue: - if gate.symbolic_parameters: - gate.substitute_symbols() - state = gate.apply_density_matrix(self, state, nqubits) - else: - if circuit.accelerators: # pragma: no cover - # pylint: disable=E1111 - state = self.execute_distributed_circuit(circuit, initial_state) - else: - if initial_state is None: - state = self.zero_state(nqubits) - else: - state = self.cast(initial_state, copy=True) - - for gate in circuit.queue: - if gate.symbolic_parameters: - gate.substitute_symbols() - state = gate.apply(self, state, nqubits) - - if circuit.density_matrix: - final_states.append(state) - if circuit.measurements: - result = CircuitResult( - state, circuit.measurements, backend=self, nshots=1 - ) - sample = result.samples()[0] - results.append(sample) - if not circuit.density_matrix: - samples.append("".join([str(int(s)) for s in sample])) - for gate in circuit.measurements: - gate.result.reset() - - if circuit.density_matrix: # this implies also it has_collapse - assert circuit.has_collapse - final_state = self.cast(np.mean(self.to_numpy(final_states), 0)) - if circuit.measurements: - final_result = CircuitResult( - final_state, - circuit.measurements, - backend=self, - samples=self.aggregate_shots(results), - nshots=nshots, - ) - else: - final_result = QuantumState(final_state, backend=self) - circuit._final_state = final_result - return final_result - else: - final_result = MeasurementOutcomes( - circuit.measurements, - backend=self, - samples=self.aggregate_shots(results), - nshots=nshots, - ) - final_result._repeated_execution_frequencies = self.calculate_frequencies( - samples - ) - circuit._final_state = final_result - return final_result - - def execute_distributed_circuit(self, circuit, initial_state=None, nshots=None): - raise_error( - NotImplementedError, f"{self} does not support distributed execution." - ) + @staticmethod + def seed(seed=None): + """ + Numpy-like random seed: https://numpy.org/devdocs/reference/random/generated/numpy.random.seed.html + """ + return np.random.seed(seed) - def calculate_symbolic( - self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 - ): - state = self.to_numpy(state) - terms = [] - for i in np.nonzero(state)[0]: - b = bin(i)[2:].zfill(nqubits) - if np.abs(state[i]) >= cutoff: - x = np.round(state[i], decimals) - terms.append(f"{x}|{b}>") - if len(terms) >= max_terms: - terms.append("...") - return terms - return terms - - def calculate_symbolic_density_matrix( - self, state, nqubits, decimals=5, cutoff=1e-10, max_terms=20 - ): - state = self.to_numpy(state) - terms = [] - indi, indj = np.nonzero(state) - for i, j in zip(indi, indj): - bi = bin(i)[2:].zfill(nqubits) - bj = bin(j)[2:].zfill(nqubits) - if np.abs(state[i, j]) >= cutoff: - x = np.round(state[i, j], decimals) - terms.append(f"{x}|{bi}><{bj}|") - if len(terms) >= max_terms: - terms.append("...") - return terms - return terms - - def _order_probabilities(self, probs, qubits, nqubits): - """Arrange probabilities according to the given ``qubits`` ordering.""" - unmeasured, reduced = [], {} - for i in range(nqubits): - if i in qubits: - reduced[i] = i - len(unmeasured) - else: - unmeasured.append(i) - return self.np.transpose(probs, [reduced.get(i) for i in qubits]) - - def calculate_probabilities(self, state, qubits, nqubits): - rtype = self.np.real(state).dtype - unmeasured_qubits = tuple(i for i in range(nqubits) if i not in qubits) - state = self.np.reshape(self.np.abs(state) ** 2, nqubits * (2,)) - probs = self.np.sum(self.cast(state, dtype=rtype), axis=unmeasured_qubits) - return self._order_probabilities(probs, qubits, nqubits).ravel() - - def calculate_probabilities_density_matrix(self, state, qubits, nqubits): - order = tuple(sorted(qubits)) - order += tuple(i for i in range(nqubits) if i not in qubits) - order = order + tuple(i + nqubits for i in order) - shape = 2 * (2 ** len(qubits), 2 ** (nqubits - len(qubits))) - state = self.np.reshape(state, 2 * nqubits * (2,)) - state = self.np.reshape(self.np.transpose(state, order), shape) - probs = self.np.abs(self.np.einsum("abab->a", state)) - probs = self.np.reshape(probs, len(qubits) * (2,)) - return self._order_probabilities(probs, qubits, nqubits).ravel() - - def set_seed(self, seed): - self.np.random.seed(seed) - - def sample_shots(self, probabilities, nshots): - return self.np.random.choice( - range(len(probabilities)), size=nshots, p=probabilities - ) + @staticmethod + def permutation(x): + """ + Numpy-like random permutation: https://numpy.org/doc/stable/reference/random/generated/numpy.random.permutation.html + """ + return np.random.permutation(x) - def aggregate_shots(self, shots): - return self.cast(shots, dtype=shots[0].dtype) - - def samples_to_binary(self, samples, nqubits): - qrange = np.arange(nqubits - 1, -1, -1, dtype=np.int32) - return np.mod(np.right_shift(samples[:, None], qrange), 2) - - def samples_to_decimal(self, samples, nqubits): - ### This is faster just staying @ NumPy. - qrange = np.arange(nqubits - 1, -1, -1, dtype=np.int32) - qrange = (2**qrange)[:, None] - samples = np.asarray(samples.tolist()) - return np.matmul(samples, qrange)[:, 0] - - def calculate_frequencies(self, samples): - # Samples are a list of strings so there is no advantage in using other backends - res, counts = np.unique(samples, return_counts=True) - res = self.to_numpy(res).tolist() - counts = self.to_numpy(counts).tolist() - return collections.Counter(dict(zip(res, counts))) - - def update_frequencies(self, frequencies, probabilities, nsamples): - samples = self.sample_shots(probabilities, nsamples) - res, counts = self.np.unique(samples, return_counts=True) - frequencies[res] += counts - return frequencies - - def sample_frequencies(self, probabilities, nshots): - from qibo.config import SHOT_BATCH_SIZE - - nprobs = probabilities / self.np.sum(probabilities) - frequencies = self.np.zeros(len(nprobs), dtype=self.np.int64) - for _ in range(nshots // SHOT_BATCH_SIZE): - frequencies = self.update_frequencies(frequencies, nprobs, SHOT_BATCH_SIZE) - frequencies = self.update_frequencies( - frequencies, nprobs, nshots % SHOT_BATCH_SIZE - ) - return collections.Counter( - {i: int(f) for i, f in enumerate(frequencies) if f > 0} - ) + @staticmethod + def multinomial(n, pvals, size=None): + """ + Numpy-like multinomial: https://numpy.org/doc/2.0/reference/random/generated/numpy.random.multinomial.html + """ + return np.random.multinomial(n, pvals, size=size) - def apply_bitflips(self, noiseless_samples, bitflip_probabilities): - noiseless_samples = self.cast(noiseless_samples, dtype=noiseless_samples.dtype) - fprobs = self.cast(bitflip_probabilities, dtype="float64") - sprobs = self.cast(np.random.random(noiseless_samples.shape), dtype="float64") - flip_0 = self.cast(sprobs < fprobs[0], dtype=noiseless_samples.dtype) - flip_1 = self.cast(sprobs < fprobs[1], dtype=noiseless_samples.dtype) - noisy_samples = noiseless_samples + (1 - noiseless_samples) * flip_0 - noisy_samples = noisy_samples - noiseless_samples * flip_1 - return noisy_samples - - def calculate_norm(self, state, order=2): - state = self.cast(state) - return self.np.linalg.norm(state, order) - - def calculate_norm_density_matrix(self, state, order="nuc"): - state = self.cast(state) - return self.np.linalg.norm(state, ord=order) - - def calculate_overlap(self, state1, state2): - return self.np.abs( - self.np.sum(self.np.conj(self.cast(state1)) * self.cast(state2)) - ) + @staticmethod + def default_rng(seed=None): + """ + Numpy-like random default_rng: https://numpy.org/doc/stable/reference/random/generator.html + """ + return np.random.default_rng(seed) - def calculate_overlap_density_matrix(self, state1, state2): - return self.np.trace( - self.np.matmul(self.np.conj(self.cast(state1)).T, self.cast(state2)) - ) + @staticmethod + def rand(*args): + """ + Numpy-like random rand: https://numpy.org/doc/stable/reference/random/generated/numpy.random.rand.html + """ + return np.random.rand(*args) - def calculate_eigenvalues(self, matrix, k: int = 6, hermitian: bool = True): - if self.is_sparse(matrix): - log.warning( - "Calculating sparse matrix eigenvectors because " - "sparse modules do not provide ``eigvals`` method." - ) - return self.calculate_eigenvectors(matrix, k=k)[0] - if hermitian: - return np.linalg.eigvalsh(matrix) - return np.linalg.eigvals(matrix) - - def calculate_eigenvectors(self, matrix, k: int = 6, hermitian: bool = True): - if self.is_sparse(matrix): - if k < matrix.shape[0]: - from scipy.sparse.linalg import eigsh - - return eigsh(matrix, k=k, which="SA") - else: # pragma: no cover - matrix = self.to_numpy(matrix) - if hermitian: - return np.linalg.eigh(matrix) - return np.linalg.eig(matrix) - - def calculate_expectation_state(self, hamiltonian, state, normalize): - statec = self.np.conj(state) - hstate = hamiltonian @ state - ev = self.np.real(self.np.sum(statec * hstate)) - if normalize: - ev /= self.np.sum(self.np.square(self.np.abs(state))) - return ev - - def calculate_expectation_density_matrix(self, hamiltonian, state, normalize): - ev = self.np.real(self.np.trace(self.cast(hamiltonian @ state))) - if normalize: - norm = self.np.real(self.np.trace(state)) - ev /= norm - return ev - - def calculate_matrix_exp(self, a, matrix, eigenvectors=None, eigenvalues=None): - if eigenvectors is None or self.is_sparse(matrix): - if self.is_sparse(matrix): - from scipy.sparse.linalg import expm - else: - from scipy.linalg import expm - return expm(-1j * a * matrix) - expd = self.np.diag(self.np.exp(-1j * a * eigenvalues)) - ud = self.np.transpose(np.conj(eigenvectors)) - return self.np.matmul(eigenvectors, self.np.matmul(expd, ud)) - - def calculate_matrix_power( - self, - matrix, - power: Union[float, int], - precision_singularity: float = 1e-14, - ): - if not isinstance(power, (float, int)): - raise_error( - TypeError, - f"``power`` must be either float or int, but it is type {type(power)}.", - ) + # logical operations + # ^^^^^^^^^^^^^^^^^^ - if power < 0.0: - # negative powers of singular matrices via SVD - determinant = self.np.linalg.det(matrix) - if abs(determinant) < precision_singularity: - return _calculate_negative_power_singular_matrix( - matrix, power, precision_singularity, self.np, self - ) + @staticmethod + def less(x1, x2, **kwargs): + """ + Numpy-like less: https://numpy.org/doc/stable/reference/generated/numpy.less.html + """ + return np.less(x1, x2, **kwargs) - return fractional_matrix_power(matrix, power) + @staticmethod + def any(a, **kwargs): + """ + Numpy-like any: https://numpy.org/doc/stable/reference/generated/numpy.any.html + """ + return np.any(a, **kwargs) - def calculate_singular_value_decomposition(self, matrix): - return self.np.linalg.svd(matrix) + @staticmethod + def allclose(a, b, **kwargs): + """ + Numpy-like allclose: https://numpy.org/doc/stable/reference/generated/numpy.allclose.html + """ + return np.allclose(a, b, **kwargs) - def calculate_jacobian_matrix( - self, circuit, parameters=None, initial_state=None, return_complex: bool = True - ): - raise_error( - NotImplementedError, - "This method is only implemented in backends that allow automatic differentiation, " - + "e.g. ``PytorchBackend`` and ``TensorflowBackend``.", - ) + @staticmethod + def right_shift(x1, x2, **kwargs): + """ + Numpy-like element-wise right shift: https://numpy.org/doc/stable/reference/generated/numpy.right_shift.html + """ + return np.right_shift(x1, x2, **kwargs) + + # mathematical operations + # ^^^^^^^^^^^^^^^^^^^^^^^ + + @staticmethod + def sum(a, axis=None, **kwargs): + """Numpy-like sum: https://numpy.org/devdocs/reference/generated/numpy.sum.html""" + return np.sum(a, axis=axis, **kwargs) + + @staticmethod + def conj(a, **kwargs): + """Numpy-like conj: https://numpy.org/devdocs/reference/generated/numpy.conj.html""" + return np.conj(a, **kwargs) + + @staticmethod + def exp(a, **kwargs): + """Numpy-like exp: https://numpy.org/devdocs/reference/generated/numpy.exp.html""" + return np.exp(a, **kwargs) + + @staticmethod + def log(a, **kwargs): + """Numpy-like log: https://numpy.org/doc/stable/reference/generated/numpy.log.html""" + return np.log(a, **kwargs) + + @staticmethod + def log2(a, **kwargs): + """Numpy-like log2: https://numpy.org/doc/stable/reference/generated/numpy.log2.html""" + return np.log2(a, **kwargs) + + @staticmethod + def real(a): + """Numpy-like real: https://numpy.org/devdocs/reference/generated/numpy.real.html""" + return np.real(a) + + @staticmethod + def imag(a): + """Numpy-like imag: https://numpy.org/doc/stable/reference/generated/numpy.imag.html""" + return np.imag(a) + + @staticmethod + def abs(a, **kwargs): + """Numpy-like abs: https://numpy.org/devdocs/reference/generated/numpy.abs.html""" + return np.abs(a, **kwargs) + + @staticmethod + def pow(a, b, **kwargs): + """Numpy-like element-wise power: https://numpy.org/doc/stable/reference/generated/numpy.power.html""" + return np.power(a, b, **kwargs) + + @staticmethod + def square(a, **kwargs): + """Numpy-like element-wise square: https://numpy.org/doc/stable/reference/generated/numpy.square.html""" + return np.square(a, **kwargs) + + @staticmethod + def sqrt(a, **kwargs): + """Numpy-like sqrt: https://numpy.org/devdocs/reference/generated/numpy.sqrt.html""" + return np.sqrt(a, **kwargs) + + @staticmethod + def mean(a, axis=None, **kwargs): + """Numpy-like mean: https://numpy.org/doc/stable/reference/generated/numpy.mean.html""" + return np.mean(a, axis=axis, **kwargs) + + @staticmethod + def std(a, **kwargs): + """Numpy-like standard deviation: https://numpy.org/doc/stable/reference/generated/numpy.std.html""" + return np.std(a, **kwargs) + + @staticmethod + def cos(x, **kwargs): + """Numpy-like cos: https://numpy.org/devdocs/reference/generated/numpy.cos.html""" + return np.cos(x, **kwargs) + + @staticmethod + def sin(x, **kwargs): + """Numpy-like sin: https://numpy.org/devdocs/reference/generated/numpy.sin.html""" + return np.sin(x, **kwargs) + + @staticmethod + def arccos(x, **kwargs): + """Numpy-like arccos: https://numpy.org/doc/stable/reference/generated/numpy.arccos.html""" + return np.arccos(x, **kwargs) + + @staticmethod + def arctan2(y, x, **kwargs): + """Numpy-like arctan2: https://numpy.org/doc/stable/reference/generated/numpy.arctan2.html""" + return np.arctan2(y, x, **kwargs) + + @staticmethod + def angle(z, **kwargs): + """Numpy-like angle: https://numpy.org/doc/stable/reference/generated/numpy.angle.html""" + return np.angle(z, **kwargs) + + @staticmethod + def mod(x, y, **kwargs): + """Numpy-like element-wise modulus: https://numpy.org/doc/stable/reference/generated/numpy.mod.html""" + return np.mod(x, y, **kwargs) + + @staticmethod + def round(a, decimals=0, out=None): + """Numpy-like element-wise round: https://numpy.org/doc/stable/reference/generated/numpy.round.html""" + return np.round(a, decimals=decimals, out=out) + + # misc + # ^^^^ + + @staticmethod + def sort(a, **kwargs): + """Numpy-like sort: https://numpy.org/doc/stable/reference/generated/numpy.sort.html""" + return np.sort(a, **kwargs) + + @staticmethod + def argsort(a, **kwargs): + """Numpy-like argsort: https://numpy.org/doc/stable/reference/generated/numpy.argsort.html""" + return np.argsort(a, **kwargs) + + @staticmethod + def count_nonzero(a, **kwargs): + """Numpy-like count_nonzero: https://numpy.org/doc/stable/reference/generated/numpy.count_nonzero.html""" + return np.count_nonzero(a, **kwargs) + + @staticmethod + def finfo(dtype): + """Numpy-like finfo: https://numpy.org/doc/stable/reference/generated/numpy.finfo.html""" + return np.finfo(dtype) + + @staticmethod + def __version__(): + """Version of the backend engine.""" + return np.__version__ + + @staticmethod + @cache + def get_dtype(type_name: str): + """Backend engine dtype""" + return getattr(np, type_name) + + @staticmethod + def assert_allclose(a, b, **kwargs): + """ + Numpy-like allclose: https://numpy.org/doc/stable/reference/generated/numpy.allclose.html + """ + return np.testing.assert_allclose(a, b, **kwargs) - # TODO: remove this method - def calculate_hamiltonian_matrix_product(self, matrix1, matrix2): - return matrix1 @ matrix2 + # Optimization + # ^^^^^^^^^^^^^ - # TODO: remove this method - def calculate_hamiltonian_state_product(self, matrix, state): - if len(tuple(state.shape)) > 2: - raise_error( - ValueError, - f"Cannot multiply Hamiltonian with rank-{len(tuple(state.shape))} tensor.", - ) - return matrix @ state - - def assert_allclose(self, value, target, rtol=1e-7, atol=0.0): - if isinstance(value, CircuitResult) or isinstance(value, QuantumState): - value = value.state() - if isinstance(target, CircuitResult) or isinstance(target, QuantumState): - target = target.state() - value = self.to_numpy(value) - target = self.to_numpy(target) - np.testing.assert_allclose(value, target, rtol=rtol, atol=atol) - - def _test_regressions(self, name): - if name == "test_measurementresult_apply_bitflips": - return [ - [0, 0, 0, 0, 2, 3, 0, 0, 0, 0], - [0, 0, 0, 0, 2, 3, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 2, 0, 0, 0, 0, 0], - ] - elif name == "test_probabilistic_measurement": - return {0: 249, 1: 231, 2: 253, 3: 267} - elif name == "test_unbalanced_probabilistic_measurement": - return {0: 171, 1: 148, 2: 161, 3: 520} - elif name == "test_post_measurement_bitflips_on_circuit": - return [ - {5: 30}, - {5: 18, 4: 5, 7: 4, 1: 2, 6: 1}, - {4: 8, 2: 6, 5: 5, 1: 3, 3: 3, 6: 2, 7: 2, 0: 1}, - ] - - -def _calculate_negative_power_singular_matrix( - matrix, power: Union[float, int], precision_singularity: float, engine, backend -): - """Calculate negative power of singular matrix.""" - U, S, Vh = backend.calculate_singular_value_decomposition(matrix) - # cast needed because of different dtypes in `torch` - S = backend.cast(S) - S_inv = engine.where(engine.abs(S) < precision_singularity, 0.0, S**power) - - return engine.linalg.inv(Vh) @ backend.np.diag(S_inv) @ engine.linalg.inv(U) + @staticmethod + def jacobian(*args, **kwargs): + """Compute the Jacobian matrix""" + raise NotImplementedError diff --git a/src/qibo/callbacks.py b/src/qibo/callbacks.py index 315db67429..50b0266a29 100644 --- a/src/qibo/callbacks.py +++ b/src/qibo/callbacks.py @@ -331,20 +331,20 @@ def apply(self, backend, state): hamiltonian.eigenvectors() eigvals = hamiltonian.eigenvalues() if isinstance(self.mode, int): - gap = backend.np.real(eigvals[self.mode]) + gap = backend.real(eigvals[self.mode]) self.append(gap) return gap # case: self.mode == "gap" excited = 1 - gap = backend.np.real(eigvals[excited] - eigvals[0]) + gap = backend.real(eigvals[excited] - eigvals[0]) if not self.check_degenerate: self.append(gap) return gap - while backend.np.less(gap, EIGVAL_CUTOFF): - gap = backend.np.real(eigvals[excited] - eigvals[0]) + while backend.less(gap, EIGVAL_CUTOFF): + gap = backend.real(eigvals[excited] - eigvals[0]) excited += 1 if excited > 1: log.warning( diff --git a/src/qibo/gates/channels.py b/src/qibo/gates/channels.py index 2d178c1831..f895334e15 100644 --- a/src/qibo/gates/channels.py +++ b/src/qibo/gates/channels.py @@ -100,8 +100,8 @@ def to_choi(self, nqubits: Optional[int] = None, order: str = "row", backend=Non kraus_op.append(gate) kraus_op = kraus_op.matrix(backend) kraus_op = vectorization(kraus_op, order=order, backend=backend) - super_op = super_op + coeff * backend.np.outer( - kraus_op, backend.np.conj(kraus_op) + super_op = super_op + coeff * backend.outer( + kraus_op, backend.conj(kraus_op) ) del kraus_op @@ -181,9 +181,7 @@ def to_pauli_liouville( nqubits, normalize, pauli_order=pauli_order, backend=backend ) - super_op = ( - unitary @ super_op @ backend.np.transpose(backend.np.conj(unitary), (1, 0)) - ) + super_op = unitary @ super_op @ backend.transpose(backend.conj(unitary), (1, 0)) return super_op diff --git a/src/qibo/hamiltonians/hamiltonians.py b/src/qibo/hamiltonians/hamiltonians.py index 0016ddb05b..57dd02e42a 100644 --- a/src/qibo/hamiltonians/hamiltonians.py +++ b/src/qibo/hamiltonians/hamiltonians.py @@ -147,8 +147,8 @@ def expectation(self, state, normalize=False): def expectation_from_samples(self, freq, qubit_map=None): obs = self.matrix if ( - self.backend.np.count_nonzero( - obs - self.backend.np.diag(self.backend.np.diagonal(obs)) + self.backend.count_nonzero( + obs - self.backend.diag(self.backend.diagonal(obs)) ) != 0 ): @@ -167,7 +167,7 @@ def expectation_from_samples(self, freq, qubit_map=None): for i in qubit_map: index += int(k[qubit_map.index(i)]) * 2 ** (size - 1 - i) expval += obs[index, index] * counts[j] - return self.backend.np.real(expval) + return self.backend.real(expval) def eye(self, dim: Optional[int] = None): """Generate Identity matrix with dimension ``dim``""" @@ -196,7 +196,7 @@ def energy_fluctuation(self, state): h = self.matrix h2 = Hamiltonian(nqubits=self.nqubits, matrix=h @ h, backend=self.backend) average_h2 = self.backend.calculate_expectation_state(h2, state, normalize=True) - return self.backend.np.sqrt(self.backend.np.abs(average_h2 - energy**2)) + return self.backend.sqrt(self.backend.abs(average_h2 - energy**2)) def __add__(self, o): if isinstance(o, self.__class__): @@ -262,13 +262,13 @@ def __mul__(self, o): r = self.__class__(self.nqubits, new_matrix, backend=self.backend) o = self.backend.cast(o) if self._eigenvalues is not None: - if self.backend.np.real(o) >= 0: # TODO: check for side effects K.qnp + if self.backend.real(o) >= 0: # TODO: check for side effects K.qnp r._eigenvalues = o * self._eigenvalues elif not self.backend.is_sparse(self.matrix): axis = (0,) if (self.backend.platform == "pytorch") else 0 - r._eigenvalues = o * self.backend.np.flip(self._eigenvalues, axis) + r._eigenvalues = o * self.backend.flip(self._eigenvalues, axis) if self._eigenvectors is not None: - if self.backend.np.real(o) > 0: # TODO: see above + if self.backend.real(o) > 0: # TODO: see above r._eigenvectors = self._eigenvectors elif o == 0: r._eigenvectors = self.eye(int(self._eigenvectors.shape[0])) @@ -668,7 +668,7 @@ def expectation_from_samples(self, freq: dict, qubit_map: dict = None) -> float: expvals = self.backend.cast(expvals, dtype=counts.dtype).reshape( len(self.terms), len(freq) ) - return self.backend.np.sum(expvals @ counts.T) + self.constant.real + return self.backend.sum(expvals @ counts.T) + self.constant.real def __add__(self, o): if isinstance(o, self.__class__): diff --git a/src/qibo/models/dbi/utils.py b/src/qibo/models/dbi/utils.py index 4a04c7a4f8..f8e0ce5c55 100644 --- a/src/qibo/models/dbi/utils.py +++ b/src/qibo/models/dbi/utils.py @@ -70,15 +70,15 @@ def cs_angle_sgn(dbi_object, d, backend=None): """Calculates the sign of Cauchy-Schwarz Angle :math:`\\langle W(Z), W({\\rm canonical}) \\rangle_{\\rm HS}`.""" backend = _check_backend(backend) d = backend.cast(d) - norm = backend.np.trace( - backend.np.matmul( - backend.np.conj( + norm = backend.trace( + backend.matmul( + backend.conj( dbi_object.commutator(dbi_object.diagonal_h_matrix, dbi_object.h.matrix) ).T, dbi_object.commutator(d, dbi_object.h.matrix), ) ) - return backend.np.real(backend.np.sign(norm)) + return backend.real(backend.sign(norm)) def decompose_into_pauli_basis(h_matrix: np.array, pauli_operators: list, backend=None): @@ -87,7 +87,7 @@ def decompose_into_pauli_basis(h_matrix: np.array, pauli_operators: list, backen backend = _check_backend(backend) decomposition = [] for Z_i in pauli_operators: - expect = backend.np.trace(h_matrix @ Z_i) / 2**nqubits + expect = backend.trace(h_matrix @ Z_i) / 2**nqubits decomposition.append(expect) return decomposition @@ -221,9 +221,8 @@ def least_squares_polynomial_expansion_coef(dbi_object, d, n: int = 3, backend=N # coefficients coef = np.empty(n) for i in range(n): - coef[i] = backend.np.real( - exp_list[i] - * backend.np.trace(dbi_object.backend.cast(d) @ Gamma_list[i + 1]) + coef[i] = backend.real( + exp_list[i] * backend.trace(dbi_object.backend.cast(d) @ Gamma_list[i + 1]) ) coef = list(reversed(coef)) return coef diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index fe7b0bb307..4ec0982ab5 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -214,7 +214,7 @@ def ZNE( ) expected_values = backend.cast(expected_values, backend.precision) - return backend.np.sum(gamma * expected_values) + return backend.sum(gamma * expected_values) def sample_training_circuit_cdr( @@ -266,8 +266,8 @@ def sample_training_circuit_cdr( replacement.append(rep_gates) distance.append( - backend.np.real( - backend.np.linalg.norm( + backend.real( + backend.linalg_norm( gate.matrix(backend) - backend.cast( [rep_gate.matrix(backend) for rep_gate in rep_gates] @@ -278,14 +278,14 @@ def sample_training_circuit_cdr( ) ) - distance = backend.np.vstack(distance) - prob = backend.np.exp(-(distance**2) / sigma**2) + distance = backend.vstack(distance) + prob = backend.exp(-(distance**2) / sigma**2) index = local_state.choice( range(len(gates_to_replace)), size=min(int(len(gates_to_replace) / 2), 50), replace=False, - p=backend.to_numpy(backend.np.sum(prob, -1) / backend.np.sum(prob)), + p=backend.to_numpy(backend.sum(prob, -1) / backend.sum(prob)), ) gates_to_replace = np.array([gates_to_replace[i] for i in index]) @@ -332,8 +332,8 @@ def _curve_fit( # pytorch has some problems with the `scipy.optim.curve_fit` function # thus we use a `torch.optim` optimizer params.requires_grad = True - loss = lambda pred, target: backend.np.mean((pred - target) ** 2) - optimizer = backend.np.optim.LBFGS( + loss = lambda pred, target: backend.mean((pred - target) ** 2) + optimizer = backend.optim.LBFGS( [params], lr=lr, max_iter=max_iter, tolerance_grad=tolerance_grad ) @@ -530,7 +530,7 @@ def vnCDR( backend, local_state = _check_backend_and_local_state(seed, backend) if model is None: - model = lambda x, *params: backend.np.sum(x * backend.np.vstack(params), axis=0) + model = lambda x, *params: backend.sum(x * backend.vstack(params), axis=0) if readout is None: readout = {} @@ -981,7 +981,7 @@ def error_sensitive_circuit(circuit, observable, seed=None, backend=None): comp_to_pauli = comp_basis_to_pauli(num_qubits, backend=backend) observable.nqubits = num_qubits observable_liouville = vectorization( - backend.np.transpose(backend.np.conj(unitary_matrix), (1, 0)) + backend.transpose(backend.conj(unitary_matrix), (1, 0)) @ observable.matrix @ unitary_matrix, order="row", @@ -989,9 +989,7 @@ def error_sensitive_circuit(circuit, observable, seed=None, backend=None): ) observable_pauli_liouville = comp_to_pauli @ observable_liouville - index = int( - backend.np.where(backend.np.abs(observable_pauli_liouville) >= 1e-5)[0][0] - ) + index = int(backend.where(backend.abs(observable_pauli_liouville) >= 1e-5)[0][0]) observable_pauli = list(product(["I", "X", "Y", "Z"], repeat=num_qubits))[index] @@ -1006,14 +1004,14 @@ def error_sensitive_circuit(circuit, observable, seed=None, backend=None): for i in range(num_qubits): observable_i = pauli_gates[observable_pauli[i]] random_init = pauli_gates["I"] - while backend.np.any( - backend.np.abs(observable_i - pauli_gates["Z"]) > 1e-5 - ) and backend.np.any(abs(observable_i - pauli_gates["I"]) > 1e-5): + while backend.any( + backend.abs(observable_i - pauli_gates["Z"]) > 1e-5 + ) and backend.any(abs(observable_i - pauli_gates["I"]) > 1e-5): random_init = random_clifford( 1, return_circuit=False, seed=local_state, backend=backend ) observable_i = ( - backend.np.conj(backend.np.transpose(random_init, (1, 0))) + backend.conj(backend.transpose(random_init, (1, 0))) @ pauli_gates[observable_pauli[i]] @ random_init ) @@ -1119,8 +1117,8 @@ def ICS( lambda_list.append(1 - noisy_expectation / expectation) lambda_list = backend.cast(lambda_list, backend.precision) - dep_param = backend.np.mean(lambda_list) - dep_param_std = backend.np.std(lambda_list) + dep_param = backend.mean(lambda_list) + dep_param_std = backend.std(lambda_list) noisy_expectation = get_expectation_val_with_readout_mitigation( circuit, diff --git a/src/qibo/models/variational.py b/src/qibo/models/variational.py index a855dc95e0..fd229df965 100644 --- a/src/qibo/models/variational.py +++ b/src/qibo/models/variational.py @@ -96,7 +96,7 @@ def minimize( if method == "cma": # TODO: check if we can use this shortcut # dtype = getattr(self.hamiltonian.backend.np, self.hamiltonian.backend._dtypes.get('DTYPE')) - dtype = self.hamiltonian.backend.np.float64 + dtype = self.hamiltonian.backend.get_dtype("float64") loss = ( (lambda p, c, h: loss_func(p, c, h).item()) if str(dtype) == "torch.float64" diff --git a/src/qibo/quantum_info/basis.py b/src/qibo/quantum_info/basis.py index 673f7e48ca..f9475f7f18 100644 --- a/src/qibo/quantum_info/basis.py +++ b/src/qibo/quantum_info/basis.py @@ -93,7 +93,7 @@ def pauli_basis( pauli_labels = {"I": matrices.I, "X": matrices.X, "Y": matrices.Y, "Z": matrices.Z} dim = 2**nqubits basis_single = backend.cast([pauli_labels[label] for label in pauli_order]) - einsum = np.einsum if backend.platform == "tensorflow" else backend.np.einsum + einsum = np.einsum if backend.platform == "tensorflow" else backend.einsum if nqubits > 1: input_indices = [range(3 * i, 3 * (i + 1)) for i in range(nqubits)] @@ -105,12 +105,15 @@ def pauli_basis( basis_full = basis_single if vectorize and sparse: - if backend.platform == "pytorch": - nonzero = lambda x: backend.np.nonzero(x, as_tuple=True) - else: - nonzero = backend.np.nonzero + + # if backend.platform == "pytorch": + # nonzero = lambda x: backend.nonzero(x, as_tuple=True) + # else: + # nonzero = backend.nonzero basis = vectorization(basis_full, order=order, backend=backend) - indices = nonzero(backend.np.abs(basis)) # abs needed because of ``tensorflow`` + indices = backend.nonzero( + backend.abs(basis) + ) # abs needed because of ``tensorflow`` basis = basis[indices].reshape(-1, dim) indices = indices[1].reshape(-1, dim) @@ -195,7 +198,7 @@ def comp_basis_to_pauli( pauli_order=pauli_order, backend=backend, ) - elements = backend.np.conj(elements) + elements = backend.conj(elements) return elements, indexes @@ -209,7 +212,7 @@ def comp_basis_to_pauli( backend=backend, ) - unitary = backend.np.conj(unitary) + unitary = backend.conj(unitary) return unitary @@ -273,7 +276,7 @@ def pauli_to_comp_basis( if sparse: elements, indexes = [], [] for row in unitary: - index_list = backend.np.flatnonzero(row) + index_list = backend.nonzero(backend.ravel(row)) indexes.append(index_list) elements.append(row[index_list]) diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index 3851739e4c..3c277e0c75 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -147,10 +147,10 @@ def negativity(state, bipartition, backend=None): backend = _check_backend(backend) reduced = partial_transpose(state, bipartition, backend) - reduced = backend.np.conj(reduced.T) @ reduced - norm = backend.np.trace(matrix_power(reduced, 1 / 2, backend=backend)) + reduced = backend.conj(reduced.T) @ reduced + norm = backend.trace(matrix_power(reduced, 1 / 2, backend=backend)) - return backend.np.real((norm - 1) / 2) + return backend.real((norm - 1) / 2) def entanglement_fidelity( diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 48767896d0..1adb8164a8 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -54,19 +54,19 @@ def shannon_entropy(prob_dist, base: float = 2, backend=None): "All elements of the probability array must be between 0. and 1..", ) - total_sum = backend.np.sum(prob_dist) + total_sum = backend.sum(prob_dist) if np.abs(float(total_sum) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") - log_prob = backend.np.where( - prob_dist != 0, backend.np.log2(prob_dist) / np.log2(base), 0.0 + log_prob = backend.where( + prob_dist != 0, backend.log2(prob_dist) / np.log2(base), 0.0 ) - shan_entropy = -backend.np.sum(prob_dist * log_prob) + shan_entropy = -backend.sum(prob_dist * log_prob) # absolute value if entropy == 0.0 to avoid returning -0.0 - shan_entropy = backend.np.abs(shan_entropy) if shan_entropy == 0.0 else shan_entropy + shan_entropy = backend.abs(shan_entropy) if shan_entropy == 0.0 else shan_entropy return np.real(float(shan_entropy)) @@ -118,9 +118,9 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen ValueError, "All elements of the probability array must be between 0. and 1..", ) - total_sum_p = backend.np.sum(prob_dist_p) + total_sum_p = backend.sum(prob_dist_p) - total_sum_q = backend.np.sum(prob_dist_q) + total_sum_q = backend.sum(prob_dist_q) if np.abs(float(total_sum_p) - 1.0) > PRECISION_TOL: raise_error(ValueError, "First probability array must sum to 1.") @@ -130,13 +130,13 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) - log_prob_q = backend.np.where( - prob_dist_q != 0.0, backend.np.log2(prob_dist_q) / np.log2(base), -np.inf + log_prob_q = backend.where( + prob_dist_q != 0.0, backend.log2(prob_dist_q) / np.log2(base), -np.inf ) - log_prob = backend.np.where(prob_dist_p != 0.0, log_prob_q, 0.0) + log_prob = backend.where(prob_dist_p != 0.0, log_prob_q, 0.0) - relative = backend.np.sum(prob_dist_p * log_prob) + relative = backend.sum(prob_dist_p * log_prob) return entropy_p - relative @@ -240,7 +240,7 @@ def classical_renyi_entropy( "All elements of the probability array must be between 0. and 1..", ) - total_sum = backend.np.sum(prob_dist) + total_sum = backend.sum(prob_dist) if np.abs(float(total_sum) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") @@ -252,11 +252,11 @@ def classical_renyi_entropy( return shannon_entropy(prob_dist, base=base, backend=backend) if alpha == np.inf: - return -1 * backend.np.log2(max(prob_dist)) / np.log2(base) + return -1 * backend.log2(max(prob_dist)) / np.log2(base) - total_sum = backend.np.sum(prob_dist**alpha) + total_sum = backend.sum(prob_dist**alpha) - renyi_ent = (1 / (1 - alpha)) * backend.np.log2(total_sum) / np.log2(base) + renyi_ent = (1 / (1 - alpha)) * backend.log2(total_sum) / np.log2(base) return renyi_ent @@ -333,8 +333,8 @@ def classical_relative_renyi_entropy( "All elements of the probability array must be between 0. and 1..", ) - total_sum_p = backend.np.sum(prob_dist_p) - total_sum_q = backend.np.sum(prob_dist_q) + total_sum_p = backend.sum(prob_dist_p) + total_sum_q = backend.sum(prob_dist_q) if np.abs(float(total_sum_p) - 1.0) > PRECISION_TOL: raise_error(ValueError, "First probability array must sum to 1.") @@ -343,10 +343,10 @@ def classical_relative_renyi_entropy( raise_error(ValueError, "Second probability array must sum to 1.") if alpha == 0.5: - total_sum = backend.np.sqrt(prob_dist_p * prob_dist_q) - total_sum = backend.np.sum(total_sum) + total_sum = backend.sqrt(prob_dist_p * prob_dist_q) + total_sum = backend.sum(total_sum) - return -2 * backend.np.log2(total_sum) / np.log2(base) + return -2 * backend.log2(total_sum) / np.log2(base) if alpha == 1.0: return classical_relative_entropy( @@ -354,14 +354,14 @@ def classical_relative_renyi_entropy( ) if alpha == np.inf: - return backend.np.log2(max(prob_dist_p / prob_dist_q)) / np.log2(base) + return backend.log2(max(prob_dist_p / prob_dist_q)) / np.log2(base) prob_p = prob_dist_p**alpha prob_q = prob_dist_q ** (1 - alpha) - total_sum = backend.np.sum(prob_p * prob_q) + total_sum = backend.sum(prob_p * prob_q) - return (1 / (alpha - 1)) * backend.np.log2(total_sum) / np.log2(base) + return (1 / (alpha - 1)) * backend.log2(total_sum) / np.log2(base) def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend=None): @@ -417,7 +417,7 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= "All elements of the probability array must be between 0. and 1..", ) - total_sum = backend.np.sum(prob_dist) + total_sum = backend.sum(prob_dist) if np.abs(float(total_sum) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") @@ -426,7 +426,7 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= return shannon_entropy(prob_dist, base=base, backend=backend) total_sum = prob_dist**alpha - total_sum = backend.np.sum(total_sum) + total_sum = backend.sum(total_sum) return (1 / (alpha - 1)) * (1 - total_sum) @@ -478,7 +478,7 @@ def classical_relative_tsallis_entropy( element_wise = prob_dist_p**alpha element_wise = element_wise * _q_logarithm(prob_dist_p / prob_dist_q, alpha) - return backend.np.sum(element_wise) + return backend.sum(element_wise) def von_neumann_entropy( @@ -543,15 +543,15 @@ def von_neumann_entropy( hermitian=(not check_hermitian or _check_hermitian(state, backend=backend)), ) - log_prob = backend.np.where( - backend.np.real(eigenvalues) > 0.0, - backend.np.log2(eigenvalues) / np.log2(base), + log_prob = backend.where( + backend.real(eigenvalues) > 0.0, + backend.log2(eigenvalues) / np.log2(base), 0.0, ) - ent = -backend.np.sum(eigenvalues * log_prob) + ent = -backend.sum(eigenvalues * log_prob) # absolute value if entropy == 0.0 to avoid returning -0.0 - ent = backend.np.abs(ent) if ent == 0.0 else backend.np.real(ent) + ent = backend.abs(ent) if ent == 0.0 else backend.real(ent) if return_spectrum: log_prob = backend.cast(log_prob, dtype=log_prob.dtype) @@ -632,10 +632,10 @@ def relative_von_neumann_entropy( return 0.0 if len(state.shape) == 1: - state = backend.np.outer(state, backend.np.conj(state)) + state = backend.outer(state, backend.conj(state)) if len(target.shape) == 1: - target = backend.np.outer(target, backend.np.conj(target)) + target = backend.outer(target, backend.conj(target)) eigenvalues_state, eigenvectors_state = backend.calculate_eigenvectors( state, @@ -646,29 +646,29 @@ def relative_von_neumann_entropy( hermitian=(not check_hermitian or _check_hermitian(target, backend=backend)), ) - overlaps = backend.np.conj(eigenvectors_state.T) @ eigenvectors_target - overlaps = backend.np.abs(overlaps) ** 2 + overlaps = backend.conj(eigenvectors_state.T) @ eigenvectors_target + overlaps = backend.abs(overlaps) ** 2 - log_state = backend.np.where( - backend.np.real(eigenvalues_state) > precision_tol, - backend.np.log2(eigenvalues_state) / np.log2(base), + log_state = backend.where( + backend.real(eigenvalues_state) > precision_tol, + backend.log2(eigenvalues_state) / np.log2(base), 0.0, ) - log_target = backend.np.where( - backend.np.real(eigenvalues_target) > precision_tol, - backend.np.log2(eigenvalues_target) / np.log2(base), + log_target = backend.where( + backend.real(eigenvalues_target) > precision_tol, + backend.log2(eigenvalues_target) / np.log2(base), 0.0, ) log_target = overlaps @ log_target - log_target = backend.np.where(eigenvalues_state != 0.0, log_target, 0.0) + log_target = backend.where(eigenvalues_state != 0.0, log_target, 0.0) - entropy_state = backend.np.sum(eigenvalues_state * log_state) + entropy_state = backend.sum(eigenvalues_state * log_state) - relative = backend.np.sum(eigenvalues_state * log_target) + relative = backend.sum(eigenvalues_state * log_target) - return float(backend.np.real(entropy_state - relative)) + return float(backend.real(entropy_state - relative)) def mutual_information( @@ -783,11 +783,11 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None if alpha == np.inf: return ( -1 - * backend.np.log2(backend.calculate_norm_density_matrix(state, order=2)) + * backend.log2(backend.calculate_norm_density_matrix(state, order=2)) / np.log2(base) ) - log = backend.np.log2(backend.np.trace(matrix_power(state, alpha, backend=backend))) + log = backend.log2(backend.trace(matrix_power(state, alpha, backend=backend))) return (1 / (1 - alpha)) * log / np.log2(base) @@ -880,7 +880,7 @@ def relative_renyi_entropy( ) if len(state.shape) == 1: - state = backend.np.outer(state, backend.np.conj(state)) + state = backend.outer(state, backend.conj(state)) if alpha == 1.0: return relative_von_neumann_entropy(state, target, base, backend=backend) @@ -889,7 +889,7 @@ def relative_renyi_entropy( new_state = matrix_power(state, 0.5, backend=backend) new_target = matrix_power(target, 0.5, backend=backend) - log = backend.np.log2( + log = backend.log2( backend.calculate_norm_density_matrix(new_state @ new_target, order=1) ) @@ -897,7 +897,7 @@ def relative_renyi_entropy( log = matrix_power(state, alpha, backend=backend) log = log @ matrix_power(target, 1 - alpha, backend=backend) - log = backend.np.log2(backend.np.trace(log)) + log = backend.log2(backend.trace(log)) return (1 / (alpha - 1)) * log / np.log2(base) @@ -954,7 +954,7 @@ def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): return von_neumann_entropy(state, base=base, backend=backend) return (1 / (1 - alpha)) * ( - backend.np.trace(matrix_power(state, alpha, backend=backend)) - 1 + backend.trace(matrix_power(state, alpha, backend=backend)) - 1 ) @@ -1027,14 +1027,14 @@ def relative_tsallis_entropy( factor = 1 - alpha if len(state.shape) == 1: - state = backend.np.outer(state, backend.np.conj(state.T)) + state = backend.outer(state, backend.conj(state.T)) if len(target.shape) == 1: - target = backend.np.outer(target, backend.np.conj(target.T)) + target = backend.outer(target, backend.conj(target.T)) trace = matrix_power(state, alpha, backend=backend) trace = trace @ matrix_power(target, factor, backend=backend) - trace = backend.np.trace(trace) + trace = backend.trace(trace) return (1 - trace) / factor diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 6918be9cd4..15ccc9b62f 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -141,24 +141,24 @@ def partial_trace( statevector = bool(len(state.shape) == 1) factor = 1 if statevector else 2 - state = backend.np.reshape(state, factor * nqubits * (2,)) + state = backend.reshape(state, factor * nqubits * (2,)) if statevector: axes = 2 * [list(traced_qubits)] - rho = backend.np.tensordot(state, backend.np.conj(state), axes) + rho = backend.tensordot(state, backend.conj(state), axes) shape = 2 * (2 ** (nqubits - len(traced_qubits)),) - return backend.np.reshape(rho, shape) + return backend.reshape(rho, shape) order = tuple(sorted(traced_qubits)) order += tuple(set(list(range(nqubits))) ^ set(traced_qubits)) order += tuple(k + nqubits for k in order) shape = 2 * (2 ** len(traced_qubits), 2 ** (nqubits - len(traced_qubits))) - state = backend.np.transpose(state, order) - state = backend.np.reshape(state, shape) + state = backend.transpose(state, order) + state = backend.reshape(state, shape) - return backend.np.einsum("abac->bc", state) + return backend.einsum("abac->bc", state) def partial_transpose( @@ -215,10 +215,10 @@ def partial_transpose( nqubits = int(nqubits) if len(shape) == 1: - operator = backend.np.outer(operator, backend.np.conj(operator.T)) + operator = backend.outer(operator, backend.conj(operator.T)) elif len(shape) == 3 and shape[1] == 1: - operator = backend.np.einsum( - "aij,akl->aijkl", operator, backend.np.conj(operator) + operator = backend.einsum( + "aij,akl->aijkl", operator, backend.conj(operator) ).reshape(nstates, dims, dims) new_shape = list(range(2 * nqubits + 1)) @@ -228,14 +228,14 @@ def partial_transpose( new_shape[ind + nqubits] = ind new_shape = tuple(new_shape) - reshaped = backend.np.reshape(operator, [-1] + [2] * (2 * nqubits)) - reshaped = backend.np.transpose(reshaped, new_shape) + reshaped = backend.reshape(operator, [-1] + [2] * (2 * nqubits)) + reshaped = backend.transpose(reshaped, new_shape) final_shape = (dims, dims) if len(operator.shape) == 3: final_shape = (nstates,) + final_shape - return backend.np.reshape(reshaped, final_shape) + return backend.reshape(reshaped, final_shape) def matrix_exponentiation( @@ -377,8 +377,8 @@ def schmidt_decomposition( nqubits = int(nqubits) partition_2 = partition.__class__(set(list(range(nqubits))) ^ set(partition)) - tensor = backend.np.reshape(state, [2] * nqubits) - tensor = backend.np.transpose(tensor, partition + partition_2) - tensor = backend.np.reshape(tensor, (2 ** len(partition), -1)) + tensor = backend.reshape(state, [2] * nqubits) + tensor = backend.transpose(tensor, partition + partition_2) + tensor = backend.reshape(tensor, (2 ** len(partition), -1)) return singular_value_decomposition(tensor, backend=backend) diff --git a/src/qibo/quantum_info/metrics.py b/src/qibo/quantum_info/metrics.py index 61503cb48c..0e9eba2295 100644 --- a/src/qibo/quantum_info/metrics.py +++ b/src/qibo/quantum_info/metrics.py @@ -34,9 +34,9 @@ def purity(state, backend=None): ) if len(state.shape) == 1: - pur = backend.np.real(backend.calculate_norm(state)) ** 2 + pur = backend.real(backend.calculate_norm(state)) ** 2 else: - pur = backend.np.real(backend.np.trace(backend.np.matmul(state, state))) + pur = backend.real(backend.trace(backend.matmul(state, state))) return float(pur) @@ -102,16 +102,15 @@ def trace_distance(state, target, check_hermitian: bool = False, backend=None): ) if len(state.shape) == 1: - state = backend.np.outer(backend.np.conj(state), state) - target = backend.np.outer(backend.np.conj(target), target) + state = backend.outer(backend.conj(state), state) + target = backend.outer(backend.conj(target), target) difference = state - target if check_hermitian is True: hermitian = bool( float( backend.calculate_norm_density_matrix( - backend.np.transpose(backend.np.conj(difference), (1, 0)) - - difference, + backend.transpose(backend.conj(difference), (1, 0)) - difference, order=2, ) ) @@ -129,7 +128,7 @@ def trace_distance(state, target, check_hermitian: bool = False, backend=None): else: eigenvalues = backend.calculate_eigenvalues(difference) - distance = backend.np.sum(backend.np.absolute(eigenvalues)) / 2 + distance = backend.sum(backend.abs(eigenvalues)) / 2 return distance @@ -155,9 +154,9 @@ def hilbert_schmidt_inner_product(operator_A, operator_B, backend=None): """ backend = _check_backend(backend) - inner_product = backend.np.trace(backend.np.conj(operator_A.T) @ operator_B) + inner_product = backend.trace(backend.conj(operator_A.T) @ operator_B) - return backend.np.real(inner_product) + return backend.real(inner_product) def hilbert_schmidt_distance(state, target, backend=None): @@ -202,8 +201,8 @@ def hilbert_schmidt_distance(state, target, backend=None): ) if len(state.shape) == 1: - state = backend.np.outer(backend.np.conj(state), state) - target = backend.np.outer(backend.np.conj(target), target) + state = backend.outer(backend.conj(state), state) + target = backend.outer(backend.conj(target), target) difference = state - target @@ -277,11 +276,9 @@ def fidelity(state, target, check_hermitian: bool = False, backend=None): state = np.zeros(state.shape, dtype=complex) state = backend.cast(state, dtype=state.dtype) for eig, eigvec in zip( - eigenvalues, backend.np.transpose(eigenvectors, (1, 0)) + eigenvalues, backend.transpose(eigenvectors, (1, 0)) ): - matrix = backend.np.sqrt(eig) * backend.np.outer( - eigvec, backend.np.conj(eigvec) - ) + matrix = backend.sqrt(eig) * backend.outer(eigvec, backend.conj(eigvec)) matrix = backend.cast(matrix, dtype=matrix.dtype) state = state + matrix del matrix @@ -295,25 +292,25 @@ def fidelity(state, target, check_hermitian: bool = False, backend=None): fid = np.zeros(state.shape, dtype=complex) fid = backend.cast(fid, dtype=fid.dtype) for eig, eigvec in zip( - eigenvalues, backend.np.transpose(eigenvectors, (1, 0)) + eigenvalues, backend.transpose(eigenvectors, (1, 0)) ): - if backend.np.real(eig) > PRECISION_TOL: - matrix = backend.np.sqrt(eig) * backend.np.outer( - eigvec, backend.np.conj(eigvec) + if backend.real(eig) > PRECISION_TOL: + matrix = backend.sqrt(eig) * backend.outer( + eigvec, backend.conj(eigvec) ) matrix = backend.cast(matrix, dtype=matrix.dtype) fid = fid + matrix del matrix - fid = backend.np.real(backend.np.trace(fid)) + fid = backend.real(backend.trace(fid)) return fid # if any of the states is pure, perform lighter calculation fid = ( - backend.np.abs(backend.np.matmul(backend.np.conj(state), target)) ** 2 + backend.abs(backend.matmul(backend.conj(state), target)) ** 2 if len(state.shape) == 1 - else backend.np.real(backend.np.trace(backend.np.matmul(state, target))) + else backend.real(backend.trace(backend.matmul(state, target))) ) return fid @@ -368,8 +365,8 @@ def bures_angle(state, target, check_hermitian: bool = False, backend=None): """ backend = _check_backend(backend) - angle = backend.np.arccos( - backend.np.sqrt(fidelity(state, target, check_hermitian, backend=backend)) + angle = backend.arccos( + backend.sqrt(fidelity(state, target, check_hermitian, backend=backend)) ) return angle @@ -398,10 +395,8 @@ def bures_distance(state, target, check_hermitian: bool = False, backend=None): float: Bures distance between ``state`` and ``target``. """ backend = _check_backend(backend) - sqrt_fid = backend.np.sqrt( - fidelity(state, target, check_hermitian, backend=backend) - ) - distance = backend.np.sqrt(2 * (1 - sqrt_fid)) + sqrt_fid = backend.sqrt(fidelity(state, target, check_hermitian, backend=backend)) + distance = backend.sqrt(2 * (1 - sqrt_fid)) return distance @@ -441,10 +436,10 @@ def process_fidelity(channel, target=None, check_unitary: bool = False, backend= if check_unitary is True: norm_channel = float( backend.calculate_norm_density_matrix( - backend.np.matmul( - backend.np.conj(backend.np.transpose(channel, (1, 0))), channel + backend.matmul( + backend.conj(backend.transpose(channel, (1, 0))), channel ) - - backend.np.eye(dim**2) + - backend.eye(dim**2) ) ) if target is None and norm_channel > PRECISION_TOL: @@ -452,10 +447,10 @@ def process_fidelity(channel, target=None, check_unitary: bool = False, backend= if target is not None: norm_target = float( backend.calculate_norm( - backend.np.matmul( - backend.np.conj(backend.np.transpose(target, (1, 0))), target + backend.matmul( + backend.conj(backend.transpose(target, (1, 0))), target ) - - backend.np.eye(dim**2) + - backend.eye(dim**2) ) ) if (norm_channel > PRECISION_TOL) and (norm_target > PRECISION_TOL): @@ -463,15 +458,15 @@ def process_fidelity(channel, target=None, check_unitary: bool = False, backend= if target is None: # With no target, return process fidelity with Identity channel - process_fid = backend.np.real(backend.np.trace(channel)) / dim**2 + process_fid = backend.real(backend.trace(channel)) / dim**2 process_fid = float(process_fid) return process_fid - process_fid = backend.np.matmul( - backend.np.transpose(backend.np.conj(channel), (1, 0)), target + process_fid = backend.matmul( + backend.transpose(backend.conj(channel), (1, 0)), target ) - process_fid = backend.np.real(backend.np.trace(process_fid)) / dim**2 + process_fid = backend.real(backend.trace(process_fid)) / dim**2 return process_fid @@ -644,9 +639,9 @@ def diamond_norm(channel, target=None, backend=None, **kwargs): # pragma: no co channel = backend.to_numpy(channel) - channel = backend.np.transpose(channel, (1, 0)) - channel_real = backend.np.real(channel) - channel_imag = backend.np.imag(channel) + channel = backend.transpose(channel, (1, 0)) + channel_real = backend.real(channel) + channel_imag = backend.imag(channel) dim = int(np.sqrt(channel.shape[0])) @@ -836,9 +831,9 @@ def frame_potential( unitary_2.set_parameters(params_2) unitary_2 = unitary_2.unitary(backend) / np.sqrt(dim) - potential += backend.np.abs( - backend.np.trace( - backend.np.transpose(backend.np.conj(unitary_1), (1, 0)) @ unitary_2 + potential += backend.abs( + backend.trace( + backend.transpose(backend.conj(unitary_1), (1, 0)) @ unitary_2 ) ) ** (2 * power_t) @@ -910,9 +905,9 @@ def quantum_fisher_information_matrix( overlaps = jacobian.T @ state qfim = jacobian.T @ jacobian - qfim = qfim - backend.np.outer(overlaps, backend.np.conj(overlaps.T)) + qfim = qfim - backend.outer(overlaps, backend.conj(overlaps.T)) - return 4 * backend.np.real(qfim) + return 4 * backend.real(qfim) def _check_hermitian(matrix, backend=None): @@ -930,7 +925,7 @@ def _check_hermitian(matrix, backend=None): backend = _check_backend(backend) norm = backend.calculate_norm_density_matrix( - backend.np.conj(matrix).T - matrix, order=2 + backend.conj(matrix).T - matrix, order=2 ) hermitian = bool(float(norm) <= PRECISION_TOL) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 0976094978..81eceb2fed 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -224,7 +224,7 @@ def operator(self, full: bool = False, backend=None): n = len(self.partition) order = self._order_tensor_to_operator(n) - operator = self._backend.np.transpose( + operator = self._backend.transpose( tensor.reshape(tuple(np.repeat(self.partition, 2))), order ) @@ -293,11 +293,11 @@ def is_hermitian( dtype=self._tensor.dtype, ) if self._backend.__class__.__name__ == "PyTorchBackend": - adjoint = self._backend.np.transpose(reshaped, (1, 0)) + adjoint = self._backend.transpose(reshaped, (1, 0)) else: - adjoint = self._backend.np.transpose(reshaped) + adjoint = self._backend.transpose(reshaped) - mat_diff = self._backend.np.conj(adjoint) - reshaped + mat_diff = self._backend.conj(adjoint) - reshaped norm = self._backend.calculate_norm_density_matrix(mat_diff, order=order) return float(norm) <= precision_tol @@ -335,7 +335,7 @@ def is_positive_semidefinite(self, precision_tol: float = 1e-8): return False return all( - self._backend.np.real(eigenvalue) >= -precision_tol + self._backend.real(eigenvalue) >= -precision_tol for eigenvalue in eigenvalues ) @@ -365,7 +365,7 @@ def link_product(self, subscripts: str, second_network): def copy(self): """Returns a copy of the :class:`qibo.quantum_info.QuantumNetwork` object.""" return self.__class__( - self._backend.np.copy(self._tensor), + self._backend.copy(self._tensor), partition=self.partition, system_input=self.system_input, pure=self._pure, @@ -375,7 +375,7 @@ def copy(self): def conj(self): """Returns the conjugate of the quantum network.""" return self.__class__( - self._backend.np.conj(self._tensor), + self._backend.conj(self._tensor), partition=self.partition, system_input=self.system_input, pure=self._pure, @@ -629,8 +629,8 @@ def _set_parameters(self): self.system_input = self._check_system_input(self.system_input, self.partition) - self._einsum = self._backend.np.einsum - self._tensordot = self._backend.np.tensordot + self._einsum = self._backend.einsum + self._tensordot = self._backend.tensordot self._tensor = self._backend.cast(self._tensor, dtype=self._tensor.dtype) if self._pure: @@ -641,7 +641,7 @@ def _set_parameters(self): + f"Cannot reshape matrix of size {self._tensor.shape} " + f"to partition {self.partition}.", ) - self._tensor = self._backend.np.reshape(self._tensor, self.partition) + self._tensor = self._backend.reshape(self._tensor, self.partition) else: if np.prod(tuple(self._tensor.shape)) != np.prod( tuple(dim**2 for dim in self.partition) @@ -653,7 +653,7 @@ def _set_parameters(self): + f"to partition {self.partition}.", ) matrix_partition = [dim**2 for dim in self.partition] - self._tensor = self._backend.np.reshape(self._tensor, matrix_partition) + self._tensor = self._backend.reshape(self._tensor, matrix_partition) def full(self, update: bool = False, backend=None): """Convert the internal representation to the full tensor of the network. @@ -670,9 +670,9 @@ def full(self, update: bool = False, backend=None): """ if backend is None: # pragma: no cover backend = self._backend - tensor = self._backend.np.copy(self._tensor) + tensor = self._backend.copy(self._tensor) tensor = backend.cast(tensor, dtype=self._tensor.dtype) - conj = backend.np.conj + conj = backend.conj if self.is_pure(): # Reshapes input matrix based on purity. @@ -978,7 +978,7 @@ def apply(self, state): ndarray: Resulting state :math:`\\mathcal{E}(\\varrho)`. """ operator = self.copy().operator() - conj = self._backend.np.conj + conj = self._backend.conj if self.is_pure(): return self._einsum("ij,lk,il", operator, conj(operator), state) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index cb1ba72a2b..6004f0531c 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -184,12 +184,12 @@ def random_hermitian( matrix = random_gaussian_matrix(dims, dims, seed=local_state, backend=backend) if semidefinite: - matrix = backend.np.matmul(backend.np.conj(matrix).T, matrix) + matrix = backend.matmul(backend.conj(matrix).T, matrix) else: - matrix = (matrix + backend.np.conj(matrix).T) / 2 + matrix = (matrix + backend.conj(matrix).T) / 2 if normalize: - matrix = matrix / np.linalg.norm(backend.to_numpy(matrix)) + matrix = matrix / backend.linalg_norm(backend.to_numpy(matrix)) return matrix @@ -231,11 +231,11 @@ def random_unitary(dims: int, measure: Optional[str] = None, seed=None, backend= if measure == "haar": unitary = random_gaussian_matrix(dims, dims, seed=local_state, backend=backend) # Tensorflow experi - Q, R = backend.np.linalg.qr(unitary) - D = backend.np.diag(R) - D = D / backend.np.abs(D) - R = backend.np.diag(D) - unitary = backend.np.matmul(Q, R) + Q, R = backend.qr(unitary) + D = backend.diag(R) + D = D / backend.abs(D) + R = backend.diag(D) + unitary = backend.matmul(Q, R) elif measure is None: from scipy.linalg import expm @@ -351,7 +351,7 @@ def random_quantum_channel( else: super_op = random_unitary(dims, measure, local_state, backend) super_op = vectorization(super_op, order=order, backend=backend) - super_op = backend.np.outer(super_op, backend.np.conj(super_op)) + super_op = backend.outer(super_op, backend.conj(super_op)) if "chi" in representation: pauli_order = "IXYZ" @@ -438,7 +438,7 @@ def random_statevector(dims: int, seed=None, backend=None): state = backend.cast(local_state.standard_normal(dims).astype(complex)) state = state + 1.0j * backend.cast(local_state.standard_normal(dims)) - state = state / backend.np.linalg.norm(state) + state = state / backend.linalg_norm(state) return state @@ -545,35 +545,35 @@ def random_density_matrix( if pure: state = random_statevector(dims, seed=local_state, backend=backend) - state = backend.np.outer(state, backend.np.conj(state).T) + state = backend.outer(state, backend.conj(state).T) else: if metric in ["hilbert-schmidt", "ginibre"]: state = random_gaussian_matrix( dims, rank, mean=0, stddev=1, seed=local_state, backend=backend ) - state = backend.np.matmul( - state, backend.np.transpose(backend.np.conj(state), (1, 0)) + state = backend.matmul( + state, backend.transpose(backend.conj(state), (1, 0)) ) - state = state / backend.np.trace(state) + state = state / backend.trace(state) else: - nqubits = int(np.log2(dims)) + nqubits = int(backend.log2(dims)) state = backend.identity_density_matrix(nqubits, normalize=False) state += random_unitary(dims, seed=local_state, backend=backend) - state = backend.np.matmul( + state = backend.matmul( state, random_gaussian_matrix(dims, rank, seed=local_state, backend=backend), ) - state = backend.np.matmul( - state, backend.np.transpose(backend.np.conj(state), (1, 0)) + state = backend.matmul( + state, backend.transpose(backend.conj(state), (1, 0)) ) - state /= backend.np.trace(state) + state /= backend.trace(state) state = backend.cast(state, dtype=state.dtype) if basis is not None: pauli_order = basis.split("-")[1] unitary = comp_basis_to_pauli( - int(np.log2(dims)), + int(backend.log2(dims)), normalize=normalize, order=order, pauli_order=pauli_order, @@ -637,15 +637,15 @@ def random_clifford( nqubits, local_state=local_state ) - delta_matrix = np.eye(nqubits, dtype=int) - delta_matrix_prime = np.copy(delta_matrix) + delta_matrix = backend.eye(nqubits, dtype=int) + delta_matrix_prime = backend.copy(delta_matrix) gamma_matrix_prime = local_state.integers(0, 2, size=nqubits) - gamma_matrix_prime = np.diag(gamma_matrix_prime) + gamma_matrix_prime = backend.diag(gamma_matrix_prime) gamma_matrix = local_state.integers(0, 2, size=nqubits) gamma_matrix = hadamards * gamma_matrix - gamma_matrix = np.diag(gamma_matrix) + gamma_matrix = backend.diag(gamma_matrix) # filling off-diagonal elements of gammas and deltas matrices for j in range(nqubits): @@ -937,21 +937,21 @@ def random_pauli_hamiltonian( ) eigenvalues[shift:] = eigenvalues[shift:] * max_eigenvalue / eigenvalues[-1] - hamiltonian = np.zeros((d, d), dtype=complex) + hamiltonian = backend.zeros((d, d), dtype=complex) hamiltonian = backend.cast(hamiltonian, dtype=hamiltonian.dtype) # excluding the first eigenvector because first eigenvalue is zero for eigenvalue, eigenvector in zip( - eigenvalues[1:], backend.np.transpose(eigenvectors, (1, 0))[1:] + eigenvalues[1:], backend.transpose(eigenvectors, (1, 0))[1:] ): - hamiltonian = hamiltonian + eigenvalue * backend.np.outer( - eigenvector, backend.np.conj(eigenvector) + hamiltonian = hamiltonian + eigenvalue * backend.outer( + eigenvector, backend.conj(eigenvector) ) U = comp_basis_to_pauli( nqubits, normalize=True, pauli_order=pauli_order, backend=backend ) - hamiltonian = backend.np.real(U @ vectorization(hamiltonian, backend=backend)) + hamiltonian = backend.real(U @ vectorization(hamiltonian, backend=backend)) return hamiltonian, eigenvalues @@ -1035,9 +1035,9 @@ def random_stochastic_matrix( if diagonally_dominant: matrix /= dims**2 for k, row in enumerate(matrix): - row = np.delete(row, obj=k) - matrix[k, k] = 1 - np.sum(row) - row_sum = np.sum(matrix, axis=1) + row = backend.delete(row, obj=k) + matrix[k, k] = 1 - backend.sum(row) + row_sum = backend.sum(matrix, axis=1) row_sum = matrix.sum(axis=1) @@ -1046,23 +1046,23 @@ def random_stochastic_matrix( count = 0 while count <= max_iterations - 1 and ( ( - np.any(row_sum >= 1 + precision_tol) - or np.any(row_sum <= 1 - precision_tol) + backend.any(row_sum >= 1 + precision_tol) + or backend.any(row_sum <= 1 - precision_tol) ) or ( - np.any(column_sum >= 1 + precision_tol) - or np.any(column_sum <= 1 - precision_tol) + backend.any(column_sum >= 1 + precision_tol) + or backend.any(column_sum <= 1 - precision_tol) ) ): matrix = matrix / matrix.sum(axis=0) - matrix = matrix / matrix.sum(axis=1)[:, np.newaxis] + matrix = matrix / matrix.sum(axis=1)[:, None] row_sum = matrix.sum(axis=1) column_sum = matrix.sum(axis=0) count += 1 if count == max_iterations: warnings.warn("Reached max iterations.", RuntimeWarning) else: - matrix = matrix / np.outer(row_sum, [1] * dims) + matrix = matrix / backend.outer(row_sum, [1] * dims) matrix = backend.cast(matrix, dtype=matrix.dtype) @@ -1196,37 +1196,37 @@ def _super_op_from_bcsz_measure(dims: int, rank: int, order: str, seed, backend) in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ - nqubits = int(np.log2(dims)) + nqubits = int(backend.log2(dims)) super_op = random_gaussian_matrix( dims**2, rank=rank, mean=0, stddev=1, seed=seed, backend=backend ) - super_op = super_op @ backend.np.conj(super_op).T + super_op = super_op @ backend.conj(super_op).T # partial trace implemented with einsum - super_op_reduced = np.einsum( - "ijik->jk", np.reshape(backend.to_numpy(super_op), (dims,) * 4) + super_op_reduced = backend.einsum( + "ijik->jk", backend.reshape(backend.to_numpy(super_op), (dims,) * 4) ) - eigenvalues, eigenvectors = np.linalg.eigh(super_op_reduced) + eigenvalues, eigenvectors = backend.eigh(super_op_reduced) - eigenvalues = np.sqrt(1.0 / eigenvalues) + eigenvalues = backend.sqrt(1.0 / eigenvalues) - operator = np.zeros((dims, dims), dtype=complex) + operator = backend.zeros((dims, dims), dtype=complex) operator = backend.cast(operator, dtype=operator.dtype) for eigenvalue, eigenvector in zip( backend.cast(eigenvalues), backend.cast(eigenvectors).T ): - operator = operator + eigenvalue * backend.np.outer( - eigenvector, backend.np.conj(eigenvector) + operator = operator + eigenvalue * backend.outer( + eigenvector, backend.conj(eigenvector) ) if order == "row": - operator = backend.np.kron( + operator = backend.kron( backend.identity_density_matrix(nqubits, normalize=False), operator ) if order == "column": - operator = backend.np.kron( + operator = backend.kron( operator, backend.identity_density_matrix(nqubits, normalize=False) ) diff --git a/src/qibo/quantum_info/superoperator_transformations.py b/src/qibo/quantum_info/superoperator_transformations.py index fa7d2902ba..dc4b1f564f 100644 --- a/src/qibo/quantum_info/superoperator_transformations.py +++ b/src/qibo/quantum_info/superoperator_transformations.py @@ -69,19 +69,19 @@ def vectorization(state, order: str = "row", backend=None): dims = state.shape[-1] if len(state.shape) == 1: - state = backend.np.outer(state, backend.np.conj(state)) + state = backend.outer(state, backend.conj(state)) elif len(state.shape) == 3 and state.shape[1] == 1: - state = backend.np.einsum( - "aij,akl->aijkl", state, backend.np.conj(state) - ).reshape(state.shape[0], dims, dims) + state = backend.einsum("aij,akl->aijkl", state, backend.conj(state)).reshape( + state.shape[0], dims, dims + ) if order == "row": - state = backend.np.reshape(state, (-1, dims**2)) + state = backend.reshape(state, (-1, dims**2)) elif order == "column": indices = list(range(len(state.shape))) indices[-2:] = reversed(indices[-2:]) - state = backend.np.transpose(state, indices) - state = backend.np.reshape(state, (-1, dims**2)) + state = backend.transpose(state, indices) + state = backend.reshape(state, (-1, dims**2)) else: nqubits = int(np.log2(state.shape[-1])) @@ -89,11 +89,11 @@ def vectorization(state, order: str = "row", backend=None): for qubit in range(nqubits): new_axis.extend([qubit + nqubits + 1, qubit + 1]) - state = backend.np.reshape(state, [-1] + [2] * 2 * nqubits) - state = backend.np.transpose(state, new_axis) - state = backend.np.reshape(state, (-1, 2 ** (2 * nqubits))) + state = backend.reshape(state, [-1] + [2] * 2 * nqubits) + state = backend.transpose(state, new_axis) + state = backend.reshape(state, (-1, 2 ** (2 * nqubits))) - state = backend.np.squeeze( + state = backend.squeeze( state, axis=tuple(i for i, ax in enumerate(state.shape) if ax == 1) ) @@ -155,9 +155,9 @@ def unvectorization(state, order: str = "row", backend=None): else: nqubits = int(np.log2(dim)) axes_old = list(np.arange(0, 2 * nqubits)) - state = backend.np.reshape(state, [2] * 2 * nqubits) - state = backend.np.transpose(state, axes_old[1::2] + axes_old[0::2]) - state = backend.np.reshape(state, [2**nqubits] * 2) + state = backend.reshape(state, [2] * 2 * nqubits) + state = backend.transpose(state, axes_old[1::2] + axes_old[0::2]) + state = backend.reshape(state, [2**nqubits] * 2) return state @@ -187,7 +187,7 @@ def to_choi(channel, order: str = "row", backend=None): backend = _check_backend(backend) channel = vectorization(channel, order=order, backend=backend) - channel = backend.np.outer(channel, backend.np.conj(channel)) + channel = backend.outer(channel, backend.conj(channel)) return channel @@ -259,7 +259,7 @@ def to_pauli_liouville( nqubits, normalize, pauli_order=pauli_order, backend=backend ) - channel = unitary @ channel @ backend.np.conj(unitary).T + channel = unitary @ channel @ backend.conj(unitary).T return channel @@ -518,7 +518,7 @@ def choi_to_kraus( if validate_cp: norm = float( backend.calculate_norm_density_matrix( - choi_super_op - backend.np.conj(choi_super_op).T, order=2 + choi_super_op - backend.conj(choi_super_op).T, order=2 ) ) if norm > PRECISION_TOL: @@ -529,7 +529,7 @@ def choi_to_kraus( eigenvalues, eigenvectors = backend.calculate_eigenvectors(choi_super_op) eigenvectors = eigenvectors.T - non_cp = bool(any(backend.np.real(eigenvalues) < -PRECISION_TOL)) + non_cp = bool(any(backend.real(eigenvalues) < -PRECISION_TOL)) else: non_cp = False # using eigh because, in this case, choi_super_op is @@ -545,8 +545,8 @@ def choi_to_kraus( choi_super_op, backend=backend ) U = U.T - coefficients = backend.np.sqrt(coefficients) - V = backend.np.conj(V) + coefficients = backend.sqrt(coefficients) + V = backend.conj(V) kraus_left, kraus_right = [], [] for coeff, eigenvector_left, eigenvector_right in zip(coefficients, U, V): @@ -563,8 +563,8 @@ def choi_to_kraus( # when choi_super_op is CP kraus_ops, coefficients = [], [] for eig, kraus in zip(eigenvalues, eigenvectors): - if backend.np.abs(eig) > precision_tol: - eig = backend.np.sqrt(eig) + if backend.abs(eig) > precision_tol: + eig = backend.sqrt(eig) kraus_ops.append( eig * unvectorization(kraus, order=order, backend=backend) ) @@ -736,7 +736,7 @@ def kraus_to_choi(kraus_ops, order: str = "row", backend=None): kraus_op.append(gate) kraus_op = kraus_op.matrix(backend) kraus_op = vectorization(kraus_op, order=order, backend=backend) - super_op = super_op + backend.np.outer(kraus_op, backend.np.conj(kraus_op)) + super_op = super_op + backend.outer(kraus_op, backend.conj(kraus_op)) del kraus_op return super_op @@ -875,7 +875,7 @@ def kraus_to_chi( kraus_op = kraus_op.matrix(backend) kraus_op = vectorization(kraus_op, order=order, backend=backend) kraus_op = comp_to_pauli @ kraus_op - super_op = super_op + backend.np.outer(kraus_op, backend.np.conj(kraus_op)) + super_op = super_op + backend.outer(kraus_op, backend.conj(kraus_op)) del kraus_op return super_op @@ -945,7 +945,7 @@ def kraus_to_stinespring( # only utility is for outer product, # so np.conj here to only do it once - initial_state_env = backend.np.conj(initial_state_env) + initial_state_env = backend.conj(initial_state_env) stinespring = np.zeros((dim_stinespring, dim_stinespring), dtype=complex) stinespring = backend.cast(stinespring, dtype=stinespring.dtype) @@ -957,9 +957,9 @@ def kraus_to_stinespring( kraus_op.append(gate) kraus_op = kraus_op.matrix(backend) kraus_op = backend.cast(kraus_op, dtype=kraus_op.dtype) - stinespring = stinespring + backend.np.kron( + stinespring = stinespring + backend.kron( kraus_op, - backend.np.outer(vector_alpha, initial_state_env), + backend.outer(vector_alpha, initial_state_env), ) del kraus_op, vector_alpha @@ -1052,7 +1052,7 @@ def liouville_to_pauli( backend=backend, ) - return comp_to_pauli @ super_op @ backend.np.conj(comp_to_pauli.T) + return comp_to_pauli @ super_op @ backend.conj(comp_to_pauli.T) def liouville_to_kraus( @@ -1253,7 +1253,7 @@ def pauli_to_liouville( backend=backend, ) - return pauli_to_comp @ pauli_op @ backend.np.conj(pauli_to_comp).T + return pauli_to_comp @ pauli_op @ backend.conj(pauli_to_comp).T def pauli_to_choi( @@ -1981,15 +1981,15 @@ def stinespring_to_kraus( initial_state_env, dtype=initial_state_env.dtype ) - stinespring = backend.np.reshape(stinespring, (dim, dim_env, dim, dim_env)) - stinespring = backend.np.swapaxes(stinespring, 1, 2) + stinespring = backend.reshape(stinespring, (dim, dim_env, dim, dim_env)) + stinespring = backend.swapaxes(stinespring, 1, 2) kraus_ops = [] for alpha in range(dim_env): vector_alpha = np.zeros(dim_env, dtype=complex) vector_alpha[alpha] = 1.0 vector_alpha = backend.cast(vector_alpha, dtype=vector_alpha.dtype) - kraus = backend.np.conj(vector_alpha) @ stinespring @ initial_state_env + kraus = backend.conj(vector_alpha) @ stinespring @ initial_state_env kraus_ops.append(kraus) return kraus_ops @@ -2226,12 +2226,12 @@ def _reshuffling(super_op, order: str = "row", backend=None): raise_error(ValueError, "super_op must be of shape (4^n, 4^n)") dim = int(dim) - super_op = backend.np.reshape(super_op, [dim] * 4) + super_op = backend.reshape(super_op, [dim] * 4) axes = [1, 2] if order == "row" else [0, 3] - super_op = backend.np.swapaxes(super_op, *axes) + super_op = backend.swapaxes(super_op, *axes) - super_op = backend.np.reshape(super_op, [dim**2, dim**2]) + super_op = backend.reshape(super_op, [dim**2, dim**2]) return super_op @@ -2290,7 +2290,7 @@ def _individual_kraus_to_liouville( kraus_op.append(gate) kraus_op = kraus_op.matrix(backend) kraus_op = vectorization(kraus_op, order=order, backend=backend) - kraus_op = backend.np.outer(kraus_op, backend.np.conj(kraus_op)) + kraus_op = backend.outer(kraus_op, backend.conj(kraus_op)) super_ops.append(choi_to_liouville(kraus_op, order=order, backend=backend)) return super_ops diff --git a/src/qibo/quantum_info/utils.py b/src/qibo/quantum_info/utils.py index 273e9af9dc..2da3a7133f 100644 --- a/src/qibo/quantum_info/utils.py +++ b/src/qibo/quantum_info/utils.py @@ -244,16 +244,14 @@ def hellinger_distance(prob_dist_p, prob_dist_q, validate: bool = False, backend ValueError, "All elements of the probability array must be between 0. and 1..", ) - if backend.np.abs(backend.np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + if backend.abs(backend.sum(prob_dist_p) - 1.0) > PRECISION_TOL: raise_error(ValueError, "First probability array must sum to 1.") - if backend.np.abs(backend.np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + if backend.abs(backend.sum(prob_dist_q) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Second probability array must sum to 1.") distance = float( - backend.calculate_norm( - backend.np.sqrt(prob_dist_p) - backend.np.sqrt(prob_dist_q) - ) + backend.calculate_norm(backend.sqrt(prob_dist_p) - backend.sqrt(prob_dist_q)) / np.sqrt(2) ) @@ -331,7 +329,7 @@ def hellinger_shot_error( hellinger_error = hellinger_fidelity( prob_dist_p, prob_dist_q, validate=validate, backend=backend ) - hellinger_error = np.sqrt(hellinger_error / nshots) * backend.np.sum( + hellinger_error = np.sqrt(hellinger_error / nshots) * backend.sum( np.sqrt(prob_dist_q * (1 - prob_dist_p)) + np.sqrt(prob_dist_p * (1 - prob_dist_q)) ) @@ -380,10 +378,10 @@ def total_variation_distance( ValueError, "All elements of the probability array must be between 0. and 1..", ) - if backend.np.abs(backend.np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + if backend.abs(backend.sum(prob_dist_p) - 1.0) > PRECISION_TOL: raise_error(ValueError, "First probability array must sum to 1.") - if backend.np.abs(backend.np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + if backend.abs(backend.sum(prob_dist_q) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Second probability array must sum to 1.") tvd = backend.calculate_norm(prob_dist_p - prob_dist_q, order=1) @@ -450,14 +448,14 @@ def haar_integral( rand_unit_density, dtype=rand_unit_density.dtype ) for _ in range(samples): - haar_state = backend.np.reshape( + haar_state = backend.reshape( random_statevector(dim, backend=backend), (-1, 1) ) - rho = haar_state @ backend.np.conj(haar_state).T + rho = haar_state @ backend.conj(haar_state).T rand_unit_density = rand_unit_density + reduce( - backend.np.kron, [rho] * power_t + backend.kron, [rho] * power_t ) integral = rand_unit_density / samples @@ -478,8 +476,8 @@ def haar_integral( integral = np.zeros((dim**power_t, dim**power_t), dtype=float) integral = backend.cast(integral, dtype=integral.dtype) for indices in permutations_list: - integral = integral + backend.np.reshape( - backend.np.transpose(identity, indices), (-1, dim**power_t) + integral = integral + backend.reshape( + backend.transpose(identity, indices), (-1, dim**power_t) ) integral = integral * normalization @@ -540,15 +538,15 @@ def _hadamard_transform_1d(array, backend=None): # necessary because of tf.EagerTensor # does not accept item assignment backend = _check_backend(backend) - array_copied = backend.np.copy(array) + array_copied = backend.copy(array) indexes = [2**k for k in range(int(np.log2(len(array_copied))))] for index in indexes: for k in range(0, len(array_copied), 2 * index): for j in range(k, k + index): # copy necessary because of cupy backend - elem_1 = backend.np.copy(array_copied[j]) - elem_2 = backend.np.copy(array_copied[j + index]) + elem_1 = backend.copy(array_copied[j]) + elem_2 = backend.copy(array_copied[j + index]) array_copied[j] = elem_1 + elem_2 array_copied[j + index] = elem_1 - elem_2 array_copied /= 2.0 diff --git a/src/qibo/result.py b/src/qibo/result.py index b2cdf2fe9f..e6d76aa3d0 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -38,6 +38,37 @@ def __init__(self, state, backend=None): self.nqubits = int(np.log2(state.shape[0])) self._state = state + # state symbolic/array representation + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + def _calculate_symbolic(self, decimals=5, cutoff=1e-10, max_terms=20): + terms = [] + for i in np.nonzero(self._state)[0]: + b = bin(i)[2:].zfill(self.nqubits) + if np.abs(self._state[i]) >= cutoff: + x = np.round(self._state[i], decimals) + terms.append(f"{x}|{b}>") + if len(terms) >= max_terms: + terms.append("...") + return terms + return terms + + def _calculate_symbolic_density_matrix( + self, decimals=5, cutoff=1e-10, max_terms=20 + ): + terms = [] + indi, indj = np.nonzero(self._state) + for i, j in zip(indi, indj): + bi = bin(i)[2:].zfill(self.nqubits) + bj = bin(j)[2:].zfill(self.nqubits) + if np.abs(self._state[i, j]) >= cutoff: + x = np.round(self._state[i, j], decimals) + terms.append(f"{x}|{bi}><{bj}|") + if len(terms) >= max_terms: + terms.append("...") + return terms + return terms + def symbolic(self, decimals: int = 5, cutoff: float = 1e-10, max_terms: int = 20): """Dirac notation representation of the state in the computational basis. @@ -53,13 +84,9 @@ def symbolic(self, decimals: int = 5, cutoff: float = 1e-10, max_terms: int = 20 (str): A string representing the state in the computational basis. """ if self.density_matrix: - terms = self.backend.calculate_symbolic_density_matrix( - self._state, self.nqubits, decimals, cutoff, max_terms - ) + terms = self._calculate_symbolic_density_matrix(decimals, cutoff, max_terms) else: - terms = self.backend.calculate_symbolic( - self._state, self.nqubits, decimals, cutoff, max_terms - ) + terms = self._calculate_symbolic(decimals, cutoff, max_terms) return " + ".join(terms) def state(self, numpy: bool = False): @@ -78,6 +105,37 @@ def state(self, numpy: bool = False): return self._state + # probabilities + # ^^^^^^^^^^^^^ + + def _order_probabilities(self, probs, qubits): + """Arrange probabilities according to the given ``qubits`` ordering.""" + unmeasured, reduced = [], {} + for i in range(self.nqubits): + if i in qubits: + reduced[i] = i - len(unmeasured) + else: + unmeasured.append(i) + return np.transpose(probs, [reduced.get(i) for i in qubits]) + + def _calculate_probabilities(self, qubits): + rtype = np.real(self._state).dtype + unmeasured_qubits = tuple(i for i in range(self.nqubits) if i not in qubits) + state = np.reshape(np.abs(self._state) ** 2, self.nqubits * (2,)) + probs = np.sum(state.astype(dtype=rtype), axis=unmeasured_qubits) + return np.ravel(self._order_probabilities(probs, qubits)) + + def _calculate_probabilities_density_matrix(self, qubits): + order = tuple(sorted(qubits)) + order += tuple(i for i in range(self.nqubits) if i not in qubits) + order = order + tuple(i + self.nqubits for i in order) + shape = 2 * (2 ** len(qubits), 2 ** (self.nqubits - len(qubits))) + state = np.reshape(self._state, 2 * self.nqubits * (2,)) + state = np.reshape(np.transpose(state, order), shape) + probs = np.abs(np.einsum("abab->a", state)) + probs = np.reshape(probs, len(qubits) * (2,)) + return np.ravel(self._order_probabilities(probs, qubits)) + def probabilities(self, qubits: Optional[Union[list, set]] = None): """Calculates measurement probabilities by tracing out qubits. @@ -98,11 +156,12 @@ def probabilities(self, qubits: Optional[Union[list, set]] = None): qubits = tuple(range(self.nqubits)) if self.density_matrix: - return self.backend.calculate_probabilities_density_matrix( - self._state, qubits, self.nqubits - ) + return self._calculate_probabilities_density_matrix(qubits) + + return self._calculate_probabilities(qubits) - return self.backend.calculate_probabilities(self._state, qubits, self.nqubits) + # serialization + # ^^^^^^^^^^^^^ def __str__(self): return self.symbolic() @@ -291,7 +350,7 @@ def probabilities(self, qubits: Optional[Union[list, set]] = None): probs = self.backend.cast(probs) self._probs = probs return self.backend.calculate_probabilities( - self.backend.np.sqrt(probs), qubits, nqubits + self.backend.sqrt(probs), qubits, nqubits ) def has_samples(self): @@ -326,7 +385,7 @@ def samples(self, binary: bool = True, registers: bool = False): qubits = self.measurement_gate.target_qubits if self._samples is None: if self.measurements[0].result.has_samples(): - self._samples = self.backend.np.concatenate( + self._samples = self.backend.concatenate( [gate.result.samples() for gate in self.measurements], axis=1, ) diff --git a/src/qibo/transpiler/unitary_decompositions.py b/src/qibo/transpiler/unitary_decompositions.py index 40bda6d296..b3b2c4f6bf 100644 --- a/src/qibo/transpiler/unitary_decompositions.py +++ b/src/qibo/transpiler/unitary_decompositions.py @@ -26,10 +26,10 @@ def u3_decomposition(unitary, backend): """ unitary = backend.cast(unitary) # https://github.com/Qiskit/qiskit-terra/blob/d2e3340adb79719f9154b665e8f6d8dc26b3e0aa/qiskit/quantum_info/synthesis/one_qubit_decompose.py#L221 - su2 = unitary / backend.np.sqrt(backend.np.linalg.det(unitary)) - theta = 2 * backend.np.arctan2(backend.np.abs(su2[1, 0]), backend.np.abs(su2[0, 0])) - plus = backend.np.angle(su2[1, 1]) - minus = backend.np.angle(su2[1, 0]) + su2 = unitary / backend.sqrt(backend.det(unitary)) + theta = 2 * backend.arctan2(backend.abs(su2[1, 0]), backend.abs(su2[0, 0])) + plus = backend.angle(su2[1, 1]) + minus = backend.angle(su2[1, 0]) phi = plus + minus lam = plus - minus @@ -65,12 +65,10 @@ def calculate_psi(unitary, backend, magic_basis=magic_basis): unitary = backend.cast(unitary) # write unitary in magic basis u_magic = ( - backend.np.transpose(backend.np.conj(magic_basis), (1, 0)) - @ unitary - @ magic_basis + backend.transpose(backend.conj(magic_basis), (1, 0)) @ unitary @ magic_basis ) # construct and diagonalize UT_U - ut_u = backend.np.transpose(u_magic, (1, 0)) @ u_magic + ut_u = backend.transpose(u_magic, (1, 0)) @ u_magic if backend.__class__.__name__ != "PyTorchBackend": # eig seems to have a different behavior based on backend/hardware, # use np.round to increase precision seems to fix the issue @@ -78,9 +76,9 @@ def calculate_psi(unitary, backend, magic_basis=magic_basis): else: eigvals, psi_magic = backend.calculate_eigenvectors(ut_u, hermitian=False) # orthogonalize eigenvectors in the case of degeneracy (Gram-Schmidt) - psi_magic, _ = backend.np.linalg.qr(psi_magic) + psi_magic, _ = backend.qr(psi_magic) # write psi in computational basis - psi = backend.np.matmul(magic_basis, psi_magic) + psi = backend.matmul(magic_basis, psi_magic) return psi, eigvals @@ -95,11 +93,9 @@ def calculate_single_qubit_unitaries(psi, backend=None): Returns: (ndarray, ndarray): Local unitaries UA and UB that map the given basis to the magic basis. """ - psi_magic = backend.np.matmul(backend.np.conj(backend.cast(magic_basis)).T, psi) + psi_magic = backend.matmul(backend.conj(backend.cast(magic_basis)).T, psi) if ( - backend.np.real( - backend.calculate_norm_density_matrix(backend.np.imag(psi_magic)) - ) + backend.real(backend.calculate_norm_density_matrix(backend.imag(psi_magic))) > 1e-6 ): # pragma: no cover raise_error(NotImplementedError, "Given state is not real in the magic basis.") @@ -113,21 +109,19 @@ def calculate_single_qubit_unitaries(psi, backend=None): e_, _, f_ = schmidt_decomposition(e_f_, [0], backend=backend) e_, f_ = e_[:, 0], f_[0] # find exp(1j * delta) using (A5a) - ef_ = backend.np.kron(e, f_) + ef_ = backend.kron(e, f_) phase = ( - 1j - * np.sqrt(2) - * backend.np.sum(backend.np.multiply(backend.np.conj(ef_), psi_bar[2])) + 1j * np.sqrt(2) * backend.sum(backend.multiply(backend.conj(ef_), psi_bar[2])) ) v0 = backend.cast(np.asarray([1, 0])) v1 = backend.cast(np.asarray([0, 1])) # construct unitaries UA, UB using (A6a), (A6b) - ua = backend.np.tensordot(v0, backend.np.conj(e), 0) + phase * backend.np.tensordot( - v1, backend.np.conj(e_), 0 + ua = backend.tensordot(v0, backend.conj(e), 0) + phase * backend.tensordot( + v1, backend.conj(e_), 0 ) - ub = backend.np.tensordot(v0, backend.np.conj(f), 0) + backend.np.conj( + ub = backend.tensordot(v0, backend.conj(f), 0) + backend.conj( phase - ) * backend.np.tensordot(v1, backend.np.conj(f_), 0) + ) * backend.tensordot(v1, backend.conj(f_), 0) return ua, ub @@ -143,21 +137,21 @@ def calculate_diagonal(unitary, ua, ub, va, vb, backend): if backend.__class__.__name__ == "TensorflowBackend": det = np.linalg.det(unitary) ** (1 / 16) else: - det = backend.np.linalg.det(unitary) ** (1 / 16) + det = backend.det(unitary) ** (1 / 16) ua *= det ub *= det va *= det vb *= det - u_dagger = backend.np.transpose( - backend.np.conj( - backend.np.kron( + u_dagger = backend.transpose( + backend.conj( + backend.kron( ua, ub, ) ), (1, 0), ) - v_dagger = backend.np.transpose(backend.np.conj(backend.np.kron(va, vb)), (1, 0)) + v_dagger = backend.transpose(backend.conj(backend.kron(va, vb)), (1, 0)) ud = u_dagger @ unitary @ v_dagger return ua, ub, ud, va, vb @@ -167,14 +161,12 @@ def magic_decomposition(unitary, backend=None): unitary = backend.cast(unitary) psi, eigvals = calculate_psi(unitary, backend=backend) - psi_tilde = backend.np.conj(backend.np.sqrt(eigvals)) * backend.np.matmul( - unitary, psi - ) + psi_tilde = backend.conj(backend.sqrt(eigvals)) * backend.matmul(unitary, psi) va, vb = calculate_single_qubit_unitaries(psi, backend=backend) ua_dagger, ub_dagger = calculate_single_qubit_unitaries(psi_tilde, backend=backend) - ua, ub = backend.np.transpose( - backend.np.conj(ua_dagger), (1, 0) - ), backend.np.transpose(backend.np.conj(ub_dagger), (1, 0)) + ua, ub = backend.transpose(backend.conj(ua_dagger), (1, 0)), backend.transpose( + backend.conj(ub_dagger), (1, 0) + ) return calculate_diagonal(unitary, ua, ub, va, vb, backend=backend) @@ -183,15 +175,13 @@ def to_bell_diagonal(ud, backend, bell_basis=bell_basis): ud = backend.cast(ud) bell_basis = backend.cast(bell_basis) - ud_bell = ( - backend.np.transpose(backend.np.conj(bell_basis), (1, 0)) @ ud @ bell_basis - ) - ud_diag = backend.np.diag(ud_bell) - if not backend.np.allclose( - backend.np.diag(ud_diag), ud_bell, atol=1e-6, rtol=1e-6 + ud_bell = backend.transpose(backend.conj(bell_basis), (1, 0)) @ ud @ bell_basis + ud_diag = backend.diag(ud_bell) + if not backend.allclose( + backend.diag(ud_diag), ud_bell, atol=1e-6, rtol=1e-6 ): # pragma: no cover return None - uprod = backend.to_numpy(backend.np.prod(ud_diag)) + uprod = backend.to_numpy(backend.prod(ud_diag)) if not np.allclose(uprod, 1.0, atol=1e-6, rtol=1e-6): # pragma: no cover return None return ud_diag @@ -202,7 +192,7 @@ def calculate_h_vector(ud_diag, backend): See Eq. (4)-(5) in arXiv:quant-ph/0307177. """ - lambdas = -backend.np.angle(ud_diag) + lambdas = -backend.angle(ud_diag) hx = (lambdas[0] + lambdas[2]) / 2.0 hy = (lambdas[1] + lambdas[2]) / 2.0 hz = (lambdas[0] + lambdas[1]) / 2.0 @@ -230,7 +220,7 @@ def cnot_decomposition(q0, q1, hx, hy, hz, backend): gates.Unitary(h @ v3 @ h, q1), gates.CZ(q0, q1), gates.Unitary(w, q0), - gates.Unitary(backend.np.conj(w).T @ h, q1), + gates.Unitary(backend.conj(w).T @ h, q1), ] @@ -242,14 +232,14 @@ def cnot_decomposition_light(q0, q1, hx, hy, backend): v2 = gates.RZ(0, -2 * hy).matrix(backend) # change CNOT to CZ using Hadamard gates return [ - gates.Unitary(backend.np.conj(w).T, q0), + gates.Unitary(backend.conj(w).T, q0), gates.Unitary(h @ w, q1), gates.CZ(q0, q1), gates.Unitary(u2, q0), gates.Unitary(h @ v2 @ h, q1), gates.CZ(q0, q1), gates.Unitary(w, q0), - gates.Unitary(backend.np.conj(w).T @ h, q1), + gates.Unitary(backend.conj(w).T @ h, q1), ] diff --git a/tests/conftest.py b/tests/conftest.py index 344accf983..a98b9de50f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,11 +13,11 @@ # backends to be tested BACKENDS = [ "numpy", - "qibojit-numba", - "qibojit-cupy", - "qibojit-cuquantum", - "qiboml-tensorflow", - "qiboml-pytorch", + # "pytorch", + # "qibojit-numba", + # "qibojit-cupy", + # "qibojit-cuquantum", + # "qiboml-tensorflow", ] # multigpu configurations to be tested (only with qibojit-cupy) ACCELERATORS = [ diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 6cd1cd9e2c..721fe917ad 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -4,7 +4,6 @@ import numpy as np import pytest -from qiboml.backends import PyTorchBackend, TensorflowBackend from qibo import Circuit, gates, get_backend, set_backend from qibo.backends import CliffordBackend, NumpyBackend @@ -16,9 +15,10 @@ def construct_clifford_backend(backend): - if ( - isinstance(backend, (TensorflowBackend, PyTorchBackend)) - or backend.__class__.__name__ == "CuQuantumBackend" + if backend.__class__.__name__ in ( + "CuQuantumBackend", + "TensorflowBackend", + "PyTorchBackend", ): with pytest.raises(NotImplementedError): clifford_backend = CliffordBackend(backend.name) diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index b599a904f1..a6ee5b7b68 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -98,9 +98,7 @@ def test_entropy_in_circuit(backend, density_matrix, base): backend.assert_allclose(values, target, atol=PRECISION_TOL) target_spectrum = [0.0] + list([0, 0, np.log(2), np.log(2)] / np.log(base)) - entropy_spectrum = backend.np.ravel( - backend.np.concatenate(entropy.spectrum) - ).tolist() + entropy_spectrum = backend.ravel(backend.concatenate(entropy.spectrum)).tolist() backend.assert_allclose(entropy_spectrum, target_spectrum, atol=PRECISION_TOL) @@ -121,7 +119,7 @@ def test_entropy_in_distributed_circuit( """Check that various entropy configurations work in distributed circuit.""" target_c = Circuit(4) target_c.add([gates.H(0), gates.CNOT(0, 1)]) - target_state = backend.execute_circuit(target_c) + target_state = backend.execute_circuit(target_c).state() entropy = callbacks.EntanglementEntropy([0]) c = Circuit(4, accelerators) @@ -132,7 +130,7 @@ def test_entropy_in_distributed_circuit( c.add(gates.CNOT(0, 1)) elif gate == "entropy": c.add(gates.CallbackGate(entropy)) - final_state = backend.execute_circuit(c) + final_state = backend.execute_circuit(c).state() backend.assert_allclose(final_state, target_state) values = [backend.to_numpy(x) for x in entropy[:]] backend.assert_allclose(values, target_entropy, atol=PRECISION_TOL) @@ -142,7 +140,7 @@ def test_entropy_multiple_executions(backend, accelerators): """Check entropy calculation when the callback is used in multiple executions.""" target_c = Circuit(4) target_c.add([gates.RY(0, 0.1234), gates.CNOT(0, 1)]) - target_state = backend.execute_circuit(target_c) + target_state = backend.execute_circuit(target_c).state() entropy = callbacks.EntanglementEntropy([0]) c = Circuit(4, accelerators) @@ -150,19 +148,19 @@ def test_entropy_multiple_executions(backend, accelerators): c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) - state = backend.execute_circuit(c) + state = backend.execute_circuit(c).state() backend.assert_allclose(state, target_state) target_c = Circuit(4) target_c.add([gates.RY(0, 0.4321), gates.CNOT(0, 1)]) - target_state = backend.execute_circuit(target_c) + target_state = backend.execute_circuit(target_c).state() c = Circuit(4, accelerators) c.add(gates.RY(0, 0.4321)) c.add(gates.CallbackGate(entropy)) c.add(gates.CNOT(0, 1)) c.add(gates.CallbackGate(entropy)) - state = backend.execute_circuit(c) + state = backend.execute_circuit(c).state() backend.assert_allclose(state, target_state) def target_entropy(t): @@ -217,7 +215,7 @@ def test_entropy_large_circuit(backend, accelerators): c.add(gates.RY(i, thetas[2, i]) for i in range(8)) c.add(gates.CZ(i, i + 1) for i in range(0, 7, 2)) c.add(gates.CallbackGate(entropy)) - state = backend.execute_circuit(c) + state = backend.execute_circuit(c).state() backend.assert_allclose(state3, state) values = [backend.to_numpy(x) for x in entropy[:]] @@ -234,9 +232,9 @@ def test_entropy_density_matrix(backend): u = backend.cast(u, dtype=u.dtype) matrix = np.random.random(u.shape[0]) matrix = backend.cast(matrix, dtype=u.dtype) - rho = backend.np.matmul( - backend.np.matmul(u, backend.np.diag(5 * matrix)), - backend.np.conj(backend.np.transpose(u, (1, 0))), + rho = backend.matmul( + backend.matmul(u, backend.diag(5 * matrix)), + backend.conj(backend.transpose(u, (1, 0))), ) # this is a positive rho @@ -284,7 +282,7 @@ def test_norm(backend, density_matrix, seed): if density_matrix: norm.nqubits = 1 state = random_density_matrix(2**norm.nqubits, seed=seed, backend=backend) - target_norm = backend.np.trace(state) + target_norm = backend.trace(state) final_norm = norm.apply_density_matrix(backend, state) else: norm.nqubits = 2 @@ -336,7 +334,7 @@ def test_energy(backend, density_matrix): from qibo.quantum_info import random_density_matrix state = random_density_matrix(2**4, backend=backend) - target_energy = backend.np.trace(backend.np.matmul(matrix, state)) + target_energy = backend.trace(backend.matmul(matrix, state)) final_energy = energy.apply_density_matrix(backend, state) else: from qibo.quantum_info import random_statevector diff --git a/tests/test_gates_channels.py b/tests/test_gates_channels.py index a1a7974541..7fd2dafb16 100644 --- a/tests/test_gates_channels.py +++ b/tests/test_gates_channels.py @@ -21,22 +21,22 @@ def test_general_channel(backend): * np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) ) initial_state = random_density_matrix(2**2, backend=backend) - m_1 = backend.np.kron(backend.identity_density_matrix(1, normalize=False), a_1) + m_1 = backend.kron(backend.identity_density_matrix(1, normalize=False), a_1) m_1 = backend.cast(m_1, dtype=m_1.dtype) m_2 = backend.cast(a_2, dtype=a_2.dtype) - target_state = backend.np.matmul( - backend.np.matmul(m_1, initial_state), - backend.np.transpose(backend.np.conj(m_1), (1, 0)), + target_state = backend.matmul( + backend.matmul(m_1, initial_state), + backend.transpose(backend.conj(m_1), (1, 0)), ) - target_state = target_state + backend.np.matmul( - backend.np.matmul(m_2, initial_state), - backend.np.transpose(backend.np.conj(m_2), (1, 0)), + target_state = target_state + backend.matmul( + backend.matmul(m_2, initial_state), + backend.transpose(backend.conj(m_2), (1, 0)), ) channel1 = gates.KrausChannel([(1,), (0, 1)], [a_1, a_2]) assert channel1.target_qubits == (0, 1) final_state = backend.apply_channel_density_matrix( - channel1, backend.np.copy(initial_state), 2 + channel1, backend.copy(initial_state), 2 ) backend.assert_allclose(final_state, target_state) @@ -45,7 +45,7 @@ def test_general_channel(backend): channel2 = gates.KrausChannel([(1,), (0, 1)], [a_1, a_2]) assert channel2.target_qubits == (0, 1) final_state = backend.apply_channel_density_matrix( - channel2, backend.np.copy(initial_state), 2 + channel2, backend.copy(initial_state), 2 ) backend.assert_allclose(final_state, target_state) @@ -152,18 +152,18 @@ def test_unitary_channel(backend): channel = gates.UnitaryChannel(qubits, matrices_) initial_state = random_density_matrix(2**4, backend=backend) final_state = backend.apply_channel_density_matrix( - channel, backend.np.copy(initial_state), 4 + channel, backend.copy(initial_state), 4 ) eye = backend.identity_density_matrix(1, normalize=False) - ma_1 = backend.np.kron(backend.np.kron(a_1, eye), backend.np.kron(eye, eye)) - ma_2 = backend.np.kron(backend.np.kron(eye, eye), a_2) + ma_1 = backend.kron(backend.kron(a_1, eye), backend.kron(eye, eye)) + ma_2 = backend.kron(backend.kron(eye, eye), a_2) ma_1 = backend.cast(ma_1, dtype=ma_1.dtype) ma_2 = backend.cast(ma_2, dtype=ma_2.dtype) target_state = ( 0.3 * initial_state - + 0.4 * backend.np.matmul(ma_1, backend.np.matmul(initial_state, ma_1)) - + 0.3 * backend.np.matmul(ma_2, backend.np.matmul(initial_state, ma_2)) + + 0.4 * backend.matmul(ma_1, backend.matmul(initial_state, ma_1)) + + 0.3 * backend.matmul(ma_2, backend.matmul(initial_state, ma_2)) ) backend.assert_allclose(final_state, target_state) @@ -186,7 +186,7 @@ def test_unitary_channel_probability_tolerance(backend): matrices_ = [(p, np.random.random((4, 4))) for p in probs] identity_channel = gates.UnitaryChannel(qubits, matrices_) backend.assert_allclose( - identity_channel.to_liouville(backend=backend), backend.np.eye(num_terms) + identity_channel.to_liouville(backend=backend), backend.eye(num_terms) ) @@ -217,11 +217,11 @@ def test_pauli_noise_channel(backend, pauli_order): qubits = (1,) channel = gates.PauliNoiseChannel(qubits, [("X", 0.3)]) final_state = backend.apply_channel_density_matrix( - channel, backend.np.copy(initial_state), 2 + channel, backend.copy(initial_state), 2 ) gate = gates.X(1) target_state = backend.apply_gate_density_matrix( - gate, backend.np.copy(initial_state), 2 + gate, backend.copy(initial_state), 2 ) target_state = 0.3 * target_state + 0.7 * initial_state backend.assert_allclose(final_state, target_state) @@ -262,9 +262,7 @@ def test_depolarizing_channel(backend): initial_state = random_density_matrix(2**3, backend=backend) initial_state_r = partial_trace(initial_state, (2,), backend=backend) channel = gates.DepolarizingChannel((0, 1), lam) - final_state = channel.apply_density_matrix( - backend, backend.np.copy(initial_state), 3 - ) + final_state = channel.apply_density_matrix(backend, backend.copy(initial_state), 3) final_state_r = partial_trace(final_state, (2,), backend=backend) target_state_r = (1 - lam) * initial_state_r + lam * backend.cast( np.identity(4) @@ -288,12 +286,10 @@ def test_amplitude_damping_channel(backend): channel = gates.AmplitudeDampingChannel(0, gamma) initial_state = random_density_matrix(2**1, backend=backend) - final_state = channel.apply_density_matrix( - backend, backend.np.copy(initial_state), 1 - ) - target_state = kraus_0 @ initial_state @ backend.np.transpose( - backend.np.conj(kraus_0), (1, 0) - ) + kraus_1 @ initial_state @ backend.np.transpose(backend.np.conj(kraus_1), (1, 0)) + final_state = channel.apply_density_matrix(backend, backend.copy(initial_state), 1) + target_state = kraus_0 @ initial_state @ backend.transpose( + backend.conj(kraus_0), (1, 0) + ) + kraus_1 @ initial_state @ backend.transpose(backend.conj(kraus_1), (1, 0)) backend.assert_allclose(final_state, target_state) @@ -314,12 +310,10 @@ def test_phase_damping_channel(backend): channel = gates.PhaseDampingChannel(0, gamma) initial_state = random_density_matrix(2**1, backend=backend) - final_state = channel.apply_density_matrix( - backend, backend.np.copy(initial_state), 1 - ) - target_state = kraus_0 @ initial_state @ backend.np.transpose( - backend.np.conj(kraus_0), (1, 0) - ) + kraus_1 @ initial_state @ backend.np.transpose(backend.np.conj(kraus_1), (1, 0)) + final_state = channel.apply_density_matrix(backend, backend.copy(initial_state), 1) + target_state = kraus_0 @ initial_state @ backend.transpose( + backend.conj(kraus_0), (1, 0) + ) + kraus_1 @ initial_state @ backend.transpose(backend.conj(kraus_1), (1, 0)) backend.assert_allclose(final_state, target_state) @@ -331,7 +325,7 @@ def test_thermal_relaxation_channel(backend, t_1, t_2, time, excpop): """Check ``gates.ThermalRelaxationChannel`` on a 3-qubit random density matrix.""" initial_state = random_density_matrix(2**3, backend=backend) gate = gates.ThermalRelaxationChannel(0, [t_1, t_2, time, excpop]) - final_state = gate.apply_density_matrix(backend, backend.np.copy(initial_state), 3) + final_state = gate.apply_density_matrix(backend, backend.copy(initial_state), 3) if t_2 > t_1: p_0, p_1, exp = ( @@ -343,7 +337,7 @@ def test_thermal_relaxation_channel(backend, t_1, t_2, time, excpop): matrix[0, -1], matrix[-1, 0] = exp, exp matrix = matrix.reshape(4 * (2,)) # Apply matrix using Eq. (3.28) from arXiv:1111.6950 - target_state = backend.np.copy(initial_state).reshape(6 * (2,)) + target_state = backend.copy(initial_state).reshape(6 * (2,)) target_state = np.einsum( "abcd,aJKcjk->bJKdjk", matrix, backend.to_numpy(target_state) ) @@ -354,9 +348,9 @@ def test_thermal_relaxation_channel(backend, t_1, t_2, time, excpop): gate.init_kwargs["p_1"], gate.init_kwargs["p_z"], ) - m_z = backend.np.kron( + m_z = backend.kron( backend.cast(matrices.Z), - backend.np.kron(backend.cast(matrices.I), backend.cast(matrices.I)), + backend.kron(backend.cast(matrices.I), backend.cast(matrices.I)), ) m_z = backend.cast(m_z, dtype=m_z.dtype) z_rho = m_z @ initial_state @ m_z @@ -376,9 +370,7 @@ def test_thermal_relaxation_channel(backend, t_1, t_2, time, excpop): ones = backend.cast(ones, dtype=ones.dtype) target_state = (1 - p_0 - p_1 - p_z) * initial_state + p_z * z_rho - target_state += backend.np.reshape( - p_0 * zeros + p_1 * ones, initial_state.shape - ) + target_state += backend.reshape(p_0 * zeros + p_1 * ones, initial_state.shape) target_state = backend.cast(target_state, dtype=target_state.dtype) @@ -433,7 +425,7 @@ def test_reset_channel(backend): initial_state = random_density_matrix(2**3, backend=backend) gate = gates.ResetChannel(0, [0.2, 0.2]) final_state = backend.reset_error_density_matrix( - gate, backend.np.copy(initial_state), 3 + gate, backend.copy(initial_state), 3 ) trace = backend.to_numpy(partial_trace(initial_state, (0,), backend=backend)) @@ -446,7 +438,7 @@ def test_reset_channel(backend): zeros = backend.cast(zeros, dtype=zeros.dtype) ones = backend.cast(ones, dtype=ones.dtype) - target_state = 0.6 * initial_state + 0.2 * backend.np.reshape( + target_state = 0.6 * initial_state + 0.2 * backend.reshape( zeros + ones, initial_state.shape ) diff --git a/tests/test_gates_density_matrix.py b/tests/test_gates_density_matrix.py index ec4fde3e27..541ad98cfc 100644 --- a/tests/test_gates_density_matrix.py +++ b/tests/test_gates_density_matrix.py @@ -9,7 +9,7 @@ def apply_gates(backend, gatelist, nqubits=None, initial_state=None): - state = backend.cast(backend.np.copy(initial_state)) + state = backend.cast(backend.copy(initial_state)) for gate in gatelist: state = backend.apply_gate_density_matrix(gate, state, nqubits) return backend.to_numpy(state) @@ -24,7 +24,7 @@ def test_hgate_density_matrix(backend): matrix = np.array([[1 + 0j, 1], [1 + 0j, -1]]) / np.sqrt(2) matrix = np.kron(np.eye(2), matrix) matrix = backend.cast(matrix, dtype=matrix.dtype) - target_rho = backend.np.matmul(backend.np.matmul(matrix, initial_rho), matrix) + target_rho = backend.matmul(backend.matmul(matrix, initial_rho), matrix) backend.assert_allclose(final_rho, target_rho) @@ -38,8 +38,8 @@ def test_rygate_density_matrix(backend): phase = np.exp(1j * theta / 2.0) matrix = phase * np.array([[phase.real, -phase.imag], [phase.imag, phase.real]]) matrix = backend.cast(matrix, dtype=matrix.dtype) - target_rho = backend.np.matmul( - backend.np.matmul(matrix, initial_rho), backend.np.conj(matrix).T + target_rho = backend.matmul( + backend.matmul(matrix, initial_rho), backend.conj(matrix).T ) backend.assert_allclose(final_rho, target_rho, atol=PRECISION_TOL) @@ -85,7 +85,7 @@ def test_controlled_by_one_qubit_gates(backend, gatename): nqubits = 2 initial_rho = random_density_matrix(2**nqubits, seed=1, backend=backend) gate = getattr(gates, gatename)(1).controlled_by(0) - final_rho = apply_gates(backend, [gate], 2, backend.np.copy(initial_rho)) + final_rho = apply_gates(backend, [gate], 2, backend.copy(initial_rho)) matrix = backend.to_numpy(backend.matrix(getattr(gates, gatename)(1))) cmatrix = np.eye(4, dtype=matrix.dtype) @@ -169,8 +169,8 @@ def test_cu1gate_application_twoqubit(backend): matrix[3, 3] = np.exp(1j * theta) matrix = np.kron(matrix, np.eye(2)) matrix = backend.cast(matrix, dtype=matrix.dtype) - target_rho = backend.np.matmul( - backend.np.matmul(matrix, initial_rho), backend.np.conj(matrix).T + target_rho = backend.matmul( + backend.matmul(matrix, initial_rho), backend.conj(matrix).T ) backend.assert_allclose(final_rho, target_rho) @@ -203,7 +203,7 @@ def test_controlled_with_effect(backend): c.add(gates.X(2)) c.add(gates.SWAP(1, 3).controlled_by(0, 2)) final_rho = backend.execute_circuit( - c, backend.np.copy(backend.cast(initial_rho)) + c, backend.copy(backend.cast(initial_rho)) ).state() c = Circuit(4, density_matrix=True) @@ -211,7 +211,7 @@ def test_controlled_with_effect(backend): c.add(gates.X(2)) c.add(gates.SWAP(1, 3)) target_rho = backend.execute_circuit( - c, backend.np.copy(backend.cast(initial_rho)) + c, backend.copy(backend.cast(initial_rho)) ).state() backend.assert_allclose(final_rho, target_rho) @@ -221,15 +221,15 @@ def test_controlled_by_random(backend, nqubits): """Check controlled_by method on gate.""" initial_psi = random_statevector(2**nqubits, backend=backend) - initial_rho = backend.np.outer(initial_psi, backend.np.conj(initial_psi)) + initial_rho = backend.outer(initial_psi, backend.conj(initial_psi)) c = Circuit(nqubits, density_matrix=True) c.add(gates.RX(1, theta=0.789).controlled_by(2)) c.add(gates.fSim(0, 2, theta=0.123, phi=0.321).controlled_by(1, 3)) - final_rho = backend.execute_circuit(c, backend.np.copy(initial_rho)).state() + final_rho = backend.execute_circuit(c, backend.copy(initial_rho)).state() c = Circuit(nqubits) c.add(gates.RX(1, theta=0.789).controlled_by(2)) c.add(gates.fSim(0, 2, theta=0.123, phi=0.321).controlled_by(1, 3)) - target_psi = backend.execute_circuit(c, backend.np.copy(initial_psi)).state() - target_rho = backend.np.outer(target_psi, backend.np.conj(target_psi)) + target_psi = backend.execute_circuit(c, backend.copy(initial_psi)).state() + target_rho = backend.outer(target_psi, backend.conj(target_psi)) backend.assert_allclose(final_rho, target_rho) diff --git a/tests/test_gates_gates.py b/tests/test_gates_gates.py index f47f26d613..a204f7b8d3 100644 --- a/tests/test_gates_gates.py +++ b/tests/test_gates_gates.py @@ -367,7 +367,7 @@ def test_gpi(backend): matrix = np.array([[0, np.conj(phase)], [phase, 0]]) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) backend.assert_allclose(final_state, target_state, atol=1e-6) assert gates.GPI(0, phi).qasm_label == "gpi" @@ -387,7 +387,7 @@ def test_gpi2(backend): matrix = np.array([[1, -1.0j * np.conj(phase)], [-1.0j * phase, 1]]) / np.sqrt(2) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) backend.assert_allclose(final_state, target_state, atol=1e-6) assert gates.GPI2(0, phi).qasm_label == "gpi2" @@ -455,17 +455,17 @@ def test_u3(backend, seed_state, seed_observable): matrix = np.array([[ep.conj() * cost, -em.conj() * sint], [em * sint, ep * cost]]) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) backend.assert_allclose(final_state, target_state, atol=1e-6) # testing random expectation value due to global phase difference observable = random_hermitian(2**nqubits, seed=seed_observable, backend=backend) backend.assert_allclose( - backend.cast(backend.np.conj(final_state_decompose).T) + backend.cast(backend.conj(final_state_decompose).T) @ observable @ final_state_decompose, - backend.cast(backend.np.conj(target_state).T) + backend.cast(backend.conj(target_state).T) @ observable @ backend.cast(target_state), atol=1e-6, @@ -491,7 +491,7 @@ def test_u1q(backend, seed_state): ) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) backend.assert_allclose(final_state, target_state, atol=1e-6) @@ -531,7 +531,7 @@ def test_cy(backend, seed_state, seed_observable): ) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) # test decomposition final_state_decompose = apply_gates( backend, @@ -549,10 +549,10 @@ def test_cy(backend, seed_state, seed_observable): # testing random expectation value due to global phase difference observable = random_hermitian(2**nqubits, seed=seed_observable, backend=backend) backend.assert_allclose( - backend.cast(backend.np.conj(final_state_decompose).T) + backend.cast(backend.conj(final_state_decompose).T) @ observable @ final_state_decompose, - backend.cast(backend.np.conj(target_state).T) + backend.cast(backend.conj(target_state).T) @ observable @ backend.cast(target_state), atol=1e-6, @@ -573,7 +573,7 @@ def test_cz(backend, seed_state, seed_observable): matrix[3, 3] = -1 matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, initial_state) + target_state = backend.matmul(matrix, initial_state) # test decomposition final_state_decompose = apply_gates( backend, @@ -591,10 +591,10 @@ def test_cz(backend, seed_state, seed_observable): # testing random expectation value due to global phase difference observable = random_hermitian(2**nqubits, seed=seed_observable, backend=backend) backend.assert_allclose( - backend.cast(backend.np.conj(final_state_decompose).T) + backend.cast(backend.conj(final_state_decompose).T) @ observable @ final_state_decompose, - backend.cast(backend.np.conj(target_state).T) + backend.cast(backend.conj(target_state).T) @ observable @ backend.cast(target_state), atol=1e-6, @@ -718,7 +718,7 @@ def test_cun(backend, name, params): _matrix = gate.matrix(backend) gate = backend.cast(_matrix, dtype=_matrix.dtype) - target_state = backend.np.matmul(gate, initial_state) + target_state = backend.matmul(gate, initial_state) backend.assert_allclose(final_state, target_state, atol=1e-6) @@ -814,7 +814,7 @@ def test_fsim(backend): matrix[1:3, 1:3] = rotation matrix[3, 3] = np.exp(-1j * phi) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, backend.cast(target_state)) + target_state = backend.matmul(matrix, backend.cast(target_state)) backend.assert_allclose(final_state, target_state, atol=1e-6) @@ -1034,10 +1034,10 @@ def test_rxxyy(backend): backend.assert_allclose(final_state, target_state, atol=1e-6) # testing random expectation value due to global phase difference backend.assert_allclose( - backend.cast(backend.np.conj(final_state_decompose).T) + backend.cast(backend.conj(final_state_decompose).T) @ observable @ final_state_decompose, - backend.cast(backend.np.conj(target_state).T) @ observable @ target_state, + backend.cast(backend.conj(target_state).T) @ observable @ target_state, atol=1e-6, ) @@ -1072,7 +1072,7 @@ def test_ms(backend): matrix[1, 2] = -1.0j * np.conj(minus) matrix /= np.sqrt(2) matrix = backend.cast(matrix) - target_state = backend.np.matmul(matrix, backend.cast(target_state)) + target_state = backend.matmul(matrix, backend.cast(target_state)) backend.assert_allclose(final_state, target_state, atol=1e-6) @@ -1194,10 +1194,10 @@ def test_ecr(backend): # testing random expectation value due to global phase difference observable = random_hermitian(2**nqubits, backend=backend) backend.assert_allclose( - backend.cast(backend.np.conj(final_state_decompose).T) + backend.cast(backend.conj(final_state_decompose).T) @ observable @ final_state_decompose, - backend.cast(backend.np.conj(target_state).T) @ observable @ target_state, + backend.cast(backend.conj(target_state).T) @ observable @ target_state, atol=1e-6, ) @@ -1705,8 +1705,8 @@ def test_unitary_dagger(backend, nqubits): gate = gates.Unitary(matrix, *range(nqubits)) initial_state = random_statevector(2**nqubits, backend=backend) final_state = apply_gates(backend, [gate, gate.dagger()], nqubits, initial_state) - target_state = backend.np.matmul(matrix, initial_state) - target_state = backend.np.matmul(backend.np.conj(matrix).T, target_state) + target_state = backend.matmul(matrix, initial_state) + target_state = backend.matmul(backend.conj(matrix).T, target_state) backend.assert_allclose(final_state, target_state, atol=1e-6) @@ -1774,9 +1774,9 @@ def test_x_decomposition_execution(backend, target, controls, free, use_toffolis gate = gates.X(target).controlled_by(*controls) nqubits = max((target,) + controls + free) + 1 initial_state = random_statevector(2**nqubits, backend=backend) - target_state = backend.apply_gate(gate, backend.np.copy(initial_state), nqubits) + target_state = backend.apply_gate(gate, backend.copy(initial_state), nqubits) dgates = gate.decompose(*free, use_toffolis=use_toffolis) - final_state = backend.np.copy(initial_state) + final_state = backend.copy(initial_state) for gate in dgates: final_state = backend.apply_gate(gate, final_state, nqubits) backend.assert_allclose(final_state, target_state, atol=1e-6) diff --git a/tests/test_hamiltonians.py b/tests/test_hamiltonians.py index e66c824da2..8038f50a32 100644 --- a/tests/test_hamiltonians.py +++ b/tests/test_hamiltonians.py @@ -89,10 +89,8 @@ def transformation_d(a, b, use_eye=False): HT3 = transformation_c(H1, H2) HT4 = transformation_d(H1, H2) - backend.assert_allclose(hH1, HT1.matrix) - backend.assert_allclose(hH2, HT2.matrix) - backend.assert_allclose(hH3, HT3.matrix) - backend.assert_allclose(hH4, HT4.matrix) + for hH, HT in zip((hH1, hH2, hH3, hH4), (HT1, HT2, HT3, HT4)): + backend.assert_allclose(backend.to_numpy(hH), backend.to_numpy(HT.matrix)) @pytest.mark.parametrize("sparse_type", [None, "coo", "csr", "csc", "dia"]) @@ -118,10 +116,10 @@ def test_hamiltonian_addition(backend, sparse_type): H = H1 + H2 matrix = H1.matrix + H2.matrix - backend.assert_allclose(H.matrix, matrix) + backend.assert_allclose(backend.to_numpy(H.matrix), backend.to_numpy(matrix)) H = H1 - 0.5 * H2 matrix = H1.matrix - 0.5 * H2.matrix - backend.assert_allclose(H.matrix, matrix) + backend.assert_allclose(backend.to_numpy(H.matrix), backend.to_numpy(matrix)) H1 = hamiltonians.XXZ(nqubits=2, delta=0.5, backend=backend) H2 = hamiltonians.XXZ(nqubits=3, delta=0.1, backend=backend) @@ -177,8 +175,8 @@ def test_hamiltonian_matmul(backend, sparse_type): with pytest.raises(NotImplementedError): _ = H1 @ H2 else: - backend.assert_allclose((H1 @ H2).matrix, (m1 @ m2)) - backend.assert_allclose((H2 @ H1).matrix, (m2 @ m1)) + backend.assert_allclose(backend.to_numpy((H1 @ H2).matrix), (m1 @ m2)) + backend.assert_allclose(backend.to_numpy((H2 @ H1).matrix), (m2 @ m1)) with pytest.raises(ValueError): H1 @ np.zeros(3 * (2**nqubits,), dtype=m1.dtype) @@ -449,8 +447,8 @@ def construct_hamiltonian(): H1 = construct_hamiltonian() _ = H1.eigenvectors() - backend.assert_allclose(H.exp(0.5), target_matrix, atol=1e-6) - backend.assert_allclose(H1.exp(0.5), target_matrix, atol=1e-6) + backend.assert_allclose(backend.to_numpy(H.exp(0.5)), target_matrix, atol=1e-6) + backend.assert_allclose(backend.to_numpy(H1.exp(0.5)), target_matrix, atol=1e-6) def test_hamiltonian_energy_fluctuation(backend): @@ -459,7 +457,7 @@ def test_hamiltonian_energy_fluctuation(backend): ham = hamiltonians.XXZ(nqubits=2, backend=backend) # take ground state and zero state ground_state = ham.ground_state() - zero_state = backend.np.ones(2**2) / np.sqrt(2**2) + zero_state = backend.ones(2**2) / np.sqrt(2**2) # collect energy fluctuations gs_energy_fluctuation = ham.energy_fluctuation(ground_state) zs_energy_fluctuation = ham.energy_fluctuation(zero_state) diff --git a/tests/test_hamiltonians_terms.py b/tests/test_hamiltonians_terms.py index 0addb08adc..2931af3b7a 100644 --- a/tests/test_hamiltonians_terms.py +++ b/tests/test_hamiltonians_terms.py @@ -48,12 +48,10 @@ def test_hamiltonian_term_gates(backend): backend.assert_allclose(gate.matrix(backend), matrix) initial_state = random_statevector(2**nqubits, backend=backend) - final_state = term(backend, backend.np.copy(initial_state), nqubits) + final_state = term(backend, backend.copy(initial_state), nqubits) circuit = Circuit(nqubits) circuit.add(gates.Unitary(matrix, 1, 2)) - target_state = backend.execute_circuit( - circuit, backend.np.copy(initial_state) - ).state() + target_state = backend.execute_circuit(circuit, backend.copy(initial_state)).state() backend.assert_allclose(final_state, target_state) @@ -67,9 +65,9 @@ def test_hamiltonian_term_exponentiation(backend): backend.assert_allclose(term.exp(0.5), exp_matrix) initial_state = random_statevector(4, backend=backend) - final_state = term(backend, backend.np.copy(initial_state), 2, term.expgate(0.5)) + final_state = term(backend, backend.copy(initial_state), 2, term.expgate(0.5)) exp_gate = gates.Unitary(exp_matrix, 1) - target_state = backend.apply_gate(exp_gate, backend.np.copy(initial_state), 2) + target_state = backend.apply_gate(exp_gate, backend.copy(initial_state), 2) backend.assert_allclose(final_state, target_state) @@ -187,9 +185,9 @@ def test_symbolic_term_call(backend, density_matrix): else random_statevector(2**3, backend=backend) ) final_state = term( - backend, backend.np.copy(initial_state), 3, density_matrix=density_matrix + backend, backend.copy(initial_state), 3, density_matrix=density_matrix ) - target_state = 2 * backend.np.copy(initial_state) + target_state = 2 * backend.copy(initial_state) for matrix in matrixlist: target_state = matrix @ target_state backend.assert_allclose(final_state, target_state) diff --git a/tests/test_hamiltonians_trotter.py b/tests/test_hamiltonians_trotter.py index 0c2d2f1756..c75bd58f70 100644 --- a/tests/test_hamiltonians_trotter.py +++ b/tests/test_hamiltonians_trotter.py @@ -123,25 +123,23 @@ def test_trotter_hamiltonian_three_qubit_term(backend): # Test that the `TrotterHamiltonian` dense matrix is correct eye = np.eye(2, dtype=complex) eye = backend.cast(eye, dtype=eye.dtype) - mm1 = backend.np.kron(m1, eye) - mm2 = backend.np.kron(backend.np.kron(eye, eye), m2) - mm3 = backend.np.kron(backend.np.kron(eye, m3), backend.np.kron(eye, eye)) + mm1 = backend.kron(m1, eye) + mm2 = backend.kron(backend.kron(eye, eye), m2) + mm3 = backend.kron(backend.kron(eye, m3), backend.kron(eye, eye)) target_ham = hamiltonians.Hamiltonian(4, mm1 + mm2 + mm3, backend=backend) backend.assert_allclose(ham.matrix, target_ham.matrix) dt = 1e-2 initial_state = random_statevector(2**4, backend=backend) circuit = ham.circuit(dt=dt) - final_state = backend.execute_circuit( - circuit, backend.np.copy(initial_state) - ).state() + final_state = backend.execute_circuit(circuit, backend.copy(initial_state)).state() mm1 = backend.to_numpy(mm1) mm2 = backend.to_numpy(mm2) mm3 = backend.to_numpy(mm3) u = [expm(-0.5j * dt * (mm1 + mm3)), expm(-0.5j * dt * mm2)] u = backend.cast(u) - target_state = backend.np.matmul(u[1], backend.np.matmul(u[0], initial_state)) - target_state = backend.np.matmul(u[0], backend.np.matmul(u[1], target_state)) + target_state = backend.matmul(u[1], backend.matmul(u[0], initial_state)) + target_state = backend.matmul(u[0], backend.matmul(u[1], target_state)) backend.assert_allclose(final_state, target_state) diff --git a/tests/test_measurements.py b/tests/test_measurements.py index af5344fb4f..d781760892 100644 --- a/tests/test_measurements.py +++ b/tests/test_measurements.py @@ -287,7 +287,7 @@ def test_final_state(backend, accelerators): c.add(gates.X(2)) c.add(gates.X(3)) target_state = backend.execute_circuit(c) - backend.assert_allclose(c.final_state, target_state) + backend.assert_allclose(c.final_state.state(), target_state.state()) def test_measurement_gate_bitflip_errors(): @@ -482,7 +482,7 @@ def test_measurementresult_nshots(backend): # nshots starting from samples nshots = 10 samples = backend.cast( - [[i % 2, i % 2, i % 2] for i in range(nshots)], backend.np.int64 + [[i % 2, i % 2, i % 2] for i in range(nshots)], backend.get_dtype("int64") ) result.register_samples(samples) assert result.nshots == nshots @@ -505,7 +505,9 @@ def test_measurement_serialization(backend): "p1": 0.2, } gate = gates.M(*range(3), **kwargs) - samples = backend.cast(np.random.randint(2, size=(100, 3)), backend.np.int64) + samples = backend.cast( + np.random.randint(2, size=(100, 3)), backend.get_dtype("int64") + ) gate.result.register_samples(samples) dump = gate.to_json() load = gates.M.from_dict(json.loads(dump)) diff --git a/tests/test_measurements_collapse.py b/tests/test_measurements_collapse.py index ce38b039a9..7dae573579 100644 --- a/tests/test_measurements_collapse.py +++ b/tests/test_measurements_collapse.py @@ -41,10 +41,10 @@ def assign_value(rho, index, value): initial_rho = random_density_matrix(2**nqubits, backend=backend) c = Circuit(nqubits, density_matrix=True) r = c.add(gates.M(*targets, collapse=True)) - final_rho = backend.execute_circuit(c, backend.np.copy(initial_rho), nshots=1) + final_rho = backend.execute_circuit(c, backend.copy(initial_rho), nshots=1).state() samples = r.samples()[0] - target_rho = backend.np.reshape(initial_rho, 2 * nqubits * (2,)) + target_rho = backend.reshape(initial_rho, 2 * nqubits * (2,)) for q, r in zip(targets, samples): r = int(r) slicer = 2 * nqubits * [slice(None)] @@ -54,8 +54,8 @@ def assign_value(rho, index, value): target_rho = assign_value(target_rho, tuple(slicer), 0) slicer[q], slicer[q + nqubits] = 1 - r, r target_rho = assign_value(target_rho, tuple(slicer), 0) - target_rho = backend.np.reshape(target_rho, initial_rho.shape) - target_rho = target_rho / backend.np.trace(target_rho) + target_rho = backend.reshape(target_rho, initial_rho.shape) + target_rho = target_rho / backend.trace(target_rho) backend.assert_allclose(final_rho, target_rho) @@ -88,6 +88,9 @@ def test_measurement_result_parameters(backend, effect, density_matrix): if not density_matrix: final_state = final_state.samples()[0] target_state = target_state.samples()[0] + else: + final_state = final_state.state() + target_state = target_state.state() backend.assert_allclose(final_state, target_state) @@ -99,21 +102,21 @@ def test_measurement_result_parameters_random(backend): c.add(gates.RY(0, theta=np.pi * r.symbols[0] / 5)) c.add(gates.RX(2, theta=np.pi * r.symbols[0] / 4)) final_state = backend.execute_circuit( - c, initial_state=backend.np.copy(initial_state), nshots=1 + c, initial_state=backend.copy(initial_state), nshots=1 ) backend.set_seed(123) c = Circuit(4, density_matrix=True) m = c.add(gates.M(1, collapse=True)) target_state = backend.execute_circuit( - c, initial_state=backend.np.copy(initial_state), nshots=1 + c, initial_state=backend.copy(initial_state), nshots=1 ).state() if int(m.symbols[0].outcome()): c = Circuit(4, density_matrix=True) c.add(gates.RY(0, theta=np.pi / 5)) c.add(gates.RX(2, theta=np.pi / 4)) target_state = backend.execute_circuit(c, initial_state=target_state) - backend.assert_allclose(final_state, target_state) + backend.assert_allclose(final_state.state(), target_state.state()) @pytest.mark.parametrize("use_loop", [True, False]) @@ -127,13 +130,13 @@ def test_measurement_result_parameters_repeated_execution(backend, use_loop): final_states = [] for _ in range(20): final_state = backend.execute_circuit( - c, initial_state=backend.np.copy(initial_state), nshots=1 + c, initial_state=backend.copy(initial_state), nshots=1 ) final_states.append(final_state.state()) - final_states = backend.np.mean(backend.cast(final_states), 0) + final_states = backend.mean(backend.cast(final_states), 0) else: final_states = backend.execute_circuit( - c, initial_state=backend.np.copy(initial_state), nshots=20 + c, initial_state=backend.copy(initial_state), nshots=20 ).state() backend.set_seed(123) @@ -142,7 +145,7 @@ def test_measurement_result_parameters_repeated_execution(backend, use_loop): c = Circuit(4, density_matrix=True) m = c.add(gates.M(1, collapse=True)) target_state = backend.execute_circuit( - c, backend.np.copy(initial_state), nshots=1 + c, backend.copy(initial_state), nshots=1 ).state() if int(m.symbols[0].outcome()): target_state = backend.apply_gate_density_matrix( @@ -173,7 +176,7 @@ def test_measurement_result_parameters_repeated_execution_final_measurements(bac c = Circuit(4, density_matrix=True) m = c.add(gates.M(1, collapse=True)) target_state = backend.execute_circuit( - c, backend.np.copy(initial_state), nshots=1 + c, backend.copy(initial_state), nshots=1 ).state() c = Circuit(4, density_matrix=True) if int(m.symbols[0].outcome()): @@ -192,13 +195,13 @@ def test_measurement_result_parameters_multiple_qubits(backend): r = c.add(gates.M(0, 1, 2, collapse=True)) c.add(gates.RY(1, theta=np.pi * r.symbols[0] / 5)) c.add(gates.RX(3, theta=np.pi * r.symbols[2] / 3)) - final_state = backend.execute_circuit(c, backend.np.copy(initial_state), nshots=1) + final_state = backend.execute_circuit(c, backend.copy(initial_state), nshots=1) backend.set_seed(123) c = Circuit(4, density_matrix=True) m = c.add(gates.M(0, 1, 2, collapse=True)) target_state = backend.execute_circuit( - c, backend.np.copy(initial_state), nshots=1 + c, backend.copy(initial_state), nshots=1 ).state() # not including in coverage because outcomes are probabilistic and may # not occur for the CI run @@ -210,7 +213,7 @@ def test_measurement_result_parameters_multiple_qubits(backend): target_state = backend.apply_gate_density_matrix( gates.RX(3, theta=np.pi / 3), target_state, 4 ) - backend.assert_allclose(final_state, target_state) + backend.assert_allclose(final_state.state(), target_state) @pytest.mark.skip(reason="this has to be updated for density matrices") @@ -248,7 +251,7 @@ def test_collapse_after_measurement(backend): ct.add(gates.X(i)) ct.add(gates.H(i) for i in qubits) target_state = backend.execute_circuit(ct) - backend.assert_allclose(final_state, target_state, atol=1e-15) + backend.assert_allclose(final_state.state(), target_state.state(), atol=1e-15) def test_collapse_error(backend): diff --git a/tests/test_models_circuit_execution.py b/tests/test_models_circuit_execution.py index 297b715a1e..79bfa96ff5 100644 --- a/tests/test_models_circuit_execution.py +++ b/tests/test_models_circuit_execution.py @@ -88,7 +88,7 @@ def test_final_state_property(backend): backend.execute_circuit(c)._state target_state = np.ones(4) / 2 - backend.assert_allclose(c.final_state, target_state) + backend.assert_allclose(c.final_state.state(), target_state) def test_density_matrix_circuit(backend): @@ -99,7 +99,7 @@ def test_density_matrix_circuit(backend): c.add(gates.H(1)) c.add(gates.CNOT(0, 1)) c.add(gates.H(2)) - final_rho = backend.execute_circuit(c, backend.np.copy(initial_rho)).state() + final_rho = backend.execute_circuit(c, backend.copy(initial_rho)).state() h = np.array([[1, 1], [1, -1]]) / np.sqrt(2) cnot = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index 164e287e57..c545caecec 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -134,7 +134,7 @@ def test_unary_encoder(backend, nqubits, architecture, kind): circuit = unary_encoder(data, architecture=architecture) state = backend.execute_circuit(circuit).state() indexes = np.flatnonzero(backend.to_numpy(state)) - state = backend.np.real(state[indexes]) + state = backend.real(state[indexes]) backend.assert_allclose( state, @@ -298,6 +298,6 @@ def test_ghz_circuit(backend, nqubits, density_matrix): state = backend.execute_circuit(GHZ_circ).state() if density_matrix: - target = backend.np.outer(target, backend.np.conj(target.T)) + target = backend.outer(target, backend.conj(target.T)) backend.assert_allclose(state, target) diff --git a/tests/test_models_error_mitigation.py b/tests/test_models_error_mitigation.py index 62bd804f5e..3b10d8005b 100644 --- a/tests/test_models_error_mitigation.py +++ b/tests/test_models_error_mitigation.py @@ -133,7 +133,7 @@ def test_zne(backend, nqubits, noise, solve, GUF, insertion_gate, readout): backend=backend, ) - assert backend.np.abs(exact - estimate) <= backend.np.abs(exact - noisy) + assert backend.abs(exact - estimate) <= backend.abs(exact - noisy) @pytest.mark.parametrize("nqubits", [3]) @@ -190,7 +190,7 @@ def test_cdr(backend, nqubits, noise, full_output, readout): if full_output: estimate = estimate[0] - assert backend.np.abs(exact - estimate) <= backend.np.abs(exact - noisy) + assert backend.abs(exact - estimate) <= backend.abs(exact - noisy) @pytest.mark.parametrize("nqubits", [3]) @@ -271,7 +271,7 @@ def test_vncdr(backend, nqubits, noise, full_output, insertion_gate, readout): if full_output: estimate = estimate[0] - assert backend.np.abs(exact - estimate) <= backend.np.abs(exact - noisy) + assert backend.abs(exact - estimate) <= backend.abs(exact - noisy) @pytest.mark.parametrize("nqubits,nmeas", [(3, 2)]) @@ -309,7 +309,7 @@ def test_readout_mitigation(backend, nqubits, nmeas, method, ibu_iters): c, obs, noise, nshots, readout, backend=backend ) - assert backend.np.abs(true_val - mit_val) <= backend.np.abs(true_val - noisy_val) + assert backend.abs(true_val - mit_val) <= backend.abs(true_val - noisy_val) @pytest.mark.parametrize("nqubits", [3]) @@ -364,4 +364,4 @@ def test_ics(backend, nqubits, noise, full_output, readout): if full_output: estimate = estimate[0] - assert backend.np.abs(exact - estimate) <= backend.np.abs(exact - noisy) + assert backend.abs(exact - estimate) <= backend.abs(exact - noisy) diff --git a/tests/test_models_qft.py b/tests/test_models_qft.py index 1ead4cb865..5ad57872e3 100644 --- a/tests/test_models_qft.py +++ b/tests/test_models_qft.py @@ -31,7 +31,7 @@ def exact_qft( if backend is not None: matrix = backend.cast(matrix, dtype=matrix.dtype) if density_matrix: - return matrix @ x @ backend.np.conj(matrix).T + return matrix @ x @ backend.conj(matrix).T return matrix @ x @@ -65,9 +65,9 @@ def test_qft_execution(backend, nqubits, random, density_matrix): else backend.zero_state(nqubits) ) if density_matrix: - initial_state = backend.np.outer(initial_state, backend.np.conj(initial_state)) + initial_state = backend.outer(initial_state, backend.conj(initial_state)) - final_state = backend.execute_circuit(c, backend.np.copy(initial_state))._state + final_state = backend.execute_circuit(c, backend.copy(initial_state))._state target_state = exact_qft(initial_state, density_matrix, backend) backend.assert_allclose(final_state, target_state, atol=1e-6, rtol=1e-6) diff --git a/tests/test_models_variational.py b/tests/test_models_variational.py index 08031b853f..e605d3719e 100644 --- a/tests/test_models_variational.py +++ b/tests/test_models_variational.py @@ -163,7 +163,7 @@ def callback(parameters, loss_values=loss_values, vqe=v): backend.assert_allclose(best, min(loss_values), rtol=1e-6, atol=1e-6) # test energy fluctuation - state = backend.np.ones(2**nqubits) / np.sqrt(2**nqubits) + state = backend.ones(2**nqubits) / np.sqrt(2**nqubits) energy_fluctuation = v.energy_fluctuation(state) assert energy_fluctuation >= 0 backend.set_threads(n_threads) diff --git a/tests/test_noise.py b/tests/test_noise.py index fb634fa1cd..7c093bf2a8 100644 --- a/tests/test_noise.py +++ b/tests/test_noise.py @@ -67,12 +67,12 @@ def test_kraus_error(backend, density_matrix, nshots): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(initial_psi), nshots=nshots + noise.apply(circuit), initial_state=backend.copy(initial_psi), nshots=nshots ) final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -125,12 +125,12 @@ def test_unitary_error(backend, density_matrix, nshots): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(initial_psi), nshots=nshots + noise.apply(circuit), initial_state=backend.copy(initial_psi), nshots=nshots ) final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -180,12 +180,12 @@ def test_pauli_error(backend, density_matrix, nshots): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(initial_psi), nshots=nshots + noise.apply(circuit), initial_state=backend.copy(initial_psi), nshots=nshots ) final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -237,7 +237,7 @@ def test_depolarizing_error(backend, density_matrix, nshots): final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -282,11 +282,11 @@ def test_thermal_error(backend, density_matrix): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), backend.np.copy(initial_psi) + noise.apply(circuit), backend.copy(initial_psi) )._state backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, backend.np.copy(initial_psi) + target_circuit, backend.copy(initial_psi) )._state backend.assert_allclose(final_state, target_final_state) @@ -335,7 +335,7 @@ def test_amplitude_damping_error(backend, density_matrix, nshots): final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -388,7 +388,7 @@ def test_phase_damping_error(backend, density_matrix, nshots): final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -416,14 +416,14 @@ def test_readout_error(backend, density_matrix): circuit = Circuit(nqubits, density_matrix=density_matrix) circuit.add(gates.M(0)) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(state) + noise.apply(circuit), initial_state=backend.copy(state) ) target_state = gates.ReadoutErrorChannel(0, P).apply_density_matrix( - backend, backend.np.copy(state), nqubits + backend, backend.copy(state), nqubits ) - backend.assert_allclose(final_state, target_state) + backend.assert_allclose(final_state.state(), target_state) @pytest.mark.parametrize("density_matrix", [False, True]) @@ -454,11 +454,11 @@ def test_reset_error(backend, density_matrix): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), backend.np.copy(initial_psi) + noise.apply(circuit), backend.copy(initial_psi) )._state backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, backend.np.copy(initial_psi) + target_circuit, backend.copy(initial_psi) )._state backend.assert_allclose(final_state, target_final_state) @@ -505,12 +505,12 @@ def test_custom_error(backend, density_matrix, nshots): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(initial_psi), nshots=nshots + noise.apply(circuit), initial_state=backend.copy(initial_psi), nshots=nshots ) final_state_samples = final_state.samples() if nshots else None backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi), nshots=nshots + target_circuit, initial_state=backend.copy(initial_psi), nshots=nshots ) target_final_state_samples = target_final_state.samples() if nshots else None @@ -564,11 +564,11 @@ def condition_3_pi_2(gate): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), backend.np.copy(initial_psi) + noise.apply(circuit), backend.copy(initial_psi) )._state backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, backend.np.copy(initial_psi) + target_circuit, backend.copy(initial_psi) )._state backend.assert_allclose(final_state, target_final_state) @@ -606,11 +606,11 @@ def test_gate_independent_noise(backend, density_matrix): ) backend.set_seed(123) final_state = backend.execute_circuit( - noise.apply(circuit), initial_state=backend.np.copy(initial_psi) + noise.apply(circuit), initial_state=backend.copy(initial_psi) )._state backend.set_seed(123) target_final_state = backend.execute_circuit( - target_circuit, initial_state=backend.np.copy(initial_psi) + target_circuit, initial_state=backend.copy(initial_psi) )._state backend.assert_allclose(final_state, target_final_state) @@ -766,4 +766,4 @@ def test_ibmq_noise( backend.set_seed(2024) state_target = backend.execute_circuit(noisy_circuit_target, nshots=10) - backend.assert_allclose(state, state_target) + backend.assert_allclose(state.state(), state_target.state()) diff --git a/tests/test_quantum_info_clifford.py b/tests/test_quantum_info_clifford.py index e39232e264..4598448adf 100644 --- a/tests/test_quantum_info_clifford.py +++ b/tests/test_quantum_info_clifford.py @@ -3,7 +3,6 @@ import numpy as np import pytest -from qiboml.backends import PyTorchBackend, TensorflowBackend from qibo import Circuit, gates, matrices from qibo.backends import CliffordBackend @@ -18,9 +17,10 @@ def construct_clifford_backend(backend): - if ( - isinstance(backend, (TensorflowBackend, PyTorchBackend)) - or backend.__class__.__name__ == "CuQuantumBackend" + if backend.__class__.__name__ in ( + "CuQuantumBackend", + "TensorflowBackend", + "PyTorchBackend", ): with pytest.raises(NotImplementedError): clifford_backend = CliffordBackend(backend.name) diff --git a/tests/test_quantum_info_entanglement.py b/tests/test_quantum_info_entanglement.py index ed7e98f300..e7206a84ff 100644 --- a/tests/test_quantum_info_entanglement.py +++ b/tests/test_quantum_info_entanglement.py @@ -51,7 +51,7 @@ def test_concurrence_and_formation(backend, bipartition, base, check_purity): backend.assert_allclose(0.0 <= concur <= np.sqrt(2), True) backend.assert_allclose(0.0 <= ent_form <= 1.0, True) - state = backend.np.kron( + state = backend.kron( random_density_matrix(2, pure=True, backend=backend), random_density_matrix(2, pure=True, backend=backend), ) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 7c289009f9..255f8ba617 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -401,7 +401,7 @@ def test_classical_relative_tsallis_entropy(backend, alpha, base, kind): target = classical_relative_entropy(prob_dist_p, prob_dist_q, base, backend) else: target = ((prob_dist_p / prob_dist_q) ** (1 - alpha) - 1) / (1 - alpha) - target = backend.np.sum(prob_dist_p**alpha * target) + target = backend.sum(prob_dist_p**alpha * target) if kind is not None: prob_dist_p = kind(prob_dist_p) @@ -527,7 +527,7 @@ def test_relative_von_neumann_entropy(backend, base, check_hermitian, statevecto ) if statevector: - state = backend.np.outer(state, backend.np.conj(state.T)) + state = backend.outer(state, backend.conj(state.T)) entropy_target = von_neumann_entropy( state, base=base, check_hermitian=check_hermitian, backend=backend @@ -557,7 +557,7 @@ def test_mutual_information(backend, base, check_hermitian): state_a = random_density_matrix(4, backend=backend) state_b = random_density_matrix(4, backend=backend) - state = backend.np.kron(state_a, state_b) + state = backend.kron(state_a, state_b) backend.assert_allclose( mutual_information(state, [0, 1], base, check_hermitian, backend), @@ -591,7 +591,7 @@ def test_renyi_entropy(backend, alpha, base): target = von_neumann_entropy(state, base=base, backend=backend) elif alpha == np.inf: target = backend.calculate_norm_density_matrix(state, order=2) - target = -1 * backend.np.log2(target) / np.log2(base) + target = -1 * backend.log2(target) / np.log2(base) else: target = np.log2( np.trace(np.linalg.matrix_power(backend.to_numpy(state), alpha)) @@ -674,19 +674,17 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): ) elif alpha == np.inf: state_outer = ( - backend.np.outer(state, backend.np.conj(state.T)) - if state_flag - else state + backend.outer(state, backend.conj(state.T)) if state_flag else state ) target_outer = ( - backend.np.outer(target, backend.np.conj(target.T)) + backend.outer(target, backend.conj(target.T)) if target_flag else target ) new_state = matrix_power(state_outer, 0.5, backend=backend) new_target = matrix_power(target_outer, 0.5, backend=backend) - log = backend.np.log2( + log = backend.log2( backend.calculate_norm_density_matrix( new_state @ new_target, order=1 ) @@ -695,14 +693,14 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): log = -2 * log / np.log2(base) else: if len(state.shape) == 1: - state = backend.np.outer(state, backend.np.conj(state)) + state = backend.outer(state, backend.conj(state)) if len(target.shape) == 1: - target = backend.np.outer(target, backend.np.conj(target)) + target = backend.outer(target, backend.conj(target)) log = matrix_power(state, alpha, backend=backend) log = log @ matrix_power(target, 1 - alpha, backend=backend) - log = backend.np.log2(backend.np.trace(log)) + log = backend.log2(backend.trace(log)) log = (1 / (alpha - 1)) * log / np.log2(base) @@ -747,7 +745,7 @@ def test_tsallis_entropy(backend, alpha, base): target = von_neumann_entropy(state, base=base, backend=backend) else: target = (1 / (1 - alpha)) * ( - backend.np.trace(matrix_power(state, alpha, backend=backend)) - 1 + backend.trace(matrix_power(state, alpha, backend=backend)) - 1 ) backend.assert_allclose( @@ -808,14 +806,14 @@ def test_relative_tsallis_entropy( alpha = 2 - alpha if state_flag: - state = backend.np.outer(state, backend.np.conj(state.T)) + state = backend.outer(state, backend.conj(state.T)) if target_flag: - target = backend.np.outer(target, backend.np.conj(target.T)) + target = backend.outer(target, backend.conj(target.T)) target_value = matrix_power(state, alpha, backend=backend) target_value = target_value @ matrix_power(target, 1 - alpha, backend=backend) - target_value = (1 - backend.np.trace(target_value)) / (1 - alpha) + target_value = (1 - backend.trace(target_value)) / (1 - alpha) backend.assert_allclose(value, target_value, atol=1e-10) @@ -879,7 +877,7 @@ def test_entanglement_entropy(backend, bipartition, base, check_hermitian): backend.assert_allclose(entang_entrop, test, atol=PRECISION_TOL) # Product state - state = backend.np.kron( + state = backend.kron( random_statevector(2, backend=backend), random_statevector(2, backend=backend) ) diff --git a/tests/test_quantum_info_metrics.py b/tests/test_quantum_info_metrics.py index a4c53dfdfa..2819d9242a 100644 --- a/tests/test_quantum_info_metrics.py +++ b/tests/test_quantum_info_metrics.py @@ -41,7 +41,7 @@ def test_purity_and_impurity(backend): backend.assert_allclose(purity(state, backend=backend), 1.0, atol=PRECISION_TOL) backend.assert_allclose(impurity(state, backend=backend), 0.0, atol=PRECISION_TOL) - state = backend.np.outer(backend.np.conj(state), state) + state = backend.outer(backend.conj(state), state) state = backend.cast(state, dtype=state.dtype) backend.assert_allclose(purity(state, backend=backend), 1.0, atol=PRECISION_TOL) backend.assert_allclose(impurity(state, backend=backend), 0.0, atol=PRECISION_TOL) @@ -96,8 +96,8 @@ def test_trace_distance(backend, check_hermitian): atol=PRECISION_TOL, ) - state = backend.np.outer(backend.np.conj(state), state) - target = backend.np.outer(backend.np.conj(target), target) + state = backend.outer(backend.conj(state), state) + target = backend.outer(backend.conj(target), target) backend.assert_allclose( trace_distance(state, target, check_hermitian=check_hermitian, backend=backend), 0.0, @@ -144,8 +144,8 @@ def test_hilbert_schmidt_distance(backend): hilbert_schmidt_distance(state, target, backend=backend), 0.0 ) - state = backend.np.outer(backend.np.conj(state), state) - target = backend.np.outer(backend.np.conj(target), target) + state = backend.outer(backend.conj(state), state) + target = backend.outer(backend.conj(target), target) backend.assert_allclose( hilbert_schmidt_distance(state, target, backend=backend), 0.0 ) @@ -209,8 +209,8 @@ def test_fidelity_and_infidelity_and_bures(backend, check_hermitian): atol=PRECISION_TOL, ) - state = backend.np.outer(backend.np.conj(state), state) - target = backend.np.outer(backend.np.conj(target), target) + state = backend.outer(backend.conj(state), state) + target = backend.outer(backend.conj(target), target) backend.assert_allclose( fidelity(state, target, check_hermitian, backend=backend), 1.0, @@ -404,9 +404,9 @@ def test_qfim(backend, nqubits, return_complex, params_flag): target = [1] for param in params[:-1]: - elem = float(target[-1] * backend.np.sin(param) ** 2) + elem = float(target[-1] * backend.sin(param) ** 2) target.append(elem) - target = 4 * backend.np.diag(backend.cast(target, dtype=np.float64)) + target = 4 * backend.diag(backend.cast(target, dtype=np.float64)) # numerical qfim from quantum_info circuit = unary_encoder(data, "diagonal") diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index 4791ff5df0..a8b119637c 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -230,7 +230,7 @@ def test_matrix_power(backend, power, singular): power = matrix_power(state, power, backend=backend) backend.assert_allclose( - float(backend.np.real(backend.np.trace(power))), + float(backend.real(backend.trace(power))), purity(state, backend=backend), ) @@ -253,15 +253,15 @@ def test_singular_value_decomposition(backend): for k, coeff in enumerate(coeffs): bitstring = f"{k:0{2}b}" a, b = int(bitstring[0]), int(bitstring[1]) - ket = backend.np.kron(base[a], base[b]) - state = state + coeff * backend.np.outer(ket, ket.T) + ket = backend.kron(base[a], base[b]) + state = state + coeff * backend.outer(ket, ket.T) _, S, _ = singular_value_decomposition(state, backend=backend) - S_sorted = backend.np.sort(S) - coeffs_sorted = backend.np.sort(coeffs) - if backend.platform == "pytorch": - S_sorted, coeffs_sorted = S_sorted[0], coeffs_sorted[0] + S_sorted = backend.sort(S) + coeffs_sorted = backend.sort(coeffs) + # if backend.platform == "pytorch": + # S_sorted, coeffs_sorted = S_sorted[0], coeffs_sorted[0] backend.assert_allclose(S_sorted, coeffs_sorted) @@ -273,7 +273,7 @@ def test_schmidt_decomposition(backend): state_A = random_statevector(4, seed=10, backend=backend) state_B = random_statevector(4, seed=11, backend=backend) - state = backend.np.kron(state_A, state_B) + state = backend.kron(state_A, state_B) U, S, Vh = schmidt_decomposition(state, [0, 1], backend=backend) @@ -282,13 +282,13 @@ def test_schmidt_decomposition(backend): recovered = backend.cast(recovered, dtype=recovered.dtype) for coeff, u, vh in zip(S, U.T, Vh): if abs(coeff) > 1e-10: - recovered = recovered + coeff * backend.np.kron(u, vh) + recovered = recovered + coeff * backend.kron(u, vh) backend.assert_allclose(recovered, state) # entropy test - coeffs = backend.np.abs(S) ** 2 - entropy = backend.np.where(backend.np.abs(S) < 1e-10, 0.0, backend.np.log(coeffs)) - entropy = -backend.np.sum(coeffs * entropy) + coeffs = backend.abs(S) ** 2 + entropy = backend.where(backend.abs(S) < 1e-10, 0.0, backend.log(coeffs)) + entropy = -backend.sum(coeffs * entropy) backend.assert_allclose(entropy, 0.0, atol=1e-14) diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index daa8ab53f7..076340b857 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -216,7 +216,7 @@ def test_operational_logic(backend): # Complex conjugate of a network has to match the complex conjugate of the operator backend.assert_allclose( network.conj().operator(backend=backend), - backend.np.conj(network.operator(backend=backend)), + backend.conj(network.operator(backend=backend)), ) @@ -416,7 +416,7 @@ def test_apply(backend): ) applied = network.apply(state) - target = unitary @ state @ backend.np.conj(unitary).T + target = unitary @ state @ backend.conj(unitary).T backend.assert_allclose(applied, target, atol=1e-8) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 3d2b6d92dd..a1eb888257 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -49,14 +49,14 @@ def test_uniform_sampling_U3(backend, seed): expectation_values.append( [ - backend.np.conj(state) @ X @ state, - backend.np.conj(state) @ Y @ state, - backend.np.conj(state) @ Z @ state, + backend.conj(state) @ X @ state, + backend.conj(state) @ Y @ state, + backend.conj(state) @ Z @ state, ] ) expectation_values = backend.cast(expectation_values) - expectation_values = backend.np.mean(expectation_values, axis=0) + expectation_values = backend.mean(expectation_values, axis=0) backend.assert_allclose(expectation_values[0], expectation_values[1], atol=1e-1) backend.assert_allclose(expectation_values[0], expectation_values[2], atol=1e-1) @@ -111,14 +111,14 @@ def test_random_hermitian(backend): # test if function returns Hermitian operator dims = 4 matrix = random_hermitian(dims, backend=backend) - matrix_dagger = backend.np.conj(matrix).T + matrix_dagger = backend.conj(matrix).T norm = float(backend.calculate_norm_density_matrix(matrix - matrix_dagger, order=2)) backend.assert_allclose(norm < PRECISION_TOL, True) # test if function returns semidefinite Hermitian operator dims = 4 matrix = random_hermitian(dims, semidefinite=True, backend=backend) - matrix_dagger = backend.np.conj(matrix).T + matrix_dagger = backend.conj(matrix).T norm = float(backend.calculate_norm_density_matrix(matrix - matrix_dagger, order=2)) backend.assert_allclose(norm < PRECISION_TOL, True) @@ -129,7 +129,7 @@ def test_random_hermitian(backend): # test if function returns normalized Hermitian operator dims = 4 matrix = random_hermitian(dims, normalize=True, backend=backend) - matrix_dagger = backend.np.conj(matrix).T + matrix_dagger = backend.conj(matrix).T norm = float(backend.calculate_norm_density_matrix(matrix - matrix_dagger, order=2)) backend.assert_allclose(norm < PRECISION_TOL, True) @@ -140,7 +140,7 @@ def test_random_hermitian(backend): # test if function returns normalized and semidefinite Hermitian operator dims = 4 matrix = random_hermitian(dims, semidefinite=True, normalize=True, backend=backend) - matrix_dagger = backend.np.conj(matrix).T + matrix_dagger = backend.conj(matrix).T norm = float(backend.calculate_norm(matrix - matrix_dagger, order=2)) backend.assert_allclose(norm < PRECISION_TOL, True) @@ -171,11 +171,10 @@ def test_random_unitary(backend, measure): # tests if operator is unitary (measure == "haar") dims = 4 matrix = random_unitary(dims, measure=measure, backend=backend) - matrix_dagger = backend.np.conj(matrix).T + matrix_dagger = backend.conj(matrix).T matrix_inv = ( - backend.np.inverse(matrix) - if backend.platform == "pytorch" - else np.linalg.inv(matrix) + backend.inverse(matrix) + # backend.inverse(matrix) if backend.platform == "pytorch" else np.linalg.inv(matrix) ) norm = float( backend.calculate_norm_density_matrix(matrix_inv - matrix_dagger, order=2) @@ -302,9 +301,7 @@ def test_random_density_matrix(backend, dims, pure, metric, basis, normalize): purity(state, backend=backend) >= 1.0 - PRECISION_TOL, True ) norm = np.abs( - backend.to_numpy( - norm_function(state - backend.np.conj(state).T, order=2) - ) + backend.to_numpy(norm_function(state - backend.conj(state).T, order=2)) ) backend.assert_allclose(norm < PRECISION_TOL, True) else: @@ -475,9 +472,9 @@ def test_random_pauli( True, ) else: - matrix = backend.np.transpose(matrix, (1, 0, 2, 3)) - matrix = [reduce(backend.np.kron, row) for row in matrix] - matrix = reduce(backend.np.matmul, matrix) + matrix = backend.transpose(matrix, (1, 0, 2, 3)) + matrix = [reduce(backend.kron, row) for row in matrix] + matrix = reduce(backend.matmul, matrix) if subset is None: backend.assert_allclose( @@ -576,7 +573,7 @@ def test_random_stochastic_matrix(backend): # tests if matrix is row-stochastic dims = 4 matrix = random_stochastic_matrix(dims, backend=backend) - sum_rows = backend.np.sum(matrix, axis=1) + sum_rows = backend.sum(matrix, axis=1) backend.assert_allclose(all(sum_rows < 1 + PRECISION_TOL), True) backend.assert_allclose(all(sum_rows > 1 - PRECISION_TOL), True) @@ -587,18 +584,18 @@ def test_random_stochastic_matrix(backend): dims, diagonally_dominant=True, max_iterations=1000, backend=backend ) - sum_rows = backend.np.sum(matrix, axis=1) + sum_rows = backend.sum(matrix, axis=1) backend.assert_allclose(all(sum_rows < 1 + PRECISION_TOL), True) backend.assert_allclose(all(sum_rows > 1 - PRECISION_TOL), True) - backend.assert_allclose(all(2 * backend.np.diag(matrix) - sum_rows > 0), True) + backend.assert_allclose(all(2 * backend.diag(matrix) - sum_rows > 0), True) # tests if matrix is bistochastic dims = 4 matrix = random_stochastic_matrix(dims, bistochastic=True, backend=backend) - sum_rows = backend.np.sum(matrix, axis=1) - column_rows = backend.np.sum(matrix, axis=0) + sum_rows = backend.sum(matrix, axis=1) + column_rows = backend.sum(matrix, axis=0) backend.assert_allclose(all(sum_rows < 1 + PRECISION_TOL), True) backend.assert_allclose(all(sum_rows > 1 - PRECISION_TOL), True) @@ -615,8 +612,8 @@ def test_random_stochastic_matrix(backend): max_iterations=1000, backend=backend, ) - sum_rows = backend.np.sum(matrix, axis=1) - column_rows = backend.np.sum(matrix, axis=0) + sum_rows = backend.sum(matrix, axis=1) + column_rows = backend.sum(matrix, axis=0) backend.assert_allclose(all(sum_rows < 1 + PRECISION_TOL), True) backend.assert_allclose(all(sum_rows > 1 - PRECISION_TOL), True) @@ -624,8 +621,8 @@ def test_random_stochastic_matrix(backend): backend.assert_allclose(all(column_rows < 1 + PRECISION_TOL), True) backend.assert_allclose(all(column_rows > 1 - PRECISION_TOL), True) - backend.assert_allclose(all(2 * backend.np.diag(matrix) - sum_rows > 0), True) - backend.assert_allclose(all(2 * backend.np.diag(matrix) - column_rows > 0), True) + backend.assert_allclose(all(2 * backend.diag(matrix) - sum_rows > 0), True) + backend.assert_allclose(all(2 * backend.diag(matrix) - column_rows > 0), True) # tests warning for max_iterations dims = 4 diff --git a/tests/test_quantum_info_superoperator_transformations.py b/tests/test_quantum_info_superoperator_transformations.py index 03f0ae2baf..cda8aaeda6 100644 --- a/tests/test_quantum_info_superoperator_transformations.py +++ b/tests/test_quantum_info_superoperator_transformations.py @@ -371,17 +371,17 @@ def test_to_stinespring(backend, test_a0, partition): test_a0_ = backend.cast(test_a0) state = random_density_matrix(2, seed=8, backend=backend) - target = test_a0_ @ state @ backend.np.conj(test_a0_.T) + target = test_a0_ @ state @ backend.conj(test_a0_.T) environment = (1, 2) global_state = backend.identity_density_matrix(len(environment), normalize=True) - global_state = backend.np.kron(state, global_state) + global_state = backend.kron(state, global_state) stinespring = to_stinespring( test_a0_, partition=partition, nqubits=len(environment) + 1, backend=backend ) - stinespring = stinespring @ global_state @ backend.np.conj(stinespring.T) + stinespring = stinespring @ global_state @ backend.conj(stinespring.T) stinespring = partial_trace(stinespring, traced_qubits=environment, backend=backend) backend.assert_allclose(stinespring, target, atol=PRECISION_TOL) @@ -415,8 +415,8 @@ def test_choi_to_pauli(backend, normalize, order, pauli_order, test_superop): test_superop = backend.cast(test_superop, dtype=test_superop.dtype) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.swapaxes( - backend.np.reshape(test_superop * aux, [2] * 4), *axes + test_choi = backend.swapaxes( + backend.reshape(test_superop * aux, [2] * 4), *axes ).reshape([4, 4]) pauli_op = choi_to_pauli( @@ -472,11 +472,11 @@ def test_choi_to_kraus( state = random_density_matrix(2, backend=backend) - evolution_a0 = a0 @ state @ backend.np.conj(a0).T - evolution_a1 = a1 @ state @ backend.np.conj(a1).T + evolution_a0 = a0 @ state @ backend.conj(a0).T + evolution_a1 = a1 @ state @ backend.conj(a1).T - test_evolution_a0 = test_a0 @ state @ backend.np.conj(test_a0).T - test_evolution_a1 = test_a1 @ state @ backend.np.conj(test_a1).T + test_evolution_a0 = test_a0 @ state @ backend.conj(test_a0).T + test_evolution_a1 = test_a1 @ state @ backend.conj(test_a1).T backend.assert_allclose(evolution_a0, test_evolution_a0, atol=2 * PRECISION_TOL) backend.assert_allclose(evolution_a1, test_evolution_a1, atol=2 * PRECISION_TOL) @@ -495,9 +495,9 @@ def test_choi_to_kraus( test_coefficients, ): state = random_density_matrix(2, backend=backend) - evolution = left @ state @ backend.np.conj(right).T + evolution = left @ state @ backend.conj(right).T test_evolution = ( - test_coeff**2 * test_left @ state @ backend.np.conj(test_right).T + test_coeff**2 * test_left @ state @ backend.conj(test_right).T ) backend.assert_allclose(evolution, test_evolution, atol=2 * PRECISION_TOL) @@ -516,8 +516,8 @@ def test_choi_to_chi(backend, normalize, order, pauli_order, test_superop): test_chi = backend.cast(test_chi, dtype=test_chi.dtype) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.swapaxes( - backend.np.reshape(test_superop * aux, [2] * 4), *axes + test_choi = backend.swapaxes( + backend.reshape(test_superop * aux, [2] * 4), *axes ).reshape([4, 4]) chi_matrix = choi_to_chi( @@ -578,13 +578,13 @@ def test_choi_to_stinespring( # action of stinespring channel on state + environment stinespring = ( stinespring - @ backend.np.kron(state, backend.np.outer(v_0, v_0)) - @ backend.np.conj(stinespring).T + @ backend.kron(state, backend.outer(v_0, v_0)) + @ backend.conj(stinespring).T ) # partial trace of the environment - stinespring = backend.np.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) - stinespring = backend.np.swapaxes(stinespring, 1, 2) + stinespring = backend.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) + stinespring = backend.swapaxes(stinespring, 1, 2) state_final = np.zeros((2**nqubits, 2**nqubits), dtype=complex) state_final = backend.cast(state_final, dtype=state_final.dtype) for alpha in range(2): @@ -592,7 +592,7 @@ def test_choi_to_stinespring( vector_alpha[alpha] = 1.0 vector_alpha = backend.cast(vector_alpha, dtype=vector_alpha.dtype) state_final = ( - state_final + backend.np.conj(vector_alpha) @ stinespring @ vector_alpha + state_final + backend.conj(vector_alpha) @ stinespring @ vector_alpha ) backend.assert_allclose(state_final, state_final_test, atol=PRECISION_TOL) @@ -606,9 +606,9 @@ def test_liouville_to_choi(backend, order, test_superop): choi = liouville_to_choi(test_superop, order=order, backend=backend) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.reshape(test_superop, [2] * 4) - test_choi = backend.np.swapaxes(test_choi, *axes) - test_choi = backend.np.reshape(test_choi, (4, 4)) + test_choi = backend.reshape(test_superop, [2] * 4) + test_choi = backend.swapaxes(test_choi, *axes) + test_choi = backend.reshape(test_choi, (4, 4)) backend.assert_allclose(choi, test_choi, atol=PRECISION_TOL) @@ -656,11 +656,11 @@ def test_liouville_to_kraus(backend, order, test_a0, test_a1): state = random_density_matrix(2, backend=backend) - evolution_a0 = a0 @ state @ backend.np.conj(a0).T - evolution_a1 = a1 @ state @ backend.np.conj(a1).T + evolution_a0 = a0 @ state @ backend.conj(a0).T + evolution_a1 = a1 @ state @ backend.conj(a1).T - test_evolution_a0 = test_a0 @ state @ backend.np.conj(test_a0).T - test_evolution_a1 = test_a1 @ state @ backend.np.conj(test_a1).T + test_evolution_a0 = test_a0 @ state @ backend.conj(test_a0).T + test_evolution_a1 = test_a1 @ state @ backend.conj(test_a1).T backend.assert_allclose(evolution_a0, test_evolution_a0, atol=PRECISION_TOL) backend.assert_allclose(evolution_a1, test_evolution_a1, atol=PRECISION_TOL) @@ -728,13 +728,13 @@ def test_liouville_to_stinespring( # action of stinespring channel on state + environment stinespring = ( stinespring - @ backend.np.kron(state, backend.np.outer(v_0, v_0)) - @ backend.np.conj(stinespring).T + @ backend.kron(state, backend.outer(v_0, v_0)) + @ backend.conj(stinespring).T ) # partial trace of the environment - stinespring = backend.np.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) - stinespring = backend.np.swapaxes(stinespring, 1, 2) + stinespring = backend.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) + stinespring = backend.swapaxes(stinespring, 1, 2) state_final = np.zeros((2**nqubits, 2**nqubits), dtype=complex) state_final = backend.cast(state_final, dtype=state_final.dtype) for alpha in range(2): @@ -742,7 +742,7 @@ def test_liouville_to_stinespring( vector_alpha[alpha] = 1.0 vector_alpha = backend.cast(vector_alpha, dtype=vector_alpha.dtype) state_final = ( - state_final + backend.np.conj(vector_alpha) @ stinespring @ vector_alpha + state_final + backend.conj(vector_alpha) @ stinespring @ vector_alpha ) backend.assert_allclose(state_final, state_final_test, atol=PRECISION_TOL) @@ -873,8 +873,8 @@ def test_pauli_to_choi(backend, normalize, order, pauli_order, test_superop): ) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.swapaxes(backend.np.reshape(test_superop, [2] * 4), *axes) - test_choi = backend.np.reshape(test_choi, (4, 4)) + test_choi = backend.swapaxes(backend.reshape(test_superop, [2] * 4), *axes) + test_choi = backend.reshape(test_choi, (4, 4)) backend.assert_allclose(test_choi, choi_super_op, atol=PRECISION_TOL) @@ -909,11 +909,11 @@ def test_pauli_to_kraus(backend, normalize, order, pauli_order, test_a0, test_a1 state = random_density_matrix(2, backend=backend) - evolution_a0 = a0 @ state @ backend.np.conj(a0).T - evolution_a1 = a1 @ state @ backend.np.conj(a1).T + evolution_a0 = a0 @ state @ backend.conj(a0).T + evolution_a1 = a1 @ state @ backend.conj(a1).T - test_evolution_a0 = test_a0 @ state @ backend.np.conj(test_a0).T - test_evolution_a1 = test_a1 @ state @ backend.np.conj(test_a1).T + test_evolution_a0 = test_a0 @ state @ backend.conj(test_a0).T + test_evolution_a1 = test_a1 @ state @ backend.conj(test_a1).T backend.assert_allclose(evolution_a0, test_evolution_a0, atol=2 * PRECISION_TOL) backend.assert_allclose(evolution_a1, test_evolution_a1, atol=2 * PRECISION_TOL) @@ -985,13 +985,13 @@ def test_pauli_to_stinespring( # action of stinespring channel on state + environment stinespring = ( stinespring - @ backend.np.kron(state, backend.np.outer(v_0, v_0)) - @ backend.np.conj(stinespring).T + @ backend.kron(state, backend.outer(v_0, v_0)) + @ backend.conj(stinespring).T ) # partial trace of the environment - stinespring = backend.np.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) - stinespring = backend.np.swapaxes(stinespring, 1, 2) + stinespring = backend.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) + stinespring = backend.swapaxes(stinespring, 1, 2) state_final = np.zeros((2**nqubits, 2**nqubits), dtype=complex) state_final = backend.cast(state_final, dtype=state_final.dtype) for alpha in range(2): @@ -999,7 +999,7 @@ def test_pauli_to_stinespring( vector_alpha[alpha] = 1.0 vector_alpha = backend.cast(vector_alpha, dtype=vector_alpha.dtype) state_final = ( - state_final + backend.np.conj(vector_alpha) @ stinespring @ vector_alpha + state_final + backend.conj(vector_alpha) @ stinespring @ vector_alpha ) backend.assert_allclose(state_final, aux * state_final_test, atol=PRECISION_TOL) @@ -1018,9 +1018,9 @@ def test_chi_to_choi(backend, normalize, order, pauli_order, test_superop): test_superop = backend.cast(test_superop, dtype=backend.dtype) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.swapaxes( - backend.np.reshape(test_superop, [2] * 4), *axes - ).reshape([4, 4]) + test_choi = backend.swapaxes(backend.reshape(test_superop, [2] * 4), *axes).reshape( + [4, 4] + ) choi_super_op = chi_to_choi( test_chi / aux, normalize, order, pauli_order, backend=backend @@ -1093,11 +1093,11 @@ def test_chi_to_kraus(backend, normalize, order, pauli_order, test_a0, test_a1): state = random_density_matrix(2, backend=backend) - evolution_a0 = a0 @ state @ backend.np.conj(a0).T - evolution_a1 = a1 @ state @ backend.np.conj(a1).T + evolution_a0 = a0 @ state @ backend.conj(a0).T + evolution_a1 = a1 @ state @ backend.conj(a1).T - test_evolution_a0 = test_a0 @ state @ backend.np.conj(test_a0).T - test_evolution_a1 = test_a1 @ state @ backend.np.conj(test_a1).T + test_evolution_a0 = test_a0 @ state @ backend.conj(test_a0).T + test_evolution_a1 = test_a1 @ state @ backend.conj(test_a1).T backend.assert_allclose(evolution_a0, test_evolution_a0, atol=2 * PRECISION_TOL) backend.assert_allclose(evolution_a1, test_evolution_a1, atol=2 * PRECISION_TOL) @@ -1142,13 +1142,13 @@ def test_chi_to_stinespring( # action of stinespring channel on state + environment stinespring = ( stinespring - @ backend.np.kron(state, backend.np.outer(v_0, v_0)) - @ backend.np.conj(stinespring).T + @ backend.kron(state, backend.outer(v_0, v_0)) + @ backend.conj(stinespring).T ) # partial trace of the environment - stinespring = backend.np.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) - stinespring = backend.np.swapaxes(stinespring, 1, 2) + stinespring = backend.reshape(stinespring, (2**nqubits, 2, 2**nqubits, 2)) + stinespring = backend.swapaxes(stinespring, 1, 2) state_final = np.zeros((2**nqubits, 2**nqubits), dtype=complex) state_final = backend.cast(state_final, dtype=state_final.dtype) for alpha in range(2): @@ -1156,7 +1156,7 @@ def test_chi_to_stinespring( vector_alpha[alpha] = 1.0 vector_alpha = backend.cast(vector_alpha, dtype=vector_alpha.dtype) state_final = ( - state_final + backend.np.conj(vector_alpha) @ stinespring @ vector_alpha + state_final + backend.conj(vector_alpha) @ stinespring @ vector_alpha ) backend.assert_allclose(state_final, aux * state_final_test, atol=PRECISION_TOL) @@ -1360,8 +1360,8 @@ def test_reshuffling(backend, order, test_superop): ) axes = [1, 2] if order == "row" else [0, 3] - test_choi = backend.np.reshape( - backend.np.swapaxes(backend.np.reshape(test_superop, [2] * 4), *axes), [4, 4] + test_choi = backend.reshape( + backend.swapaxes(backend.reshape(test_superop, [2] * 4), *axes), [4, 4] ) reshuffled = _reshuffling(test_choi, order, backend=backend) diff --git a/tests/test_quantum_info_utils.py b/tests/test_quantum_info_utils.py index f9b8c0ff2b..e17d908a5a 100644 --- a/tests/test_quantum_info_utils.py +++ b/tests/test_quantum_info_utils.py @@ -167,8 +167,7 @@ def test_hellinger(backend, validate, kind): prob_q = backend.cast(prob_q, dtype=prob_q.dtype) target = float( - backend.calculate_norm(backend.np.sqrt(prob_p) - backend.np.sqrt(prob_q)) - / np.sqrt(2) + backend.calculate_norm(backend.sqrt(prob_p) - backend.sqrt(prob_q)) / np.sqrt(2) ) prob_p = ( diff --git a/tests/test_result.py b/tests/test_result.py index 3d57f0140a..f2fd2627e1 100644 --- a/tests/test_result.py +++ b/tests/test_result.py @@ -106,5 +106,5 @@ def test_circuitresult_dump_load(backend, agnostic_load): loaded_freq = loaded_res.frequencies() for state, f in freq.items(): assert loaded_freq[state] == f - assert backend.np.sum(result.state() - backend.cast(loaded_res.state())) == 0 + assert backend.sum(result.state() - backend.cast(loaded_res.state())) == 0 remove("tmp.npy") diff --git a/tests/test_transpiler_decompositions.py b/tests/test_transpiler_decompositions.py index e26af68841..e906ea953f 100644 --- a/tests/test_transpiler_decompositions.py +++ b/tests/test_transpiler_decompositions.py @@ -35,7 +35,7 @@ def assert_matrices_allclose(gate, natives, backend): # There can still be phase differences of -1, -1j, 1j c = 0 for phase in [1, -1, 1j, -1j]: - if backend.np.allclose( + if backend.allclose( phase * native_unitary, target_unitary, atol=1e-6, diff --git a/tests/test_transpiler_unitary_decompositions.py b/tests/test_transpiler_unitary_decompositions.py index 25a0ec25f3..530c3b4784 100644 --- a/tests/test_transpiler_unitary_decompositions.py +++ b/tests/test_transpiler_unitary_decompositions.py @@ -31,7 +31,7 @@ def bell_unitary(hx, hy, hz, backend): def assert_single_qubits(backend, psi, ua, ub): """Assert UA, UB map the maximally entangled basis ``psi`` to the magic basis.""" - uaub = backend.to_numpy(backend.np.kron(ua, ub)) + uaub = backend.to_numpy(backend.kron(ua, ub)) psi = backend.to_numpy(psi) for i, j in zip(range(4), [0, 1, 3, 2]): final_state = np.matmul(uaub, psi[:, i]) @@ -66,7 +66,7 @@ def test_eigenbasis_entanglement(backend, seed): """Check that the eigenvectors of UT_U are maximally entangled.""" states, eigvals = calculate_psi(unitary, backend=backend) eigvals = backend.cast(eigvals, dtype=eigvals.dtype) - backend.assert_allclose(backend.np.abs(eigvals), np.ones(4)) + backend.assert_allclose(backend.abs(eigvals), np.ones(4)) for state in states.T: state = partial_trace(state, [1], backend=backend) backend.assert_allclose(purity(state, backend=backend), 0.5) @@ -94,9 +94,7 @@ def test_u_decomposition(backend, seed): calculate_psi(unitary, backend=backend) else: psi, eigvals = calculate_psi(unitary, backend=backend) - psi_tilde = backend.np.conj(backend.np.sqrt(eigvals)) * backend.np.matmul( - unitary, psi - ) + psi_tilde = backend.conj(backend.sqrt(eigvals)) * backend.matmul(unitary, psi) ua_dagger, ub_dagger = calculate_single_qubit_unitaries( psi_tilde, backend=backend ) @@ -113,17 +111,17 @@ def test_ud_eigenvalues(backend, seed): else: ua, ub, ud, va, vb = magic_decomposition(unitary, backend=backend) # Check kron - unitary_recon = backend.np.kron(ua, ub) @ ud @ backend.np.kron(va, vb) + unitary_recon = backend.kron(ua, ub) @ ud @ backend.kron(va, vb) backend.assert_allclose(unitary_recon, unitary) ud_bell = ( - backend.np.transpose(backend.np.conj(backend.cast(bell_basis)), (1, 0)) + backend.transpose(backend.conj(backend.cast(bell_basis)), (1, 0)) @ ud @ backend.cast(bell_basis) ) - ud_diag = backend.np.diag(ud_bell) - backend.assert_allclose(backend.np.diag(ud_diag), ud_bell, atol=1e-6, rtol=1e-6) - backend.assert_allclose(backend.np.prod(ud_diag), 1, atol=1e-6, rtol=1e-6) + ud_diag = backend.diag(ud_bell) + backend.assert_allclose(backend.diag(ud_diag), ud_bell, atol=1e-6, rtol=1e-6) + backend.assert_allclose(backend.prod(ud_diag), 1, atol=1e-6, rtol=1e-6) @pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)])