diff --git a/.gitignore b/.gitignore index 4c9bc5cdc..7da525d7d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ qcs-api/docs # macOS .DS_Store + +# pytest artifacts +**/__pycache__ diff --git a/Cargo.lock b/Cargo.lock index ec4ccbf36..a256c8bf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "async-stream" @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1" dependencies = [ "proc-macro2", "quote", @@ -55,7 +55,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -68,9 +68,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.17" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +checksum = "678c5130a507ae3a7c797f9a17393c14849300b8440eac47cdb90a5bdcb3a543" dependencies = [ "async-trait", "axum-core", @@ -86,9 +86,9 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustversion", "serde", "sync_wrapper", - "tokio", "tower", "tower-http", "tower-layer", @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.9" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34" dependencies = [ "async-trait", "bytes", @@ -107,6 +107,7 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", "tower-layer", "tower-service", ] @@ -117,6 +118,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "bitflags" version = "1.3.2" @@ -132,21 +139,11 @@ dependencies = [ "generic-array", ] -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecount" @@ -162,15 +159,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "cc" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" @@ -222,11 +219,21 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", @@ -281,9 +288,9 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11" +checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d" dependencies = [ "serde", ] @@ -443,6 +450,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghost" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41973d4c45f7a35af8753ba3457cc99d406d863941fd7f52663cff54a5ab99b3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "h2" version = "0.3.15" @@ -474,7 +492,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ - "base64", + "base64 0.13.1", "bitflags", "bytes", "headers-core", @@ -508,6 +526,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -580,9 +607,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -615,9 +642,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -625,9 +652,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" [[package]] name = "instant" @@ -638,11 +665,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "inventory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16fe3b35d64bd1f72917f06425e7573a2f63f74f42c8f56e53ea6826dde3a2b5" +dependencies = [ + "ctor", + "ghost", +] + [[package]] name = "ipnet" -version = "2.5.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "itertools" @@ -655,9 +692,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" @@ -670,11 +707,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "8.1.1" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c" +checksum = "09f4f04699947111ec1733e71778d763555737579e44b85844cae8e1940a1828" dependencies = [ - "base64", + "base64 0.13.1", "pem", "ring", "serde", @@ -763,9 +800,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "lock_api" @@ -794,9 +831,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matchit" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "memchr" @@ -855,7 +892,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -864,29 +901,11 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", -] - [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -894,9 +913,9 @@ dependencies = [ [[package]] name = "nom_locate" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605" +checksum = "b1e299bf5ea7b212e811e71174c5d1a5d065c4c0ad0c8691ecb1f97e3e66025e" dependencies = [ "bytecount", "memchr", @@ -926,15 +945,17 @@ dependencies = [ "autocfg", "num-integer", "num-traits", + "serde", ] [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -968,6 +989,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -981,19 +1003,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "openssl-probe" @@ -1013,22 +1035,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "pbjson" @@ -1036,7 +1058,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "599fe9aefc2ca0df4a96179b3075faee2cacb89d4cf947a00b9a89152dfffc9d" dependencies = [ - "base64", + "base64 0.13.1", "serde", ] @@ -1054,11 +1076,11 @@ dependencies = [ [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -1123,9 +1145,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ "proc-macro2", "syn", @@ -1133,18 +1155,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" +checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" dependencies = [ "bytes", "prost-derive", @@ -1152,9 +1174,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8b442418ea0822409d9e7d047cbf1e7e9e1760b172bf9982cf29d517c93511" +checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" dependencies = [ "bytes", "heck", @@ -1174,9 +1196,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306" +checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" dependencies = [ "anyhow", "itertools", @@ -1187,9 +1209,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" +checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" dependencies = [ "bytes", "prost", @@ -1203,8 +1225,10 @@ checksum = "268be0c73583c183f2b14052337465768c07726936a260f480f0857cb95ba543" dependencies = [ "cfg-if", "indoc", + "inventory", "libc", "memoffset", + "num-complex", "parking_lot", "pyo3-build-config", "pyo3-ffi", @@ -1268,16 +1292,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pythonize" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7f0c136f5fbc01868185eef462800e49659eb23acca83b9e884367a006acb6" -dependencies = [ - "pyo3", - "serde", -] - [[package]] name = "qcs" version = "0.9.2" @@ -1308,7 +1322,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "toml 0.5.9", + "toml 0.5.11", "tonic", "uuid", "warp", @@ -1341,7 +1355,7 @@ dependencies = [ "serde", "thiserror", "tokio", - "toml 0.5.9", + "toml 0.5.11", ] [[package]] @@ -1383,21 +1397,16 @@ dependencies = [ "pyo3", "pyo3-asyncio", "pyo3-build-config", - "pythonize", "qcs", "qcs-api", "qcs-api-client-common", + "qcs-api-client-grpc", "quil-rs", + "rigetti-pyo3", "serde_json", "tokio", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quil-rs" version = "0.15.0" @@ -1417,9 +1426,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1476,9 +1485,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -1502,11 +1511,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -1525,7 +1534,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile 1.0.1", + "rustls-pemfile 1.0.2", "serde", "serde_json", "serde_urlencoded", @@ -1540,6 +1549,19 @@ dependencies = [ "winreg", ] +[[package]] +name = "rigetti-pyo3" +version = "0.1.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298f878d681dbe7bea9652f48816534c16f165c259b2b19d1dc5a4f00f929ad6" +dependencies = [ + "num-complex", + "num-traits", + "paste", + "pyo3", + "time", +] + [[package]] name = "ring" version = "0.16.20" @@ -1579,9 +1601,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -1596,7 +1618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.1", + "rustls-pemfile 1.0.2", "schannel", "security-framework", ] @@ -1607,44 +1629,37 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" - -[[package]] -name = "ryu" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] -name = "safemem" -version = "0.3.3" +name = "ryu" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys", ] [[package]] @@ -1671,9 +1686,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36" dependencies = [ "bitflags", "core-foundation", @@ -1684,9 +1699,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -1694,27 +1709,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -1723,9 +1738,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -1744,17 +1759,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha1" version = "0.10.5" @@ -1859,9 +1863,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.103" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1896,18 +1900,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -1958,9 +1962,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" dependencies = [ "autocfg", "bytes", @@ -1973,7 +1977,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys", ] [[package]] @@ -1988,9 +1992,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -2019,18 +2023,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -2053,23 +2045,23 @@ checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "tonic" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b9af819e54b8f33d453655bef9b9acc171568fb49523078d0cc4e7484200ec" +checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.13.1", "bytes", "futures-core", "futures-util", @@ -2083,7 +2075,7 @@ dependencies = [ "prost", "prost-derive", "rustls-native-certs", - "rustls-pemfile 1.0.1", + "rustls-pemfile 1.0.2", "tokio", "tokio-rustls", "tokio-stream", @@ -2097,9 +2089,9 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c6fd7c2581e36d63388a9e04c350c21beb7a8b059580b2e93993c526899ddc" +checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" dependencies = [ "prettyplease", "proc-macro2", @@ -2130,9 +2122,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" dependencies = [ "bitflags", "bytes", @@ -2204,43 +2196,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "tungstenite" -version = "0.17.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "sha-1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicase" @@ -2253,15 +2217,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -2274,9 +2238,9 @@ dependencies = [ [[package]] name = "unindent" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ee9362deb4a96cef4d437d1ad49cffc9b9e92d202b6995674e928ce684f112" +checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" [[package]] name = "untrusted" @@ -2295,12 +2259,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "uuid" version = "1.2.2" @@ -2341,7 +2299,6 @@ dependencies = [ "log", "mime", "mime_guess", - "multipart", "percent-encoding", "pin-project", "rustls-pemfile 0.2.1", @@ -2351,7 +2308,6 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-stream", - "tokio-tungstenite", "tokio-util", "tower-service", "tracing", @@ -2451,18 +2407,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -2491,19 +2447,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -2511,85 +2454,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" diff --git a/crates/lib/Cargo.toml b/crates/lib/Cargo.toml index e8a9dbaf8..07436d7fb 100644 --- a/crates/lib/Cargo.toml +++ b/crates/lib/Cargo.toml @@ -19,7 +19,7 @@ futures = "0.3.24" indexmap = "1.9.1" lazy_static = "1.4.0" log = "0.4.17" -num = "0.4.0" +num = { version = "0.4.0", features = ["serde"] } qcs-api = "0.2.1" qcs-api-client-common = "0.2.7" qcs-api-client-openapi = "0.3.8" @@ -31,7 +31,7 @@ serde = { version = "1.0.145", features = ["derive"] } serde_bytes = "0.11.7" serde_json = "1.0.86" thiserror = "1.0.37" -tokio = { version = "1.21.2", features = ["fs"] } +tokio = { version = "1.24.2", features = ["fs"] } toml = "0.5.9" uuid = { version = "1.2.1", features = ["v4"] } tonic = { version = "0.8.2", features = ["tls", "tls-roots"] } @@ -46,5 +46,5 @@ qcs-api-client-grpc = { version = "0.2.7", features = ["server"] } simple_logger = { version = "2.3.0", default-features = false } tempfile = "3.3.0" tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } -warp = "0.3.3" +warp = { version = "0.3.3", default-features = false } regex = "1.7.0" diff --git a/crates/lib/src/api.rs b/crates/lib/src/api.rs index f53e33bc7..85186bf14 100644 --- a/crates/lib/src/api.rs +++ b/crates/lib/src/api.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, str::FromStr}; +use num::Complex; use qcs_api_client_grpc::{ models::controller::{readout_values, ControllerJobExecutionResult}, services::controller::{ @@ -55,7 +56,7 @@ pub enum RewriteArithmeticError { /// The result of a call to [`rewrite_arithmetic`] which provides the /// information necessary to later patch-in memory values to a compiled program. -#[derive(Debug, Serialize)] +#[derive(Clone, Debug, Serialize)] pub struct RewriteArithmeticResult { /// The rewritten program pub program: String, @@ -193,17 +194,13 @@ pub fn build_patch_values( .iter() .map(|expr| Expression::from_str(expr)) .collect::>() - .map_err(|e| format!("Unable to interpret recalculation table: {:?}", e))?; + .map_err(|e| format!("Unable to interpret recalculation table: {e:?}"))?; rewrite_arithmetic::get_substitutions(&substitutions, memory) } -/// A convenience type that describes a Complex-64 value whose real -/// and imaginary parts of both f32. -pub type Complex64 = [f32; 2]; - /// Data from an individual register. Each variant contains a vector with the expected data type /// where each value in the vector corresponds to a shot. -#[derive(Debug, PartialEq, Serialize)] +#[derive(Clone, Debug, PartialEq, Serialize)] #[serde(untagged)] // Don't include the discriminant name in serialized output. pub enum Register { /// A register of 64-bit floating point numbers @@ -213,7 +210,7 @@ pub enum Register { /// A register of 32-bit integers I32(Vec), /// A register of 64-bit complex numbers - Complex64(Vec), + Complex64(Vec>), /// A register of 8-bit integers (bytes) I8(Vec), } @@ -224,7 +221,7 @@ impl From for Register { runner::Register::F64(f) => Register::F64(f), runner::Register::I16(i) => Register::I16(i), runner::Register::Complex32(c) => { - Register::Complex64(c.iter().map(|c| [c.re, c.im]).collect()) + Register::Complex64(c.iter().map(|c| Complex::::new(c.re, c.im)).collect()) } runner::Register::I8(i) => Register::I8(i), } @@ -232,7 +229,7 @@ impl From for Register { } /// The execution readout data from a particular memory location. -#[derive(Debug, Serialize)] +#[derive(Clone, Debug, Serialize)] pub struct ExecutionResult { shape: Vec, data: Register, @@ -248,7 +245,9 @@ impl From for ExecutionResult { data: Register::Complex64( c.values .iter() - .map(|c| [c.real.unwrap_or(0.0), c.imaginary.unwrap_or(0.0)]) + .map(|c| { + Complex::::new(c.real.unwrap_or(0.0), c.imaginary.unwrap_or(0.0)) + }) .collect(), ), }, @@ -262,7 +261,7 @@ impl From for ExecutionResult { } /// Execution readout data for all memory locations. -#[derive(Debug, Serialize)] +#[derive(Clone, Debug, Serialize)] pub struct ExecutionResults { buffers: HashMap, execution_duration_microseconds: Option, diff --git a/crates/lib/src/configuration/mod.rs b/crates/lib/src/configuration/mod.rs deleted file mode 100644 index 50513e0e0..000000000 --- a/crates/lib/src/configuration/mod.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! This module is used for loading configuration that will be used to connect either to real QPUs -//! (and supporting services) or the QVM. -//! -//! By default, all settings are loaded from files located -//! under your home directory in a `.qcs` folder. `settings.toml` will be used to load general -//! settings (e.g. which URLs to connect to) and `secrets.toml` will be used to load tokens for -//! authentication. Both "settings" and "secrets" files should contain profiles. The -//! `default_profile_name` in settings sets the profile to be used when there is no override. You -//! can set the [`PROFILE_NAME_VAR`] to select a different profile. You can also use -//! [`SECRETS_PATH_VAR`] and [`SETTINGS_PATH_VAR`] to change which files are loaded. - -use std::path::PathBuf; - -use futures::future::try_join; -use serde::{Deserialize, Serialize}; - -use qcs_api::apis::configuration as api; -use secrets::Secrets; -pub use secrets::SECRETS_PATH_VAR; -pub use settings::SETTINGS_PATH_VAR; -use settings::{AuthServer, Pyquil, Settings}; - -use crate::configuration::LoadError::AuthServerNotFound; - -mod path; -mod secrets; -mod settings; - -/// All the config data that's parsed from config sources -#[derive(Clone, Debug)] -pub struct Configuration { - api_config: api::Configuration, - auth_server: AuthServer, - refresh_token: Option, - /// The URL for the quilc server. - pub quilc_url: String, - /// The URL for the QVM server. - pub qvm_url: String, -} - -/// Setting this environment variable will change which profile is used from the loaded config files -pub const PROFILE_NAME_VAR: &str = "QCS_PROFILE_NAME"; - -/// Errors raised when attempting to refresh the user's token -#[derive(Debug, thiserror::Error)] -pub enum RefreshError { - /// Error due to no token available to refresh. - #[error("No refresh token is in secrets")] - NoRefreshToken, - /// Error when trying to fetch the new token. - #[error("Error fetching new token")] - FetchError(#[from] reqwest::Error), -} - -/// Errors raised when attempting to load the user's configuration files. -#[derive(Debug, thiserror::Error)] -pub enum LoadError { - /// Error due to requested profile missing in the user's configuration. - #[error("Expected profile {0} in settings.profiles but it didn't exist")] - ProfileNotFound(String), - /// Error due to authentication server missing in the user's configuration. - #[error("Expected auth server {0} in settings.auth_servers but it didn't exist")] - AuthServerNotFound(String), - /// Error due to failing to find the user's home directory. - #[error("Failed to determine home directory. You can use an explicit path by setting the {env} environment variable")] - HomeDirError { - /// Environment variable to set to configure the home directory. - env: String, - }, - /// Error due to failing to open a file. - #[error("Could not open file at {path}")] - FileOpenError { - /// Path to file that could not be opened. - path: PathBuf, - /// The source error. - source: std::io::Error, - }, - /// Error due to failing to parse a file. - #[error("Could not parse file at {path}")] - FileParseError { - /// Path to file that could not be parsed. - path: PathBuf, - /// Source error. - source: toml::de::Error, - }, -} - -impl Configuration { - /// Attempt to load config files from ~/.qcs and create a Configuration object - /// for use with qcs-api. - /// - /// # Errors - /// - /// See [`LoadError`]. - pub async fn load() -> Result { - let (settings, secrets) = try_join(settings::load(), secrets::load()).await?; - Self::new(settings, secrets) - } - - /// Refresh the `access_token` and return a new `Configuration` if successful. - /// - /// # Errors - /// - /// See [`RefreshError`]. - pub async fn refresh(mut self) -> Result { - let refresh_token = self.refresh_token.ok_or(RefreshError::NoRefreshToken)?; - let token_url = format!("{}/v1/token", &self.auth_server.issuer); - let data = TokenRequest::new(&self.auth_server.client_id, &refresh_token); - let resp = self - .api_config - .client - .post(token_url) - .form(&data) - .send() - .await?; - let response_data: TokenResponse = resp.error_for_status()?.json().await?; - self.api_config.bearer_access_token = Some(response_data.access_token); - self.refresh_token = Some(response_data.refresh_token); - Ok(self) - } - - fn new(settings: Settings, mut secrets: Secrets) -> Result { - let Settings { - default_profile_name, - mut profiles, - mut auth_servers, - } = settings; - let profile_name = std::env::var(PROFILE_NAME_VAR).unwrap_or(default_profile_name); - let profile = profiles - .remove(&profile_name) - .ok_or(LoadError::ProfileNotFound(profile_name))?; - let auth_server = auth_servers - .remove(&profile.auth_server_name) - .ok_or_else(|| AuthServerNotFound(profile.auth_server_name.clone()))?; - - let credential = secrets.credentials.remove(&profile.credentials_name); - let (access_token, refresh_token) = match credential { - Some(secrets::Credential { - token_payload: Some(token_payload), - }) => (token_payload.access_token, token_payload.refresh_token), - _ => (None, None), - }; - - Ok(Self { - api_config: api::Configuration { - base_path: profile.api_url, - bearer_access_token: access_token, - ..api::Configuration::default() - }, - auth_server, - refresh_token, - quilc_url: profile.applications.pyquil.quilc_url, - qvm_url: profile.applications.pyquil.qvm_url, - }) - } -} - -#[derive(Debug, Serialize, Copy, Clone, Eq, PartialEq)] -struct TokenRequest<'a> { - grant_type: &'static str, - client_id: &'a str, - refresh_token: &'a str, -} - -impl<'a> TokenRequest<'a> { - fn new(client_id: &'a str, refresh_token: &'a str) -> TokenRequest<'a> { - Self { - grant_type: "refresh_token", - client_id, - refresh_token, - } - } -} - -#[derive(Deserialize, Debug, Clone, Eq, PartialEq)] -struct TokenResponse { - refresh_token: String, - access_token: String, -} - -impl AsRef for Configuration { - fn as_ref(&self) -> &api::Configuration { - &self.api_config - } -} - -impl Default for Configuration { - fn default() -> Self { - let Pyquil { quilc_url, qvm_url } = Pyquil::default(); - Self { - quilc_url, - qvm_url, - api_config: api::Configuration::default(), - auth_server: AuthServer::default(), - refresh_token: None, - } - } -} diff --git a/crates/lib/src/configuration/path.rs b/crates/lib/src/configuration/path.rs deleted file mode 100644 index fbd5b2c6b..000000000 --- a/crates/lib/src/configuration/path.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::path::PathBuf; - -use super::LoadError; - -pub(crate) fn path_from_env_or_home(env: &str, file_name: &str) -> Result { - match std::env::var(env) { - Ok(path) => Ok(PathBuf::from(path)), - Err(_) => dirs::home_dir() - .map(|path| path.join(".qcs").join(file_name)) - .ok_or_else(|| LoadError::HomeDirError { - env: env.to_string(), - }), - } -} diff --git a/crates/lib/src/configuration/secrets.rs b/crates/lib/src/configuration/secrets.rs deleted file mode 100644 index 31690a2df..000000000 --- a/crates/lib/src/configuration/secrets.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -use crate::configuration::LoadError; - -use super::path::path_from_env_or_home; - -/// Setting the `QCS_SECRETS_FILE_PATH` environment variable will change which file is used for loading secrets -pub const SECRETS_PATH_VAR: &str = "QCS_SECRETS_FILE_PATH"; - -pub(crate) async fn load() -> Result { - let path = path_from_env_or_home(SECRETS_PATH_VAR, "secrets.toml")?; - let content = - tokio::fs::read_to_string(&path) - .await - .map_err(|source| LoadError::FileOpenError { - path: path.clone(), - source, - })?; - toml::from_str(&content).map_err(|source| LoadError::FileParseError { path, source }) -} - -#[cfg(test)] -mod describe_load { - use std::io::Write; - - use tempfile::NamedTempFile; - - use super::{load, Credential, Secrets, SECRETS_PATH_VAR}; - - #[tokio::test] - async fn it_returns_default_if_missing_path() { - std::env::set_var(SECRETS_PATH_VAR, "/blah/doesnt_exist.toml"); - - let settings = load().await; - - std::env::remove_var(SECRETS_PATH_VAR); - assert!(settings.is_err()); - } - - #[tokio::test] - async fn it_loads_from_env_var_path() { - let mut file = NamedTempFile::new().expect("Failed to create temporary settings file"); - let mut secrets = Secrets::default(); - secrets - .credentials - .insert("test".to_string(), Credential::default()); - let secrets_string = toml::to_string(&secrets).expect("Could not serialize test settings"); - let _ = file - .write(secrets_string.as_bytes()) - .expect("Failed to write test settings"); - std::env::set_var(SECRETS_PATH_VAR, file.path()); - - let loaded = load().await.expect("Failed to load secrets"); - - assert_eq!(secrets, loaded); - } -} - -#[derive(Deserialize, Debug, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Secrets { - pub credentials: HashMap, -} - -impl Default for Secrets { - fn default() -> Self { - Self { - credentials: default_credentials(), - } - } -} - -fn default_credentials() -> HashMap { - let mut map = HashMap::with_capacity(1); - map.insert("default".to_string(), Credential::default()); - map -} - -#[derive(Deserialize, Debug, Default, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Credential { - pub token_payload: Option, -} - -#[derive(Deserialize, Debug, Default, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct TokenPayload { - pub refresh_token: Option, - pub access_token: Option, - scope: Option, - expires_in: Option, - id_token: Option, - token_type: Option, -} diff --git a/crates/lib/src/configuration/settings.rs b/crates/lib/src/configuration/settings.rs deleted file mode 100644 index c7f9b8934..000000000 --- a/crates/lib/src/configuration/settings.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::collections::HashMap; - -use serde::{Deserialize, Serialize}; - -use super::path::path_from_env_or_home; -use super::LoadError; - -/// Setting the `QCS_SETTINGS_FILE_PATH` environment variable will change which file is used for loading settings -pub const SETTINGS_PATH_VAR: &str = "QCS_SETTINGS_FILE_PATH"; - -pub(crate) async fn load() -> Result { - let path = path_from_env_or_home(SETTINGS_PATH_VAR, "settings.toml")?; - let content = - tokio::fs::read_to_string(&path) - .await - .map_err(|source| LoadError::FileOpenError { - path: path.clone(), - source, - })?; - toml::from_str(&content).map_err(|source| LoadError::FileParseError { path, source }) -} - -#[cfg(test)] -mod describe_load { - use std::io::Write; - - use tempfile::NamedTempFile; - - use crate::configuration::{settings::load, SETTINGS_PATH_VAR}; - - use super::Settings; - - #[tokio::test] - async fn it_returns_default_if_missing_path() { - std::env::set_var(SETTINGS_PATH_VAR, "/blah/doesnt_exist.toml"); - - let settings = load().await; - - std::env::remove_var(SETTINGS_PATH_VAR); - - assert!(settings.is_err()); - } - - #[tokio::test] - async fn it_loads_from_env_var_path() { - let mut file = NamedTempFile::new().expect("Failed to create temporary settings file"); - let settings = Settings { - default_profile_name: "THIS IS A TEST".to_string(), - ..Default::default() - }; - let settings_string = - toml::to_string(&settings).expect("Could not serialize test settings"); - let _ = file - .write(settings_string.as_bytes()) - .expect("Failed to write test settings"); - std::env::set_var(SETTINGS_PATH_VAR, file.path()); - - let loaded = load().await.expect("Failed to load settings"); - - assert_eq!(settings, loaded); - } -} - -#[derive(Deserialize, Debug, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Settings { - /// Which profile to select settings from when none is specified. - pub default_profile_name: String, - /// All available configuration profiles, keyed by profile name. - #[serde(default = "default_profiles")] - pub profiles: HashMap, - #[serde(default)] - pub(crate) auth_servers: HashMap, -} - -impl Default for Settings { - fn default() -> Self { - Self { - default_profile_name: "default".to_string(), - profiles: default_profiles(), - auth_servers: default_auth_servers(), - } - } -} - -fn default_profiles() -> HashMap { - let mut map = HashMap::with_capacity(1); - map.insert("default".to_string(), Profile::default()); - map -} - -fn default_auth_servers() -> HashMap { - let mut map = HashMap::with_capacity(1); - map.insert("default".to_string(), AuthServer::default()); - map -} - -#[derive(Deserialize, Debug, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Profile { - /// URL of the QCS API to use for all API calls - pub api_url: String, - pub auth_server_name: String, - pub credentials_name: String, - #[serde(default)] - pub applications: Applications, -} - -impl Default for Profile { - fn default() -> Self { - Self { - api_url: "https://api.qcs.rigetti.com".to_string(), - auth_server_name: "default".to_string(), - credentials_name: "default".to_string(), - applications: Applications::default(), - } - } -} - -#[derive(Deserialize, Debug, Default, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Applications { - pub pyquil: Pyquil, -} - -#[derive(Deserialize, Debug, PartialEq, Serialize, Clone, Eq)] -pub(crate) struct Pyquil { - pub qvm_url: String, - pub quilc_url: String, -} - -impl Default for Pyquil { - fn default() -> Self { - Self { - qvm_url: "http://127.0.0.1:5000".to_string(), - quilc_url: "tcp://127.0.0.1:5555".to_string(), - } - } -} - -#[derive(Clone, Deserialize, Debug, PartialEq, Serialize, Eq)] -pub(crate) struct AuthServer { - pub(crate) client_id: String, - pub(crate) issuer: String, -} - -impl Default for AuthServer { - fn default() -> Self { - Self { - client_id: "0oa3ykoirzDKpkfzk357".to_string(), - issuer: "https://auth.qcs.rigetti.com/oauth2/aus8jcovzG0gW2TUG355".to_string(), - } - } -} diff --git a/crates/lib/src/executable.rs b/crates/lib/src/executable.rs index 7319ffed4..489a6187d 100644 --- a/crates/lib/src/executable.rs +++ b/crates/lib/src/executable.rs @@ -1,6 +1,7 @@ //! This module contains the public-facing API for executing programs. [`Executable`] is the how //! users will interact with QCS, quilc, and QVM. +use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -66,7 +67,7 @@ use quil_rs::Program; pub struct Executable<'executable, 'execution> { quil: Arc, shots: u16, - readout_memory_region_names: Option>, + readout_memory_region_names: Option>>, params: Parameters, compile_with_quilc: bool, compiler_options: CompilerOpts, @@ -160,9 +161,12 @@ impl<'executable> Executable<'executable, '_> { /// } /// ``` #[must_use] - pub fn read_from(mut self, register: &'executable str) -> Self { + pub fn read_from(mut self, register: S) -> Self + where + S: Into>, + { let mut readouts = self.readout_memory_region_names.take().unwrap_or_default(); - readouts.push(register); + readouts.push(register.into()); self.readout_memory_region_names = Some(readouts); self } @@ -264,11 +268,11 @@ impl Executable<'_, '_> { self } - fn get_readouts(&self) -> &[&str] { + fn get_readouts(&self) -> &[Cow<'_, str>] { return self .readout_memory_region_names .as_ref() - .map_or(&["ro"], Vec::as_slice); + .map_or(&[Cow::Borrowed("ro")], Vec::as_slice); } /// Execute on a QVM which must be available at the configured URL (default ). @@ -330,12 +334,13 @@ impl Executable<'_, '_> { impl<'execution> Executable<'_, 'execution> { /// Remove and return `self.qpu` if it's set and still valid. Otherwise, create a new one. - async fn qpu_for_id( - &mut self, - id: &'execution str, - ) -> Result, Error> { + async fn qpu_for_id(&mut self, id: S) -> Result, Error> + where + S: Into>, + { + let id = id.into(); if let Some(qpu) = self.qpu.take() { - if qpu.quantum_processor_id == id && qpu.shots == self.shots { + if qpu.quantum_processor_id == id.as_ref() && qpu.shots == self.shots { return Ok(qpu); } } @@ -377,10 +382,10 @@ impl<'execution> Executable<'_, 'execution> { /// 1. Missing parameters that should be filled with [`Executable::with_parameter`] /// /// [quilc]: https://github.com/quil-lang/quilc - pub async fn execute_on_qpu( - &mut self, - quantum_processor_id: &'execution str, - ) -> ExecuteResultQPU { + pub async fn execute_on_qpu(&mut self, quantum_processor_id: S) -> ExecuteResultQPU + where + S: Into>, + { let job_handle = self.submit_to_qpu(quantum_processor_id).await?; self.retrieve_results(job_handle).await } @@ -393,16 +398,20 @@ impl<'execution> Executable<'_, 'execution> { /// # Errors /// /// See [`Executable::execute_on_qpu`]. - pub async fn submit_to_qpu( + pub async fn submit_to_qpu( &mut self, - quantum_processor_id: &'execution str, - ) -> Result, Error> { + quantum_processor_id: S, + ) -> Result, Error> + where + S: Into>, + { + let quantum_processor_id = quantum_processor_id.into(); let JobHandle { job_id, readout_map, .. } = self - .qpu_for_id(quantum_processor_id) + .qpu_for_id(quantum_processor_id.clone()) .await? .submit(&self.params) .await?; @@ -527,11 +536,11 @@ pub enum Service { impl From for Error { fn from(err: ExecutionError) -> Self { match err { - ExecutionError::Unexpected(inner) => Self::Unexpected(format!("{:?}", inner)), + ExecutionError::Unexpected(inner) => Self::Unexpected(format!("{inner:?}")), ExecutionError::Quilc { .. } => Self::Connection(Service::Quilc), - ExecutionError::QcsClient(v) => Self::Unexpected(format!("{:?}", v)), - ExecutionError::IsaError(v) => Self::Unexpected(format!("{:?}", v)), - ExecutionError::ReadoutParse(v) => Self::Unexpected(format!("{:?}", v)), + ExecutionError::QcsClient(v) => Self::Unexpected(format!("{v:?}")), + ExecutionError::IsaError(v) => Self::Unexpected(format!("{v:?}")), + ExecutionError::ReadoutParse(v) => Self::Unexpected(format!("{v:?}")), ExecutionError::Quil(e) => Self::Quil(e), ExecutionError::Compilation { details } => Self::Compilation(details), ExecutionError::RewriteArithmetic(e) => Self::RewriteArithmetic(e), @@ -548,7 +557,7 @@ impl From for Error { | qvm::Error::ShotsMustBePositive | qvm::Error::RegionSizeMismatch { .. } | qvm::Error::RegionNotFound { .. } - | qvm::Error::Qvm { .. } => Self::Compilation(format!("{}", err)), + | qvm::Error::Qvm { .. } => Self::Compilation(format!("{err}")), } } } @@ -558,20 +567,23 @@ impl From for Error { #[derive(Debug, Clone, PartialEq, Eq)] pub struct JobHandle<'executable> { job_id: JobId, - quantum_processor_id: &'executable str, + quantum_processor_id: Cow<'executable, str>, readout_map: HashMap, } impl<'a> JobHandle<'a> { #[must_use] - pub(crate) fn new( + pub(crate) fn new( job_id: JobId, - quantum_processor_id: &'a str, + quantum_processor_id: S, readout_map: HashMap, - ) -> Self { + ) -> Self + where + S: Into>, + { Self { job_id, - quantum_processor_id, + quantum_processor_id: quantum_processor_id.into(), readout_map, } } diff --git a/crates/lib/src/execution_data.rs b/crates/lib/src/execution_data.rs index cf0b2bb96..e5f602a37 100644 --- a/crates/lib/src/execution_data.rs +++ b/crates/lib/src/execution_data.rs @@ -15,7 +15,7 @@ use crate::RegisterData; pub struct Qvm { /// The readout data that was read from the [`Executable`](crate::Executable). /// Key is the name of the register, value is the data of the register after execution. - pub registers: HashMap, RegisterData>, + pub registers: HashMap, /// The time it took to execute the program on the QPU, not including any network or queueing /// time. If paying for on-demand execution, this is the amount you will be billed for. /// diff --git a/crates/lib/src/lib.rs b/crates/lib/src/lib.rs index eaa5444aa..0182bbbca 100644 --- a/crates/lib/src/lib.rs +++ b/crates/lib/src/lib.rs @@ -10,7 +10,6 @@ absolute_paths_not_starting_with_crate, anonymous_parameters, bad_style, - const_err, dead_code, deprecated_in_future, keyword_idents, diff --git a/crates/lib/src/qpu/execution.rs b/crates/lib/src/qpu/execution.rs index b8867772e..00606abfc 100644 --- a/crates/lib/src/qpu/execution.rs +++ b/crates/lib/src/qpu/execution.rs @@ -1,5 +1,6 @@ //! Contains QPU-specific executable stuff. +use std::borrow::Cow; use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; @@ -28,7 +29,7 @@ use super::{get_isa, IsaError}; #[derive(Debug, Clone)] pub(crate) struct Execution<'a> { program: RewrittenProgram, - pub(crate) quantum_processor_id: &'a str, + pub(crate) quantum_processor_id: Cow<'a, str>, pub(crate) shots: u16, client: Arc, } @@ -58,10 +59,10 @@ pub(crate) enum Error { impl From for Error { fn from(source: quilc::Error) -> Self { match source { - quilc::Error::Isa(source) => Self::Unexpected(Unexpected::Isa(format!("{:?}", source))), + quilc::Error::Isa(source) => Self::Unexpected(Unexpected::Isa(format!("{source:?}"))), quilc::Error::QuilcConnection(uri, details) => Self::Quilc { uri, - details: format!("{:?}", details), + details: format!("{details:?}"), }, quilc::Error::QuilcCompilation(details) => Self::Compilation { details }, quilc::Error::Parse(details) => Self::Compilation { @@ -113,12 +114,12 @@ impl<'a> Execution<'a> { pub(crate) async fn new( quil: Arc, shots: u16, - quantum_processor_id: &'a str, + quantum_processor_id: Cow<'a, str>, client: Arc, compile_with_quilc: bool, compiler_options: CompilerOpts, ) -> Result, Error> { - let isa = get_isa(quantum_processor_id, &client).await?; + let isa = get_isa(quantum_processor_id.as_ref(), &client).await?; let target_device = TargetDevice::try_from(isa)?; let program = if compile_with_quilc { @@ -150,7 +151,7 @@ impl<'a> Execution<'a> { /// Run on a real QPU and wait for the results. pub(crate) async fn submit(&mut self, params: &Parameters) -> Result, Error> { let EncryptedTranslationResult { job, readout_map } = translate( - self.quantum_processor_id, + self.quantum_processor_id.as_ref(), &self.program.to_string().0, self.shots.into(), self.client.as_ref(), @@ -162,7 +163,7 @@ impl<'a> Execution<'a> { .map_err(Error::Substitution)?; let job_id = submit( - self.quantum_processor_id, + self.quantum_processor_id.as_ref(), job, &patch_values, self.client.as_ref(), @@ -171,7 +172,7 @@ impl<'a> Execution<'a> { Ok(JobHandle::new( job_id, - self.quantum_processor_id, + self.quantum_processor_id.clone(), readout_map, )) } @@ -181,8 +182,12 @@ impl<'a> Execution<'a> { job_id: JobId, readout_mappings: HashMap, ) -> Result { - let response = - retrieve_results(job_id, self.quantum_processor_id, self.client.as_ref()).await?; + let response = retrieve_results( + job_id, + self.quantum_processor_id.as_ref(), + self.client.as_ref(), + ) + .await?; Ok(Qpu { readout_data: ReadoutMap::from_mappings_and_values( diff --git a/crates/lib/src/qpu/quilc/isa/mod.rs b/crates/lib/src/qpu/quilc/isa/mod.rs index 75a056131..02049a4ae 100644 --- a/crates/lib/src/qpu/quilc/isa/mod.rs +++ b/crates/lib/src/qpu/quilc/isa/mod.rs @@ -178,7 +178,7 @@ mod describe_compiler_isa { let compiler_isa = Compiler::try_from(qcs_isa).expect("Could not convert ISA to CompilerIsa"); let serialized = - serde_json::to_value(&compiler_isa).expect("Unable to serialize CompilerIsa"); + serde_json::to_value(compiler_isa).expect("Unable to serialize CompilerIsa"); let result = json_is_equivalent(&serialized, &expected); result.expect("JSON was not equivalent"); diff --git a/crates/lib/src/qpu/quilc/mod.rs b/crates/lib/src/qpu/quilc/mod.rs index a86285ddf..fc3a9a392 100644 --- a/crates/lib/src/qpu/quilc/mod.rs +++ b/crates/lib/src/qpu/quilc/mod.rs @@ -194,7 +194,7 @@ mod tests { use super::*; use qcs_api_client_openapi::models::InstructionSetArchitecture; use regex::Regex; - use std::fs::File; + use std::{borrow::Cow, fs::File}; const EXPECTED_H0_OUTPUT: &str = "MEASURE 0\n"; @@ -239,7 +239,12 @@ MEASURE 1 ro[1] .expect("Could not compile"); let mut results = crate::qvm::Execution::new(&output.to_string(true)) .unwrap() - .run(10, &["ro"], &HashMap::default(), &client.get_config()) + .run( + 10, + &[Cow::Borrowed("ro")], + &HashMap::default(), + &client.get_config(), + ) .await .expect("Could not run program on QVM"); for shot in results diff --git a/crates/lib/src/qpu/rewrite_arithmetic.rs b/crates/lib/src/qpu/rewrite_arithmetic.rs index 3094c8541..4e20fb619 100644 --- a/crates/lib/src/qpu/rewrite_arithmetic.rs +++ b/crates/lib/src/qpu/rewrite_arithmetic.rs @@ -129,7 +129,7 @@ pub(crate) fn get_substitutions( .map(|substitution: &Expression| { substitution .evaluate(&HashMap::new(), ¶ms) - .map_err(|e| format!("Could not evaluate expression {}: {:?}", substitution, e)) + .map_err(|e| format!("Could not evaluate expression {substitution}: {e:?}")) .and_then(|complex| { if complex.im == 0.0 { Ok(complex.re) diff --git a/crates/lib/src/qvm/execution.rs b/crates/lib/src/qvm/execution.rs index 2f3715cad..a2e4182c7 100644 --- a/crates/lib/src/qvm/execution.rs +++ b/crates/lib/src/qvm/execution.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use std::str::FromStr; +use std::{borrow::Cow, collections::HashMap}; use qcs_api_client_common::ClientConfiguration; use quil_rs::{ @@ -58,10 +58,10 @@ impl Execution { pub(crate) async fn run( &mut self, shots: u16, - readouts: &[&str], + readouts: &[Cow<'_, str>], params: &Parameters, config: &ClientConfiguration, - ) -> Result, RegisterData>, Error> { + ) -> Result, Error> { if shots == 0 { return Err(Error::ShotsMustBePositive); } @@ -108,9 +108,9 @@ impl Execution { async fn execute( &self, shots: u16, - readouts: &[&str], + readouts: &[Cow<'_, str>], config: &ClientConfiguration, - ) -> Result, RegisterData>, Error> { + ) -> Result, Error> { let request = Request::new(&self.program.to_string(true), shots, readouts); let client = reqwest::Client::new(); @@ -129,11 +129,7 @@ impl Execution { qvm_url: config.qvm_url().into(), source, }), - Ok(Response::Success(response)) => Ok(response - .registers - .into_iter() - .map(|(key, value)| (key.into_boxed_str(), value)) - .collect()), + Ok(Response::Success(response)) => Ok(response.registers), Ok(Response::Failure(response)) => Err(Error::Qvm { message: response.status, }), diff --git a/crates/lib/src/qvm/mod.rs b/crates/lib/src/qvm/mod.rs index e17921675..33dd3f8c9 100644 --- a/crates/lib/src/qvm/mod.rs +++ b/crates/lib/src/qvm/mod.rs @@ -1,7 +1,7 @@ //! This module contains all the functionality for running Quil programs on a QVM. Specifically, //! the [`Execution`] struct in this module. -use std::collections::HashMap; +use std::{borrow::Cow, collections::HashMap}; use serde::{Deserialize, Serialize}; @@ -41,8 +41,8 @@ struct Request<'request> { } impl<'request> Request<'request> { - fn new(program: &str, shots: u16, readouts: &[&'request str]) -> Self { - let addresses: HashMap<&str, bool> = readouts.iter().map(|v| (*v, true)).collect(); + fn new(program: &str, shots: u16, readouts: &'request [Cow<'request, str>]) -> Self { + let addresses: HashMap<&str, bool> = readouts.iter().map(|v| (v.as_ref(), true)).collect(); Self { quil_instructions: program.to_string(), addresses, @@ -60,6 +60,8 @@ enum RequestType { #[cfg(test)] mod describe_request { + use std::borrow::Cow; + use super::Request; #[test] @@ -71,7 +73,7 @@ mod describe_request { #[test] fn it_uses_kebab_case_for_json() { - let request = Request::new("H 0", 10, &["ro"]); + let request = Request::new("H 0", 10, &[Cow::Borrowed("ro")]); let json_string = serde_json::to_string(&request).expect("Could not serialize QVMRequest"); assert_eq!( serde_json::from_str::(&json_string).unwrap(), diff --git a/crates/python/Cargo.toml b/crates/python/Cargo.toml index cfafcd44d..b38fa38f9 100644 --- a/crates/python/Cargo.toml +++ b/crates/python/Cargo.toml @@ -18,12 +18,13 @@ crate-type = ["cdylib"] [dependencies] qcs = { path = "../lib" } qcs-api-client-common = "0.2.7" +qcs-api-client-grpc = "0.2.7" pyo3 = { version = "0.17", features = ["extension-module"] } pyo3-asyncio = { version = "0.17", features = ["tokio-runtime"] } -pythonize = "0.17" quil-rs = "0.15" tokio = "1.21" qcs-api = "0.2.1" +rigetti-pyo3 = { version = "0.1.0-rc.0", features = ["extension-module", "complex"] } serde_json = "1.0.86" [build-dependencies] diff --git a/crates/python/poetry.lock b/crates/python/poetry.lock index 388b8c467..e92cf03ec 100644 --- a/crates/python/poetry.lock +++ b/crates/python/poetry.lock @@ -1,24 +1,26 @@ [[package]] name = "attrs" -version = "22.1.0" +version = "22.2.0" description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] +cov = ["attrs", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs"] +docs = ["furo", "sphinx", "myst-parser", "zope.interface", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["attrs", "zope.interface"] +tests-no-zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] +tests_no_zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] [[package]] name = "black" -version = "22.8.0" +version = "22.12.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" @@ -26,7 +28,6 @@ mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -45,44 +46,37 @@ python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] -name = "importlib-metadata" -version = "4.12.0" -description = "Read metadata from Python packages" +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" category = "dev" optional = false python-versions = ">=3.7" -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] -perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +test = ["pytest (>=6)"] [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "maturin" -version = "0.13.3" +version = "0.13.7" description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" category = "dev" optional = false @@ -105,18 +99,15 @@ python-versions = "*" [[package]] name = "packaging" -version = "21.3" +version = "23.0" description = "Core utilities for Python packages" category = "dev" optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +python-versions = ">=3.7" [[package]] name = "pathspec" -version = "0.10.1" +version = "0.10.3" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false @@ -124,15 +115,15 @@ python-versions = ">=3.7" [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.6.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx-autodoc-typehints (>=1.19.5)", "sphinx (>=5.3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest (>=7.2)"] [[package]] name = "pluggy" @@ -142,35 +133,13 @@ category = "dev" optional = false python-versions = ">=3.6" -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" -optional = false -python-versions = ">=3.6.8" - -[package.extras] -diagrams = ["railroad-diagrams", "jinja2"] - [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -179,12 +148,11 @@ python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] @@ -199,7 +167,6 @@ python-versions = ">=3.7" [package.dependencies] pytest = ">=6.1.0" -typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} [package.extras] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] @@ -212,38 +179,18 @@ category = "dev" optional = false python-versions = ">=3.7" -[[package]] -name = "typed-ast" -version = "1.5.4" -description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" -optional = false -python-versions = ">=3.6" - [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "dev" optional = false python-versions = ">=3.7" -[[package]] -name = "zipp" -version = "3.8.1" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] - [metadata] lock-version = "1.1" -python-versions = "^3.7" -content-hash = "d974c959893832d70b661e1805ddc82b886d828edd542b944f11512e6f2a3914" +python-versions = "^3.8" +content-hash = "67c0952caa1ebf2881aec378850a3188a6650b6b9cc9cda838dec5d23ed15e72" [metadata.files] attrs = [] @@ -253,68 +200,24 @@ click = [ {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] colorama = [] -importlib-metadata = [] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] +exceptiongroup = [] +iniconfig = [] maturin = [] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] +packaging = [] pathspec = [] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] +platformdirs = [] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] pytest = [] pytest-asyncio = [] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -typed-ast = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] typing-extensions = [] -zipp = [] diff --git a/crates/python/pyproject.toml b/crates/python/pyproject.toml index 59989028f..fd435aede 100644 --- a/crates/python/pyproject.toml +++ b/crates/python/pyproject.toml @@ -40,7 +40,7 @@ compatibility = "linux" sdist-include = ["README.md"] [tool.poetry.dependencies] -python = "^3.7" +python = "^3.8" [tool.poetry.dev-dependencies] maturin = "^0.13.2" diff --git a/crates/python/src/api.rs b/crates/python/src/api.rs new file mode 100644 index 000000000..ca8bfb975 --- /dev/null +++ b/crates/python/src/api.rs @@ -0,0 +1,223 @@ +use std::collections::HashMap; + +use pyo3::{ + create_exception, + exceptions::{PyRuntimeError, PyValueError}, + prelude::*, + pyfunction, + types::{PyComplex, PyDict, PyFloat, PyInt, PyList, PyString}, + Py, PyResult, +}; +use qcs::{ + api::{ + ExecutionResult, ExecutionResults, Register, RewriteArithmeticResult, TranslationResult, + }, + qpu::{ + quilc::{CompilerOpts, TargetDevice, DEFAULT_COMPILER_TIMEOUT}, + Qcs, + }, +}; +use rigetti_pyo3::{ + create_init_submodule, py_wrap_data_struct, py_wrap_error, py_wrap_type, py_wrap_union_enum, + wrap_error, ToPython, +}; + +create_init_submodule! { + classes: [ + PyExecutionResult, + PyExecutionResults, + PyRegister, + PyRewriteArithmeticResult, + PyTranslationResult + ], + errors: [ + InvalidConfigError, + ExecutionError, + TranslationError, + CompilationError, + RewriteArithmeticError, + DeviceIsaError, + QcsSubmitError + ], + funcs: [ + compile, + rewrite_arithmetic, + translate, + submit, + retrieve_results, + build_patch_values, + get_quilc_version + ], +} + +py_wrap_data_struct! { + PyRewriteArithmeticResult(RewriteArithmeticResult) as "RewriteArithmeticResult" { + program: String => Py, + recalculation_table: Vec => Py + } +} + +py_wrap_data_struct! { + PyTranslationResult(TranslationResult) as "TranslationResult" { + program: String => Py, + ro_sources: Option> => Option> + } +} + +py_wrap_type! { + PyExecutionResults(ExecutionResults) as "ExecutionResults"; +} + +py_wrap_union_enum! { + PyRegister(Register) as "Register" { + f64: F64 => Vec>, + i16: I16 => Vec>, + i32: I32 => Vec>, + i8: I8 => Vec>, + complex64: Complex64 => Vec> + } +} + +py_wrap_type! { + PyExecutionResult(ExecutionResult) as "ExecutionResult"; +} + +create_exception!(qcs, InvalidConfigError, PyRuntimeError); +create_exception!(qcs, ExecutionError, PyRuntimeError); +create_exception!(qcs, TranslationError, PyRuntimeError); +create_exception!(qcs, CompilationError, PyRuntimeError); +create_exception!(qcs, RewriteArithmeticError, PyRuntimeError); +create_exception!(qcs, DeviceIsaError, PyValueError); + +wrap_error!(SubmitError(qcs::api::SubmitError)); +py_wrap_error!(api, SubmitError, QcsSubmitError, PyRuntimeError); + +#[pyfunction(kwds = "**")] +pub fn compile<'a>( + py: Python<'a>, + quil: String, + target_device: String, + kwds: Option<&PyDict>, +) -> PyResult<&'a PyAny> { + let target_device: TargetDevice = + serde_json::from_str(&target_device).map_err(|e| DeviceIsaError::new_err(e.to_string()))?; + + let mut compiler_timeout = Some(DEFAULT_COMPILER_TIMEOUT); + if let Some(kwargs) = kwds { + if let Some(timeout_arg) = kwargs.get_item("timeout") { + let timeout: Result, _> = timeout_arg.extract(); + if let Ok(option) = timeout { + compiler_timeout = option + } + } + } + + pyo3_asyncio::tokio::future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; + let options = CompilerOpts::default().with_timeout(compiler_timeout); + let result = qcs::api::compile(&quil, target_device, &client, options) + .map_err(|e| CompilationError::new_err(e.to_string()))?; + Ok(result) + }) +} + +#[pyfunction] +pub fn rewrite_arithmetic(native_quil: String) -> PyResult { + let native_program = native_quil + .parse::() + .map_err(|e| TranslationError::new_err(e.to_string()))?; + let result = qcs::api::rewrite_arithmetic(native_program) + .map_err(|e| RewriteArithmeticError::new_err(e.to_string()))?; + let pyed = result.into(); + Ok(pyed) +} + +#[pyfunction] +pub fn build_patch_values( + py: Python<'_>, + recalculation_table: Vec, + memory: HashMap>, +) -> PyResult> { + let memory = memory + .into_iter() + .map(|(k, v)| (k.into_boxed_str(), v)) + .collect(); + let patch_values = qcs::api::build_patch_values(&recalculation_table, &memory) + .map_err(TranslationError::new_err)?; + patch_values + .into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect::>() + .to_python(py) +} + +#[pyfunction] +pub fn translate( + py: Python<'_>, + native_quil: String, + num_shots: u16, + quantum_processor_id: String, +) -> PyResult<&PyAny> { + pyo3_asyncio::tokio::future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; + let result = qcs::api::translate(&native_quil, num_shots, &quantum_processor_id, &client) + .await + .map_err(|e| TranslationError::new_err(e.to_string()))?; + Python::with_gil(|py| PyTranslationResult::from(result).to_python(py)) + }) +} + +#[pyfunction] +pub fn submit( + py: Python<'_>, + program: String, + patch_values: HashMap>, + quantum_processor_id: String, + use_gateway: bool, +) -> PyResult<&PyAny> { + pyo3_asyncio::tokio::future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(|e| InvalidConfigError::new_err(e.to_string()))? + .with_use_gateway(use_gateway); + let job_id = qcs::api::submit(&program, patch_values, &quantum_processor_id, &client) + .await + .map_err(|e| ExecutionError::new_err(e.to_string()))?; + Ok(Python::with_gil(|_py| job_id)) + }) +} + +#[pyfunction] +pub fn retrieve_results( + py: Python<'_>, + job_id: String, + quantum_processor_id: String, + use_gateway: bool, +) -> PyResult<&PyAny> { + pyo3_asyncio::tokio::future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(|e| InvalidConfigError::new_err(e.to_string()))? + .with_use_gateway(use_gateway); + let results = qcs::api::retrieve_results(&job_id, &quantum_processor_id, &client) + .await + .map_err(|e| ExecutionError::new_err(e.to_string()))?; + Ok(PyExecutionResults::from(results)) + }) +} + +#[pyfunction] +pub fn get_quilc_version(py: Python<'_>) -> PyResult<&PyAny> { + pyo3_asyncio::tokio::future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; + let version = qcs::api::get_quilc_version(&client) + .map_err(|e| CompilationError::new_err(e.to_string()))?; + Ok(version) + }) +} diff --git a/crates/python/src/executable.rs b/crates/python/src/executable.rs new file mode 100644 index 000000000..b2ae881fe --- /dev/null +++ b/crates/python/src/executable.rs @@ -0,0 +1,162 @@ +use std::sync::Arc; + +use pyo3::{ + exceptions::PyRuntimeError, pyclass, pymethods, types::PyDict, FromPyObject, Py, PyAny, + PyResult, Python, +}; +use qcs::{Error, Executable, JobHandle, Qpu, Qvm, Service}; +use rigetti_pyo3::{ + impl_as_mut_for_wrapper, py_wrap_error, py_wrap_simple_enum, py_wrap_type, wrap_error, + PyWrapper, ToPython, ToPythonError, +}; +use tokio::sync::Mutex; + +use crate::qpu::quilc::PyCompilerOpts; + +wrap_error!(ExecutionError(Error)); + +py_wrap_error!( + executable, + ExecutionError, + QcsExecutionError, + PyRuntimeError +); + +// Because Python is garbage-collected, no lifetimes can be guaranteed except `'static`. +// +// `Arc>` to work around https://github.com/awestlake87/pyo3-asyncio/issues/50 +py_wrap_type! { + PyExecutable(Arc>>) as "Executable"; +} + +impl_as_mut_for_wrapper!(PyExecutable); + +#[pyclass] +#[pyo3(name = "ExeParameter")] +#[derive(FromPyObject)] +pub struct PyParameter { + name: String, + index: usize, + value: f64, +} + +#[pymethods] +impl PyExecutable { + #[new] + #[args( + "/", + registers = "Vec::new()", + parameters = "Vec::new()", + shots = "None", + compile_with_quilc = "None", + compiler_options = "None" + )] + pub fn new( + quil: String, + registers: Vec, + parameters: Vec, + shots: Option, + compile_with_quilc: Option, + compiler_options: Option, + ) -> Self { + let mut exe = Executable::from_quil(quil); + + for reg in registers { + exe = exe.read_from(reg); + } + + for param in parameters { + exe.with_parameter(param.name, param.index, param.value); + } + + if let Some(shots) = shots { + exe = exe.with_shots(shots); + } + + if let Some(compile_with_quilc) = compile_with_quilc { + exe = exe.compile_with_quilc(compile_with_quilc); + } + + if let Some(options) = compiler_options { + exe = exe.compiler_options(options.into_inner()); + } + + Self::from(Arc::new(Mutex::new(exe))) + } + + pub fn execute_on_qvm<'py>(&self, py: Python<'py>) -> PyResult<&'py PyAny> { + let arc = self.as_inner().clone(); + pyo3_asyncio::tokio::local_future_into_py(py, async move { + arc.lock() + .await + .execute_on_qvm() + .await + .map(Qvm::from) + .map(|qvm| Python::with_gil(|py| qvm.to_python(py))) + .map_err(ExecutionError::from) + .map_err(ExecutionError::to_py_err)? + }) + } + + pub fn execute_on_qpu<'py>( + &self, + py: Python<'py>, + quantum_processor_id: String, + ) -> PyResult<&'py PyAny> { + let arc = self.as_inner().clone(); + pyo3_asyncio::tokio::local_future_into_py(py, async move { + arc.lock() + .await + .execute_on_qpu(quantum_processor_id) + .await + .map(Qpu::from) + .map(|qpu| Python::with_gil(|py| qpu.to_python(py))) + .map_err(ExecutionError::from) + .map_err(ExecutionError::to_py_err)? + }) + } + + pub fn retrieve_results<'py>( + &mut self, + py: Python<'py>, + job_handle: PyJobHandle, + ) -> PyResult<&'py PyAny> { + let arc = self.as_inner().clone(); + pyo3_asyncio::tokio::local_future_into_py(py, async move { + arc.lock() + .await + .retrieve_results(job_handle.into_inner()) + .await + .map(Qpu::from) + .map(|qpu| Python::with_gil(|py| qpu.to_python(py))) + .map_err(ExecutionError::from) + .map_err(ExecutionError::to_py_err)? + }) + } +} + +py_wrap_simple_enum! { + PyService(Service) as "Service" { + Quilc, + Qvm, + Qcs, + Qpu + } +} + +py_wrap_type! { + PyJobHandle(JobHandle<'static>); +} + +#[pymethods] +impl PyJobHandle { + #[getter] + pub fn job_id(&self) -> &str { + self.as_inner().job_id() + } + + #[getter] + pub fn readout_map(&self, py: Python) -> PyResult> { + self.as_inner().readout_map().to_python(py) + } +} diff --git a/crates/python/src/execution_data.rs b/crates/python/src/execution_data.rs new file mode 100644 index 000000000..076881545 --- /dev/null +++ b/crates/python/src/execution_data.rs @@ -0,0 +1,61 @@ +use std::{collections::HashMap, time::Duration}; + +use pyo3::{ + pymethods, + types::{PyDelta, PyDict}, + Py, PyResult, Python, +}; +use qcs::{Qpu, Qvm, ReadoutMap, RegisterData}; +use qcs_api_client_grpc::models::controller::{readout_values::Values, ReadoutValues}; +use rigetti_pyo3::{py_wrap_data_struct, py_wrap_type, PyWrapper, ToPython}; + +use crate::grpc::models::controller::PyReadoutValuesValues; +use crate::register_data::PyRegisterData; + +py_wrap_data_struct! { + PyQvm(Qvm) as "QVM" { + registers: HashMap => HashMap => Py, + duration: Option => Option> + } +} + +py_wrap_data_struct! { + PyQpu(Qpu) as "QPU" { + readout_data: ReadoutMap => PyReadoutMap, + duration: Option => Option> + } +} + +// From gRPC +py_wrap_data_struct! { + PyReadoutValues(ReadoutValues) as "ReadoutValues" { + values: Option => Option + } +} + +py_wrap_type! { + PyReadoutMap(ReadoutMap) as "ReadoutMap"; +} + +#[pymethods] +impl PyReadoutMap { + pub fn get_readout_values(&self, field: String, index: u64) -> Option { + self.as_inner() + .get_readout_values(field, index) + .map(PyReadoutValues::from) + } + + pub fn get_readout_values_for_field( + &self, + py: Python, + field: &str, + ) -> PyResult>>> { + let op = self.as_inner().get_readout_values_for_field(field)?; + op.map(|list| { + list.into_iter() + .map(|op| op.to_python(py)) + .collect::>() + }) + .transpose() + } +} diff --git a/crates/python/src/grpc/mod.rs b/crates/python/src/grpc/mod.rs new file mode 100644 index 000000000..c446ac883 --- /dev/null +++ b/crates/python/src/grpc/mod.rs @@ -0,0 +1 @@ +pub mod models; diff --git a/crates/python/src/grpc/models/controller.rs b/crates/python/src/grpc/models/controller.rs new file mode 100644 index 000000000..cd8302023 --- /dev/null +++ b/crates/python/src/grpc/models/controller.rs @@ -0,0 +1,59 @@ +use pyo3::{ + prelude::*, + types::{PyComplex, PyInt, PyList}, +}; +use qcs_api_client_grpc::models::controller::{ + readout_values::Values, Complex64, Complex64ReadoutValues, IntegerReadoutValues, ReadoutValues, +}; +use rigetti_pyo3::{num_complex::Complex32 as NumComplex32, py_wrap_struct}; +use rigetti_pyo3::{py_wrap_data_struct, py_wrap_union_enum, PyTryFrom, ToPython}; + +py_wrap_data_struct! { + PyReadoutValues(ReadoutValues) as "ReadoutValues" { + values: Option => Option + } +} + +py_wrap_union_enum! { + PyReadoutValuesValues(Values) as "ReadoutValuesValues" { + integer_values: IntegerValues => PyIntegerReadoutValues, + complex_values: ComplexValues => PyComplexReadoutValues + } +} + +py_wrap_data_struct! { + PyIntegerReadoutValues(IntegerReadoutValues) as "IntegerReadoutValues" { + values: Vec => Vec> + } +} + +py_wrap_struct! { + PyComplexReadoutValues(Complex64ReadoutValues) as "ComplexReadoutValues" { + py -> rs { + list: Py => Complex64ReadoutValues { + let list = >>::py_try_from(py, &list)?; + let values = list.into_iter().map(|complex| { + let complex = NumComplex32::py_try_from(py, &complex)?; + Ok::<_, PyErr>(Complex64 { + real: Some(complex.re), + imaginary: Some(complex.im), + }) + }).collect::>()?; + + Ok::<_, PyErr>(Complex64ReadoutValues { values }) + } + }, + rs -> py { + values: Complex64ReadoutValues => Py { + let list = values.values.into_iter().map(|complex| { + NumComplex32 { + re: complex.real.unwrap_or_default(), + im: complex.imaginary.unwrap_or_default(), + } + }).collect::>(); + + list.to_python(py) + } + } + } +} diff --git a/crates/python/src/grpc/models/mod.rs b/crates/python/src/grpc/models/mod.rs new file mode 100644 index 000000000..cb9e0ac5c --- /dev/null +++ b/crates/python/src/grpc/models/mod.rs @@ -0,0 +1 @@ +pub mod controller; diff --git a/crates/python/src/lib.rs b/crates/python/src/lib.rs index a02336e27..3ca002a28 100644 --- a/crates/python/src/lib.rs +++ b/crates/python/src/lib.rs @@ -1,165 +1,42 @@ -use pythonize::pythonize; -use qcs::api; -use qcs::qpu::client::Qcs; -use qcs::qpu::quilc::{CompilerOpts, TargetDevice, DEFAULT_COMPILER_TIMEOUT}; -use std::collections::HashMap; - -use pyo3::{ - create_exception, - exceptions::{PyRuntimeError, PyValueError}, - prelude::*, - types::PyDict, -}; - -create_exception!(qcs, InvalidConfigError, PyRuntimeError); -create_exception!(qcs, ExecutionError, PyRuntimeError); -create_exception!(qcs, TranslationError, PyRuntimeError); -create_exception!(qcs, CompilationError, PyRuntimeError); -create_exception!(qcs, RewriteArithmeticError, PyRuntimeError); -create_exception!(qcs, DeviceIsaError, PyValueError); - -#[pyfunction(kwds = "**")] -fn compile<'a>( - py: Python<'a>, - quil: String, - target_device: String, - kwds: Option<&PyDict>, -) -> PyResult<&'a PyAny> { - let target_device: TargetDevice = - serde_json::from_str(&target_device).map_err(|e| DeviceIsaError::new_err(e.to_string()))?; - - let mut compiler_timeout = Some(DEFAULT_COMPILER_TIMEOUT); - if let Some(kwargs) = kwds { - if let Some(timeout_arg) = kwargs.get_item("timeout") { - let timeout: Result, _> = timeout_arg.extract(); - if let Ok(option) = timeout { - compiler_timeout = option - } - } - } - - pyo3_asyncio::tokio::future_into_py(py, async move { - let client = Qcs::load() - .await - .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; - let options = CompilerOpts::default().with_timeout(compiler_timeout); - let result = api::compile(&quil, target_device, &client, options) - .map_err(|e| CompilationError::new_err(e.to_string()))?; - Ok(Python::with_gil(|_py| result)) - }) -} - -#[pyfunction] -fn rewrite_arithmetic(py: Python<'_>, native_quil: String) -> PyResult { - let native_program = native_quil - .parse::() - .map_err(|e| TranslationError::new_err(e.to_string()))?; - let result = api::rewrite_arithmetic(native_program) - .map_err(|e| RewriteArithmeticError::new_err(e.to_string()))?; - let pyed = pythonize(py, &result).map_err(|e| TranslationError::new_err(e.to_string()))?; - Ok(pyed) -} - -#[pyfunction] -fn build_patch_values( - py: Python<'_>, - recalculation_table: Vec, - memory: HashMap>, -) -> PyResult { - let memory = memory - .into_iter() - .map(|(k, v)| (k.into_boxed_str(), v)) - .collect(); - let patch_values = api::build_patch_values(&recalculation_table, &memory) - .map_err(TranslationError::new_err)?; - let patch_values = - pythonize(py, &patch_values).map_err(|e| TranslationError::new_err(e.to_string()))?; - Ok(patch_values) -} - -#[pyfunction] -fn translate( - py: Python<'_>, - native_quil: String, - num_shots: u16, - quantum_processor_id: String, -) -> PyResult<&PyAny> { - pyo3_asyncio::tokio::future_into_py(py, async move { - let client = Qcs::load() - .await - .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; - let result = api::translate(&native_quil, num_shots, &quantum_processor_id, &client) - .await - .map_err(|e| TranslationError::new_err(e.to_string()))?; - let result = Python::with_gil(|py| { - pythonize(py, &result).map_err(|e| TranslationError::new_err(e.to_string())) - })?; - Ok(result) - }) -} - -#[pyfunction] -fn submit( - py: Python<'_>, - program: String, - patch_values: HashMap>, - quantum_processor_id: String, - use_gateway: bool, -) -> PyResult<&PyAny> { - pyo3_asyncio::tokio::future_into_py(py, async move { - let client = Qcs::load() - .await - .map_err(|e| InvalidConfigError::new_err(e.to_string()))? - .with_use_gateway(use_gateway); - let job_id = api::submit(&program, patch_values, &quantum_processor_id, &client) - .await - .map_err(|e| ExecutionError::new_err(e.to_string()))?; - Ok(Python::with_gil(|_py| job_id)) - }) -} - -#[pyfunction] -fn retrieve_results( - py: Python<'_>, - job_id: String, - quantum_processor_id: String, - use_gateway: bool, -) -> PyResult<&PyAny> { - pyo3_asyncio::tokio::future_into_py(py, async move { - let client = Qcs::load() - .await - .map_err(|e| InvalidConfigError::new_err(e.to_string()))? - .with_use_gateway(use_gateway); - let results = api::retrieve_results(&job_id, &quantum_processor_id, &client) - .await - .map_err(|e| ExecutionError::new_err(e.to_string()))?; - let results = Python::with_gil(|py| { - pythonize(py, &results).map_err(|e| ExecutionError::new_err(e.to_string())) - })?; - Ok(results) - }) -} - -#[pyfunction] -fn get_quilc_version(py: Python<'_>) -> PyResult<&PyAny> { - pyo3_asyncio::tokio::future_into_py(py, async move { - let client = Qcs::load() - .await - .map_err(|e| InvalidConfigError::new_err(e.to_string()))?; - let version = api::get_quilc_version(&client) - .map_err(|e| CompilationError::new_err(e.to_string()))?; - Ok(version) - }) +use pyo3::prelude::*; +use rigetti_pyo3::create_init_submodule; + +pub mod api; +pub mod executable; +pub mod execution_data; +pub mod grpc; +pub mod qpu; +pub mod register_data; + +create_init_submodule! { + classes: [ + execution_data::PyQpu, + execution_data::PyQvm, + execution_data::PyReadoutMap, + executable::PyExecutable, + executable::PyJobHandle, + executable::PyService, + register_data::PyRegisterData + ], + errors: [ + executable::QcsExecutionError + ], + funcs: [ + api::compile, + api::rewrite_arithmetic, + api::translate, + api::submit, + api::retrieve_results, + api::build_patch_values, + api::get_quilc_version + ], + submodules: [ + "api": api::init_submodule, + "qpu": qpu::init_submodule + ], } #[pymodule] -fn qcs_sdk(_py: Python<'_>, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_pyfunction!(compile, m)?)?; - m.add_function(wrap_pyfunction!(rewrite_arithmetic, m)?)?; - m.add_function(wrap_pyfunction!(translate, m)?)?; - m.add_function(wrap_pyfunction!(submit, m)?)?; - m.add_function(wrap_pyfunction!(retrieve_results, m)?)?; - m.add_function(wrap_pyfunction!(build_patch_values, m)?)?; - m.add_function(wrap_pyfunction!(get_quilc_version, m)?)?; - Ok(()) +fn qcs_sdk(py: Python<'_>, m: &PyModule) -> PyResult<()> { + init_submodule("qcs_sdk", py, m) } diff --git a/crates/python/src/qpu/client.rs b/crates/python/src/qpu/client.rs new file mode 100644 index 000000000..842e6fec8 --- /dev/null +++ b/crates/python/src/qpu/client.rs @@ -0,0 +1,67 @@ +use pyo3::{exceptions::PyRuntimeError, pymethods, PyResult, Python}; +use pyo3_asyncio::tokio::future_into_py; +use qcs::qpu::Qcs; +use rigetti_pyo3::{ + create_init_submodule, py_wrap_error, py_wrap_type, wrap_error, ToPython, ToPythonError, +}; + +create_init_submodule! { + classes: [PyQcsClient], + errors: [ + QcsGrpcClientError, + QcsGrpcEndpointError, + QcsGrpcError, + QcsLoadError + ], +} + +wrap_error! { + LoadError(qcs::qpu::client::LoadError); +} +py_wrap_error!(client, LoadError, QcsLoadError, PyRuntimeError); + +wrap_error! { + GrpcError(qcs::qpu::client::GrpcError); +} +py_wrap_error!(client, GrpcError, QcsGrpcError, PyRuntimeError); + +wrap_error! { + GrpcClientError(qcs::qpu::client::GrpcClientError); +} +py_wrap_error!(client, GrpcClientError, QcsGrpcClientError, PyRuntimeError); + +wrap_error! { + GrpcEndpointError(qcs::qpu::client::GrpcEndpointError); +} +py_wrap_error!( + client, + GrpcEndpointError, + QcsGrpcEndpointError, + PyRuntimeError +); + +py_wrap_type! { + PyQcsClient(Qcs) as "QcsClient"; +} + +#[pymethods] +impl PyQcsClient { + #[new] + #[args("/", use_gateway = "None")] + pub fn new(py: Python<'_>, use_gateway: Option) -> PyResult { + future_into_py(py, async move { + let client = Qcs::load() + .await + .map_err(LoadError) + .map_err(ToPythonError::to_py_err)?; + + let client = match use_gateway { + None => client, + Some(use_gateway) => client.with_use_gateway(use_gateway), + }; + + Python::with_gil(|py| Self(client).to_python(py)) + })? + .extract() + } +} diff --git a/crates/python/src/qpu/mod.rs b/crates/python/src/qpu/mod.rs new file mode 100644 index 000000000..5037ceb22 --- /dev/null +++ b/crates/python/src/qpu/mod.rs @@ -0,0 +1,19 @@ +use pyo3::exceptions::PyRuntimeError; +use rigetti_pyo3::{create_init_submodule, py_wrap_error, wrap_error}; + +pub mod client; +pub mod quilc; + +create_init_submodule! { + errors: [QcsIsaError], + submodules: [ + "client": client::init_submodule, + "quilc": quilc::init_submodule + ], +} + +wrap_error! { + IsaError(qcs::qpu::IsaError); +} + +py_wrap_error!(qpu, IsaError, QcsIsaError, PyRuntimeError); diff --git a/crates/python/src/qpu/quilc/mod.rs b/crates/python/src/qpu/quilc/mod.rs new file mode 100644 index 000000000..9eb74f2aa --- /dev/null +++ b/crates/python/src/qpu/quilc/mod.rs @@ -0,0 +1,41 @@ +use pyo3::{exceptions::PyRuntimeError, pymethods}; +use qcs::qpu::quilc::{CompilerOpts, TargetDevice, DEFAULT_COMPILER_TIMEOUT}; +use rigetti_pyo3::{ + create_init_submodule, py_wrap_error, py_wrap_struct, py_wrap_type, wrap_error, +}; + +create_init_submodule! { + classes: [ + PyCompilerOpts, + PyTargetDevice + ], + consts: [DEFAULT_COMPILER_TIMEOUT], + errors: [QuilcError], +} + +py_wrap_type! { + #[derive(Default)] + PyCompilerOpts(CompilerOpts) as "CompilerOpts"; +} + +#[pymethods] +impl PyCompilerOpts { + #[new] + #[args("/", timeout = "DEFAULT_COMPILER_TIMEOUT")] + pub fn new(timeout: Option) -> Self { + Self::from(CompilerOpts::new().with_timeout(timeout)) + } + + #[staticmethod] + #[allow(clippy::should_implement_trait)] + pub fn default() -> Self { + ::default() + } +} + +wrap_error!(Error(qcs::qpu::quilc::Error)); +py_wrap_error!(quilc, Error, QuilcError, PyRuntimeError); + +py_wrap_struct! { + PyTargetDevice(TargetDevice) as "TargetDevice" {} +} diff --git a/crates/python/src/register_data.rs b/crates/python/src/register_data.rs new file mode 100644 index 000000000..9f6fbc1ac --- /dev/null +++ b/crates/python/src/register_data.rs @@ -0,0 +1,15 @@ +use pyo3::{ + types::{PyComplex, PyFloat, PyInt}, + Py, +}; +use qcs::RegisterData; +use rigetti_pyo3::py_wrap_union_enum; + +py_wrap_union_enum! { + PyRegisterData(RegisterData) as "RegisterData" { + i8: I8 => Vec>>, + f64: F64 => Vec>>, + i16: I16 => Vec>>, + complex32: Complex32 => Vec>> + } +} diff --git a/crates/python/tests/test_api.py b/crates/python/tests/test_api.py index 7abefc608..03805b293 100644 --- a/crates/python/tests/test_api.py +++ b/crates/python/tests/test_api.py @@ -33,7 +33,8 @@ def test_rewrite_arithmetic(): "program": "DECLARE __SUBST REAL[1]\nRX(__SUBST[0]) 0\n", "recalculation_table": ["((2*theta[0])/6.283185307179586)"], } - assert rewritten_arithmetic == expected + assert rewritten_arithmetic.program == expected["program"] + assert rewritten_arithmetic.recalculation_table == expected["recalculation_table"] def test_build_patch_values():