From 2f7a2425dd7b53b198eff929b38f7748be812c2d Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 1 Apr 2025 00:12:52 +0200 Subject: [PATCH 01/27] Use petgraph at master branch Signed-off-by: daehiff --- Cargo.lock | 252 ++++++++++++------------------- Cargo.toml | 2 +- src/architecture.rs | 11 ++ src/architecture/complete.rs | 10 +- src/architecture/connectivity.rs | 165 ++++++++++++++++++-- src/architecture/line.rs | 10 +- 6 files changed, 286 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44a2850f..5af79281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -29,12 +35,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitvec" version = "1.0.1" @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cast" @@ -94,18 +94,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" dependencies = [ "anstyle", "clap_lex", @@ -117,15 +117,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - [[package]] name = "criterion" version = "0.5.1" @@ -189,33 +180,33 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "funty" @@ -225,9 +216,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "cfg-if", "crunchy", @@ -235,21 +226,26 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown", @@ -257,13 +253,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -286,15 +282,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -302,15 +298,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -329,24 +325,25 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "petgraph" -version = "0.6.5" -source = "git+https://github.com/daehiff/petgraph?branch=art-points#856b32c23131518eebfeb5ce7d415a9a426a5061" +version = "0.7.1" +source = "git+https://github.com/petgraph/petgraph.git?rev=74339abdfd665ac7c44d84b48dc22a77625267e8#74339abdfd665ac7c44d84b48dc22a77625267e8" dependencies = [ "fixedbitset", + "hashbrown", "indexmap", - "rand", + "serde", ] [[package]] @@ -379,18 +376,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -401,34 +398,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "winapi", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rayon" version = "1.10.0" @@ -478,11 +447,17 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -495,29 +470,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -538,9 +513,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -565,15 +540,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "walkdir" @@ -587,34 +562,35 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -622,71 +598,43 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", + "windows-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6c2992a3..bd96888d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { git = "https://github.com/daehiff/petgraph", branch = "art-points", version = "0.6.5" } +petgraph = { git = "https://github.com/petgraph/petgraph.git", rev = "74339abdfd665ac7c44d84b48dc22a77625267e8", features = ["stable_graph"]} typenum = "1.17.0" [dev-dependencies] diff --git a/src/architecture.rs b/src/architecture.rs index ba39e6b4..0c4e4005 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -6,9 +6,20 @@ type GraphIndex = usize; type EdgeWeight = usize; type NodeWeight = (); +#[derive(Debug, PartialEq)] +enum LadderError { + ConversionError, + RootNotFound, +} + pub trait Architecture { fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec; fn distance(&self, i: GraphIndex, j: GraphIndex) -> GraphIndex; fn neighbors(&self, i: GraphIndex) -> Vec; fn non_cutting(&mut self) -> &Vec; + fn get_cx_ladder( + &self, + nodes: &[GraphIndex], + root: &GraphIndex, + ) -> Result, LadderError>; } diff --git a/src/architecture/complete.rs b/src/architecture/complete.rs index 6319d4bc..5d365d74 100644 --- a/src/architecture/complete.rs +++ b/src/architecture/complete.rs @@ -1,4 +1,4 @@ -use super::{Architecture, GraphIndex}; +use super::{Architecture, GraphIndex, LadderError}; #[derive(Debug)] pub struct Complete { @@ -65,6 +65,14 @@ impl Architecture for Complete { fn non_cutting(&mut self) -> &Vec { &self.nodes } + + fn get_cx_ladder( + &self, + nodes: &[usize], + root: &GraphIndex, + ) -> Result, LadderError> { + todo!() + } } #[cfg(test)] diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 3e5cbed1..3d0303e7 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -1,18 +1,24 @@ +use super::{Architecture, EdgeWeight, GraphIndex, LadderError, NodeWeight}; +use petgraph::algo::floyd_warshall::floyd_warshall_path; +use petgraph::algo::steiner_tree::steiner_tree; +use petgraph::prelude::EdgeRef; +use petgraph::visit::{Bfs, Dfs, GraphBase, IntoNeighbors, VisitMap, Visitable, Walker}; use petgraph::{ - algo::{articulation_points::articulation_points, floyd_warshall_path}, + algo::articulation_points::articulation_points, graph::{NodeIndex, UnGraph}, visit::{IntoNodeReferences, NodeIndexable, NodeRef}, + Graph, Undirected, }; +use std::borrow::Borrow; use std::collections::HashMap; - -use super::{Architecture, EdgeWeight, GraphIndex, NodeWeight}; +use std::ops::Index; #[derive(Debug)] pub struct Connectivity { graph: UnGraph, non_cutting: Vec, prev: Vec>>, - distance: HashMap<(NodeIndex, NodeIndex), usize>, + distance: HashMap<(NodeIndex, NodeIndex), EdgeWeight>, } impl Connectivity { @@ -35,6 +41,7 @@ impl Connectivity { let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); + let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); Connectivity { graph, non_cutting, @@ -52,7 +59,7 @@ impl Connectivity { .collect(); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); - + let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); Connectivity { graph, non_cutting, @@ -76,7 +83,9 @@ impl Connectivity { .collect(); let (distance, prev) = floyd_warshall_path(&self.graph, |e| *e.weight()).unwrap(); - println!("prev: {:?}", prev); + + let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); + self.non_cutting = non_cutting; self.distance = distance; self.prev = prev; @@ -122,6 +131,31 @@ impl Connectivity { } } +/// Small helper since we have different and incompatible assumptions as Petgraph +/// TODO fix this in petgraph +fn convert_graph( + old_graph: &Graph, +) -> Graph { + let mut new_graph = Graph::::new_undirected(); + // Map from old node indices to new node indices. + let mut index_map: HashMap, NodeIndex> = HashMap::new(); + + // Add nodes from the old graph to the new graph. + for old_node in old_graph.node_indices() { + let new_node = new_graph.add_node(old_graph[old_node].clone()); + index_map.insert(old_node, new_node); + } + + // Add edges, converting the node indices using our mapping. + for edge in old_graph.edge_references() { + let new_source = index_map[&edge.source()]; + let new_target = index_map[&edge.target()]; + new_graph.add_edge(new_source, new_target, edge.weight().clone()); + } + + new_graph +} + impl Architecture for Connectivity { fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { assert!( @@ -144,7 +178,7 @@ impl Architecture for Connectivity { j < self.graph.node_count(), "architecture does not contain node {j}" ); - self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] + self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] as usize } fn neighbors(&self, i: GraphIndex) -> Vec { @@ -161,11 +195,53 @@ impl Architecture for Connectivity { fn non_cutting(&mut self) -> &Vec { &self.non_cutting } + + fn get_cx_ladder( + &self, + nodes: &[GraphIndex], + root: &GraphIndex, + ) -> Result, LadderError> { + // TODO fix me we currently have to convert the graph + let terminals: Result, LadderError> = self + .graph + .node_indices() + .filter(|node_index| nodes.contains(&self.graph.to_index(*node_index))) + .map(|node_index| { + let idx = node_index.index() as u32; + idx.try_into() + .map(NodeIndex::new) + .map_err(|_| LadderError::ConversionError) + }) + .collect(); + let terminals = terminals?; + + let tree = steiner_tree(&convert_graph(&self.graph), &terminals); + + let root_node = tree + .node_indices() + .find(|item| item.index() == *root as usize) + .ok_or(LadderError::RootNotFound)?; + + let mut bfs = Bfs::new(&tree, root_node); + let mut edge_list = Vec::new(); + let mut visited = tree.visit_map(); + visited.visit(root_node); + + while let Some(node) = bfs.next(&tree) { + for neighbor in tree.neighbors(node) { + if !visited.is_visited(&neighbor) { + visited.visit(neighbor); + edge_list.push((node.index(), neighbor.index())); + } + } + } + Ok(edge_list) + } } #[cfg(test)] mod tests { - use crate::architecture::{Architecture, EdgeWeight, GraphIndex}; + use crate::architecture::{Architecture, EdgeWeight, GraphIndex, LadderError}; use super::Connectivity; fn setup_weighted() -> Vec<(GraphIndex, GraphIndex, EdgeWeight)> { @@ -197,11 +273,76 @@ mod tests { } #[test] - fn test_simple_constuctor() { + fn test_weight_is_considered() { + let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![1, 2, 3, 4], &2) + .unwrap() + .sort(), + vec![(2, 1), (2, 3), (3, 4)].sort() + ); + } + + #[test] + fn test_root_is_not_present() { + let new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![1, 2, 3, 4], &42) + .expect_err("Should return a Error that the root was not found"), + LadderError::RootNotFound + ); + } + + #[test] + fn test_simple_constructor() { let new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); } + #[test] + fn test_cx_ladder_line_setup() { + let new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![0, 1, 2, 3], &0) + .unwrap(), + vec![(0, 1), (1, 2), (2, 3)] + ); + } + + #[test] + fn test_cx_ladder_extended_triangle() { + let new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![0, 1, 2, 4, 5], &1) + .unwrap() + .sort(), + vec![(0, 1), (1, 5), (1, 2), (2, 4)].sort() + ); + } + + #[test] + fn test_cx_ladder_small_triangle() { + let new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![2, 3, 4], &2) + .unwrap() + .sort(), + vec![(2, 4), (2, 3)].sort() + ); + assert_eq!( + new_architecture + .get_cx_ladder(&vec![2, 3, 4], &4) + .unwrap() + .sort(), + vec![(4, 2), (4, 3)].sort() + ); + } + #[test] fn test_weighted_constructor() { let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); @@ -262,4 +403,10 @@ mod tests { let mut new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!(&Vec::::new(), new_architecture.non_cutting()); } + + #[test] + fn test_steiner_tree() { + let mut new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!(&Vec::::new(), new_architecture.non_cutting()); + } } diff --git a/src/architecture/line.rs b/src/architecture/line.rs index 00d90146..ee49269d 100644 --- a/src/architecture/line.rs +++ b/src/architecture/line.rs @@ -1,4 +1,4 @@ -use super::{Architecture, GraphIndex}; +use super::{Architecture, GraphIndex, LadderError}; /// Describes a line architecture. This ensures that consecutive numbers are adjacent. Allows for disjoint breaking of architecture in case this is required. #[derive(Debug)] @@ -117,6 +117,14 @@ impl Architecture for Line { } &self.non_cutting } + + fn get_cx_ladder( + &self, + nodes: &[usize], + root: &GraphIndex, + ) -> Result, LadderError> { + todo!() + } } #[cfg(test)] From aeea986f0c8e23f4677b1d13a15399e96cc6ee0d Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 1 Apr 2025 01:23:13 +0200 Subject: [PATCH 02/27] Add benchmarks Signed-off-by: daehiff --- Cargo.lock | 102 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + benches/clifford_tableau.rs | 5 +- benches/connectivity.rs | 57 ++++++++++++++++++++ src/architecture.rs | 2 +- 5 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 benches/connectivity.rs diff --git a/Cargo.lock b/Cargo.lock index 5af79281..d8d930ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + [[package]] name = "bitvec" version = "1.0.1" @@ -214,6 +220,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + [[package]] name = "half" version = "2.5.0" @@ -374,6 +392,15 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -392,12 +419,48 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha", + "rand_core", + "zerocopy", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.10.0" @@ -508,6 +571,7 @@ dependencies = [ "criterion", "itertools 0.13.0", "petgraph", + "rand", "typenum", ] @@ -560,6 +624,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -710,6 +783,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "wyz" version = "0.5.1" @@ -718,3 +800,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] diff --git a/Cargo.toml b/Cargo.toml index bd96888d..6a24e582 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ typenum = "1.17.0" [dev-dependencies] criterion = "0.5.1" +rand = "0.9.0" [[bench]] name = "clifford_tableau" diff --git a/benches/clifford_tableau.rs b/benches/clifford_tableau.rs index f6b3796d..d6632afc 100644 --- a/benches/clifford_tableau.rs +++ b/benches/clifford_tableau.rs @@ -1,3 +1,4 @@ +use crate::connectivity::connectivity_benchmark; use bitvec::bitvec; use bitvec::prelude::Lsb0; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; @@ -8,6 +9,8 @@ use syn::ir::CliffordGates; use syn::synthesis_methods::custom::Custom; use syn::synthesis_methods::naive::Naive; +mod connectivity; + #[derive(Debug, Default)] pub struct MockCircuit { commands: Vec, @@ -153,4 +156,4 @@ pub fn ct_bench(c: &mut Criterion) { } criterion_group!(benches, ct_bench); -criterion_main!(benches); +criterion_main!(benches, connectivity_benchmark); diff --git a/benches/connectivity.rs b/benches/connectivity.rs new file mode 100644 index 00000000..6306e94c --- /dev/null +++ b/benches/connectivity.rs @@ -0,0 +1,57 @@ +use criterion::{black_box, criterion_group, Criterion}; +use petgraph::visit::Walker; +use rand::prelude::IndexedRandom; +use rand::seq::SliceRandom; +use rand::Rng; +use syn::architecture::connectivity::Connectivity; +use syn::architecture::Architecture; + +fn random_connected_connectivity( + num_nodes: usize, + extra_edges: usize, + subset_length: usize, +) -> (Connectivity, Vec, usize) { + let mut rng = rand::thread_rng(); + let mut edges = Vec::new(); + + let mut nodes: Vec = (0..num_nodes).collect(); + nodes.shuffle(&mut rng); + for i in 1..num_nodes { + edges.push((nodes[i - 1], nodes[i])); + } + + // Add extra random edges: + while edges.len() < (num_nodes - 1) + extra_edges { + let a = rng.gen_range(0..num_nodes); + let b = rng.gen_range(0..num_nodes); + if a != b && !edges.contains(&(a, b)) && !edges.contains(&(b, a)) { + edges.push((a, b)); + } + } + + let mut subset_nodes = nodes.clone(); + subset_nodes.shuffle(&mut rng); + let subset: Vec = subset_nodes.into_iter().take(subset_length).collect(); + + let random_element = *subset.choose(&mut rng).expect("Subset cannot be empty"); + + (Connectivity::from_edges(&edges), subset, random_element) +} + +fn get_cx_ladder_connectivity((connectivity, nodes, root): &(Connectivity, Vec, usize)) { + let _ = connectivity.get_cx_ladder(&nodes, &root); +} + +pub fn connectivity_bench(c: &mut Criterion) { + let input = random_connected_connectivity(30, 15, 10); + c.bench_function("get_cx_ladder_connectivity: 30, 15, 10", |b| { + b.iter(|| get_cx_ladder_connectivity(black_box(&input))) + }); + + let input = random_connected_connectivity(100, 50, 50); + c.bench_function("get_cx_ladder_connectivity: 100, 15, 10", |b| { + b.iter(|| get_cx_ladder_connectivity(black_box(&input))) + }); +} + +criterion_group!(connectivity_benchmark, connectivity_bench); diff --git a/src/architecture.rs b/src/architecture.rs index 0c4e4005..10384428 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -7,7 +7,7 @@ type EdgeWeight = usize; type NodeWeight = (); #[derive(Debug, PartialEq)] -enum LadderError { +pub enum LadderError { ConversionError, RootNotFound, } From 924fad2327f18b21dbb45686d41c914534381692 Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 1 Apr 2025 21:49:59 +0200 Subject: [PATCH 03/27] Refactoring of connectivity Signed-off-by: daehiff --- Cargo.lock | 159 ++++++++++---------- src/architecture.rs | 2 - src/architecture/complete.rs | 163 -------------------- src/architecture/connectivity.rs | 175 +++++++++++++++------- src/architecture/line.rs | 249 ------------------------------- 5 files changed, 202 insertions(+), 546 deletions(-) delete mode 100644 src/architecture/complete.rs delete mode 100644 src/architecture/line.rs diff --git a/Cargo.lock b/Cargo.lock index d8d930ea..8116fbff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cast" @@ -100,18 +100,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.34" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.34" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstyle", "clap_lex", @@ -186,21 +186,21 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "either" -version = "1.15.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fixedbitset" @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", @@ -244,9 +244,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "allocator-api2", "equivalent", @@ -255,15 +255,15 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" -version = "2.8.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -271,13 +271,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.16" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -300,15 +300,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -316,15 +316,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "log" -version = "0.4.27" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" @@ -343,15 +343,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" -version = "11.1.5" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "petgraph" @@ -403,18 +403,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -510,17 +510,11 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -533,29 +527,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -577,9 +571,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -604,15 +598,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "walkdir" @@ -635,35 +629,34 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", - "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -671,31 +664,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -707,7 +697,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", ] [[package]] @@ -818,5 +817,5 @@ checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.90", ] diff --git a/src/architecture.rs b/src/architecture.rs index 10384428..6d37d684 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -1,6 +1,4 @@ -pub mod complete; pub mod connectivity; -pub mod line; type GraphIndex = usize; type EdgeWeight = usize; diff --git a/src/architecture/complete.rs b/src/architecture/complete.rs deleted file mode 100644 index 5d365d74..00000000 --- a/src/architecture/complete.rs +++ /dev/null @@ -1,163 +0,0 @@ -use super::{Architecture, GraphIndex, LadderError}; - -#[derive(Debug)] -pub struct Complete { - nodes: Vec, -} - -impl Complete { - pub fn new(num_qubits: usize) -> Self { - Complete { - nodes: (0..num_qubits).collect(), - } - } - - pub fn remove(&mut self, i: usize) { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - self.nodes.retain(|x| *x != i); - } - - pub fn insert(&mut self, i: usize) { - assert!( - !self.nodes.contains(&i), - "architecture already contains node {i}" - ); - self.nodes.push(i); - } -} - -impl Architecture for Complete { - fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - assert!( - self.nodes.contains(&j), - "architecture does not contain node {j}" - ); - vec![i, j] - } - - fn distance(&self, i: GraphIndex, j: GraphIndex) -> GraphIndex { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - assert!( - self.nodes.contains(&j), - "architecture does not contain node {j}" - ); - 1 - } - - fn neighbors(&self, i: GraphIndex) -> Vec { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - self.nodes.iter().filter(|x| **x != i).copied().collect() - } - - fn non_cutting(&mut self) -> &Vec { - &self.nodes - } - - fn get_cx_ladder( - &self, - nodes: &[usize], - root: &GraphIndex, - ) -> Result, LadderError> { - todo!() - } -} - -#[cfg(test)] -mod tests { - use crate::architecture::Architecture; - - use super::Complete; - - #[test] - fn test_complete() { - let new_architecture = Complete::new(5); - - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 3, 4]); - } - - #[test] - fn test_insert() { - let mut new_architecture = Complete::new(5); - new_architecture.insert(5); - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 3, 4, 5]); - } - - #[test] - #[should_panic = "architecture already contains node 1"] - fn test_bad_insert() { - let mut new_architecture = Complete::new(5); - new_architecture.insert(1); - } - - #[test] - fn test_remove() { - let mut new_architecture = Complete::new(5); - new_architecture.remove(3); - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 4]); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_bad_remove() { - let mut new_architecture = Complete::new(3); - new_architecture.remove(4); - } - - #[test] - fn test_best_path() { - let new_architecture = Complete::new(3); - assert_eq!(vec![1, 2], new_architecture.best_path(1, 2)); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_best_path_missing() { - let new_architecture = Complete::new(3); - new_architecture.best_path(4, 5); - } - - #[test] - fn test_distance() { - let new_architecture = Complete::new(3); - assert_eq!(1, new_architecture.distance(1, 2)); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_distance_missing() { - let new_architecture = Complete::new(3); - new_architecture.distance(4, 5); - } - - #[test] - fn test_neighbors() { - let new_architecture = Complete::new(4); - assert_eq!(vec![0, 1, 3], new_architecture.neighbors(2)); - } - - #[test] - #[should_panic = "architecture does not contain node 3"] - fn test_neighbor_missing() { - let new_architecture = Complete::new(3); - new_architecture.distance(2, 3); - } - - #[test] - fn test_non_cutting() { - let mut new_architecture = Complete::new(4); - assert_eq!(&vec![0, 1, 2, 3], new_architecture.non_cutting()); - } -} diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 3d0303e7..129ce00c 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -13,6 +13,42 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::ops::Index; +/// Small helper since we have different and incompatible assumptions as Petgraph +/// TODO fix this in petgraph +fn convert_graph( + old_graph: &Graph, +) -> Graph { + let mut new_graph = Graph::::new_undirected(); + // Map from old node indices to new node indices. + let mut index_map: HashMap, NodeIndex> = HashMap::new(); + + // Add nodes from the old graph to the new graph. + for old_node in old_graph.node_indices() { + let new_node = new_graph.add_node(old_graph[old_node].clone()); + index_map.insert(old_node, new_node); + } + + // Add edges, converting the node indices using our mapping. + for edge in old_graph.edge_references() { + let new_source = index_map[&edge.source()]; + let new_target = index_map[&edge.target()]; + new_graph.add_edge(new_source, new_target, edge.weight().clone()); + } + + new_graph +} + +/// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) +fn get_non_cutting_vertices( + graph: &UnGraph, +) -> Vec { + let art_points = articulation_points(&graph); + println!("{:?}", art_points); + (0..graph.node_count()) + .filter(|node| !art_points.contains(&graph.from_index(*node))) + .collect() +} + #[derive(Debug)] pub struct Connectivity { graph: UnGraph, @@ -31,33 +67,50 @@ impl Connectivity { } } - pub fn from_edges(edges: &[(GraphIndex, GraphIndex)]) -> Self { - let graph = UnGraph::from_edges(edges); - let art_points = articulation_points(&graph); + pub fn line(nr_qubits: usize) -> Self { + let edges: Vec<(usize, usize)> = (0..nr_qubits - 1).map(|i| (i, i + 1)).collect(); + println!("{:?}", edges); + Connectivity::from_edges(&edges) + } - let non_cutting = (0..graph.node_count()) - .filter(|node| art_points.contains(&graph.from_index(*node))) - .collect(); + pub fn grid(num_rows: usize, num_cols: usize) -> Self { + let mut edges = Vec::new(); - let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); + for r in 0..num_rows { + for c in 0..num_cols { + if r < num_rows - 1 { + edges.push((num_cols * r + c, num_cols * (r + 1) + c)); + } + if c < num_cols - 1 { + edges.push((num_cols * r + c, num_cols * r + (c + 1))); + } + } + } + Connectivity::from_edges(&edges) + } - let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); - Connectivity { - graph, - non_cutting, - prev, - distance, + pub fn complete(num_qubits: usize) -> Self { + let mut edges = Vec::new(); + for i in 0..num_qubits { + for j in (i + 1)..num_qubits { + edges.push((i, j)); + } } + Connectivity::from_edges(&edges) } - pub fn from_weighted_edges(edges: &[(GraphIndex, GraphIndex, EdgeWeight)]) -> Self { + pub fn from_edges(edges: &[(GraphIndex, GraphIndex)]) -> Self { let graph = UnGraph::from_edges(edges); - let art_points = articulation_points(&graph); + Connectivity::from_graph(graph) + } - let non_cutting = (0..graph.node_count()) - .filter(|node| art_points.contains(&graph.from_index(*node))) - .collect(); + pub fn from_weighted_edges(edges: &[(GraphIndex, GraphIndex, EdgeWeight)]) -> Self { + let graph = UnGraph::from_edges(edges); + Connectivity::from_graph(graph) + } + pub fn from_graph(graph: UnGraph) -> Self { + let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); Connectivity { @@ -75,12 +128,22 @@ impl Connectivity { .collect() } - fn update(&mut self) { - let art_points = articulation_points(&self.graph); - - let non_cutting = (0..self.graph.node_count()) - .filter(|node| art_points.contains(&self.graph.from_index(*node))) + pub fn edges(&self) -> Vec<(GraphIndex, GraphIndex)> { + let graph_edges: Vec<(GraphIndex, GraphIndex)> = self + .graph + .edge_references() + .map(|node| { + ( + self.graph.to_index(node.source()), + self.graph.to_index(node.target()), + ) + }) .collect(); + graph_edges + } + + fn update(&mut self) { + let non_cutting = get_non_cutting_vertices(&self.graph); let (distance, prev) = floyd_warshall_path(&self.graph, |e| *e.weight()).unwrap(); @@ -131,31 +194,6 @@ impl Connectivity { } } -/// Small helper since we have different and incompatible assumptions as Petgraph -/// TODO fix this in petgraph -fn convert_graph( - old_graph: &Graph, -) -> Graph { - let mut new_graph = Graph::::new_undirected(); - // Map from old node indices to new node indices. - let mut index_map: HashMap, NodeIndex> = HashMap::new(); - - // Add nodes from the old graph to the new graph. - for old_node in old_graph.node_indices() { - let new_node = new_graph.add_node(old_graph[old_node].clone()); - index_map.insert(old_node, new_node); - } - - // Add edges, converting the node indices using our mapping. - for edge in old_graph.edge_references() { - let new_source = index_map[&edge.source()]; - let new_target = index_map[&edge.target()]; - new_graph.add_edge(new_source, new_target, edge.weight().clone()); - } - - new_graph -} - impl Architecture for Connectivity { fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { assert!( @@ -272,6 +310,39 @@ mod tests { ] } + #[test] + fn test_line_creation() { + let mut line_architecture = Connectivity::line(5); + assert_eq!( + line_architecture.edges(), + vec![(0, 1), (1, 2), (2, 3), (3, 4)] + ); + } + + #[test] + fn test_grid_creation() { + let mut line_architecture = Connectivity::grid(3, 3); + let mut edges = line_architecture.edges(); + edges.sort(); + assert_eq!( + edges, + vec![ + (0, 1), + (0, 3), + (1, 2), + (1, 4), + (2, 5), + (3, 4), + (3, 6), + (4, 5), + (4, 7), + (5, 8), + (6, 7), + (7, 8) + ] + ); + } + #[test] fn test_weight_is_considered() { let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); @@ -401,12 +472,12 @@ mod tests { #[test] fn test_non_cutting() { let mut new_architecture = Connectivity::from_edges(&setup_simple()); - assert_eq!(&Vec::::new(), new_architecture.non_cutting()); + assert_eq!(&new_architecture.nodes(), new_architecture.non_cutting()); } #[test] - fn test_steiner_tree() { - let mut new_architecture = Connectivity::from_edges(&setup_simple()); - assert_eq!(&Vec::::new(), new_architecture.non_cutting()); + fn test_non_cutting_line() { + let mut line_architecture = Connectivity::line(5); + assert_eq!(*line_architecture.non_cutting(), vec![0, 4]); } } diff --git a/src/architecture/line.rs b/src/architecture/line.rs deleted file mode 100644 index ee49269d..00000000 --- a/src/architecture/line.rs +++ /dev/null @@ -1,249 +0,0 @@ -use super::{Architecture, GraphIndex, LadderError}; - -/// Describes a line architecture. This ensures that consecutive numbers are adjacent. Allows for disjoint breaking of architecture in case this is required. -#[derive(Debug)] -pub struct Line { - nodes: Vec, - non_cutting: Vec, - updated: bool, -} - -impl Line { - pub fn new(num_qubits: usize) -> Self { - Line { - nodes: (0..num_qubits).collect(), - non_cutting: Vec::new(), - updated: false, - } - } - - pub fn remove(&mut self, i: GraphIndex) { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - self.updated = false; - self.nodes.retain(|x| *x != i); - } - - /// Ensures that strict ordering is always enforced - pub fn insert(&mut self, i: GraphIndex) { - match self.nodes.binary_search(&i) { - Ok(_) => panic!("architecture already contains node {i}"), - Err(pos) => self.nodes.insert(pos, i), - } - self.updated = false; - } -} - -impl Architecture for Line { - fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { - let (smaller, larger) = (i.min(j), i.max(j)); - assert!( - self.nodes.contains(&j), - "architecture does not contain node {i}" - ); - assert!( - self.nodes.contains(&j), - "architecture does not contain node {j}" - ); - assert!( - ((smaller + 1)..larger).all(|node| self.nodes.contains(&node)), - "no path exists between {i} and {j}" - ); - if i == smaller { - (smaller..=larger).collect() - } else { - (smaller..=larger).rev().collect() - } - } - - fn distance(&self, i: GraphIndex, j: GraphIndex) -> GraphIndex { - let (smaller, larger) = (i.min(j), i.max(j)); - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - assert!( - self.nodes.contains(&j), - "architecture does not contain node {j}" - ); - assert!( - ((smaller + 1)..larger).all(|node| self.nodes.contains(&node)), - "no path exists between {i} and {j}" - ); - larger - smaller - } - - fn neighbors(&self, i: GraphIndex) -> Vec { - assert!( - self.nodes.contains(&i), - "architecture does not contain node {i}" - ); - let mut neighbors = Vec::new(); - if let Some(left_neighbor) = i.checked_sub(1) { - if self.nodes.contains(&left_neighbor) { - neighbors.push(left_neighbor); - } - } - - if let Some(right_neighbor) = i.checked_add(1) { - if self.nodes.contains(&right_neighbor) { - neighbors.push(right_neighbor); - } - } - - neighbors - } - - fn non_cutting(&mut self) -> &Vec { - if !self.updated { - let mut non_cutting = Vec::new(); - non_cutting.push(self.nodes[0]); - for nodes in self.nodes.windows(3) { - if let &[node1, node2, node3] = nodes { - // Since strict ordering is enforced during insertion and creation, adding 1 to smaller node should not cause overflow. - if node1 + 1 != node2 || node2 + 1 != node3 { - non_cutting.push(node2); - } - } - } - - if self.nodes.len() > 1 { - non_cutting.push(*self.nodes.last().unwrap()); - } - self.non_cutting = non_cutting; - self.updated = true; - } - &self.non_cutting - } - - fn get_cx_ladder( - &self, - nodes: &[usize], - root: &GraphIndex, - ) -> Result, LadderError> { - todo!() - } -} - -#[cfg(test)] -mod tests { - use crate::architecture::Architecture; - - use super::Line; - - #[test] - fn test_complete() { - let new_architecture = Line::new(5); - - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 3, 4]); - } - - #[test] - fn test_insert() { - let mut new_architecture = Line::new(5); - new_architecture.insert(5); - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 3, 4, 5]); - } - - #[test] - #[should_panic = "architecture already contains node 1"] - fn test_bad_insert() { - let mut new_architecture = Line::new(5); - new_architecture.insert(1); - } - - #[test] - fn test_remove() { - let mut new_architecture = Line::new(5); - new_architecture.remove(3); - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 4]); - } - - #[test] - fn test_remove_remove_insert() { - let mut new_architecture = Line::new(7); - new_architecture.remove(3); - new_architecture.remove(4); - new_architecture.remove(5); - new_architecture.insert(4); - assert_eq!(new_architecture.nodes, vec![0, 1, 2, 4, 6]); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_bad_remove() { - let mut new_architecture = Line::new(3); - new_architecture.remove(4); - } - - #[test] - fn test_best_path() { - let new_architecture = Line::new(6); - assert_eq!(vec![2, 3, 4], new_architecture.best_path(2, 4)); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_best_path_missing() { - let new_architecture = Line::new(3); - new_architecture.best_path(4, 5); - } - - #[test] - fn test_distance() { - let new_architecture = Line::new(6); - assert_eq!(2, new_architecture.distance(2, 4)); - } - - #[test] - #[should_panic = "architecture does not contain node 4"] - fn test_distance_missing() { - let new_architecture = Line::new(3); - new_architecture.distance(4, 5); - } - - #[test] - fn test_neighbors() { - let new_architecture = Line::new(4); - assert_eq!(vec![1, 3], new_architecture.neighbors(2)); - } - - #[test] - fn test_neighbors_0() { - let new_architecture = Line::new(4); - assert_eq!(vec![1], new_architecture.neighbors(0)); - } - - #[test] - #[should_panic = "architecture does not contain node 3"] - fn test_neighbor_missing() { - let new_architecture = Line::new(3); - new_architecture.distance(2, 3); - } - - #[test] - fn test_non_cutting() { - let mut new_architecture = Line::new(5); - assert_eq!(&vec![0, 4], new_architecture.non_cutting()); - } - - #[test] - fn test_non_cutting_complex() { - let mut new_architecture = Line::new(7); - new_architecture.remove(1); - new_architecture.remove(5); - assert_eq!(&vec![0, 2, 4, 6], new_architecture.non_cutting()); - } - - #[test] - fn test_non_cutting_cache() { - let mut new_architecture = Line::new(7); - assert_eq!(&vec![0, 6], new_architecture.non_cutting()); - new_architecture.remove(1); - assert_eq!(&vec![0, 2, 6], new_architecture.non_cutting()); - new_architecture.remove(5); - assert_eq!(&vec![0, 2, 4, 6], new_architecture.non_cutting()); - } -} From 6de3f89171a718600e3707cd9c48485cb6ecb662 Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 1 Apr 2025 22:35:19 +0200 Subject: [PATCH 04/27] =?UTF-8?q?Temporar=C3=B6y=20move=20reference=20back?= =?UTF-8?q?=20to=20our=20fork?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: daehiff --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8116fbff..aa697540 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,7 +356,7 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "petgraph" version = "0.7.1" -source = "git+https://github.com/petgraph/petgraph.git?rev=74339abdfd665ac7c44d84b48dc22a77625267e8#74339abdfd665ac7c44d84b48dc22a77625267e8" +source = "git+https://github.com/daehiff/petgraph.git?rev=4b700d7e188f973770a61a492892d61372ea7f9e#4b700d7e188f973770a61a492892d61372ea7f9e" dependencies = [ "fixedbitset", "hashbrown", diff --git a/Cargo.toml b/Cargo.toml index 6a24e582..f6049edd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { git = "https://github.com/petgraph/petgraph.git", rev = "74339abdfd665ac7c44d84b48dc22a77625267e8", features = ["stable_graph"]} +petgraph = { git = "https://github.com/daehiff/petgraph.git", rev = "4b700d7e188f973770a61a492892d61372ea7f9e", features = ["stable_graph"]} typenum = "1.17.0" [dev-dependencies] From 66d6014705014092b598445762e008145623834d Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 1 Apr 2025 22:38:52 +0200 Subject: [PATCH 05/27] Remove unnecessary conversion Signed-off-by: daehiff --- src/architecture/connectivity.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 129ce00c..c280a919 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -7,43 +7,16 @@ use petgraph::{ algo::articulation_points::articulation_points, graph::{NodeIndex, UnGraph}, visit::{IntoNodeReferences, NodeIndexable, NodeRef}, - Graph, Undirected, }; use std::borrow::Borrow; use std::collections::HashMap; use std::ops::Index; -/// Small helper since we have different and incompatible assumptions as Petgraph -/// TODO fix this in petgraph -fn convert_graph( - old_graph: &Graph, -) -> Graph { - let mut new_graph = Graph::::new_undirected(); - // Map from old node indices to new node indices. - let mut index_map: HashMap, NodeIndex> = HashMap::new(); - - // Add nodes from the old graph to the new graph. - for old_node in old_graph.node_indices() { - let new_node = new_graph.add_node(old_graph[old_node].clone()); - index_map.insert(old_node, new_node); - } - - // Add edges, converting the node indices using our mapping. - for edge in old_graph.edge_references() { - let new_source = index_map[&edge.source()]; - let new_target = index_map[&edge.target()]; - new_graph.add_edge(new_source, new_target, edge.weight().clone()); - } - - new_graph -} - /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) fn get_non_cutting_vertices( graph: &UnGraph, ) -> Vec { let art_points = articulation_points(&graph); - println!("{:?}", art_points); (0..graph.node_count()) .filter(|node| !art_points.contains(&graph.from_index(*node))) .collect() @@ -253,7 +226,7 @@ impl Architecture for Connectivity { .collect(); let terminals = terminals?; - let tree = steiner_tree(&convert_graph(&self.graph), &terminals); + let tree = steiner_tree(&self.graph, &terminals); let root_node = tree .node_indices() From 59b74361c0f21e1be189e528209e8f0a9856f29b Mon Sep 17 00:00:00 2001 From: daehiff Date: Wed, 2 Apr 2025 08:06:35 +0200 Subject: [PATCH 06/27] Point to right version of petgraph Signed-off-by: daehiff --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/architecture/connectivity.rs | 12 ++---------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa697540..8864c8bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,7 +356,7 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "petgraph" version = "0.7.1" -source = "git+https://github.com/daehiff/petgraph.git?rev=4b700d7e188f973770a61a492892d61372ea7f9e#4b700d7e188f973770a61a492892d61372ea7f9e" +source = "git+https://github.com/petgraph/petgraph.git?rev=3145fa87fa398fd49cef44b2429d93a4fd2160bc#3145fa87fa398fd49cef44b2429d93a4fd2160bc" dependencies = [ "fixedbitset", "hashbrown", diff --git a/Cargo.toml b/Cargo.toml index f6049edd..1fc5239b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { git = "https://github.com/daehiff/petgraph.git", rev = "4b700d7e188f973770a61a492892d61372ea7f9e", features = ["stable_graph"]} +petgraph = { git = "https://github.com/petgraph/petgraph.git", rev = "3145fa87fa398fd49cef44b2429d93a4fd2160bc", features = ["stable_graph"]} typenum = "1.17.0" [dev-dependencies] diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index c280a919..afecdde2 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -212,19 +212,11 @@ impl Architecture for Connectivity { nodes: &[GraphIndex], root: &GraphIndex, ) -> Result, LadderError> { - // TODO fix me we currently have to convert the graph - let terminals: Result, LadderError> = self + let terminals: Vec<_> = self .graph .node_indices() - .filter(|node_index| nodes.contains(&self.graph.to_index(*node_index))) - .map(|node_index| { - let idx = node_index.index() as u32; - idx.try_into() - .map(NodeIndex::new) - .map_err(|_| LadderError::ConversionError) - }) + .filter(|node_index| nodes.contains(&node_index.index())) .collect(); - let terminals = terminals?; let tree = steiner_tree(&self.graph, &terminals); From b6e86eae4c54d3f5ce0b26aaca9b4398791c4758 Mon Sep 17 00:00:00 2001 From: daehiff Date: Sun, 6 Apr 2025 19:10:58 +0200 Subject: [PATCH 07/27] Point to freshly released petgraph version Signed-off-by: daehiff --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8864c8bf..8019160e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,8 +355,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "petgraph" -version = "0.7.1" -source = "git+https://github.com/petgraph/petgraph.git?rev=3145fa87fa398fd49cef44b2429d93a4fd2160bc#3145fa87fa398fd49cef44b2429d93a4fd2160bc" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96dc3f2709da98e228764d8f4c01c39a101dcc441547e8036372ee0522eb108" dependencies = [ "fixedbitset", "hashbrown", diff --git a/Cargo.toml b/Cargo.toml index 1fc5239b..5ef928bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { git = "https://github.com/petgraph/petgraph.git", rev = "3145fa87fa398fd49cef44b2429d93a4fd2160bc", features = ["stable_graph"]} +petgraph = { version = "0.8.0", features = ["stable_graph"]} typenum = "1.17.0" [dev-dependencies] From 0632b427119490596f3541a81413bc33c40a623f Mon Sep 17 00:00:00 2001 From: daehiff Date: Sun, 6 Apr 2025 19:12:58 +0200 Subject: [PATCH 08/27] Update test to only verify len Signed-off-by: daehiff --- src/architecture/connectivity.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index afecdde2..c09ff401 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -355,8 +355,8 @@ mod tests { new_architecture .get_cx_ladder(&vec![0, 1, 2, 4, 5], &1) .unwrap() - .sort(), - vec![(0, 1), (1, 5), (1, 2), (2, 4)].sort() + .len(), + 4 ); } @@ -367,15 +367,15 @@ mod tests { new_architecture .get_cx_ladder(&vec![2, 3, 4], &2) .unwrap() - .sort(), - vec![(2, 4), (2, 3)].sort() + .len(), + 2 ); assert_eq!( new_architecture .get_cx_ladder(&vec![2, 3, 4], &4) .unwrap() - .sort(), - vec![(4, 2), (4, 3)].sort() + .len(), + 2 ); } From eff57b64e041d37abc8d7f2ff9944c8a4517a777 Mon Sep 17 00:00:00 2001 From: daehiff Date: Tue, 8 Apr 2025 09:11:51 +0200 Subject: [PATCH 09/27] Update src/architecture/connectivity.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/architecture/connectivity.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index c09ff401..04cb1a18 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -42,7 +42,6 @@ impl Connectivity { pub fn line(nr_qubits: usize) -> Self { let edges: Vec<(usize, usize)> = (0..nr_qubits - 1).map(|i| (i, i + 1)).collect(); - println!("{:?}", edges); Connectivity::from_edges(&edges) } From c797e4c93c2780decb00e1cafd833ad18fd2cd2d Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Tue, 3 Jun 2025 13:23:04 +0200 Subject: [PATCH 10/27] chore: remove `test_weight_is_considered` This test does not correctly test for considered weight. --- src/architecture/connectivity.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 04cb1a18..d316df3d 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -307,18 +307,6 @@ mod tests { ); } - #[test] - fn test_weight_is_considered() { - let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); - assert_eq!( - new_architecture - .get_cx_ladder(&vec![1, 2, 3, 4], &2) - .unwrap() - .sort(), - vec![(2, 1), (2, 3), (3, 4)].sort() - ); - } - #[test] fn test_root_is_not_present() { let new_architecture = Connectivity::from_edges(&setup_simple()); From b1f123aa6fbc817f437866d12432298a506647e3 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Tue, 3 Jun 2025 13:27:06 +0200 Subject: [PATCH 11/27] chore: clean up code slightly Remove unnecessary mut declarations. Remove unnecessary vec! calls Remove unused imports Remove unneeded casts Remove unused imports --- src/architecture/connectivity.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index d316df3d..d169ae83 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -2,15 +2,13 @@ use super::{Architecture, EdgeWeight, GraphIndex, LadderError, NodeWeight}; use petgraph::algo::floyd_warshall::floyd_warshall_path; use petgraph::algo::steiner_tree::steiner_tree; use petgraph::prelude::EdgeRef; -use petgraph::visit::{Bfs, Dfs, GraphBase, IntoNeighbors, VisitMap, Visitable, Walker}; +use petgraph::visit::{Bfs, VisitMap, Visitable}; use petgraph::{ algo::articulation_points::articulation_points, graph::{NodeIndex, UnGraph}, visit::{IntoNodeReferences, NodeIndexable, NodeRef}, }; -use std::borrow::Borrow; use std::collections::HashMap; -use std::ops::Index; /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) fn get_non_cutting_vertices( @@ -84,7 +82,7 @@ impl Connectivity { pub fn from_graph(graph: UnGraph) -> Self { let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); - let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); + let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); Connectivity { graph, non_cutting, @@ -119,7 +117,7 @@ impl Connectivity { let (distance, prev) = floyd_warshall_path(&self.graph, |e| *e.weight()).unwrap(); - let distance = distance.iter().map(|(k, v)| (*k, *v as usize)).collect(); + let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); self.non_cutting = non_cutting; self.distance = distance; @@ -188,7 +186,7 @@ impl Architecture for Connectivity { j < self.graph.node_count(), "architecture does not contain node {j}" ); - self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] as usize + self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] } fn neighbors(&self, i: GraphIndex) -> Vec { @@ -276,7 +274,7 @@ mod tests { #[test] fn test_line_creation() { - let mut line_architecture = Connectivity::line(5); + let line_architecture = Connectivity::line(5); assert_eq!( line_architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)] @@ -285,7 +283,7 @@ mod tests { #[test] fn test_grid_creation() { - let mut line_architecture = Connectivity::grid(3, 3); + let line_architecture = Connectivity::grid(3, 3); let mut edges = line_architecture.edges(); edges.sort(); assert_eq!( @@ -312,7 +310,7 @@ mod tests { let new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!( new_architecture - .get_cx_ladder(&vec![1, 2, 3, 4], &42) + .get_cx_ladder(&[1, 2, 3, 4], &42) .expect_err("Should return a Error that the root was not found"), LadderError::RootNotFound ); @@ -328,9 +326,7 @@ mod tests { fn test_cx_ladder_line_setup() { let new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!( - new_architecture - .get_cx_ladder(&vec![0, 1, 2, 3], &0) - .unwrap(), + new_architecture.get_cx_ladder(&[0, 1, 2, 3], &0).unwrap(), vec![(0, 1), (1, 2), (2, 3)] ); } @@ -340,7 +336,7 @@ mod tests { let new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!( new_architecture - .get_cx_ladder(&vec![0, 1, 2, 4, 5], &1) + .get_cx_ladder(&[0, 1, 2, 4, 5], &1) .unwrap() .len(), 4 @@ -352,14 +348,14 @@ mod tests { let new_architecture = Connectivity::from_edges(&setup_simple()); assert_eq!( new_architecture - .get_cx_ladder(&vec![2, 3, 4], &2) + .get_cx_ladder(&[2, 3, 4], &2) .unwrap() .len(), 2 ); assert_eq!( new_architecture - .get_cx_ladder(&vec![2, 3, 4], &4) + .get_cx_ladder(&[2, 3, 4], &4) .unwrap() .len(), 2 From a0e45cb038a8ad2a881be3c910d097296519bce1 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Tue, 3 Jun 2025 13:35:25 +0200 Subject: [PATCH 12/27] feat: add test for Complete architecture Test only checks for correct creation. --- src/architecture/connectivity.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index d169ae83..3936202e 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -305,6 +305,14 @@ mod tests { ); } + #[test] + fn test_complete_creation() { + let line_architecture = Connectivity::complete(4); + let mut edges = line_architecture.edges(); + edges.sort(); + assert_eq!(edges, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); + } + #[test] fn test_root_is_not_present() { let new_architecture = Connectivity::from_edges(&setup_simple()); From 37a68e97f5d13e2dd101fd18f82356477eadedaf Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Tue, 3 Jun 2025 13:48:02 +0200 Subject: [PATCH 13/27] chore: remove `ConversionError` from LadderError enum This Error type is not used in any situation. --- src/architecture.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/architecture.rs b/src/architecture.rs index 6d37d684..e046ffb4 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -6,7 +6,6 @@ type NodeWeight = (); #[derive(Debug, PartialEq)] pub enum LadderError { - ConversionError, RootNotFound, } From 07fe7fd9c36d24dc8eefd428dd8b19c5ab03331e Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Wed, 4 Jun 2025 14:04:18 +0200 Subject: [PATCH 14/27] feat: use node weights to track nodes The implemented Ungraph reshuffles node ids each time a node is removed. Hence, a method to track the correct nodes is required. As we do not use node weights, we can now use these as effective node identifiers. Updated the function `remove_node` and tests to ensure correct trackable behavior. --- src/architecture.rs | 2 +- src/architecture/connectivity.rs | 213 +++++++++++++++++++++++++++++-- 2 files changed, 206 insertions(+), 9 deletions(-) diff --git a/src/architecture.rs b/src/architecture.rs index e046ffb4..68a95c65 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -2,7 +2,7 @@ pub mod connectivity; type GraphIndex = usize; type EdgeWeight = usize; -type NodeWeight = (); +type NodeWeight = usize; #[derive(Debug, PartialEq)] pub enum LadderError { diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 3936202e..4d205fe6 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -30,8 +30,12 @@ pub struct Connectivity { impl Connectivity { pub fn new(num_qubits: usize) -> Self { + let mut graph = UnGraph::with_capacity(num_qubits, 0); + for (count, weight) in graph.node_weights_mut().enumerate() { + *weight = count; + } Connectivity { - graph: UnGraph::with_capacity(num_qubits, 0), + graph, non_cutting: Default::default(), prev: Default::default(), distance: HashMap::new(), @@ -79,10 +83,14 @@ impl Connectivity { Connectivity::from_graph(graph) } - pub fn from_graph(graph: UnGraph) -> Self { + pub fn from_graph(mut graph: UnGraph) -> Self { let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + for (count, weight) in graph.node_weights_mut().enumerate() { + *weight = count; + } + Connectivity { graph, non_cutting, @@ -94,11 +102,32 @@ impl Connectivity { pub fn nodes(&self) -> Vec { self.graph .node_references() - .map(|node| self.graph.to_index(node.id())) + .map(|node| *node.weight()) + .collect() + } + + pub fn node_ids(&self) -> Vec { + self.graph + .node_references() + .map(|(node, _)| node.id().index()) .collect() } pub fn edges(&self) -> Vec<(GraphIndex, GraphIndex)> { + let graph_edges: Vec<(GraphIndex, GraphIndex)> = self + .graph + .edge_references() + .map(|edge| { + ( + *self.graph.node_weight(edge.source().id()).unwrap(), + *self.graph.node_weight(edge.target().id()).unwrap(), + ) + }) + .collect(); + graph_edges + } + + pub fn edge_ids(&self) -> Vec<(GraphIndex, GraphIndex)> { let graph_edges: Vec<(GraphIndex, GraphIndex)> = self .graph .edge_references() @@ -129,9 +158,9 @@ impl Connectivity { self.update(); } - pub fn add_node(&mut self) { - self.graph.add_node(()); - } + // pub fn add_node(&mut self) { + // self.graph.add_node(()); + // } pub fn add_edge(&mut self, i: GraphIndex, j: GraphIndex) { self.graph @@ -275,16 +304,22 @@ mod tests { #[test] fn test_line_creation() { let line_architecture = Connectivity::line(5); + assert_eq!( line_architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)] ); + + assert_eq!( + line_architecture.edge_ids(), + vec![(0, 1), (1, 2), (2, 3), (3, 4)] + ); } #[test] fn test_grid_creation() { - let line_architecture = Connectivity::grid(3, 3); - let mut edges = line_architecture.edges(); + let grid_architecture = Connectivity::grid(3, 3); + let mut edges = grid_architecture.edges(); edges.sort(); assert_eq!( edges, @@ -436,4 +471,166 @@ mod tests { let mut line_architecture = Connectivity::line(5); assert_eq!(*line_architecture.non_cutting(), vec![0, 4]); } + + #[test] + fn test_non_cutting_grid() { + let mut line_architecture = Connectivity::grid(3, 3); + assert_eq!( + *line_architecture.non_cutting(), + vec![0, 1, 2, 3, 4, 5, 6, 7, 8] + ); + } + + #[test] + fn test_non_cutting_complete() { + let mut line_architecture = Connectivity::complete(3); + assert_eq!(*line_architecture.non_cutting(), vec![0, 1, 2]); + } + + #[test] + fn test_remove_node() { + let mut architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5]); + + assert_eq!( + architecture.edges(), + vec![ + (0, 1), + (0, 5), + (1, 2), + (1, 5), + (2, 3), + (2, 4), + (3, 4), + (3, 5), + (4, 5), + ] + ); + assert_eq!( + architecture.edge_ids(), + vec![ + (0, 1), + (0, 5), + (1, 2), + (1, 5), + (2, 3), + (2, 4), + (3, 4), + (3, 5), + (4, 5), + ] + ); + + architecture.remove_node(1); + + assert_eq!(architecture.nodes(), vec![0, 5, 2, 3, 4]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); + + assert_eq!( + architecture.edges(), + vec![(3, 4), (0, 5), (3, 5), (4, 5), (2, 3), (2, 4)] + ); + assert_eq!( + architecture.edge_ids(), + vec![(3, 4), (0, 1), (3, 1), (4, 1), (2, 3), (2, 4)] + ); + } + + #[test] + fn test_remove_node_line() { + let mut architecture = Connectivity::line(5); + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); + + assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); + assert_eq!( + architecture.edge_ids(), + vec![(0, 1), (1, 2), (2, 3), (3, 4)] + ); + + architecture.remove_node(1); + + assert_eq!(architecture.nodes(), vec![0, 4, 2, 3]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3]); + + assert_eq!(architecture.edges(), vec![(2, 3), (3, 4)]); + assert_eq!(architecture.edge_ids(), vec![(2, 3), (3, 1)]); + } + + #[test] + fn test_remove_node_grid() { + let mut architecture = Connectivity::grid(3, 3); + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + + assert_eq!( + architecture.edges(), + vec![ + (0, 3), + (0, 1), + (1, 4), + (1, 2), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5), + (5, 8), + (6, 7), + (7, 8) + ] + ); + assert_eq!( + architecture.edge_ids(), + vec![ + (0, 3), + (0, 1), + (1, 4), + (1, 2), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5), + (5, 8), + (6, 7), + (7, 8) + ] + ); + + architecture.remove_node(1); + + assert_eq!(architecture.nodes(), vec![0, 8, 2, 3, 4, 5, 6, 7]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7]); + + assert_eq!( + architecture.edges(), + vec![ + (0, 3), + (5, 8), + (6, 7), + (7, 8), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5) + ] + ); + assert_eq!( + architecture.edge_ids(), + vec![ + (0, 3), + (5, 1), + (6, 7), + (7, 1), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5) + ] + ); + } } From 67df4ff8a2f5893f9f0ff9c8e0b432d82f477bdd Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Wed, 4 Jun 2025 14:06:17 +0200 Subject: [PATCH 15/27] feat: add `disconnect` to create new graphs Updated the Architecture trait to include `disconnect` as a means to update graphs during synthesis. Disconnect creates a new Architecture object while leaving the prior Architecture unchanged, as is required for some algorithms. Added tests to check behavior. Note that each time a new graph is created, the node order is effectively sorted, though the overall structure remains as expected. --- src/architecture.rs | 1 + src/architecture/connectivity.rs | 181 +++++++++++++++++++++++++++++-- 2 files changed, 173 insertions(+), 9 deletions(-) diff --git a/src/architecture.rs b/src/architecture.rs index 68a95c65..c259618b 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -19,4 +19,5 @@ pub trait Architecture { nodes: &[GraphIndex], root: &GraphIndex, ) -> Result, LadderError>; + fn disconnect(&self, i: GraphIndex) -> Self; } diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 4d205fe6..a2680ba2 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -248,7 +248,7 @@ impl Architecture for Connectivity { let root_node = tree .node_indices() - .find(|item| item.index() == *root as usize) + .find(|item| item.index() == *root) .ok_or(LadderError::RootNotFound)?; let mut bfs = Bfs::new(&tree, root_node); @@ -266,6 +266,30 @@ impl Architecture for Connectivity { } Ok(edge_list) } + + fn disconnect(&self, i: GraphIndex) -> Connectivity { + let graph = self.graph.filter_map::<_, _, usize, usize>( + |_, node| { + if *node == i { + None + } else { + println!("some node: {}", *node); + Some(*node) + } + }, + |_, e| Some(*e), + ); + let non_cutting = get_non_cutting_vertices(&graph); + let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); + let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + + Connectivity { + graph, + non_cutting, + prev, + distance, + } + } } #[cfg(test)] @@ -340,14 +364,6 @@ mod tests { ); } - #[test] - fn test_complete_creation() { - let line_architecture = Connectivity::complete(4); - let mut edges = line_architecture.edges(); - edges.sort(); - assert_eq!(edges, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); - } - #[test] fn test_root_is_not_present() { let new_architecture = Connectivity::from_edges(&setup_simple()); @@ -633,4 +649,151 @@ mod tests { ] ); } + + #[test] + fn test_disconnect() { + let architecture = Connectivity::from_edges(&setup_simple()); + let new_architecture = architecture.disconnect(1); + + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5]); + + assert_eq!( + architecture.edges(), + vec![ + (0, 1), + (0, 5), + (1, 2), + (1, 5), + (2, 3), + (2, 4), + (3, 4), + (3, 5), + (4, 5), + ] + ); + assert_eq!( + architecture.edge_ids(), + vec![ + (0, 1), + (0, 5), + (1, 2), + (1, 5), + (2, 3), + (2, 4), + (3, 4), + (3, 5), + (4, 5), + ] + ); + + assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5]); + assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4]); + + assert_eq!( + new_architecture.edges(), + vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] + ); + assert_eq!( + new_architecture.edge_ids(), + vec![(0, 4), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)] + ); + } + + #[test] + fn test_disconnect_line() { + let architecture = Connectivity::line(5); + let new_architecture = architecture.disconnect(1); + + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); + + assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); + assert_eq!( + architecture.edge_ids(), + vec![(0, 1), (1, 2), (2, 3), (3, 4)] + ); + + assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4]); + assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3]); + + assert_eq!(new_architecture.edges(), vec![(2, 3), (3, 4)]); + assert_eq!(new_architecture.edge_ids(), vec![(1, 2), (2, 3)]); + } + + #[test] + fn test_disconnect_grid() { + let architecture = Connectivity::grid(3, 3); + let new_architecture = architecture.disconnect(1); + + assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + + assert_eq!( + architecture.edges(), + vec![ + (0, 3), + (0, 1), + (1, 4), + (1, 2), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5), + (5, 8), + (6, 7), + (7, 8) + ] + ); + assert_eq!( + architecture.edge_ids(), + vec![ + (0, 3), + (0, 1), + (1, 4), + (1, 2), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5), + (5, 8), + (6, 7), + (7, 8) + ] + ); + + assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7]); + + assert_eq!( + new_architecture.edges(), + vec![ + (0, 3), + (2, 5), + (3, 6), + (3, 4), + (4, 7), + (4, 5), + (5, 8), + (6, 7), + (7, 8) + ] + ); + assert_eq!( + new_architecture.edge_ids(), + vec![ + (0, 2), + (1, 4), + (2, 5), + (2, 3), + (3, 6), + (3, 4), + (4, 7), + (5, 6), + (6, 7) + ] + ); + } } From 705669f3e9e92223d06abea9f6ee7d51a0dbbb3e Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Wed, 4 Jun 2025 14:07:44 +0200 Subject: [PATCH 16/27] feat: remove `add_node` `add_node` is removed as tracking the original size of the circuit is required if we use node weight to track nodes. The assumption is that we have all available quantum resources from the beginning. Can be updated in the future for future proofing, but should be good enough for now. --- src/architecture/connectivity.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index a2680ba2..e40eb963 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -158,10 +158,6 @@ impl Connectivity { self.update(); } - // pub fn add_node(&mut self) { - // self.graph.add_node(()); - // } - pub fn add_edge(&mut self, i: GraphIndex, j: GraphIndex) { self.graph .add_edge(self.graph.from_index(i), self.graph.from_index(j), 1); From e31f018e8874c381ea417944d9fa1cc5b912f475 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 5 Jun 2025 13:10:49 +0200 Subject: [PATCH 17/27] chore(test): add more cx_ladder tests for weighted case Ensure that the algorithms identifies the best path if it finds one. The unweighted case has many equivalent solutions, which are bounded by length. --- src/architecture/connectivity.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index e40eb963..6b0e6fea 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -396,6 +396,23 @@ mod tests { .len(), 4 ); + assert_eq!( + new_architecture + .get_cx_ladder(&[0, 1, 2, 4, 5], &1) + .unwrap(), + vec![(1, 2), (2, 3), (3, 5), (3, 4), (5, 0)] + ); + } + + #[test] + fn test_cx_ladder_weighted_extended_triangle() { + let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); + assert_eq!( + new_architecture + .get_cx_ladder(&[0, 1, 2, 4, 5], &1) + .unwrap(), + vec![(1, 2), (2, 3), (3, 5), (3, 4), (5, 0)] + ); } #[test] @@ -417,6 +434,19 @@ mod tests { ); } + #[test] + fn test_cx_ladder_weighted_small_triangle() { + let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); + assert_eq!( + new_architecture.get_cx_ladder(&[2, 3, 4], &2).unwrap(), + vec![(2, 3), (3, 4)] + ); + assert_eq!( + new_architecture.get_cx_ladder(&[2, 3, 4], &4).unwrap(), + vec![(4, 3), (3, 2)] + ); + } + #[test] fn test_weighted_constructor() { let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); From 934ad4483adc1f42d68d567f54d9e8eb4a035582 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 5 Jun 2025 14:00:45 +0200 Subject: [PATCH 18/27] chore: remove print statement from `disconnect` --- src/architecture/connectivity.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 6b0e6fea..0157fac5 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -269,7 +269,6 @@ impl Architecture for Connectivity { if *node == i { None } else { - println!("some node: {}", *node); Some(*node) } }, From 284ccf723a7a0cac74f91f13d6847d5e2ec2cd23 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 5 Jun 2025 14:02:36 +0200 Subject: [PATCH 19/27] fix: correct `get_cx_ladder` Use node weights to track nodes. Ensure that an error is thrown if a cx ladder containing non-existant nodes is requested. Add new LadderError when a node is not found. --- src/architecture.rs | 1 + src/architecture/connectivity.rs | 62 +++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/architecture.rs b/src/architecture.rs index c259618b..9b85ccb0 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -7,6 +7,7 @@ type NodeWeight = usize; #[derive(Debug, PartialEq)] pub enum LadderError { RootNotFound, + NodesNotFound(Vec), } pub trait Architecture { diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 0157fac5..90d8d158 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -229,22 +229,35 @@ impl Architecture for Connectivity { &self.non_cutting } + /// Obtain cx ladder that is architecture conforming that is rooted at `root` fn get_cx_ladder( &self, nodes: &[GraphIndex], root: &GraphIndex, ) -> Result, LadderError> { + let mut nodes = nodes.to_vec(); let terminals: Vec<_> = self .graph - .node_indices() - .filter(|node_index| nodes.contains(&node_index.index())) + .node_references() + .filter_map(|(node_index, weight)| { + if nodes.contains(weight) { + nodes.retain(|&x| x != *weight); + Some(node_index) + } else { + None + } + }) .collect(); + if !nodes.is_empty() { + return Err(LadderError::NodesNotFound(nodes)); + } + let tree = steiner_tree(&self.graph, &terminals); let root_node = tree - .node_indices() - .find(|item| item.index() == *root) + .node_references() + .find_map(|(item, weight)| if weight == root { Some(item) } else { None }) .ok_or(LadderError::RootNotFound)?; let mut bfs = Bfs::new(&tree, root_node); @@ -256,7 +269,10 @@ impl Architecture for Connectivity { for neighbor in tree.neighbors(node) { if !visited.is_visited(&neighbor) { visited.visit(neighbor); - edge_list.push((node.index(), neighbor.index())); + edge_list.push(( + *self.graph.node_weight(node).unwrap(), + *self.graph.node_weight(neighbor).unwrap(), + )); } } } @@ -370,6 +386,19 @@ mod tests { ); } + #[test] + fn test_cx_ladder_error() { + let new_architecture = Connectivity::from_edges(&setup_simple()); + assert_eq!( + new_architecture + .get_cx_ladder(&[6, 1, 2, 3], &0) + .expect_err( + "Should return an error that the nodes are not part of the architecture" + ), + LadderError::NodesNotFound(vec![6]) + ); + } + #[test] fn test_simple_constructor() { let new_architecture = Connectivity::from_edges(&setup_simple()); @@ -821,4 +850,27 @@ mod tests { ] ); } + + #[test] + fn test_disconnected_cx_ladder() { + let architecture = Connectivity::from_weighted_edges(&setup_weighted()); + let new_architecture = architecture.disconnect(3); + + assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 4, 5]); + assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4]); + + assert_eq!( + new_architecture.edges(), + vec![(0, 1), (0, 5), (1, 2), (1, 5), (2, 4), (4, 5)] + ); + assert_eq!( + new_architecture.edge_ids(), + vec![(0, 1), (0, 4), (1, 2), (1, 4), (2, 3), (3, 4)] + ); + + assert_eq!( + new_architecture.get_cx_ladder(&[1, 2, 4, 5], &2).unwrap(), + vec![(2, 4), (2, 1), (1, 5)] + ); + } } From 7398e154729305476ebd4e8895cc68ce167c7b74 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 5 Jun 2025 14:15:54 +0200 Subject: [PATCH 20/27] fix: remove unneeded assert in `test_cx_ladder_extended_triangle` --- src/architecture/connectivity.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 90d8d158..b5b9a516 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -424,12 +424,6 @@ mod tests { .len(), 4 ); - assert_eq!( - new_architecture - .get_cx_ladder(&[0, 1, 2, 4, 5], &1) - .unwrap(), - vec![(1, 2), (2, 3), (3, 5), (3, 4), (5, 0)] - ); } #[test] From 914b20ffcdf1b3de6dc1a3167cd6785b8df43612 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 26 Jun 2025 17:11:44 +0200 Subject: [PATCH 21/27] Update Cargo.lock and .toml Update to custom branch of petgraph --- Cargo.lock | 205 +++++++++++++++++++++++++---------------------------- Cargo.toml | 2 +- 2 files changed, 99 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8019160e..ea31f1f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "anes" version = "0.1.6" @@ -25,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "autocfg" @@ -37,9 +31,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" @@ -55,9 +49,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "cast" @@ -67,9 +61,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "ciborium" @@ -100,18 +94,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstyle", "clap_lex", @@ -119,9 +113,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "criterion" @@ -186,21 +180,21 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fixedbitset" @@ -222,9 +216,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -234,9 +228,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -244,26 +238,24 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "allocator-api2", - "equivalent", "foldhash", ] [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -271,13 +263,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -300,15 +292,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -316,15 +308,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -343,21 +335,20 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "petgraph" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96dc3f2709da98e228764d8f4c01c39a101dcc441547e8036372ee0522eb108" +version = "0.8.2" +source = "git+ssh://github.com/keefehuang/petgraph#1cdbae4cecd2fb6591697eb8cba3d2c9a76c438e" dependencies = [ "fixedbitset", "hashbrown", @@ -404,18 +395,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -434,13 +425,12 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -511,11 +501,17 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -528,29 +524,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.102", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -572,9 +568,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", @@ -599,15 +595,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "walkdir" @@ -630,34 +626,35 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.102", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -665,28 +662,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.102", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -698,16 +698,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", + "windows-sys", ] [[package]] @@ -803,20 +794,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.102", ] diff --git a/Cargo.toml b/Cargo.toml index 5ef928bc..c3db801b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { version = "0.8.0", features = ["stable_graph"]} +petgraph = { version = "0.8.2", features = ["stable_graph"], git = "ssh://github.com/keefehuang/petgraph" } typenum = "1.17.0" [dev-dependencies] From 0828a39546ba94fa37ba95734fa14ab6317c0eb7 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 26 Jun 2025 17:12:38 +0200 Subject: [PATCH 22/27] Update `connectivity` implementation Updated variant does not clone graph multiple times when running steiner tree algorithms. --- src/architecture/connectivity.rs | 922 +++++++++++++++++++++++++------ 1 file changed, 752 insertions(+), 170 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index b5b9a516..d44d181e 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -1,18 +1,18 @@ use super::{Architecture, EdgeWeight, GraphIndex, LadderError, NodeWeight}; use petgraph::algo::floyd_warshall::floyd_warshall_path; -use petgraph::algo::steiner_tree::steiner_tree; -use petgraph::prelude::EdgeRef; -use petgraph::visit::{Bfs, VisitMap, Visitable}; +use petgraph::algo::steiner_tree::stable_steiner_tree; +use petgraph::prelude::{EdgeRef, StableUnGraph}; +use petgraph::visit::{Bfs, IntoEdgeReferences, VisitMap, Visitable}; use petgraph::{ algo::articulation_points::articulation_points, - graph::{NodeIndex, UnGraph}, + graph::NodeIndex, visit::{IntoNodeReferences, NodeIndexable, NodeRef}, }; use std::collections::HashMap; /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) fn get_non_cutting_vertices( - graph: &UnGraph, + graph: &StableUnGraph, ) -> Vec { let art_points = articulation_points(&graph); (0..graph.node_count()) @@ -22,7 +22,7 @@ fn get_non_cutting_vertices( #[derive(Debug)] pub struct Connectivity { - graph: UnGraph, + graph: StableUnGraph, non_cutting: Vec, prev: Vec>>, distance: HashMap<(NodeIndex, NodeIndex), EdgeWeight>, @@ -30,7 +30,7 @@ pub struct Connectivity { impl Connectivity { pub fn new(num_qubits: usize) -> Self { - let mut graph = UnGraph::with_capacity(num_qubits, 0); + let mut graph = StableUnGraph::with_capacity(num_qubits, 0); for (count, weight) in graph.node_weights_mut().enumerate() { *weight = count; } @@ -74,16 +74,16 @@ impl Connectivity { } pub fn from_edges(edges: &[(GraphIndex, GraphIndex)]) -> Self { - let graph = UnGraph::from_edges(edges); + let graph = StableUnGraph::from_edges(edges); Connectivity::from_graph(graph) } pub fn from_weighted_edges(edges: &[(GraphIndex, GraphIndex, EdgeWeight)]) -> Self { - let graph = UnGraph::from_edges(edges); + let graph = StableUnGraph::from_edges(edges); Connectivity::from_graph(graph) } - pub fn from_graph(mut graph: UnGraph) -> Self { + pub fn from_graph(mut graph: StableUnGraph) -> Self { let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); @@ -100,13 +100,6 @@ impl Connectivity { } pub fn nodes(&self) -> Vec { - self.graph - .node_references() - .map(|node| *node.weight()) - .collect() - } - - pub fn node_ids(&self) -> Vec { self.graph .node_references() .map(|(node, _)| node.id().index()) @@ -114,20 +107,6 @@ impl Connectivity { } pub fn edges(&self) -> Vec<(GraphIndex, GraphIndex)> { - let graph_edges: Vec<(GraphIndex, GraphIndex)> = self - .graph - .edge_references() - .map(|edge| { - ( - *self.graph.node_weight(edge.source().id()).unwrap(), - *self.graph.node_weight(edge.target().id()).unwrap(), - ) - }) - .collect(); - graph_edges - } - - pub fn edge_ids(&self) -> Vec<(GraphIndex, GraphIndex)> { let graph_edges: Vec<(GraphIndex, GraphIndex)> = self .graph .edge_references() @@ -253,7 +232,7 @@ impl Architecture for Connectivity { return Err(LadderError::NodesNotFound(nodes)); } - let tree = steiner_tree(&self.graph, &terminals); + let tree = stable_steiner_tree(&self.graph, &terminals); let root_node = tree .node_references() @@ -313,7 +292,7 @@ mod tests { (0, 1, 7), (0, 5, 6), (1, 2, 1), - (1, 5, 5), + (1, 5, 7), (2, 3, 1), (2, 4, 3), (3, 4, 1), @@ -344,11 +323,6 @@ mod tests { line_architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)] ); - - assert_eq!( - line_architecture.edge_ids(), - vec![(0, 1), (1, 2), (2, 3), (3, 4)] - ); } #[test] @@ -555,7 +529,6 @@ mod tests { fn test_remove_node() { let mut architecture = Connectivity::from_edges(&setup_simple()); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5]); assert_eq!( architecture.edges(), @@ -571,33 +544,14 @@ mod tests { (4, 5), ] ); - assert_eq!( - architecture.edge_ids(), - vec![ - (0, 1), - (0, 5), - (1, 2), - (1, 5), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (4, 5), - ] - ); architecture.remove_node(1); - assert_eq!(architecture.nodes(), vec![0, 5, 2, 3, 4]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); + assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5]); assert_eq!( architecture.edges(), - vec![(3, 4), (0, 5), (3, 5), (4, 5), (2, 3), (2, 4)] - ); - assert_eq!( - architecture.edge_ids(), - vec![(3, 4), (0, 1), (3, 1), (4, 1), (2, 3), (2, 4)] + vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] ); } @@ -605,28 +559,20 @@ mod tests { fn test_remove_node_line() { let mut architecture = Connectivity::line(5); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); - assert_eq!( - architecture.edge_ids(), - vec![(0, 1), (1, 2), (2, 3), (3, 4)] - ); architecture.remove_node(1); - assert_eq!(architecture.nodes(), vec![0, 4, 2, 3]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3]); + assert_eq!(architecture.nodes(), vec![0, 2, 3, 4]); assert_eq!(architecture.edges(), vec![(2, 3), (3, 4)]); - assert_eq!(architecture.edge_ids(), vec![(2, 3), (3, 1)]); } #[test] fn test_remove_node_grid() { let mut architecture = Connectivity::grid(3, 3); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!( architecture.edges(), @@ -645,55 +591,23 @@ mod tests { (7, 8) ] ); - assert_eq!( - architecture.edge_ids(), - vec![ - (0, 3), - (0, 1), - (1, 4), - (1, 2), - (2, 5), - (3, 6), - (3, 4), - (4, 7), - (4, 5), - (5, 8), - (6, 7), - (7, 8) - ] - ); architecture.remove_node(1); - assert_eq!(architecture.nodes(), vec![0, 8, 2, 3, 4, 5, 6, 7]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7]); + assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); assert_eq!( architecture.edges(), vec![ (0, 3), - (5, 8), - (6, 7), - (7, 8), (2, 5), (3, 6), (3, 4), (4, 7), - (4, 5) - ] - ); - assert_eq!( - architecture.edge_ids(), - vec![ - (0, 3), - (5, 1), + (4, 5), + (5, 8), (6, 7), - (7, 1), - (2, 5), - (3, 6), - (3, 4), - (4, 7), - (4, 5) + (7, 8), ] ); } @@ -704,7 +618,6 @@ mod tests { let new_architecture = architecture.disconnect(1); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5]); assert_eq!( architecture.edges(), @@ -720,32 +633,13 @@ mod tests { (4, 5), ] ); - assert_eq!( - architecture.edge_ids(), - vec![ - (0, 1), - (0, 5), - (1, 2), - (1, 5), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (4, 5), - ] - ); assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5]); - assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4]); assert_eq!( new_architecture.edges(), vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] ); - assert_eq!( - new_architecture.edge_ids(), - vec![(0, 4), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)] - ); } #[test] @@ -754,19 +648,12 @@ mod tests { let new_architecture = architecture.disconnect(1); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4]); assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); - assert_eq!( - architecture.edge_ids(), - vec![(0, 1), (1, 2), (2, 3), (3, 4)] - ); assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4]); - assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3]); assert_eq!(new_architecture.edges(), vec![(2, 3), (3, 4)]); - assert_eq!(new_architecture.edge_ids(), vec![(1, 2), (2, 3)]); } #[test] @@ -775,7 +662,6 @@ mod tests { let new_architecture = architecture.disconnect(1); assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!( architecture.edges(), @@ -794,26 +680,8 @@ mod tests { (7, 8) ] ); - assert_eq!( - architecture.edge_ids(), - vec![ - (0, 3), - (0, 1), - (1, 4), - (1, 2), - (2, 5), - (3, 6), - (3, 4), - (4, 7), - (4, 5), - (5, 8), - (6, 7), - (7, 8) - ] - ); assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4, 5, 6, 7]); assert_eq!( new_architecture.edges(), @@ -829,20 +697,6 @@ mod tests { (7, 8) ] ); - assert_eq!( - new_architecture.edge_ids(), - vec![ - (0, 2), - (1, 4), - (2, 5), - (2, 3), - (3, 6), - (3, 4), - (4, 7), - (5, 6), - (6, 7) - ] - ); } #[test] @@ -851,16 +705,11 @@ mod tests { let new_architecture = architecture.disconnect(3); assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 4, 5]); - assert_eq!(new_architecture.node_ids(), vec![0, 1, 2, 3, 4]); assert_eq!( new_architecture.edges(), vec![(0, 1), (0, 5), (1, 2), (1, 5), (2, 4), (4, 5)] ); - assert_eq!( - new_architecture.edge_ids(), - vec![(0, 1), (0, 4), (1, 2), (1, 4), (2, 3), (3, 4)] - ); assert_eq!( new_architecture.get_cx_ladder(&[1, 2, 4, 5], &2).unwrap(), @@ -868,3 +717,736 @@ mod tests { ); } } + +// use super::{Architecture, EdgeWeight, GraphIndex, LadderError, NodeWeight}; +// use petgraph::algo::floyd_warshall::floyd_warshall_path; +// use petgraph::algo::steiner_tree::steiner_tree; +// use petgraph::prelude::{EdgeRef, StableUnGraph}; +// use petgraph::visit::{Bfs, IntoEdgeReferences, IntoNodeIdentifiers, VisitMap, Visitable}; +// use petgraph::{ +// algo::articulation_points::articulation_points, +// graph::NodeIndex, +// visit::{IntoNodeReferences, NodeIndexable, NodeRef}, +// }; +// use std::collections::HashMap; + +// /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) +// fn get_non_cutting_vertices( +// graph: &StableUnGraph, +// ) -> Vec { +// let art_points = articulation_points(&graph); +// graph +// .node_identifiers() +// .filter_map(|node| { +// if !art_points.contains(&node) { +// return Some(node.id().index()); +// } +// None +// }) +// .collect() +// // .filter(|node| !art_points.contains(&graph.from_index(*node))) +// // .collect() +// } + +// #[derive(Debug)] +// pub struct Connectivity { +// graph: StableUnGraph, +// non_cutting: Vec, +// prev: HashMap<(NodeIndex, NodeIndex), Option>>, +// distance: HashMap<(NodeIndex, NodeIndex), EdgeWeight>, +// } + +// impl Connectivity { +// pub fn new(num_qubits: usize) -> Self { +// let mut graph = StableUnGraph::with_capacity(num_qubits, 0); +// for (count, weight) in graph.node_weights_mut().enumerate() { +// *weight = count; +// } +// Connectivity { +// graph, +// non_cutting: Default::default(), +// prev: Default::default(), +// distance: HashMap::new(), +// } +// } + +// pub fn line(nr_qubits: usize) -> Self { +// let edges: Vec<(usize, usize)> = (0..nr_qubits - 1).map(|i| (i, i + 1)).collect(); +// Connectivity::from_edges(&edges) +// } + +// pub fn grid(num_rows: usize, num_cols: usize) -> Self { +// let mut edges = Vec::new(); + +// for r in 0..num_rows { +// for c in 0..num_cols { +// if r < num_rows - 1 { +// edges.push((num_cols * r + c, num_cols * (r + 1) + c)); +// } +// if c < num_cols - 1 { +// edges.push((num_cols * r + c, num_cols * r + (c + 1))); +// } +// } +// } +// Connectivity::from_edges(&edges) +// } + +// pub fn complete(num_qubits: usize) -> Self { +// let mut edges = Vec::new(); +// for i in 0..num_qubits { +// for j in (i + 1)..num_qubits { +// edges.push((i, j)); +// } +// } +// Connectivity::from_edges(&edges) +// } + +// pub fn from_edges(edges: &[(GraphIndex, GraphIndex)]) -> Self { +// let graph = StableUnGraph::from_edges(edges); +// Connectivity::from_graph(graph) +// } + +// pub fn from_weighted_edges(edges: &[(GraphIndex, GraphIndex, EdgeWeight)]) -> Self { +// let graph = StableUnGraph::from_edges(edges); +// Connectivity::from_graph(graph) +// } + +// pub fn from_graph(mut graph: StableUnGraph) -> Self { +// // let ungraph = to_ungraph(&graph); +// // println!("graph: {:?}", graph); +// let non_cutting = get_non_cutting_vertices(&graph); + +// let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); +// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); +// for (count, weight) in graph.node_weights_mut().enumerate() { +// *weight = count; +// } + +// Connectivity { +// graph, +// non_cutting, +// prev, +// distance, +// } +// } + +// pub fn nodes(&self) -> Vec { +// self.graph +// .node_references() +// .map(|(node, _)| node.id().index()) +// .collect() +// } + +// pub fn edges(&self) -> Vec<(GraphIndex, GraphIndex)> { +// let graph_edges: Vec<(GraphIndex, GraphIndex)> = self +// .graph +// .edge_references() +// .map(|node| { +// ( +// self.graph.to_index(node.source()), +// self.graph.to_index(node.target()), +// ) +// }) +// .collect(); +// graph_edges +// } + +// fn update(&mut self) { +// // let ungraph = self.to_ungraph(); +// let non_cutting = get_non_cutting_vertices(&self.graph); + +// let (distance, prev) = floyd_warshall_path(&self.graph, |e| *e.weight()).unwrap(); + +// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + +// self.non_cutting = non_cutting; +// self.distance = distance; +// self.prev = prev; +// } + +// pub fn remove_node(&mut self, i: GraphIndex) { +// self.graph.remove_node(self.graph.from_index(i)); +// self.update(); +// } + +// pub fn add_edge(&mut self, i: GraphIndex, j: GraphIndex) { +// self.graph +// .add_edge(self.graph.from_index(i), self.graph.from_index(j), 1); +// self.update(); +// } + +// pub fn add_weighted_edge(&mut self, i: GraphIndex, j: GraphIndex, weight: EdgeWeight) { +// self.graph +// .add_edge(self.graph.from_index(i), self.graph.from_index(j), weight); +// self.update(); +// } + +// fn path_from_shortest_path_tree(&self, u: GraphIndex, mut v: GraphIndex) -> Vec { +// let mut path = vec![v]; + +// if !self +// .prev +// .contains_key(&(NodeIndex::new(u), NodeIndex::new(v))) +// { +// return Vec::new(); +// } + +// while u != v { +// if let Some(new_v) = self.prev.get(&(NodeIndex::new(u), NodeIndex::new(v))) { +// v = new_v.unwrap().index(); +// path.push(v); +// } +// } + +// path.reverse(); +// path +// } +// } + +// impl Architecture for Connectivity { +// fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { +// assert!( +// i < self.graph.node_count(), +// "architecture does not contain node {i}" +// ); +// assert!( +// j < self.graph.node_count(), +// "architecture does not contain node {j}" +// ); +// self.path_from_shortest_path_tree(i, j) +// } + +// fn distance(&self, i: GraphIndex, j: GraphIndex) -> usize { +// assert!( +// i < self.graph.node_count(), +// "architecture does not contain node {i}" +// ); +// assert!( +// j < self.graph.node_count(), +// "architecture does not contain node {j}" +// ); +// self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] +// } + +// fn neighbors(&self, i: GraphIndex) -> Vec { +// assert!( +// i < self.graph.node_count(), +// "architecture does not contain node {i}" +// ); +// self.graph +// .neighbors(NodeIndex::new(i)) +// .map(|neighbor| neighbor.index()) +// .collect() +// } + +// fn non_cutting(&mut self) -> &Vec { +// &self.non_cutting +// } + +// /// Obtain cx ladder that is architecture conforming that is rooted at `root` +// fn get_cx_ladder( +// &self, +// nodes: &[GraphIndex], +// root: &GraphIndex, +// ) -> Result, LadderError> { +// let mut nodes = nodes.to_vec(); +// let terminals: Vec<_> = self +// .graph +// .node_references() +// .filter_map(|(node_index, weight)| { +// if nodes.contains(weight) { +// nodes.retain(|&x| x != *weight); +// Some(node_index) +// } else { +// None +// } +// }) +// .collect(); + +// if !nodes.is_empty() { +// return Err(LadderError::NodesNotFound(nodes)); +// } +// // let ungraph = self.to_ungraph(); +// let tree = steiner_tree(&self.graph, &terminals); + +// let root_node = tree +// .node_references() +// .find_map(|(item, weight)| if weight == root { Some(item) } else { None }) +// .ok_or(LadderError::RootNotFound)?; + +// let mut bfs = Bfs::new(&tree, root_node); +// let mut edge_list = Vec::new(); +// let mut visited = tree.visit_map(); +// visited.visit(root_node); + +// while let Some(node) = bfs.next(&tree) { +// for neighbor in tree.neighbors(node) { +// if !visited.is_visited(&neighbor) { +// visited.visit(neighbor); +// edge_list.push((node.index(), neighbor.index())); +// } +// } +// } +// Ok(edge_list) +// } + +// fn disconnect(&self, i: GraphIndex) -> Connectivity { +// let graph = self.graph.filter_map::<_, _, usize, usize>( +// |_, node| { +// if *node == i { +// None +// } else { +// Some(*node) +// } +// }, +// |_, e| Some(*e), +// ); + +// let non_cutting = get_non_cutting_vertices(&graph); +// let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); +// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); + +// Connectivity { +// graph, +// non_cutting, +// prev, +// distance, +// } +// } +// } + +// #[cfg(test)] +// mod tests { +// use crate::architecture::{Architecture, EdgeWeight, GraphIndex, LadderError}; + +// use super::Connectivity; +// fn setup_weighted() -> Vec<(GraphIndex, GraphIndex, EdgeWeight)> { +// vec![ +// (0, 1, 7), +// (0, 5, 6), +// (1, 2, 1), +// (1, 5, 5), +// (2, 3, 1), +// (2, 4, 3), +// (3, 4, 1), +// (3, 5, 4), +// (4, 5, 10), +// ] +// } + +// fn setup_simple() -> Vec<(GraphIndex, GraphIndex)> { +// vec![ +// (0, 1), +// (0, 5), +// (1, 2), +// (1, 5), +// (2, 3), +// (2, 4), +// (3, 4), +// (3, 5), +// (4, 5), +// ] +// } + +// #[test] +// fn test_line_creation() { +// let line_architecture = Connectivity::line(5); + +// assert_eq!( +// line_architecture.edges(), +// vec![(0, 1), (1, 2), (2, 3), (3, 4)] +// ); +// } + +// #[test] +// fn test_grid_creation() { +// let grid_architecture = Connectivity::grid(3, 3); +// let mut edges = grid_architecture.edges(); +// edges.sort(); +// assert_eq!( +// edges, +// vec![ +// (0, 1), +// (0, 3), +// (1, 2), +// (1, 4), +// (2, 5), +// (3, 4), +// (3, 6), +// (4, 5), +// (4, 7), +// (5, 8), +// (6, 7), +// (7, 8) +// ] +// ); +// } + +// #[test] +// fn test_root_is_not_present() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[1, 2, 3, 4], &42) +// .expect_err("Should return a Error that the root was not found"), +// LadderError::RootNotFound +// ); +// } + +// #[test] +// fn test_cx_ladder_error() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[6, 1, 2, 3], &0) +// .expect_err( +// "Should return an error that the nodes are not part of the architecture" +// ), +// LadderError::NodesNotFound(vec![6]) +// ); +// } + +// #[test] +// fn test_simple_constructor() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); +// } + +// #[test] +// fn test_cx_ladder_line_setup() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!( +// new_architecture.get_cx_ladder(&[0, 1, 2, 3], &0).unwrap(), +// vec![(0, 1), (1, 2), (2, 3)] +// ); +// } + +// #[test] +// fn test_cx_ladder_extended_triangle() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[0, 1, 2, 4, 5], &1) +// .unwrap() +// .len(), +// 4 +// ); +// } + +// #[test] +// fn test_cx_ladder_weighted_extended_triangle() { +// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[0, 1, 2, 4, 5], &1) +// .unwrap(), +// vec![(1, 2), (2, 3), (3, 5), (3, 4), (5, 0)] +// ); +// } + +// #[test] +// fn test_cx_ladder_small_triangle() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[2, 3, 4], &2) +// .unwrap() +// .len(), +// 2 +// ); +// assert_eq!( +// new_architecture +// .get_cx_ladder(&[2, 3, 4], &4) +// .unwrap() +// .len(), +// 2 +// ); +// } + +// #[test] +// fn test_cx_ladder_weighted_small_triangle() { +// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); +// assert_eq!( +// new_architecture.get_cx_ladder(&[2, 3, 4], &2).unwrap(), +// vec![(2, 3), (3, 4)] +// ); +// assert_eq!( +// new_architecture.get_cx_ladder(&[2, 3, 4], &4).unwrap(), +// vec![(4, 3), (3, 2)] +// ); +// } + +// #[test] +// fn test_weighted_constructor() { +// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); +// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); +// } + +// #[test] +// fn test_best_simple_path() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); + +// assert_eq!(vec![0, 1, 2, 4], new_architecture.best_path(0, 4)); +// } + +// #[test] +// fn test_best_weighted_path() { +// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); + +// assert_eq!(vec![0, 1, 2, 3, 4], new_architecture.best_path(0, 4)); +// } + +// #[test] +// #[should_panic = "architecture does not contain node 6"] +// fn test_best_path_missing() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// new_architecture.best_path(5, 6); +// } + +// #[test] +// fn test_distance() { +// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); +// assert_eq!(2, new_architecture.distance(2, 4)); +// assert_eq!(2, new_architecture.distance(4, 2)); +// assert_eq!(10, new_architecture.distance(0, 4)); +// } + +// #[test] +// #[should_panic = "architecture does not contain node 6"] +// fn test_distance_missing() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// new_architecture.distance(5, 6); +// } + +// #[test] +// fn test_neighbors() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!(vec![4, 3, 1], new_architecture.neighbors(2)); +// } + +// #[test] +// #[should_panic = "architecture does not contain node 7"] +// fn test_neighbor_missing() { +// let new_architecture = Connectivity::from_edges(&setup_simple()); +// new_architecture.distance(2, 7); +// } + +// #[test] +// fn test_non_cutting() { +// let mut new_architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!(&new_architecture.nodes(), new_architecture.non_cutting()); +// } + +// #[test] +// fn test_non_cutting_line() { +// let mut line_architecture = Connectivity::line(5); +// assert_eq!(*line_architecture.non_cutting(), vec![0, 4]); +// } + +// #[test] +// fn test_non_cutting_grid() { +// let mut line_architecture = Connectivity::grid(3, 3); +// assert_eq!( +// *line_architecture.non_cutting(), +// vec![0, 1, 2, 3, 4, 5, 6, 7, 8] +// ); +// } + +// #[test] +// fn test_non_cutting_complete() { +// let mut line_architecture = Connectivity::complete(3); +// assert_eq!(*line_architecture.non_cutting(), vec![0, 1, 2]); +// } + +// #[test] +// fn test_remove_node() { +// let mut architecture = Connectivity::from_edges(&setup_simple()); +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); + +// assert_eq!( +// architecture.edges(), +// vec![ +// (0, 1), +// (0, 5), +// (1, 2), +// (1, 5), +// (2, 3), +// (2, 4), +// (3, 4), +// (3, 5), +// (4, 5), +// ] +// ); + +// architecture.remove_node(1); + +// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5]); + +// assert_eq!( +// architecture.edges(), +// vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] +// ); +// } + +// #[test] +// fn test_remove_node_line() { +// let mut architecture = Connectivity::line(5); +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); + +// assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); + +// architecture.remove_node(1); + +// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4]); + +// assert_eq!(architecture.edges(), vec![(2, 3), (3, 4)]); +// } + +// #[test] +// fn test_remove_node_grid() { +// let mut architecture = Connectivity::grid(3, 3); +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + +// assert_eq!( +// architecture.edges(), +// vec![ +// (0, 3), +// (0, 1), +// (1, 4), +// (1, 2), +// (2, 5), +// (3, 6), +// (3, 4), +// (4, 7), +// (4, 5), +// (5, 8), +// (6, 7), +// (7, 8) +// ] +// ); + +// architecture.remove_node(1); + +// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); + +// assert_eq!( +// architecture.edges(), +// vec![ +// (0, 3), +// (2, 5), +// (3, 6), +// (3, 4), +// (4, 7), +// (4, 5), +// (5, 8), +// (6, 7), +// (7, 8), +// ] +// ); +// } + +// #[test] +// fn test_disconnect() { +// let architecture = Connectivity::from_edges(&setup_simple()); +// let new_architecture = architecture.disconnect(1); + +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); + +// assert_eq!( +// architecture.edges(), +// vec![ +// (0, 1), +// (0, 5), +// (1, 2), +// (1, 5), +// (2, 3), +// (2, 4), +// (3, 4), +// (3, 5), +// (4, 5), +// ] +// ); + +// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5]); + +// assert_eq!( +// new_architecture.edges(), +// vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] +// ); +// } + +// #[test] +// fn test_disconnect_line() { +// let architecture = Connectivity::line(5); +// let new_architecture = architecture.disconnect(1); + +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); + +// assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); + +// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4]); + +// assert_eq!(new_architecture.edges(), vec![(2, 3), (3, 4)]); +// } + +// #[test] +// fn test_disconnect_grid() { +// let architecture = Connectivity::grid(3, 3); +// let new_architecture = architecture.disconnect(1); + +// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); + +// assert_eq!( +// architecture.edges(), +// vec![ +// (0, 3), +// (0, 1), +// (1, 4), +// (1, 2), +// (2, 5), +// (3, 6), +// (3, 4), +// (4, 7), +// (4, 5), +// (5, 8), +// (6, 7), +// (7, 8) +// ] +// ); + +// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); + +// assert_eq!( +// new_architecture.edges(), +// vec![ +// (0, 3), +// (2, 5), +// (3, 6), +// (3, 4), +// (4, 7), +// (4, 5), +// (5, 8), +// (6, 7), +// (7, 8) +// ] +// ); +// } + +// #[test] +// fn test_disconnected_cx_ladder() { +// let architecture = Connectivity::from_weighted_edges(&setup_weighted()); +// let new_architecture = architecture.disconnect(3); + +// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 4, 5]); + +// assert_eq!( +// new_architecture.edges(), +// vec![(0, 1), (0, 5), (1, 2), (1, 5), (2, 4), (4, 5)] +// ); + +// assert_eq!( +// new_architecture.get_cx_ladder(&[1, 2, 4, 5], &2).unwrap(), +// vec![(2, 4), (2, 1), (1, 5)] +// ); +// } +// } From 91cad4f30ad7c6acf0de54870883a6f80fe696ff Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 26 Jun 2025 17:13:15 +0200 Subject: [PATCH 23/27] Remove unused imports from `clifford_tableaus` --- src/ir/clifford_tableau.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ir/clifford_tableau.rs b/src/ir/clifford_tableau.rs index bb00de76..697a01e1 100644 --- a/src/ir/clifford_tableau.rs +++ b/src/ir/clifford_tableau.rs @@ -1,7 +1,6 @@ -use core::num; -use std::iter::{self, zip}; +use std::iter::zip; -use itertools::{iproduct, Itertools}; +use itertools::Itertools; use crate::{ data_structures::{CliffordTableau, PauliLetter, PauliString, PropagateClifford}, From edaf3fba2aa8129af9b836df42dbd2be8e9709a8 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 3 Jul 2025 11:43:13 +0200 Subject: [PATCH 24/27] Format various files --- src/ir/clifford_tableau.rs | 1 - src/ir/pauli_exponential.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ir/clifford_tableau.rs b/src/ir/clifford_tableau.rs index c4e92941..177e3cef 100644 --- a/src/ir/clifford_tableau.rs +++ b/src/ir/clifford_tableau.rs @@ -4,7 +4,6 @@ use crate::data_structures::{CliffordTableau, HasAdjoint}; pub use custom_callback::CallbackCliffordSynthesizer; pub use naive::NaiveCliffordSynthesizer; - mod custom_callback; mod helper; mod naive; diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index b9eaf164..ac3824e3 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -4,10 +4,10 @@ use crate::data_structures::{CliffordTableau, HasAdjoint, PauliPolynomial}; use crate::ir::{CliffordGates, Gates, Synthesizer}; +use crate::ir::clifford_tableau::CallbackCliffordSynthesizer; +use crate::ir::clifford_tableau::NaiveCliffordSynthesizer; use crate::ir::{ - clifford_tableau::{ - CallbackCliffordSynthesizer, CliffordTableauSynthStrategy, NaiveCliffordSynthesizer, - }, + clifford_tableau::CliffordTableauSynthStrategy, pauli_polynomial::{naive::NaivePauliPolynomialSynthesizer, PauliPolynomialSynthStrategy}, }; From 3b698219dfaa3b81ffff7afc243ada3d90214d62 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 3 Jul 2025 12:01:39 +0200 Subject: [PATCH 25/27] Correct reliance on node_weight. Set default NodeWeight to () as it is no longer used. Remove all usages of node_weight. --- src/architecture.rs | 2 +- src/architecture/connectivity.rs | 787 ++----------------------------- 2 files changed, 32 insertions(+), 757 deletions(-) diff --git a/src/architecture.rs b/src/architecture.rs index 9b85ccb0..aabb3d3b 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -2,7 +2,7 @@ pub mod connectivity; type GraphIndex = usize; type EdgeWeight = usize; -type NodeWeight = usize; +type NodeWeight = (); #[derive(Debug, PartialEq)] pub enum LadderError { diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index f626941c..1fbc6197 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -8,7 +8,6 @@ use petgraph::{ graph::NodeIndex, visit::{IntoNodeReferences, NodeIndexable, NodeRef}, }; -use std::borrow::Borrow; use std::collections::HashMap; use std::ops::Index; @@ -32,10 +31,8 @@ pub struct Connectivity { impl Connectivity { pub fn new(num_qubits: usize) -> Self { - let mut graph = StableUnGraph::with_capacity(num_qubits, 0); - for (count, weight) in graph.node_weights_mut().enumerate() { - *weight = count; - } + let graph = StableUnGraph::with_capacity(num_qubits, 0); + Connectivity { graph, non_cutting: Default::default(), @@ -85,13 +82,10 @@ impl Connectivity { Connectivity::from_graph(graph) } - pub fn from_graph(mut graph: StableUnGraph) -> Self { + pub fn from_graph(graph: StableUnGraph) -> Self { let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); - for (count, weight) in graph.node_weights_mut().enumerate() { - *weight = count; - } Connectivity { graph, @@ -220,9 +214,9 @@ impl Architecture for Connectivity { let terminals: Vec<_> = self .graph .node_references() - .filter_map(|(node_index, weight)| { - if nodes.contains(weight) { - nodes.retain(|&x| x != *weight); + .filter_map(|(node_index, _)| { + if nodes.contains(&node_index.index()) { + nodes.retain(|&x| x != node_index.index()); Some(node_index) } else { None @@ -238,7 +232,7 @@ impl Architecture for Connectivity { let root_node = tree .node_references() - .find_map(|(item, weight)| if weight == root { Some(item) } else { None }) + .find_map(|(item, _)| if item.index() == *root { Some(item) } else { None }) .ok_or(LadderError::RootNotFound)?; let mut bfs = Bfs::new(&tree, root_node); @@ -251,8 +245,8 @@ impl Architecture for Connectivity { if !visited.is_visited(&neighbor) { visited.visit(neighbor); edge_list.push(( - *self.graph.node_weight(node).unwrap(), - *self.graph.node_weight(neighbor).unwrap(), + self.graph.to_index(node), + self.graph.to_index(neighbor), )); } } @@ -261,15 +255,15 @@ impl Architecture for Connectivity { } fn disconnect(&self, i: GraphIndex) -> Connectivity { - let graph = self.graph.filter_map::<_, _, usize, usize>( - |_, node| { - if *node == i { - None + let mut graph = self.graph.clone(); + graph.retain_nodes( + |_, index| { + if index.index() == i { + false } else { - Some(*node) + true } - }, - |_, e| Some(*e), + } ); let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); @@ -717,738 +711,19 @@ mod tests { new_architecture.get_cx_ladder(&[1, 2, 4, 5], &2).unwrap(), vec![(2, 4), (2, 1), (1, 5)] ); - } -} -// use super::{Architecture, EdgeWeight, GraphIndex, LadderError, NodeWeight}; -// use petgraph::algo::floyd_warshall::floyd_warshall_path; -// use petgraph::algo::steiner_tree::steiner_tree; -// use petgraph::prelude::{EdgeRef, StableUnGraph}; -// use petgraph::visit::{Bfs, IntoEdgeReferences, IntoNodeIdentifiers, VisitMap, Visitable}; -// use petgraph::{ -// algo::articulation_points::articulation_points, -// graph::NodeIndex, -// visit::{IntoNodeReferences, NodeIndexable, NodeRef}, -// }; -// use std::collections::HashMap; - -// /// Get all the vertices in a graph that are non-cutting (won't make the graph disconnected) -// fn get_non_cutting_vertices( -// graph: &StableUnGraph, -// ) -> Vec { -// let art_points = articulation_points(&graph); -// graph -// .node_identifiers() -// .filter_map(|node| { -// if !art_points.contains(&node) { -// return Some(node.id().index()); -// } -// None -// }) -// .collect() -// // .filter(|node| !art_points.contains(&graph.from_index(*node))) -// // .collect() -// } - -// #[derive(Debug)] -// pub struct Connectivity { -// graph: StableUnGraph, -// non_cutting: Vec, -// prev: HashMap<(NodeIndex, NodeIndex), Option>>, -// distance: HashMap<(NodeIndex, NodeIndex), EdgeWeight>, -// } - -// impl Connectivity { -// pub fn new(num_qubits: usize) -> Self { -// let mut graph = StableUnGraph::with_capacity(num_qubits, 0); -// for (count, weight) in graph.node_weights_mut().enumerate() { -// *weight = count; -// } -// Connectivity { -// graph, -// non_cutting: Default::default(), -// prev: Default::default(), -// distance: HashMap::new(), -// } -// } - -// pub fn line(nr_qubits: usize) -> Self { -// let edges: Vec<(usize, usize)> = (0..nr_qubits - 1).map(|i| (i, i + 1)).collect(); -// Connectivity::from_edges(&edges) -// } - -// pub fn grid(num_rows: usize, num_cols: usize) -> Self { -// let mut edges = Vec::new(); - -// for r in 0..num_rows { -// for c in 0..num_cols { -// if r < num_rows - 1 { -// edges.push((num_cols * r + c, num_cols * (r + 1) + c)); -// } -// if c < num_cols - 1 { -// edges.push((num_cols * r + c, num_cols * r + (c + 1))); -// } -// } -// } -// Connectivity::from_edges(&edges) -// } - -// pub fn complete(num_qubits: usize) -> Self { -// let mut edges = Vec::new(); -// for i in 0..num_qubits { -// for j in (i + 1)..num_qubits { -// edges.push((i, j)); -// } -// } -// Connectivity::from_edges(&edges) -// } - -// pub fn from_edges(edges: &[(GraphIndex, GraphIndex)]) -> Self { -// let graph = StableUnGraph::from_edges(edges); -// Connectivity::from_graph(graph) -// } - -// pub fn from_weighted_edges(edges: &[(GraphIndex, GraphIndex, EdgeWeight)]) -> Self { -// let graph = StableUnGraph::from_edges(edges); -// Connectivity::from_graph(graph) -// } - -// pub fn from_graph(mut graph: StableUnGraph) -> Self { -// // let ungraph = to_ungraph(&graph); -// // println!("graph: {:?}", graph); -// let non_cutting = get_non_cutting_vertices(&graph); - -// let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); -// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); -// for (count, weight) in graph.node_weights_mut().enumerate() { -// *weight = count; -// } - -// Connectivity { -// graph, -// non_cutting, -// prev, -// distance, -// } -// } - -// pub fn nodes(&self) -> Vec { -// self.graph -// .node_references() -// .map(|(node, _)| node.id().index()) -// .collect() -// } - -// pub fn edges(&self) -> Vec<(GraphIndex, GraphIndex)> { -// let graph_edges: Vec<(GraphIndex, GraphIndex)> = self -// .graph -// .edge_references() -// .map(|node| { -// ( -// self.graph.to_index(node.source()), -// self.graph.to_index(node.target()), -// ) -// }) -// .collect(); -// graph_edges -// } - -// fn update(&mut self) { -// // let ungraph = self.to_ungraph(); -// let non_cutting = get_non_cutting_vertices(&self.graph); - -// let (distance, prev) = floyd_warshall_path(&self.graph, |e| *e.weight()).unwrap(); - -// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); - -// self.non_cutting = non_cutting; -// self.distance = distance; -// self.prev = prev; -// } - -// pub fn remove_node(&mut self, i: GraphIndex) { -// self.graph.remove_node(self.graph.from_index(i)); -// self.update(); -// } - -// pub fn add_edge(&mut self, i: GraphIndex, j: GraphIndex) { -// self.graph -// .add_edge(self.graph.from_index(i), self.graph.from_index(j), 1); -// self.update(); -// } - -// pub fn add_weighted_edge(&mut self, i: GraphIndex, j: GraphIndex, weight: EdgeWeight) { -// self.graph -// .add_edge(self.graph.from_index(i), self.graph.from_index(j), weight); -// self.update(); -// } - -// fn path_from_shortest_path_tree(&self, u: GraphIndex, mut v: GraphIndex) -> Vec { -// let mut path = vec![v]; - -// if !self -// .prev -// .contains_key(&(NodeIndex::new(u), NodeIndex::new(v))) -// { -// return Vec::new(); -// } - -// while u != v { -// if let Some(new_v) = self.prev.get(&(NodeIndex::new(u), NodeIndex::new(v))) { -// v = new_v.unwrap().index(); -// path.push(v); -// } -// } - -// path.reverse(); -// path -// } -// } - -// impl Architecture for Connectivity { -// fn best_path(&self, i: GraphIndex, j: GraphIndex) -> Vec { -// assert!( -// i < self.graph.node_count(), -// "architecture does not contain node {i}" -// ); -// assert!( -// j < self.graph.node_count(), -// "architecture does not contain node {j}" -// ); -// self.path_from_shortest_path_tree(i, j) -// } - -// fn distance(&self, i: GraphIndex, j: GraphIndex) -> usize { -// assert!( -// i < self.graph.node_count(), -// "architecture does not contain node {i}" -// ); -// assert!( -// j < self.graph.node_count(), -// "architecture does not contain node {j}" -// ); -// self.distance[&(self.graph.from_index(i), self.graph.from_index(j))] -// } - -// fn neighbors(&self, i: GraphIndex) -> Vec { -// assert!( -// i < self.graph.node_count(), -// "architecture does not contain node {i}" -// ); -// self.graph -// .neighbors(NodeIndex::new(i)) -// .map(|neighbor| neighbor.index()) -// .collect() -// } - -// fn non_cutting(&mut self) -> &Vec { -// &self.non_cutting -// } - -// /// Obtain cx ladder that is architecture conforming that is rooted at `root` -// fn get_cx_ladder( -// &self, -// nodes: &[GraphIndex], -// root: &GraphIndex, -// ) -> Result, LadderError> { -// let mut nodes = nodes.to_vec(); -// let terminals: Vec<_> = self -// .graph -// .node_references() -// .filter_map(|(node_index, weight)| { -// if nodes.contains(weight) { -// nodes.retain(|&x| x != *weight); -// Some(node_index) -// } else { -// None -// } -// }) -// .collect(); - -// if !nodes.is_empty() { -// return Err(LadderError::NodesNotFound(nodes)); -// } -// // let ungraph = self.to_ungraph(); -// let tree = steiner_tree(&self.graph, &terminals); - -// let root_node = tree -// .node_references() -// .find_map(|(item, weight)| if weight == root { Some(item) } else { None }) -// .ok_or(LadderError::RootNotFound)?; - -// let mut bfs = Bfs::new(&tree, root_node); -// let mut edge_list = Vec::new(); -// let mut visited = tree.visit_map(); -// visited.visit(root_node); - -// while let Some(node) = bfs.next(&tree) { -// for neighbor in tree.neighbors(node) { -// if !visited.is_visited(&neighbor) { -// visited.visit(neighbor); -// edge_list.push((node.index(), neighbor.index())); -// } -// } -// } -// Ok(edge_list) -// } - -// fn disconnect(&self, i: GraphIndex) -> Connectivity { -// let graph = self.graph.filter_map::<_, _, usize, usize>( -// |_, node| { -// if *node == i { -// None -// } else { -// Some(*node) -// } -// }, -// |_, e| Some(*e), -// ); - -// let non_cutting = get_non_cutting_vertices(&graph); -// let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); -// let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); - -// Connectivity { -// graph, -// non_cutting, -// prev, -// distance, -// } -// } -// } - -// #[cfg(test)] -// mod tests { -// use crate::architecture::{Architecture, EdgeWeight, GraphIndex, LadderError}; - -// use super::Connectivity; -// fn setup_weighted() -> Vec<(GraphIndex, GraphIndex, EdgeWeight)> { -// vec![ -// (0, 1, 7), -// (0, 5, 6), -// (1, 2, 1), -// (1, 5, 5), -// (2, 3, 1), -// (2, 4, 3), -// (3, 4, 1), -// (3, 5, 4), -// (4, 5, 10), -// ] -// } - -// fn setup_simple() -> Vec<(GraphIndex, GraphIndex)> { -// vec![ -// (0, 1), -// (0, 5), -// (1, 2), -// (1, 5), -// (2, 3), -// (2, 4), -// (3, 4), -// (3, 5), -// (4, 5), -// ] -// } - -// #[test] -// fn test_line_creation() { -// let line_architecture = Connectivity::line(5); - -// assert_eq!( -// line_architecture.edges(), -// vec![(0, 1), (1, 2), (2, 3), (3, 4)] -// ); -// } - -// #[test] -// fn test_grid_creation() { -// let grid_architecture = Connectivity::grid(3, 3); -// let mut edges = grid_architecture.edges(); -// edges.sort(); -// assert_eq!( -// edges, -// vec![ -// (0, 1), -// (0, 3), -// (1, 2), -// (1, 4), -// (2, 5), -// (3, 4), -// (3, 6), -// (4, 5), -// (4, 7), -// (5, 8), -// (6, 7), -// (7, 8) -// ] -// ); -// } - -// #[test] -// fn test_root_is_not_present() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[1, 2, 3, 4], &42) -// .expect_err("Should return a Error that the root was not found"), -// LadderError::RootNotFound -// ); -// } - -// #[test] -// fn test_cx_ladder_error() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[6, 1, 2, 3], &0) -// .expect_err( -// "Should return an error that the nodes are not part of the architecture" -// ), -// LadderError::NodesNotFound(vec![6]) -// ); -// } - -// #[test] -// fn test_simple_constructor() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); -// } - -// #[test] -// fn test_cx_ladder_line_setup() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!( -// new_architecture.get_cx_ladder(&[0, 1, 2, 3], &0).unwrap(), -// vec![(0, 1), (1, 2), (2, 3)] -// ); -// } - -// #[test] -// fn test_cx_ladder_extended_triangle() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[0, 1, 2, 4, 5], &1) -// .unwrap() -// .len(), -// 4 -// ); -// } - -// #[test] -// fn test_cx_ladder_weighted_extended_triangle() { -// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[0, 1, 2, 4, 5], &1) -// .unwrap(), -// vec![(1, 2), (2, 3), (3, 5), (3, 4), (5, 0)] -// ); -// } - -// #[test] -// fn test_cx_ladder_small_triangle() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[2, 3, 4], &2) -// .unwrap() -// .len(), -// 2 -// ); -// assert_eq!( -// new_architecture -// .get_cx_ladder(&[2, 3, 4], &4) -// .unwrap() -// .len(), -// 2 -// ); -// } - -// #[test] -// fn test_cx_ladder_weighted_small_triangle() { -// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); -// assert_eq!( -// new_architecture.get_cx_ladder(&[2, 3, 4], &2).unwrap(), -// vec![(2, 3), (3, 4)] -// ); -// assert_eq!( -// new_architecture.get_cx_ladder(&[2, 3, 4], &4).unwrap(), -// vec![(4, 3), (3, 2)] -// ); -// } - -// #[test] -// fn test_weighted_constructor() { -// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); -// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); -// } - -// #[test] -// fn test_best_simple_path() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); - -// assert_eq!(vec![0, 1, 2, 4], new_architecture.best_path(0, 4)); -// } - -// #[test] -// fn test_best_weighted_path() { -// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); - -// assert_eq!(vec![0, 1, 2, 3, 4], new_architecture.best_path(0, 4)); -// } - -// #[test] -// #[should_panic = "architecture does not contain node 6"] -// fn test_best_path_missing() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// new_architecture.best_path(5, 6); -// } - -// #[test] -// fn test_distance() { -// let new_architecture = Connectivity::from_weighted_edges(&setup_weighted()); -// assert_eq!(2, new_architecture.distance(2, 4)); -// assert_eq!(2, new_architecture.distance(4, 2)); -// assert_eq!(10, new_architecture.distance(0, 4)); -// } - -// #[test] -// #[should_panic = "architecture does not contain node 6"] -// fn test_distance_missing() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// new_architecture.distance(5, 6); -// } - -// #[test] -// fn test_neighbors() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!(vec![4, 3, 1], new_architecture.neighbors(2)); -// } - -// #[test] -// #[should_panic = "architecture does not contain node 7"] -// fn test_neighbor_missing() { -// let new_architecture = Connectivity::from_edges(&setup_simple()); -// new_architecture.distance(2, 7); -// } - -// #[test] -// fn test_non_cutting() { -// let mut new_architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!(&new_architecture.nodes(), new_architecture.non_cutting()); -// } - -// #[test] -// fn test_non_cutting_line() { -// let mut line_architecture = Connectivity::line(5); -// assert_eq!(*line_architecture.non_cutting(), vec![0, 4]); -// } - -// #[test] -// fn test_non_cutting_grid() { -// let mut line_architecture = Connectivity::grid(3, 3); -// assert_eq!( -// *line_architecture.non_cutting(), -// vec![0, 1, 2, 3, 4, 5, 6, 7, 8] -// ); -// } - -// #[test] -// fn test_non_cutting_complete() { -// let mut line_architecture = Connectivity::complete(3); -// assert_eq!(*line_architecture.non_cutting(), vec![0, 1, 2]); -// } - -// #[test] -// fn test_remove_node() { -// let mut architecture = Connectivity::from_edges(&setup_simple()); -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); - -// assert_eq!( -// architecture.edges(), -// vec![ -// (0, 1), -// (0, 5), -// (1, 2), -// (1, 5), -// (2, 3), -// (2, 4), -// (3, 4), -// (3, 5), -// (4, 5), -// ] -// ); - -// architecture.remove_node(1); - -// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5]); - -// assert_eq!( -// architecture.edges(), -// vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] -// ); -// } - -// #[test] -// fn test_remove_node_line() { -// let mut architecture = Connectivity::line(5); -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); - -// assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); - -// architecture.remove_node(1); - -// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4]); - -// assert_eq!(architecture.edges(), vec![(2, 3), (3, 4)]); -// } - -// #[test] -// fn test_remove_node_grid() { -// let mut architecture = Connectivity::grid(3, 3); -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); - -// assert_eq!( -// architecture.edges(), -// vec![ -// (0, 3), -// (0, 1), -// (1, 4), -// (1, 2), -// (2, 5), -// (3, 6), -// (3, 4), -// (4, 7), -// (4, 5), -// (5, 8), -// (6, 7), -// (7, 8) -// ] -// ); - -// architecture.remove_node(1); - -// assert_eq!(architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); - -// assert_eq!( -// architecture.edges(), -// vec![ -// (0, 3), -// (2, 5), -// (3, 6), -// (3, 4), -// (4, 7), -// (4, 5), -// (5, 8), -// (6, 7), -// (7, 8), -// ] -// ); -// } - -// #[test] -// fn test_disconnect() { -// let architecture = Connectivity::from_edges(&setup_simple()); -// let new_architecture = architecture.disconnect(1); - -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5]); - -// assert_eq!( -// architecture.edges(), -// vec![ -// (0, 1), -// (0, 5), -// (1, 2), -// (1, 5), -// (2, 3), -// (2, 4), -// (3, 4), -// (3, 5), -// (4, 5), -// ] -// ); - -// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5]); - -// assert_eq!( -// new_architecture.edges(), -// vec![(0, 5), (2, 3), (2, 4), (3, 4), (3, 5), (4, 5)] -// ); -// } - -// #[test] -// fn test_disconnect_line() { -// let architecture = Connectivity::line(5); -// let new_architecture = architecture.disconnect(1); - -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4]); - -// assert_eq!(architecture.edges(), vec![(0, 1), (1, 2), (2, 3), (3, 4)]); - -// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4]); - -// assert_eq!(new_architecture.edges(), vec![(2, 3), (3, 4)]); -// } - -// #[test] -// fn test_disconnect_grid() { -// let architecture = Connectivity::grid(3, 3); -// let new_architecture = architecture.disconnect(1); - -// assert_eq!(architecture.nodes(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]); - -// assert_eq!( -// architecture.edges(), -// vec![ -// (0, 3), -// (0, 1), -// (1, 4), -// (1, 2), -// (2, 5), -// (3, 6), -// (3, 4), -// (4, 7), -// (4, 5), -// (5, 8), -// (6, 7), -// (7, 8) -// ] -// ); - -// assert_eq!(new_architecture.nodes(), vec![0, 2, 3, 4, 5, 6, 7, 8]); - -// assert_eq!( -// new_architecture.edges(), -// vec![ -// (0, 3), -// (2, 5), -// (3, 6), -// (3, 4), -// (4, 7), -// (4, 5), -// (5, 8), -// (6, 7), -// (7, 8) -// ] -// ); -// } - -// #[test] -// fn test_disconnected_cx_ladder() { -// let architecture = Connectivity::from_weighted_edges(&setup_weighted()); -// let new_architecture = architecture.disconnect(3); - -// assert_eq!(new_architecture.nodes(), vec![0, 1, 2, 4, 5]); - -// assert_eq!( -// new_architecture.edges(), -// vec![(0, 1), (0, 5), (1, 2), (1, 5), (2, 4), (4, 5)] -// ); - -// assert_eq!( -// new_architecture.get_cx_ladder(&[1, 2, 4, 5], &2).unwrap(), -// vec![(2, 4), (2, 1), (1, 5)] -// ); -// } -// } + let new_architecture = new_architecture.disconnect(2); + + assert_eq!(new_architecture.nodes(), vec![0, 1, 4, 5]); + + assert_eq!( + new_architecture.edges(), + vec![(0, 1), (0, 5), (1, 5), (4, 5)] + ); + + assert_eq!( + new_architecture.get_cx_ladder(&[1, 4, 5], &1).unwrap(), + vec![(1, 5), (5, 4)] + ); + } +} \ No newline at end of file From 6d1522f74630ad94c029532d35c1cdcbfabe65a4 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 3 Jul 2025 12:03:13 +0200 Subject: [PATCH 26/27] Format connectivity --- src/architecture/connectivity.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/architecture/connectivity.rs b/src/architecture/connectivity.rs index 1fbc6197..2efef0c3 100644 --- a/src/architecture/connectivity.rs +++ b/src/architecture/connectivity.rs @@ -32,7 +32,7 @@ pub struct Connectivity { impl Connectivity { pub fn new(num_qubits: usize) -> Self { let graph = StableUnGraph::with_capacity(num_qubits, 0); - + Connectivity { graph, non_cutting: Default::default(), @@ -232,7 +232,13 @@ impl Architecture for Connectivity { let root_node = tree .node_references() - .find_map(|(item, _)| if item.index() == *root { Some(item) } else { None }) + .find_map(|(item, _)| { + if item.index() == *root { + Some(item) + } else { + None + } + }) .ok_or(LadderError::RootNotFound)?; let mut bfs = Bfs::new(&tree, root_node); @@ -244,10 +250,7 @@ impl Architecture for Connectivity { for neighbor in tree.neighbors(node) { if !visited.is_visited(&neighbor) { visited.visit(neighbor); - edge_list.push(( - self.graph.to_index(node), - self.graph.to_index(neighbor), - )); + edge_list.push((self.graph.to_index(node), self.graph.to_index(neighbor))); } } } @@ -256,15 +259,7 @@ impl Architecture for Connectivity { fn disconnect(&self, i: GraphIndex) -> Connectivity { let mut graph = self.graph.clone(); - graph.retain_nodes( - |_, index| { - if index.index() == i { - false - } else { - true - } - } - ); + graph.retain_nodes(|_, index| if index.index() == i { false } else { true }); let non_cutting = get_non_cutting_vertices(&graph); let (distance, prev) = floyd_warshall_path(&graph, |e| *e.weight()).unwrap(); let distance = distance.iter().map(|(k, v)| (*k, *v)).collect(); @@ -726,4 +721,4 @@ mod tests { vec![(1, 5), (5, 4)] ); } -} \ No newline at end of file +} From 0f0441a6ae28320f638174a65ba1f3e7024108c2 Mon Sep 17 00:00:00 2001 From: Keefe Huang Date: Thu, 3 Jul 2025 12:07:40 +0200 Subject: [PATCH 27/27] Update Cargo.toml to use https --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea31f1f8..ec99d7e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -348,7 +348,7 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "petgraph" version = "0.8.2" -source = "git+ssh://github.com/keefehuang/petgraph#1cdbae4cecd2fb6591697eb8cba3d2c9a76c438e" +source = "git+https://github.com/keefehuang/petgraph#1cdbae4cecd2fb6591697eb8cba3d2c9a76c438e" dependencies = [ "fixedbitset", "hashbrown", diff --git a/Cargo.toml b/Cargo.toml index 6b8c4cf6..48a3ae9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ path = "src/lib.rs" [dependencies] bitvec = "1.0.1" itertools = "0.13.0" -petgraph = { version = "0.8.2", features = ["stable_graph"], git = "ssh://github.com/keefehuang/petgraph" } +petgraph = { version = "0.8.2", features = ["stable_graph"], git = "https://github.com/keefehuang/petgraph" } typenum = "1.17.0" [dev-dependencies]