diff --git a/.editorconfig b/.editorconfig index a54d21c..0e311ce 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,3 @@ [*] indent_style = tab -indent_size = 4 +indent_size = 4 \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 14b4770..795817c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,9 @@ jobs: - name: Run Tests with Valgrind run: | touch results - valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/dijkstra-shortest-path >> results - valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/serialization-example >> results - valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/edmonds-karp-maximum-flow >> results - valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/prim-minimum-spanning-tree >> results - valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/kojarasu-strongly-connected-components >> results - [ -s ./results ] && (cat ./results && exit -1) || echo "No leaks detected" \ No newline at end of file + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/dijkstras_shortest_path >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/serde_example >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/edmonds_karps_maximum_flow >> results + valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/prim_minimum_spanning_tree >> results + # valgrind --leak-check=full --track-origins=yes -q ./target/debug/examples/kojarasus_strongly_connected_components >> results + [ -s ./results ] && (cat ./results && exit -1) || echo "No leaks detected" diff --git a/.gitignore b/.gitignore index e184e68..9314977 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target trash -notes.md \ No newline at end of file +notes.md +*.dot \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 3d75568..2466f3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "getrandom", @@ -14,13 +14,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -37,23 +52,11 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "cast" @@ -67,28 +70,66 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" -version = "2.34.0" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "bitflags", + "clap_lex", + "indexmap", "textwrap", - "unicode-width", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", ] [[package]] name = "criterion" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", + "ciborium", "clap", "criterion-plot", - "csv", "itertools", "lazy_static", "num-traits", @@ -97,7 +138,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -106,9 +146,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -116,9 +156,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -126,9 +166,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -137,73 +177,59 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", - "once_cell", ] [[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" +name = "either" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] -name = "either" -version = "1.8.0" +name = "fixedbitset" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "gdsl" -version = "0.2.0" +version = "0.2.1" dependencies = [ "ahash", "criterion", + "once_cell", + "petgraph", "rand", + "rayon", "serde", "serde_cbor", "serde_json", + "thiserror", ] [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -216,6 +242,12 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -226,31 +258,41 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.10.3" +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "either", + "autocfg", + "hashbrown", ] [[package]] -name = "itoa" -version = "0.4.8" +name = "itertools" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -263,18 +305,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" @@ -284,9 +323,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -302,19 +341,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.2", "libc", ] [[package]] name = "once_cell" -version = "1.14.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oorandom" @@ -322,11 +361,27 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "os_str_bytes" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "plotters" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", @@ -337,39 +392,39 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -397,30 +452,28 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rayon" -version = "1.5.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -430,30 +483,38 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -472,9 +533,12 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.144" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "bd51c3db8f9500d531e6c12dd0fd4ad13d133e9117f5aebac3cdbb8b6d9824b0" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_cbor" @@ -488,9 +552,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "27738cfea0d944ab72c3ed01f3d5f23ec4322af8a1431e40ce630e4c01ea74fd" dependencies = [ "proc-macro2", "quote", @@ -499,20 +563,20 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ - "itoa 1.0.3", + "itoa", "ryu", "serde", ] [[package]] name = "syn" -version = "1.0.99" +version = "2.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "36ccaf716a23c35ff908f91c971a86a9a71af5998c1d8f10e828d9f55f68ac00" dependencies = [ "proc-macro2", "quote", @@ -521,11 +585,28 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.11.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thiserror" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ - "unicode-width", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -540,15 +621,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "version_check" @@ -558,12 +633,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -575,9 +649,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -585,9 +659,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", @@ -600,9 +674,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -610,9 +684,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", @@ -623,15 +697,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 602deee..19e36c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gdsl" -version = "0.2.0" +version = "0.2.1" edition = "2021" readme = "README.md" license = "MIT/Apache-2.0" @@ -20,13 +20,20 @@ categories = ["data-structures", "algorithms", "mathematics", "science"] [dependencies] ahash = "0.8.0" serde = "1.0.144" +thiserror = "1.0.43" [dev-dependencies] -rand = "0.8.4" -criterion = "0.3.6" +rand = "0.8.5" +criterion = "0.4.0" serde_json = "1.0.85" serde_cbor = "0.11.2" +petgraph = "0.6.2" +once_cell = "1.8.0" +rayon = "1.5.3" [[bench]] name = "graph_benchmark" harness = false + +[profile.release] +debug = true diff --git a/README.md b/README.md index 903881a..96dacbf 100644 --- a/README.md +++ b/README.md @@ -243,12 +243,12 @@ let g = digraph![ g['A'].set(0); // In order to perform a dijkstra's we can use the priority first search or -// `pfs` for short. We determine a source node create a `PFS` search-object +// `pfs` for short. We determine a source node create a `Pfs` search-object // by calling the `pfs()` method on the node. // // If we find a shorter distance to a node we are traversing, we need to // update the distance of the node. We do this by using the `for_each()` method -// on the PFS search object. The `for_each()` method takes a closure as argument +// on the Pfs search object. The `for_each()` method takes a closure as argument // and calls it for each edge that is traversed. This way we can manipulate // the distance of the node. based on the edge that is traversed. // @@ -283,4 +283,4 @@ assert!(g['E'].take() == 21); me@juliuskoskela.dev [crates]: https://img.shields.io/crates/v/gdsl -[license]: https://img.shields.io/apm/l/vim-mode \ No newline at end of file +[license]: https://img.shields.io/apm/l/vim-mode diff --git a/benches/graph_benchmark.rs b/benches/graph_benchmark.rs index 7f9f1e3..d13fd13 100644 --- a/benches/graph_benchmark.rs +++ b/benches/graph_benchmark.rs @@ -1,29 +1,28 @@ use criterion::Throughput; -use criterion::{criterion_group, criterion_main, black_box, BenchmarkId, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; mod test_graphs; use test_graphs::*; +mod page_rank; +use page_rank::*; // ============================================================================ fn digraph_creation(c: &mut Criterion) { let b = 1000; - let mut group = c.benchmark_group("digraph creation"); - for (i, size) in [b] - .iter() - .enumerate() - { - group.throughput(Throughput::Elements(*size as u64)); + let mut group = c.benchmark_group("digraph creation"); + for (i, size) in [b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); group.bench_with_input(BenchmarkId::new("graph", size), &i, |b, _| { - b.iter(|| { - black_box(create_graph_simple_1(*size, size / 10)); + b.iter(|| { + black_box(create_digraph_simple_1(*size, size / 10)); }) }); - group.bench_with_input(BenchmarkId::new("vec", size), &i, |b, _| { - b.iter(|| { - black_box(create_graph_vec_distance_1(*size)); + group.bench_with_input(BenchmarkId::new("vec", size), &i, |b, _| { + b.iter(|| { + black_box(create_graph_vec_distance_1(*size)); }) }); } @@ -33,34 +32,55 @@ fn digraph_creation(c: &mut Criterion) { fn digraph_dfs(c: &mut Criterion) { let b = 1000; - let mut group = c.benchmark_group("digraph dfs"); - for (i, size) in [b, 2 * b, 4 * b] - .iter() - .enumerate() - { - group.throughput(Throughput::Elements(*size as u64)); - let g = create_graph_simple_1(*size, size / 10); + let mut group = c.benchmark_group("digraph dfs"); + for (i, size) in [b, 2 * b, 4 * b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); + let g = create_digraph_simple_1(*size, size / 10); + let sg = create_sync_digraph_simple_1(*size, size / 10); group.bench_with_input(BenchmarkId::new("find", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - let t = &g[rand::random::() % g.len()]; - black_box(s.dfs().target(t.key()).search()); + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + let t = &g[rand::random::() % g.len()]; + black_box(s.dfs().target(t.key()).search()); }) }); - group.bench_with_input(BenchmarkId::new("path", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - let t = &g[rand::random::() % g.len()]; - black_box(s.dfs().target(t.key()).search_path()); + group.bench_with_input(BenchmarkId::new("path", size), &i, |b, _| { + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + let t = &g[rand::random::() % g.len()]; + black_box(s.dfs().target(t.key()).search_path()); }) }); - group.bench_with_input(BenchmarkId::new("cycle", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - black_box(s.dfs().search_cycle()); + group.bench_with_input(BenchmarkId::new("cycle", size), &i, |b, _| { + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + black_box(s.dfs().search_cycle()); + }) + }); + + group.bench_with_input(BenchmarkId::new("sync find", size), &i, |b, _| { + b.iter(|| { + let s = &sg[rand::random::() % g.len()]; + let t = &sg[rand::random::() % g.len()]; + black_box(s.dfs().target(t.key()).search()); + }) + }); + + group.bench_with_input(BenchmarkId::new("sync path", size), &i, |b, _| { + b.iter(|| { + let s = &sg[rand::random::() % g.len()]; + let t = &sg[rand::random::() % g.len()]; + black_box(s.dfs().target(t.key()).search_path()); + }) + }); + + group.bench_with_input(BenchmarkId::new("sync cycle", size), &i, |b, _| { + b.iter(|| { + let s = &sg[rand::random::() % g.len()]; + black_box(s.dfs().search_cycle()); }) }); } @@ -71,34 +91,31 @@ fn digraph_dfs(c: &mut Criterion) { fn digraph_bfs(c: &mut Criterion) { let b = 1000; - let mut group = c.benchmark_group("digraph bfs"); - for (i, size) in [b, 2 * b, 4 * b] - .iter() - .enumerate() - { - group.throughput(Throughput::Elements(*size as u64)); - let g = create_graph_simple_1(*size, size / 10); + let mut group = c.benchmark_group("digraph bfs"); + for (i, size) in [b, 2 * b, 4 * b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); + let g = create_digraph_simple_1(*size, size / 10); group.bench_with_input(BenchmarkId::new("find", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - let t = &g[rand::random::() % g.len()]; - black_box(s.bfs().target(t.key()).search()); + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + let t = &g[rand::random::() % g.len()]; + black_box(s.bfs().target(t.key()).search()); }) }); - group.bench_with_input(BenchmarkId::new("path", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - let t = &g[rand::random::() % g.len()]; - black_box(s.bfs().target(t.key()).search_path()); + group.bench_with_input(BenchmarkId::new("path", size), &i, |b, _| { + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + let t = &g[rand::random::() % g.len()]; + black_box(s.bfs().target(t.key()).search_path()); }) }); - group.bench_with_input(BenchmarkId::new("cycle", size), &i, |b, _| { - b.iter(|| { - let s = &g[rand::random::() % g.len()]; - black_box(s.bfs().search_cycle()); + group.bench_with_input(BenchmarkId::new("cycle", size), &i, |b, _| { + b.iter(|| { + let s = &g[rand::random::() % g.len()]; + black_box(s.bfs().search_cycle()); }) }); } @@ -109,17 +126,14 @@ fn digraph_bfs(c: &mut Criterion) { fn digraph_scc(c: &mut Criterion) { let b = 100; - let mut group = c.benchmark_group("digraph scc"); - for (i, size) in [b, 2 * b, 4 * b, 8 * b, 16 * b] - .iter() - .enumerate() - { - group.throughput(Throughput::Elements(*size as u64)); - let g = create_graph_simple_1(*size, size / 10); + let mut group = c.benchmark_group("digraph scc"); + for (i, size) in [b, 2 * b, 4 * b, 8 * b, 16 * b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); + let g = create_digraph_simple_1(*size, size / 10); group.bench_with_input(BenchmarkId::new("find scc's", size), &i, |b, _| { - b.iter(|| { - black_box(g.scc()); + b.iter(|| { + black_box(g.scc()); }) }); } @@ -128,55 +142,73 @@ fn digraph_scc(c: &mut Criterion) { } fn digraph_serde(c: &mut Criterion) { - use gdsl::digraph::*; - let b = 1000; - - let mut group = c.benchmark_group("digraph serde"); - for (i, size) in [b, 2 * b, 4 * b] - .iter() - .enumerate() - { - group.throughput(Throughput::Elements(*size as u64)); - - let g = create_graph_simple_1(*size, size / 10); - let json = serde_json::to_vec(&g).unwrap(); - let cbor = serde_cbor::to_vec(&g).unwrap(); - - group.bench_with_input(BenchmarkId::new("serialize JSON", size), &i, |b, _| { - b.iter(|| { - black_box(serde_json::to_vec(&g).unwrap()); - }) - }); - - group.bench_with_input(BenchmarkId::new("deserialize JSON", size), &i, |b, _| { - b.iter(|| { - black_box(serde_json::from_slice::>(&json).unwrap()); - }) - }); - - group.bench_with_input(BenchmarkId::new("serialize CBOR", size), &i, |b, _| { - b.iter(|| { - black_box(serde_cbor::to_vec(&g).unwrap()); - }) - }); - - group.bench_with_input(BenchmarkId::new("deserialize CBOR", size), &i, |b, _| { - b.iter(|| { - black_box(serde_cbor::from_slice::>(&cbor).unwrap()); - }) - }); - } - - group.finish(); + use gdsl::digraph::*; + let b = 1000; + + let mut group = c.benchmark_group("digraph serde"); + for (i, size) in [b, 2 * b, 4 * b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); + + let g = create_digraph_simple_1(*size, size / 10); + let json = serde_json::to_vec(&g).unwrap(); + let cbor = serde_cbor::to_vec(&g).unwrap(); + + group.bench_with_input(BenchmarkId::new("serialize JSON", size), &i, |b, _| { + b.iter(|| { + black_box(serde_json::to_vec(&g).unwrap()); + }) + }); + + group.bench_with_input(BenchmarkId::new("deserialize JSON", size), &i, |b, _| { + b.iter(|| { + black_box(serde_json::from_slice::>(&json).unwrap()); + }) + }); + + group.bench_with_input(BenchmarkId::new("serialize CBOR", size), &i, |b, _| { + b.iter(|| { + black_box(serde_cbor::to_vec(&g).unwrap()); + }) + }); + + group.bench_with_input(BenchmarkId::new("deserialize CBOR", size), &i, |b, _| { + b.iter(|| { + black_box(serde_cbor::from_slice::>(&cbor).unwrap()); + }) + }); + } + + group.finish(); } +fn digraph_page_rank(c: &mut Criterion) { + let b = 10_000; + let α = 0.85; + let ε = 0.0001; + + let mut group = c.benchmark_group("digraph PageRank"); + for (i, size) in [b, 2 * b, 4 * b].iter().enumerate() { + group.throughput(Throughput::Elements(*size as u64)); + + let g = create_page_rank_dataset(*size, 60, 0, 1000); + + group.bench_with_input(BenchmarkId::new("PageRank", size), &i, |b, _| { + b.iter(|| { + black_box(page_rank(&g, α, ε)); + }) + }); + } + + group.finish(); +} criterion_group!( benches, - digraph_creation, - digraph_dfs, - digraph_bfs, - digraph_scc, - digraph_serde + digraph_creation, + digraph_dfs, + digraph_bfs, + digraph_scc, + digraph_serde, + digraph_page_rank ); criterion_main!(benches); diff --git a/benches/page_rank.rs b/benches/page_rank.rs new file mode 100644 index 0000000..e14aa6a --- /dev/null +++ b/benches/page_rank.rs @@ -0,0 +1,60 @@ +#![allow(non_snake_case)] +use gdsl::digraph::*; +use gdsl::{digraph_connect as connect, digraph_node as node}; +use std::cell::Cell; +use std::rc::Rc; + +type N = Node, Rc>>; +type G = Vec; + +pub fn page_rank(g: &G, α: f64, ε: f64) { + let inverse = 1.0 / g.len() as f64; + for node in g { + let sum = node.iter_out().map(|e| e.value().get()).sum::(); + for Edge(_, _, e) in node { + e.set(e.get() / sum); + } + node.set(inverse); + } + let mut Δ = 1.0; + let mut nodes = vec![0.0; g.len()]; + while Δ > ε { + let mut leak = 0.0; + for u in g.iter() { + nodes[*u.key()] = u.get(); + if u.out_degree() == 0 { + leak += u.get(); + } + u.set(0.0); + } + leak *= α; + for u in g { + for Edge(_, v, e) in u { + v.set(v.get() + α * nodes[*u.key()] * e.get()); + } + u.set(u.get() + (1.0 - α) * inverse + leak * inverse); + } + + Δ = g.iter().map(|u| (u.get() - nodes[*u.key()]).abs()).sum(); + nodes.iter_mut().for_each(|x| *x = 0.0); + } +} + +pub fn create_page_rank_dataset(size: usize, avg_dgr: usize, min_dgr: usize, max_dgr: usize) -> G { + let mut g = Vec::with_capacity(size); + for i in 0..size { + g.push(node!(i, Cell::new(0.0))); + } + for u in g.iter() { + // Generate a random numer from a distribution over [min_dgr, max_dgr] with + // an average of avg_dgr. + let dgr = (min_dgr as f64 + + (max_dgr - min_dgr) as f64 * (avg_dgr as f64 / max_dgr as f64).ln().exp()) + .round() as usize; + for _ in 0..dgr { + let v = g[rand::random::() % size].clone(); + connect!(u => &v, Rc::new(Cell::new(1.0))); + } + } + g +} diff --git a/benches/test_graphs.rs b/benches/test_graphs.rs index b81acc6..e70788d 100644 --- a/benches/test_graphs.rs +++ b/benches/test_graphs.rs @@ -1,41 +1,56 @@ +use gdsl::*; use std::cell::Cell; use std::cmp::{max, min}; -use gdsl::digraph::*; -use gdsl::{ - digraph_node as node, - digraph_connect as connect, -}; +use gdsl::{digraph_connect as connect, digraph_node as node}; -pub fn create_graph_vec_distance_1(size: usize) -> Vec, usize>> { +pub fn create_graph_vec_distance_1(size: usize) -> Vec, usize>> { let mut g = Vec::new(); for i in 0..size { g.push(node!(i, Cell::new(usize::MAX))); } - for (i, node) in g.iter().enumerate() { - let neighbour_count = i % 8 + 3; - let j_from = max(0, i - neighbour_count / 2); - let j_to = min(size, j_from + neighbour_count); - for j in j_from..j_to { - connect!(&node => &g[j], (i + 3) % 10); - } - } + for (i, node) in g.iter().enumerate() { + let neighbour_count = i % 8 + 3; + let j_from = max(0, i - neighbour_count / 2); + let j_to = min(size, j_from + neighbour_count); + for j in j_from..j_to { + connect!(&node => &g[j], (i + 3) % 10); + } + } g } -pub fn create_graph_simple_1(size: usize, avg_dgr: usize) -> Graph { - let mut g = Graph::new(); +pub fn create_digraph_simple_1(size: usize, avg_dgr: usize) -> digraph::Graph { + let mut g = digraph::Graph::new(); + + for i in 0..size { + g.insert(node!(i, ())); + } - for i in 0..size { - g.insert(node!(i, ())); - } + for (_, node) in g.iter() { + for _ in 0..avg_dgr { + connect!(&node => &g[rand::random::() % size], ()); + } + } + g +} - for (_, node) in g.iter() { - for _ in 0..avg_dgr { - connect!(&node => &g[rand::random::() % size], ()); - } - } - g +pub fn create_sync_digraph_simple_1( + size: usize, + avg_dgr: usize, +) -> sync_digraph::Graph { + let mut g = sync_digraph::Graph::new(); + + for i in 0..size { + g.insert(sync_digraph_node!(i, ())); + } + + for (_, node) in g.iter() { + for _ in 0..avg_dgr { + sync_digraph_connect!(&node => &g[rand::random::() % size], ()); + } + } + g } diff --git a/examples/dijkstra-shortest-path.rs b/examples/dijkstra-shortest-path.rs deleted file mode 100644 index 5672d63..0000000 --- a/examples/dijkstra-shortest-path.rs +++ /dev/null @@ -1,70 +0,0 @@ -// # Dijkstra's Shortest Path Algorithm -// -// This example demonstrates how to implement dijkstra's shortest path algorithm -// using `gdsl`. -// -// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm - -use gdsl::*; -use gdsl::digraph::*; -use std::cell::Cell; - -fn main() { - - // We create a directed graph using the `digraph![]` macro. In the macro - // invocation we specify the type of the nodes and the type of the edges - // by specifying the type-signature `(NodeKey, NodeValue) => [EdgeValue]`. - // - // The `NodeKey` type is used to identify the nodes in the graph. The - // `NodeValue` type is used to store the value of the node. The `EdgeValue` - // type is used to store the value of the edge. - // - // In this example the node stores the distance to the source node of the - // search. The edge stores the weight of the edge. The distance is wrapped - // in a `Cell` to allow for mutable access. We initialize the distance to - // `std::u64::MAX` to indicate that the node is not part of the shortest - // path. - let g = digraph![ - (char, Cell) => [u64] - ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] - ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] - ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] - ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] - ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] - ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] - ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] - ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] - ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] - ]; - - // In order to find the shortest path we need to specify the source node and - // set its distance to 0. - g['A'].set(0); - - // In order to perform a dijkstra's we can use the priority first search or - // `pfs` for short. We determine a source node create a `PFS` search-object - // by calling the `pfs()` method on the node. - // - // If we find a shorter distance to a node we are traversing, we need to - // update the distance of the node. We do this by using the `for_each()` method - // on the PFS search object. The `for_each()` method takes a closure as argument - // and calls it for each edge that is traversed. This way we can manipulate - // the distance of the node. based on the edge that is traversed. - // - // The search-object evaluates lazily. This means that the search is only - // executed when calling either `search()` or `search_path()`. - g['A'].pfs().for_each(&mut |Edge(u, v, e)| { - // Since we are using a `Cell` to store the distance we use `get()` to - // read the distance values. - let (u_dist, v_dist) = (u.get(), v.get()); - - // Now we check if the distance stored in the node `v` is smaller than - // the distance stored in the node `u` + the length (weight) of the - // edge `e`. If this is the case we update the distance stored in the - // node `v`. - if v_dist > u_dist + e { v.set(u_dist + e); } - }).search(); - - // We expect that the distance to the node `E` is 21. - assert!(g['E'].take() == 21); -} diff --git a/examples/dijkstras_shortest_path.rs b/examples/dijkstras_shortest_path.rs new file mode 100644 index 0000000..d061b3d --- /dev/null +++ b/examples/dijkstras_shortest_path.rs @@ -0,0 +1,82 @@ +// # Dijkstra's Shortest Path Algorithm +// +// This example demonstrates how to implement dijkstra's shortest path algorithm +// using `gdsl`. +// +// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + +use gdsl::ungraph::*; +use gdsl::*; +use std::cell::Cell; + +fn main() { + // We create a directed graph using the `digraph![]` macro. In the macro + // invocation we specify the type of the nodes and the type of the edges + // by specifying the type-signature `(NodeKey, NodeValue) => [EdgeValue]`. + // + // The `NodeKey` type is used to identify the nodes in the graph. The + // `NodeValue` type is used to store the value of the node. The `EdgeValue` + // type is used to store the value of the edge. + // + // In this example the node stores the distance to the source node of the + // search. The edge stores the weight of the edge. The distance is wrapped + // in a `Cell` to allow for mutable access. We initialize the distance to + // `std::u64::MAX` to indicate that the node is not part of the shortest + // path. + let g = ungraph![ + (char, Cell) => [u64] + ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] + ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] + ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] + ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] + ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] + ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] + ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] + ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] + ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] + ]; + // https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/ + + // In order to find the shortest path we need to specify the source node and + // set its distance to 0. + g['A'].set(0); + + // In order to perform a dijkstra's we can use the priority first search or + // `pfs` for short. We determine a source node create a `Pfs` search-object + // by calling the `pfs()` method on the node. + // + // If we find a shorter distance to a node we are traversing, we need to + // update the distance of the node. We do this by using the `for_each()` method + // on the Pfs search object. The `for_each()` method takes a closure as argument + // and calls it for each edge that is traversed. This way we can manipulate + // the distance of the node. based on the edge that is traversed. + // + // The search-object evaluates lazily. This means that the search is only + // executed when calling either `search()` or `search_path()`. + g['A'] + .pfs() + .for_each(&mut |Edge(u, v, e)| { + // Since we are using a `Cell` to store the distance we use `get()` to + // read the distance values. + let (u_dist, v_dist) = (u.get(), v.get()); + + // Now we check if the distance stored in the node `v` is smaller than + // the distance stored in the node `u` + the length (weight) of the + // edge `e`. If this is the case we update the distance stored in the + // node `v`. + if v_dist > u_dist + e { + v.set(u_dist + e); + } + }) + .search(); + + assert!(g['A'].get() == 0); + assert!(g['B'].get() == 4); + assert!(g['C'].get() == 12); + assert!(g['D'].get() == 19); + assert!(g['E'].get() == 21); + assert!(g['F'].get() == 11); + assert!(g['G'].get() == 9); + assert!(g['H'].get() == 8); + assert!(g['I'].get() == 14); +} diff --git a/examples/dot-printing-example.rs b/examples/dot-printing-example.rs deleted file mode 100644 index bd34e19..0000000 --- a/examples/dot-printing-example.rs +++ /dev/null @@ -1,62 +0,0 @@ -// use gdsl::digraph::*; -use gdsl::*; -use std::cell::Cell; - -fn attr(field: &str, value: &str) -> (String, String) { - (field.to_string(), value.to_string()) -} - -pub const THEME: [&str; 5] = [ - "#ffffff", // 0. background - "#ffe5a9", // 1. medium - "#423f3b", // 2. dark - "#ff6666", // 3. accent - "#525266", // 4. theme -]; - -fn main() { - let g = digraph![ - (usize, Cell) => [f64] - (0, Cell::new(false)) => [(1, 0.1), (2, 0.4), (3, 0.8)] - (1, Cell::new(false)) => [(3, 0.16), (4, 0.32)] - (2, Cell::new(false)) => [(4, 0.64)] - (3, Cell::new(false)) => [(2, 0.12), (0, 0.24)] - (4, Cell::new(false)) => [] - ]; - - g[0].bfs() - .target(&4) - .search_path() - .unwrap() - .iter_nodes() - .for_each(|n| n.set(true)); - - let dot_str = g.to_dot_with_attr( - &|graph| { - let graph_size_mb = graph.sizeof() as f64 / 1024.0 / 1024.0; - Some(vec![ - attr("bgcolor", THEME[0]), - attr("fontcolor", THEME[4]), - attr("label", &format!("Shortest Path {:.4} Mb", graph_size_mb)), - ]) - }, - &|node| { - let color = if node.get() { THEME[3] } else { THEME[4] }; - Some(vec![ - attr("color", color), - attr("fontcolor", THEME[4]), - attr("label", &format!("{}", node.key())), - ]) - }, - &|u, v, edge| { - let color = if u.get() && v.get() { THEME[3] } else { THEME[4] }; - Some(vec![ - attr("fontcolor", THEME[4]), - attr("weight", &edge.to_string()), - attr("color", color), - ]) - } - ); - - println!("{}", dot_str); -} diff --git a/examples/dot_printing_example.rs b/examples/dot_printing_example.rs new file mode 100644 index 0000000..3a46ec6 --- /dev/null +++ b/examples/dot_printing_example.rs @@ -0,0 +1,66 @@ +// use gdsl::digraph::*; +use gdsl::*; +use std::cell::Cell; + +fn attr(field: &str, value: &str) -> (String, String) { + (field.to_string(), value.to_string()) +} + +pub const THEME: [&str; 5] = [ + "#ffffff", // 0. background + "#ffe5a9", // 1. medium + "#423f3b", // 2. dark + "#ff6666", // 3. accent + "#525266", // 4. theme +]; + +fn main() { + let g = digraph![ + (usize, Cell) => [f64] + (0, Cell::new(false)) => [(1, 0.1), (2, 0.4), (3, 0.8)] + (1, Cell::new(false)) => [(3, 0.16), (4, 0.32)] + (2, Cell::new(false)) => [(4, 0.64)] + (3, Cell::new(false)) => [(2, 0.12), (0, 0.24)] + (4, Cell::new(false)) => [] + ]; + + g[0].bfs() + .target(&4) + .search_path() + .unwrap() + .iter_nodes() + .for_each(|n| n.set(true)); + + let dot_str = g.to_dot_with_attr( + &|graph| { + let graph_size_mb = graph.sizeof() as f64 / 1024.0 / 1024.0; + Some(vec![ + attr("bgcolor", THEME[0]), + attr("fontcolor", THEME[4]), + attr("label", &format!("Shortest Path {:.4} Mb", graph_size_mb)), + ]) + }, + &|node| { + let color = if node.get() { THEME[3] } else { THEME[4] }; + Some(vec![ + attr("color", color), + attr("fontcolor", THEME[4]), + attr("label", &format!("{}", node.key())), + ]) + }, + &|u, v, edge| { + let color = if u.get() && v.get() { + THEME[3] + } else { + THEME[4] + }; + Some(vec![ + attr("fontcolor", THEME[4]), + attr("weight", &edge.to_string()), + attr("color", color), + ]) + }, + ); + + println!("{}", dot_str); +} diff --git a/examples/edmonds-karp-maximum-flow.rs b/examples/edmonds-karp-maximum-flow.rs deleted file mode 100644 index 31eaadb..0000000 --- a/examples/edmonds-karp-maximum-flow.rs +++ /dev/null @@ -1,121 +0,0 @@ -// # Edmonds–Karp algorithm for maximum flow. -// -// https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm -// -// An algorithm for finding a maximum flow in a flow network. - -use gdsl::{ - digraph_node as node, - digraph_connect as connect, - digraph::*, -}; - -use std::rc::{Weak, Rc}; -use std::cell::Cell; - -type N = Node; -type G = Graph; - -#[derive(Clone, Copy)] -struct Flow(u64, u64); - -#[derive(Clone)] -struct FlowEdge(Rc>, Weak>); - -impl FlowEdge { - - // Connect two nodes with a flow. - fn connect(s: &N, t: &N, max: u64) { - - // Create a forward and a reverse flow. - let mut fflow = FlowEdge(Rc::new(Cell::new(Flow(max, 0))), Weak::new()); - let mut rflow = FlowEdge(Rc::new(Cell::new(Flow(max, max))), Weak::new()); - - // Cross-connect the flows. - fflow.1 = Rc::downgrade(&rflow.0); - rflow.1 = Rc::downgrade(&fflow.0); - - // Connect the flows to the nodes. - connect!(s => t, fflow); - connect!(t => s, rflow); - } - - // Update flow with the augmenting flow. - fn update(&self, aug_flow: u64) { - - // Decompose the flow parameters. - let (fflow, rflow) = (&self.0, &self.1.upgrade().unwrap()); - let Flow (fmax, fcur) = fflow.get(); - let Flow (rmax, rcur) = rflow.get(); - - // Increase the flow in the forward direction and decrease - // the flow in the reverse direction. - fflow.set(Flow (fmax, fcur + aug_flow)); - rflow.set(Flow (rmax, rcur - aug_flow)); - } - - // Get the max flow. - fn max(&self) -> u64 { self.0.get().0 } - - // Get the current flow. - fn cur(&self) -> u64 { self.0.get().1 } -} - -fn max_flow(g: &G) -> u64 { - - // 1. We loop breadth-first until there is no more paths to explore. - let mut max_flow: u64 = 0; - - while let Some(path) = g[0] - .dfs() - .target(&5) - // 2. We exclude saturated edges from the search. - .filter(&mut |Edge(_, _, e)| e.cur() < e.max()) - .search_path() - { - let mut aug_flow = std::u64::MAX; - - // 3. We find the minimum augmenting flow along the path. - for Edge(_, _, flow) in path.iter_edges() { - if flow.max() - flow.cur() < aug_flow { - aug_flow = flow.max() - flow.cur(); - } - } - - // 4. We update the flow along the path. - for Edge(_, _, flow) in path.iter_edges() { - flow.update(aug_flow); - } - - // 5. We update the maximum flow. - max_flow += aug_flow; - } - max_flow -} - -fn main() { - - // Generate an example Graph with a max flow of 23 from 0 to 5. - let mut g = Graph::new(); - - g.insert(node!(0)); - g.insert(node!(1)); - g.insert(node!(2)); - g.insert(node!(3)); - g.insert(node!(4)); - g.insert(node!(5)); - - FlowEdge::connect(&g[0], &g[1], 16); - FlowEdge::connect(&g[0], &g[2], 13); - FlowEdge::connect(&g[1], &g[2], 10); - FlowEdge::connect(&g[1], &g[3], 12); - FlowEdge::connect(&g[2], &g[1], 4); - FlowEdge::connect(&g[2], &g[4], 14); - FlowEdge::connect(&g[3], &g[2], 9); - FlowEdge::connect(&g[3], &g[5], 20); - FlowEdge::connect(&g[4], &g[3], 7); - FlowEdge::connect(&g[4], &g[5], 4); - - // For this Graph we expect the maximum flow from 0 -> 5 to be 23 - assert!(max_flow(&g) == 23); -} \ No newline at end of file diff --git a/examples/edmonds_karps_maximum_flow.rs b/examples/edmonds_karps_maximum_flow.rs new file mode 100644 index 0000000..c1ef4c5 --- /dev/null +++ b/examples/edmonds_karps_maximum_flow.rs @@ -0,0 +1,116 @@ +// # Edmonds–Karp algorithm for maximum flow. +// +// https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm +// +// An algorithm for finding a maximum flow in a flow network. + +use gdsl::{digraph::*, digraph_connect as connect, digraph_node as node}; + +use std::cell::Cell; +use std::rc::{Rc, Weak}; + +type N = Node; +type G = Graph; + +#[derive(Clone, Copy)] +struct Flow(u64, u64); + +#[derive(Clone)] +struct FlowEdge(Rc>, Weak>); + +impl FlowEdge { + // Connect two nodes with a flow. + fn connect(s: &N, t: &N, max: u64) { + // Create a forward and a reverse flow. + let mut fflow = FlowEdge(Rc::new(Cell::new(Flow(max, 0))), Weak::new()); + let mut rflow = FlowEdge(Rc::new(Cell::new(Flow(max, max))), Weak::new()); + + // Cross-connect the flows. + fflow.1 = Rc::downgrade(&rflow.0); + rflow.1 = Rc::downgrade(&fflow.0); + + // Connect the flows to the nodes. + connect!(s => t, fflow); + connect!(t => s, rflow); + } + + // Update flow with the augmenting flow. + fn update(&self, aug_flow: u64) { + // Decompose the flow parameters. + let (fflow, rflow) = (&self.0, &self.1.upgrade().unwrap()); + let Flow(fmax, fcur) = fflow.get(); + let Flow(rmax, rcur) = rflow.get(); + + // Increase the flow in the forward direction and decrease + // the flow in the reverse direction. + fflow.set(Flow(fmax, fcur + aug_flow)); + rflow.set(Flow(rmax, rcur - aug_flow)); + } + + // Get the max flow. + fn max(&self) -> u64 { + self.0.get().0 + } + + // Get the current flow. + fn cur(&self) -> u64 { + self.0.get().1 + } +} + +fn max_flow(g: &G) -> u64 { + // 1. We loop breadth-first until there is no more paths to explore. + let mut max_flow: u64 = 0; + + while let Some(path) = g[0] + .dfs() + .target(&5) + // 2. We exclude saturated edges from the search. + .filter(&mut |Edge(_, _, e)| e.cur() < e.max()) + .search_path() + { + let mut aug_flow = std::u64::MAX; + + // 3. We find the minimum augmenting flow along the path. + for Edge(_, _, flow) in path.iter_edges() { + if flow.max() - flow.cur() < aug_flow { + aug_flow = flow.max() - flow.cur(); + } + } + + // 4. We update the flow along the path. + for Edge(_, _, flow) in path.iter_edges() { + flow.update(aug_flow); + } + + // 5. We update the maximum flow. + max_flow += aug_flow; + } + max_flow +} + +fn main() { + // Generate an example Graph with a max flow of 23 from 0 to 5. + let mut g = Graph::new(); + + g.insert(node!(0)); + g.insert(node!(1)); + g.insert(node!(2)); + g.insert(node!(3)); + g.insert(node!(4)); + g.insert(node!(5)); + + FlowEdge::connect(&g[0], &g[1], 16); + FlowEdge::connect(&g[0], &g[2], 13); + FlowEdge::connect(&g[1], &g[2], 10); + FlowEdge::connect(&g[1], &g[3], 12); + FlowEdge::connect(&g[2], &g[1], 4); + FlowEdge::connect(&g[2], &g[4], 14); + FlowEdge::connect(&g[3], &g[2], 9); + FlowEdge::connect(&g[3], &g[5], 20); + FlowEdge::connect(&g[4], &g[3], 7); + FlowEdge::connect(&g[4], &g[5], 4); + + // For this Graph we expect the maximum flow from 0 -> 5 to be 23 + assert!(max_flow(&g) == 23); +} diff --git a/examples/kojarasu-strongly-connected-components.rs b/examples/kojarasu-strongly-connected-components.rs deleted file mode 100644 index cba2f07..0000000 --- a/examples/kojarasu-strongly-connected-components.rs +++ /dev/null @@ -1,231 +0,0 @@ -// # Kosaraju's algorithm -// -// Kosaraju's algorithm is a linear time algorithm for finding the strongly -// connected components of a graph. -// -// https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm - -use gdsl::{ - digraph as graph, - digraph::* -}; - -use std::collections::HashSet; - -type N = Node; -type G = Vec; - -fn ordering(graph: &G) -> G { - let mut visited = HashSet::new(); - let mut ordering = Vec::new(); - - for next in graph.iter() { - if !visited.contains(next.key()) { - let partition = next - .postorder() - .filter(&mut |Edge(_, v, _)| !visited.contains(v.key())) - .search_nodes(); - for node in &partition { - visited.insert(node.key().clone()); - ordering.push(node.clone()); - } - } - } - ordering -} - -fn kojarasu(graph: &G) -> Vec { - let mut invariant = HashSet::new(); - let mut components = Vec::new(); - let mut ordering = ordering(graph); - - while let Some(node) = ordering.pop() { - if !invariant.contains(node.key()) { - let cycle = node - .dfs() - .transpose() - .filter(&mut |Edge(_, v, _)| !invariant.contains(v.key())) - .search_cycle(); - match cycle { - Some(cycle) => { - let mut cycle = cycle.to_vec_nodes(); - cycle.pop(); - for node in &cycle { - invariant.insert(node.key().clone()); - } - components.push(cycle); - }, - None => { - invariant.insert(node.key().clone()); - components.push(vec![node.clone()]); - }, - } - } - } - components -} - -// ## SCC Example 1 -// -// https://www.programiz.com/dsa/strongly-connected-components -// -// Expected SCC's: -// -// 0: [ 0 1 2 3 ] -// 1: [ 4 5 6 ] -// 2: [ 7 ] -fn ex1() { - let g = graph![ - (usize) - (0) => [1] - (1) => [2] - (2) => [3, 4] - (3) => [0] - (4) => [5] - (5) => [6] - (6) => [4, 7] - (7) => [] - ]; - - let expect = vec![ - vec![0, 1, 2, 3], - vec![4, 5, 6], - vec![7], - ]; - - let mut g = g.to_vec(); - g.sort_by(|a, b| a.key().cmp(&b.key())); - let mut components = kojarasu(&g); - - for (i, component) in components.iter_mut().enumerate() { - component.sort_by(|a, b| a.key().cmp(&b.key())); - let keys = component.iter().map(|node| node.key().clone()).collect::>(); - assert_eq!(keys, expect[i]); - } -} - -// ## SCC Example 2 -// -// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm -// -// Expected SCC's: -// -// 0: [ 8 ] -// 1: [ 4 5 ] -// 2: [ 6 7 ] -// 3: [ 1 2 3 ] -fn ex2() { - let g = graph![ - (usize) - (1) => [2] - (2) => [3] - (3) => [1] - (4) => [2, 3, 5] - (5) => [4, 6] - (6) => [7] - (7) => [6] - (8) => [5, 7, 8] - ]; - - let expect = vec![ - vec![8], - vec![4, 5], - vec![6, 7], - vec![1, 2, 3], - ]; - - let mut g = g.to_vec(); - g.sort_by(|a, b| a.key().cmp(&b.key())); - let mut components = kojarasu(&g); - - for (i, component) in components.iter_mut().enumerate() { - component.sort_by(|a, b| a.key().cmp(&b.key())); - let keys = component.iter().map(|node| node.key().clone()).collect::>(); - assert_eq!(keys, expect[i]); - } -} - -// ## SCC Example 3 -// -// https://iq.opengenus.org/tarjans-algorithm/ -// -// Expected SCC's: -// -// 0: [ 1 2 3 ] -// 1: [ 4 ] -// 2: [ 5 6 7 8 ] -fn ex3() { - let g = graph![ - (usize) - (1) => [3] - (2) => [1] - (3) => [2, 4] - (4) => [5] - (5) => [6] - (6) => [7] - (7) => [8] - (8) => [5] - ]; - - let expect = vec![ - vec![1, 2, 3], - vec![4], - vec![5, 6, 7, 8], - ]; - - let mut g = g.to_vec(); - g.sort_by(|a, b| a.key().cmp(&b.key())); - let mut components = kojarasu(&g); - - for (i, component) in components.iter_mut().enumerate() { - component.sort_by(|a, b| a.key().cmp(&b.key())); - let keys = component.iter().map(|node| node.key().clone()).collect::>(); - assert_eq!(keys, expect[i]); - } -} - -// ## SCC Example 4 -// -// https://www.youtube.com/watch?v=TyWtx7q2D7Y -// -// Expected SCC's: -// -// 0: [ 3 7 ] -// 1: [ 4 5 6 ] -// 2: [ 0 1 2 ] -fn ex4() { - let g = graph![ - (usize) - (0) => [1] - (1) => [2] - (2) => [0] - (3) => [4, 7] - (4) => [5] - (5) => [6, 0] - (6) => [0, 2, 4] - (7) => [3, 5] - ]; - - let expect = vec![ - vec![3, 7], - vec![4, 5, 6], - vec![0, 1, 2], - ]; - - let mut g = g.to_vec(); - g.sort_by(|a, b| a.key().cmp(&b.key())); - let mut components = kojarasu(&g); - - for (i, component) in components.iter_mut().enumerate() { - component.sort_by(|a, b| a.key().cmp(&b.key())); - let keys = component.iter().map(|node| node.key().clone()).collect::>(); - assert_eq!(keys, expect[i]); - } -} - -fn main() { - ex1(); - ex2(); - ex3(); - ex4(); -} diff --git a/examples/kojarasus_strongly_connected_components.rs b/examples/kojarasus_strongly_connected_components.rs new file mode 100644 index 0000000..d2759be --- /dev/null +++ b/examples/kojarasus_strongly_connected_components.rs @@ -0,0 +1,223 @@ +// # Kosaraju's algorithm +// +// Kosaraju's algorithm is a linear time algorithm for finding the strongly +// connected components of a graph. +// +// https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm + +use gdsl::{digraph as graph, digraph::*}; + +use std::collections::HashSet; + +type N = Node; +type G = Vec; + +fn ordering(graph: &G) -> G { + let mut visited = HashSet::new(); + let mut ordering = Vec::new(); + + for next in graph.iter() { + if !visited.contains(next.key()) { + let partition = next + .postorder() + .filter(&mut |Edge(_, v, _)| !visited.contains(v.key())) + .search_nodes(); + for node in &partition { + visited.insert(node.key().clone()); + ordering.push(node.clone()); + } + } + } + ordering +} + +fn kojarasu(graph: &G) -> Vec { + let mut invariant = HashSet::new(); + let mut components = Vec::new(); + let mut ordering = ordering(graph); + + while let Some(node) = ordering.pop() { + if !invariant.contains(node.key()) { + let cycle = node + .dfs() + .transpose() + .filter(&mut |Edge(_, v, _)| !invariant.contains(v.key())) + .search_cycle(); + match cycle { + Some(cycle) => { + let mut cycle = cycle.to_vec_nodes(); + cycle.pop(); + for node in &cycle { + invariant.insert(node.key().clone()); + } + components.push(cycle); + } + None => { + invariant.insert(node.key().clone()); + components.push(vec![node.clone()]); + } + } + } + } + components +} + +// ## SCC Example 1 +// +// https://www.programiz.com/dsa/strongly-connected-components +// +// Expected SCC's: +// +// 0: [ 0 1 2 3 ] +// 1: [ 4 5 6 ] +// 2: [ 7 ] +fn ex1() { + let g = graph![ + (usize) + (0) => [1] + (1) => [2] + (2) => [3, 4] + (3) => [0] + (4) => [5] + (5) => [6] + (6) => [4, 7] + (7) => [] + ]; + + let expect = vec![vec![7], vec![4, 5, 6], vec![0, 1, 2, 3]]; + + let mut g = g.to_vec(); + g.sort_by(|a, b| a.key().cmp(&b.key())); + let mut components = kojarasu(&g); + + for (i, component) in components.iter_mut().enumerate() { + component.sort_by(|a, b| a.key().cmp(&b.key())); + let keys = component + .iter() + .map(|node| node.key().clone()) + .collect::>(); + assert_eq!(keys, expect[i]); + } +} + +// ## SCC Example 2 +// +// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm +// +// Expected SCC's: +// +// 0: [ 8 ] +// 1: [ 4 5 ] +// 2: [ 6 7 ] +// 3: [ 1 2 3 ] +fn ex2() { + let g = graph![ + (usize) + (1) => [2] + (2) => [3] + (3) => [1] + (4) => [2, 3, 5] + (5) => [4, 6] + (6) => [7] + (7) => [6] + (8) => [5, 7, 8] + ]; + + let expect = vec![vec![6, 7], vec![1, 2, 3], vec![8], vec![4, 5]]; + + let mut g = g.to_vec(); + g.sort_by(|a, b| a.key().cmp(&b.key())); + let mut components = kojarasu(&g); + + for (i, component) in components.iter_mut().enumerate() { + component.sort_by(|a, b| a.key().cmp(&b.key())); + let keys = component + .iter() + .map(|node| node.key().clone()) + .collect::>(); + assert_eq!(keys, expect[i]); + } +} + +// ## SCC Example 3 +// +// https://iq.opengenus.org/tarjans-algorithm/ +// +// Expected SCC's: +// +// 0: [ 1 2 3 ] +// 1: [ 4 ] +// 2: [ 5 6 7 8 ] +fn ex3() { + let g = graph![ + (usize) + (1) => [3] + (2) => [1] + (3) => [2, 4] + (4) => [5] + (5) => [6] + (6) => [7] + (7) => [8] + (8) => [5] + ]; + + let expect = vec![vec![5, 6, 7, 8], vec![4], vec![1, 2, 3]]; + + let mut g = g.to_vec(); + g.sort_by(|a, b| a.key().cmp(&b.key())); + let mut components = kojarasu(&g); + + for (i, component) in components.iter_mut().enumerate() { + component.sort_by(|a, b| a.key().cmp(&b.key())); + let keys = component + .iter() + .map(|node| node.key().clone()) + .collect::>(); + assert_eq!(keys, expect[i]); + } +} + +// ## SCC Example 4 +// +// https://www.youtube.com/watch?v=TyWtx7q2D7Y +// +// Expected SCC's: +// +// 0: [ 3 7 ] +// 1: [ 4 5 6 ] +// 2: [ 0 1 2 ] +fn ex4() { + let g = graph![ + (usize) + (0) => [1] + (1) => [2] + (2) => [0] + (3) => [4, 7] + (4) => [5] + (5) => [6, 0] + (6) => [0, 2, 4] + (7) => [3, 5] + ]; + + let expect = vec![vec![0, 1, 2], vec![3, 7], vec![4, 5, 6]]; + + let mut g = g.to_vec(); + g.sort_by(|a, b| a.key().cmp(&b.key())); + let mut components = kojarasu(&g); + + for (i, component) in components.iter_mut().enumerate() { + component.sort_by(|a, b| a.key().cmp(&b.key())); + let keys = component + .iter() + .map(|node| node.key().clone()) + .collect::>(); + assert_eq!(keys, expect[i]); + } +} + +fn main() { + ex1(); + ex2(); + ex3(); + ex4(); +} diff --git a/examples/page_rank.rs b/examples/page_rank.rs new file mode 100644 index 0000000..54a760d --- /dev/null +++ b/examples/page_rank.rs @@ -0,0 +1,202 @@ +#![allow(non_snake_case)] +/// # PageRank algorithm +/// +/// The algorithm calculates the page rank for each node and stores it in the +/// node itself. +/// +/// Methodology derived from https://github.com/alixaxel/pagerank +use gdsl::digraph::*; +use gdsl::{digraph_connect as connect, digraph_node as node}; +use std::cell::Cell; +use std::fs::File; +use std::io::Write; +use std::rc::Rc; + +/// Types definitions for the graph and nodes. +type N = Node, Rc>>; +type G = Vec; + +/// PageRank algorithm takes in a graph `G`, a damping factor `α` and a +/// convergence threshold `ε`. Edges are expected to have non-negative weights. +/// The algorithm calculates the page rank for each node and stores it in the +/// node itself. +/// +/// The PageRank theory holds that an imaginary surfer who is randomly clicking +/// on edges will eventually stop clicking. The probability, at any step, that +/// the person will continue is a damping factor `α`. Various studies have tested +/// different damping factors, but it is generally assumed that the damping +/// factor will be set around 0.85. +pub fn page_rank(g: &G, α: f64, ε: f64) { + let inverse = 1.0 / g.len() as f64; + + // Normalize all edge weights to sum to 1 + for node in g { + let sum = node.iter_out().map(|e| e.value().get()).sum::(); + for Edge(_, _, e) in node { + e.set(e.get() / sum); + } + node.set(inverse); + } + + let mut Δ = 1.0; + + // Iterate until convergence + while Δ > ε { + let mut nodes = vec![0.0; g.len()]; + let mut leak = 0.0; + + for u in g.iter() { + // Save the current rank of the node to a temporary vector. + nodes[*u.key()] = u.get(); + + // If the node has no outgoing edges, add its page rank to the leak. + if u.out_degree() == 0 { + leak += u.get(); + } + u.set(0.0); + } + + leak *= α; + + // Move values from nodes to temporary array + // and calculate the leak. The leak is the + // amount of weight that is not distributed + // to any other node. + for u in g { + for Edge(_, v, e) in u { + v.set(v.get() + α * nodes[*u.key()] * e.get()); + } + u.set(u.get() + (1.0 - α) * inverse + leak * inverse); + } + + // Calculate the change `Δ` in node weights. + Δ = g.iter().map(|u| (u.get() - nodes[*u.key()]).abs()).sum(); + } +} + +pub fn barabasi_albert_random_graph( + size: usize, + degree: usize, +) -> Graph, Rc>> { + let mut g = Graph::new(); + + // Initialize the graph with `degree` empty nodes + for i in 0..degree { + g.insert(node!(i, Cell::new(0.0))); + } + + // Target nodes for new edges + let mut targets = g.to_vec(); + + // List of existing nodes where each node is repeated + // by the number of its incoming edges + let mut repeated_nodes = Vec::new(); + + // Add `size - degree` nodes to the graph + for i in degree..size { + let new_node = node!(i, Cell::new(0.0)); + for node in &targets { + connect!(&new_node => &node, Rc::new(Cell::new(1.0))); + repeated_nodes.push(node.clone()); + repeated_nodes.push(new_node.clone()); + } + g.insert(new_node); + for _ in 0..degree { + let node = &repeated_nodes[rand::random::() % repeated_nodes.len()]; + targets.push(node.clone()); + } + } + g +} + +#[test] +fn test() { + let mut g = graph![ + (usize, Cell) => [Rc>] + (0, Cell::new(0.0)) => [(1, Rc::new(Cell::new(1.0))), (2, Rc::new(Cell::new(2.0)))] + (1, Cell::new(0.0)) => [(2, Rc::new(Cell::new(3.0))), (3, Rc::new(Cell::new(4.0)))] + (2, Cell::new(0.0)) => [(0, Rc::new(Cell::new(5.0)))] + (3, Cell::new(0.0)) => [] + ] + .to_vec(); + + g.sort_by(|l, r| l.key().cmp(r.key())); + + page_rank(&g, 0.85, 0.0001); + + assert!(g[0].get() == 0.3498289767085323); + assert!(g[1].get() == 0.16887946089722788); + assert!(g[2].get() == 0.3295188106005262); + assert!(g[3].get() == 0.1517727517937135); +} + +fn attr(field: &str, value: &str) -> (String, String) { + (field.to_string(), value.to_string()) +} + +pub const THEME: [&str; 5] = [ + //light blue + "#121133", // 0. background + "#ffe5a9", // 1. medium + "#423f3b", // 2. dark + "#cccccc", // 3. font + "#888888", // 4. edge +]; + +fn main() { + let g = barabasi_albert_random_graph(10, 5); + let mut v = g.to_vec(); + page_rank(&v, 0.85, 0.0001); + v.sort_by(|l, r| l.key().cmp(r.key())); + let min = v + .iter() + .map(|n| n.get()) + .min_by(|l, r| l.partial_cmp(r).unwrap()) + .unwrap(); + let max = v + .iter() + .map(|n| n.get()) + .max_by(|l, r| l.partial_cmp(r).unwrap()) + .unwrap(); + + let dot_str = g.to_dot_with_attr( + &|_| { + Some(vec![ + attr("bgcolor", THEME[0]), + attr("fontcolor", THEME[3]), + attr("label", &format!("Page Ranking on a Barabasi Albert Graph")), + ]) + }, + &|node| { + let size = 1.5 * (node.get() - min) / (max - min) + 0.5; + let color = &make_color(node.get(), min, max); + Some(vec![ + attr("color", color), + attr("fontcolor", THEME[3]), + attr("style", "filled"), + attr("width", &format!("{}", size)), + attr("height", &format!("{}", size)), + ]) + }, + &|_, _, edge| { + let color = THEME[4]; + Some(vec![ + attr("weight", &edge.get().to_string()), + attr("color", color), + ]) + }, + ); + + // Write the dot file to disk. + let mut file = File::create("graph.dot").unwrap(); + file.write_all(dot_str.as_bytes()).unwrap(); +} + +fn make_color(value: f64, min: f64, max: f64) -> String { + let hue = 240.0 * (1.0 - (value - min) / (max - min)); + // convert to rgb + let r = (hue.to_radians().cos() * 127.0 + 128.0) as u8; + let g = 0; + let b = (hue.to_radians().sin() * 127.0 + 128.0) as u8; + format!("#{:02x}{:02x}{:02x}", r, g, b) +} diff --git a/examples/prim-minimum-spanning-tree.rs b/examples/prim-minimum-spanning-tree.rs deleted file mode 100644 index c0be344..0000000 --- a/examples/prim-minimum-spanning-tree.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Prim's algorithm -// -// Prim's algorithm (also known as Jarník's algorithm) is a greedy algorithm -// that finds a minimum spanning tree for a weighted undirected graph. This -// means it finds a subset of the edges that forms a tree that includes every -// vertex, where the total weight of all the edges in the tree is minimized. -// The algorithm operates by building this tree one vertex at a time, -// from an arbitrary starting vertex, at each step adding the cheapest possible -// connection from the tree to another vertex. -// -// https://en.wikipedia.org/wiki/Prim%27s_algorithm - -use gdsl::ungraph::*; -use gdsl::*; -use std::collections::{BinaryHeap, HashSet}; -use std::cmp::Reverse; - -type N = Node; -type E = Edge; - -// Standard library's BinaryHeap is a max-heap, so we need to reverse the -// ordering of the edge weights to get a min-heap using the Reverse wrapper. -type Heap = BinaryHeap>; - -fn prim_minimum_spanning_tree(s: &N) -> Vec { - - // We collect the resulting MST edges in to a vector. - let mut mst: Vec = vec![]; - - // We use a HashSet to keep track of the nodes that are in the MST. - let mut in_mst: HashSet = HashSet::new(); - - // We use a BinaryHeap to keep track of all edges sorted by weight. - let mut heap = Heap::new(); - - in_mst.insert(*s.key()); - - // Collect all edges reachable from `s` to a Min Heap. - s.bfs().for_each(&mut |edge| { - heap.push(Reverse(edge.clone())); - }).search(); - - // When we pop from the min heap, we know that the edge is the cheapest - // edge to add to the MST, but we need to make sure that the edge - // connecting to a node that is not already in the MST, otherwise we - // we store the edge and continue to the next iteration. When we find - // an edge that connects to a node that is not in the MST, we add the - // stored edges back to the heap. - let mut tmp: Vec = vec![]; - - // While the heap is not empty, search for the next edge - // that connects a node in the tree to a node not in the tree. - while let Some(Reverse(edge)) = heap.pop() { - let Edge(u, v, _) = edge.clone(); - - // If the edge's source node `u` is in the MST... - if in_mst.contains(u.key()) { - - // ...and the edge's destination node `v` is not in the MST, - // then we add the edge to the MST and add all edges - // in `tmp` back to the heap. - if in_mst.contains(v.key()) == false { - in_mst.insert(*v.key()); - mst.push(edge.clone()); - for tmp_edge in &tmp { - heap.push(Reverse(tmp_edge.clone())); - } - } - } else { - - // The edge is the cheapest edge to add to the MST, but - // it's source node `u` nor it's destination node `v` are - // in the MST, so we store the edge and continue to the next - // iteration. - if in_mst.contains(v.key()) == false { - tmp.push(edge); - } - } - - // If neither condition is met, then the edge's destination node - // `v` is already in the MST, so we continue to the next iteration. - } - mst -} - -fn main() { - // Example g1 from Wikipedia - let g1 = ungraph![ - (usize) => [u64] - (0) => [ (1, 1), (3, 4), (4, 3)] - (1) => [ (3, 4), (4, 2)] - (2) => [ (4, 4), (5, 5)] - (3) => [ (4, 4)] - (4) => [ (5, 7)] - (5) => [] - ]; - let forest = prim_minimum_spanning_tree(&g1[0]); - let sum = forest.iter().fold(0, |acc, e| acc + e.2); - assert!(sum == 16); - - // Example g2 from Figure 7.1 in https://jeffe.cs.illinois.edu/teaching/algorithms/book/07-mst.pdf - let g2 = ungraph![ - (usize) => [u64] - (0) => [ (1, 8), (2, 5)] - (1) => [ (2, 10), (3, 2), (4, 18)] - (2) => [ (3, 3), (5, 16)] - (3) => [ (4, 12), (5, 30)] - (4) => [ (6, 4)] - (5) => [ (6, 26)] - (6) => [] - ]; - let forest = prim_minimum_spanning_tree(&g2[0]); - let sum = forest.iter().fold(0, |acc, e| acc + e.2); - assert!(sum == 42); -} diff --git a/examples/prim_minimum_spanning_tree.rs b/examples/prim_minimum_spanning_tree.rs new file mode 100644 index 0000000..0a04a23 --- /dev/null +++ b/examples/prim_minimum_spanning_tree.rs @@ -0,0 +1,114 @@ +// Prim's algorithm +// +// Prim's algorithm (also known as Jarník's algorithm) is a greedy algorithm +// that finds a minimum spanning tree for a weighted undirected graph. This +// means it finds a subset of the edges that forms a tree that includes every +// vertex, where the total weight of all the edges in the tree is minimized. +// The algorithm operates by building this tree one vertex at a time, +// from an arbitrary starting vertex, at each step adding the cheapest possible +// connection from the tree to another vertex. +// +// https://en.wikipedia.org/wiki/Prim%27s_algorithm + +use gdsl::ungraph::*; +use gdsl::*; +use std::cmp::Reverse; +use std::collections::{BinaryHeap, HashSet}; + +type N = Node; +type E = Edge; + +// Standard library's BinaryHeap is a max-heap, so we need to reverse the +// ordering of the edge weights to get a min-heap using the Reverse wrapper. +type Heap = BinaryHeap>; + +fn prim_minimum_spanning_tree(s: &N) -> Vec { + // We collect the resulting MST edges in to a vector. + let mut mst: Vec = vec![]; + + // We use a HashSet to keep track of the nodes that are in the MST. + let mut in_mst: HashSet = HashSet::new(); + + // We use a BinaryHeap to keep track of all edges sorted by weight. + let mut heap = Heap::new(); + + in_mst.insert(*s.key()); + + // Collect all edges reachable from `s` to a Min Heap. + s.bfs() + .for_each(&mut |edge| { + heap.push(Reverse(edge.clone())); + }) + .search(); + + // When we pop from the min heap, we know that the edge is the cheapest + // edge to add to the MST, but we need to make sure that the edge + // connecting to a node that is not already in the MST, otherwise we + // we store the edge and continue to the next iteration. When we find + // an edge that connects to a node that is not in the MST, we add the + // stored edges back to the heap. + let mut tmp: Vec = vec![]; + + // While the heap is not empty, search for the next edge + // that connects a node in the tree to a node not in the tree. + while let Some(Reverse(edge)) = heap.pop() { + let Edge(u, v, _) = edge.clone(); + + // If the edge's source node `u` is in the MST... + if in_mst.contains(u.key()) { + // ...and the edge's destination node `v` is not in the MST, + // then we add the edge to the MST and add all edges + // in `tmp` back to the heap. + if in_mst.contains(v.key()) == false { + in_mst.insert(*v.key()); + mst.push(edge.clone()); + for tmp_edge in &tmp { + heap.push(Reverse(tmp_edge.clone())); + } + } + } else { + // The edge is the cheapest edge to add to the MST, but + // it's source node `u` nor it's destination node `v` are + // in the MST, so we store the edge and continue to the next + // iteration. + if in_mst.contains(v.key()) == false { + tmp.push(edge); + } + } + + // If neither condition is met, then the edge's destination node + // `v` is already in the MST, so we continue to the next iteration. + } + mst +} + +fn main() { + // Example g1 from Wikipedia + let g1 = ungraph![ + (usize) => [u64] + (0) => [ (1, 1), (3, 4), (4, 3) ] + (1) => [ (3, 4), (4, 2) ] + (2) => [ (4, 4), (5, 5) ] + (3) => [ (4, 4) ] + (4) => [ (5, 7) ] + (5) => [] + ]; + let forest = prim_minimum_spanning_tree(&g1[0]); + let sum = forest.iter().fold(0, |acc, e| acc + e.2); + assert!(sum == 16); + + // Example g2 from Figure 7.1 in https://jeffe.cs.illinois.edu/teaching/algorithms/book/07-mst.pdf + let g2 = ungraph![ + (usize) => [u64] + (0) => [ (1, 8), (2, 5) ] + (1) => [ (2, 10), (3, 2), (4, 18) ] + (2) => [ (3, 3), (5, 16) ] + (3) => [ (4, 12), (5, 30) ] + (4) => [ (6, 4) ] + (5) => [ (6, 26) ] + (6) => [] + ]; + let forest = prim_minimum_spanning_tree(&g2[0]); + let sum = forest.iter().fold(0, |acc, e| acc + e.2); + assert!(sum == 42); +} diff --git a/examples/serde_example.rs b/examples/serde_example.rs new file mode 100644 index 0000000..86ca28b --- /dev/null +++ b/examples/serde_example.rs @@ -0,0 +1,43 @@ +// Graph structures implement serialization and deserialization using serde. +// This allows you to serialize and deserialize graphs to and from +// JSON and CBOR as well as other formats. The following example shows how +// to serialize and deserialize a graph to JSON and CBOR and illustrate's +// the difference in the final size of the serialized data. + +use gdsl::{digraph::*, *}; + +fn main() { + let graph = digraph![ + (&str) => [i32] + ("A") => [("B", 42), ("C", 42)] + ("B") => [("C", 42)] + ("C") => [("D", 42)] + ("D") => [] + ]; + + let cbor = serde_cbor::to_vec(&graph).unwrap(); + let json = serde_json::to_vec(&graph).unwrap(); + + // CBOR's binary representation result's in a smaller size than JSON's + assert!(cbor.len() == 47); + assert!(json.len() == 101); + + let graph_cbor: Graph<&str, (), i32> = serde_cbor::from_slice(&cbor).unwrap(); + let graph_json: Graph<&str, (), i32> = serde_json::from_slice(&json).unwrap(); + + // Since the `Graph` container is a HashMap with a non-deterministic + // order, we need to sort the nodes before comparing them. + let mut graph_cbor_vec = graph_cbor.to_vec(); + let mut graph_json_vec = graph_json.to_vec(); + graph_cbor_vec.sort_by(|a, b| a.key().cmp(b.key())); + graph_json_vec.sort_by(|a, b| a.key().cmp(b.key())); + + for (a, b) in graph_cbor_vec.iter().zip(graph_json_vec.iter()) { + assert!(a == b); + for (Edge(u, v, e), Edge(uu, vv, ee)) in a.iter_out().zip(b.iter_out()) { + assert!(u == uu); + assert!(v == vv); + assert!(e == ee); + } + } +} diff --git a/examples/serialization-example.rs b/examples/serialization-example.rs deleted file mode 100644 index 66ce052..0000000 --- a/examples/serialization-example.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Graph structures implement serialization and deserialization using serde. -// This allows you to serialize and deserialize graphs to and from -// JSON and CBOR as well as other formats. The following example shows how -// to serialize and deserialize a graph to JSON and CBOR and illustrate's -// the difference in the final size of the serialized data. - -use gdsl::{*, digraph::*}; - -fn main() { - let graph = digraph![ - (&str) => [i32] - ("A") => [("B", 42), ("C", 42)] - ("B") => [("C", 42)] - ("C") => [("D", 42)] - ("D") => [] - ]; - - let cbor = serde_cbor::to_vec(&graph).unwrap(); - let json = serde_json::to_vec(&graph).unwrap(); - - // CBOR's binary representation result's in a smaller size than JSON's - assert!(cbor.len() == 47); - assert!(json.len() == 101); - - let graph_cbor: Graph<&str, (), i32> = serde_cbor::from_slice(&cbor).unwrap(); - let graph_json: Graph<&str, (), i32> = serde_json::from_slice(&json).unwrap(); - - // Since the `Graph` container is a HashMap with a non-deterministic - // order, we need to sort the nodes before comparing them. - let mut graph_cbor_vec = graph_cbor.to_vec(); - let mut graph_json_vec = graph_json.to_vec(); - graph_cbor_vec.sort_by(|a, b| a.key().cmp(b.key())); - graph_json_vec.sort_by(|a, b| a.key().cmp(b.key())); - - for (a, b) in graph_cbor_vec.iter().zip(graph_json_vec.iter()) { - assert!(a == b); - for (Edge(u, v, e), Edge(uu, vv, ee)) in a.iter_out().zip(b.iter_out()) { - assert!(u == uu); - assert!(v == vv); - assert!(e == ee); - } - } -} \ No newline at end of file diff --git a/src/digraph/graph_macros.rs b/src/digraph/graph_macros.rs index 9add024..2087000 100644 --- a/src/digraph/graph_macros.rs +++ b/src/digraph/graph_macros.rs @@ -3,46 +3,35 @@ /// Macro for creating a node. #[macro_export] macro_rules! digraph_node { + // graph::Node + ( $key:expr ) => {{ + use gdsl::digraph::*; - // graph::Node - ( $key:expr ) => { - { - use gdsl::digraph::*; - - Node::new($key, ()) - } - }; - - // graph::Node - ( $key:expr, $param:expr ) => { - { - use gdsl::digraph::*; + Node::new($key, ()) + }}; - Node::new($key, $param) - } - }; + // graph::Node + ( $key:expr, $param:expr ) => {{ + use gdsl::digraph::*; + Node::new($key, $param) + }}; } /// Macro for connecting two nodes. #[macro_export] macro_rules! digraph_connect { + ( $s:expr => $t:expr ) => {{ + use gdsl::digraph::*; - ( $s:expr => $t:expr ) => { - { - use gdsl::digraph::*; - - Node::connect($s, $t, ()) - } - }; + Node::connect($s, $t, ()) + }}; - ( $s:expr => $t:expr, $params:expr ) => { - { - use gdsl::digraph::*; + ( $s:expr => $t:expr, $params:expr ) => {{ + use gdsl::digraph::*; - Node::connect($s, $t, $params) - } - }; + Node::connect($s, $t, $params) + }}; } /// Macro for creating a graph. diff --git a/src/digraph/graph_serde.rs b/src/digraph/graph_serde.rs index f6b4956..444d7d8 100644 --- a/src/digraph/graph_serde.rs +++ b/src/digraph/graph_serde.rs @@ -1,111 +1,123 @@ +use super::*; use serde::{ - Deserialize, - ser::{Serialize, Serializer, SerializeTuple}, - de::{self, Visitor}, + de::{self, Visitor}, + ser::{Serialize, SerializeTuple, Serializer}, + Deserialize, }; -use super::*; -fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) +type GraphDecomp = (Vec<(K, N)>, Vec<(K, K, E)>); + +fn graph_serde_decompose(g: &Graph) -> GraphDecomp where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - let mut nodes = Vec::new(); - let mut edges = Vec::new(); + let mut nodes = Vec::new(); + let mut edges = Vec::new(); - for (_, n) in g.iter() { - nodes.push((n.key().clone(), n.value().clone())); + for (_, n) in g.iter() { + nodes.push((n.key().clone(), n.value().clone())); - for Edge(u, v, e) in n { - edges.push((u.key().clone(), v.key().clone(), e)); - } - } - (nodes, edges) + for Edge(u, v, e) in n { + edges.push((u.key().clone(), v.key().clone(), e)); + } + } + (nodes, edges) } impl Serialize for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tuple = serializer.serialize_tuple(2)?; - let (nodes, edges) = graph_serde_decompose(self); - tuple.serialize_element(&nodes)?; - tuple.serialize_element(&edges)?; - tuple.end() - } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(2)?; + let (nodes, edges) = graph_serde_decompose(self); + tuple.serialize_element(&nodes)?; + tuple.serialize_element(&edges)?; + tuple.end() + } } impl<'de, K, N, E> Deserialize<'de> for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, - { - _phantom: std::marker::PhantomData<(K, N, E)>, - } - - impl<'de, K, N, E> Visitor<'de> for GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, - { - type Value = Graph; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("node and edge lists") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de> - { - let mut nodes = Vec::new(); - let mut edges: Vec<(K, K, E)> = Vec::new(); - - if let Some(node_seq) = seq.next_element()? { - nodes = node_seq; - } - - if let Some(edge_seq) = seq.next_element()? { - edges = edge_seq; - } - - let mut g = Graph::new(); - - for (k, v) in nodes { - g.insert(Node::new(k, v)); - } - - for (u, v, e) in edges { - let un = g.get(&u).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, u)))?; - let vn = g.get(&v).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, v)))?; - Node::connect(&un, &vn, e); - } - - Ok(g) - } - } - - deserializer.deserialize_seq(GraphVisitor { - _phantom: std::marker::PhantomData, - }) - } -} \ No newline at end of file + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, + { + _phantom: std::marker::PhantomData<(K, N, E)>, + } + + impl<'de, K, N, E> Visitor<'de> for GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, + { + type Value = Graph; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("node and edge lists") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut nodes = Vec::new(); + let mut edges: Vec<(K, K, E)> = Vec::new(); + + if let Some(node_seq) = seq.next_element()? { + nodes = node_seq; + } + + if let Some(edge_seq) = seq.next_element()? { + edges = edge_seq; + } + + let mut g = Graph::new(); + + for (k, v) in nodes { + g.insert(Node::new(k, v)); + } + + for (u, v, e) in edges { + let un = g.get(&u).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, u + )) + })?; + let vn = g.get(&v).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, v + )) + })?; + Node::connect(&un, &vn, e); + } + + Ok(g) + } + } + + deserializer.deserialize_seq(GraphVisitor { + _phantom: std::marker::PhantomData, + }) + } +} diff --git a/src/digraph/mod.rs b/src/digraph/mod.rs index ef93484..a42c5d4 100644 --- a/src/digraph/mod.rs +++ b/src/digraph/mod.rs @@ -27,13 +27,13 @@ //! g[1].connect(&g[3], ()); //! g[2].connect(&g[4], ()); //! g[3].connect(&g[2], ()); -//! g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle +//! g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle //! -//! let cycle = g[0] // We start at node 0 -//! .bfs() // We use a breadth-first search -//! .search_cycle() // We search for a cycle -//! .unwrap() // Returns `Option>` -//! .to_vec_nodes(); // Path is converted to a vector of nodes +//! let cycle = g[0] // We start at node 0 +//! .bfs() // We use a breadth-first search +//! .search_cycle() // We search for a cycle +//! .unwrap() // Returns `Option>` +//! .to_vec_nodes(); // Path is converted to a vector of nodes //! //! assert!(cycle[0] == g[0]); //! assert!(cycle[1] == g[3]); @@ -46,7 +46,10 @@ mod node; pub use crate::digraph::node::*; use ahash::{AHashMap as HashMap, AHashSet as HashSet}; -use std::{fmt::Display, hash::Hash}; +use std::{ + fmt::{Display, Write}, + hash::Hash, +}; /// A directed graph containing nodes and edges. The graph is represented as a /// map of nodes, where each node is identified by a unique key. Each node @@ -62,7 +65,7 @@ where nodes: HashMap>, } -impl<'a, K, N, E> Graph +impl Graph where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, @@ -83,6 +86,21 @@ where } } + /// Create a new Graph with a given capacity + /// + /// # Examples + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::with_capacity(42); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + nodes: HashMap::with_capacity(capacity), + } + } + /// Check if a node with the given key exists in the Graph /// /// # Examples @@ -138,7 +156,7 @@ where /// assert!(node.key() == &"A"); /// ``` pub fn get(&self, key: &K) -> Option> { - self.nodes.get(key).map(|node| node.clone()) + self.nodes.get(key).cloned() } /// Check if Graph is empty @@ -219,7 +237,7 @@ where /// assert!(nodes.len() == 3); /// ``` pub fn to_vec(&self) -> Vec> { - self.nodes.values().map(|node| node.clone()).collect() + self.nodes.values().cloned().collect() } /// Collect roots into a vector @@ -247,7 +265,7 @@ where self.nodes .values() .filter(|node| node.is_root()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -275,7 +293,7 @@ where self.nodes .values() .filter(|node| node.is_leaf()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -303,7 +321,7 @@ where self.nodes .values() .filter(|node| node.is_orphan()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -328,51 +346,51 @@ where self.nodes.iter() } - /// Find the strongly connected components of the graph. Can be used to - /// find cycles in the graph and for topological sorting. - /// - /// # Examples - /// - /// ``` - /// use gdsl::digraph::*; - /// - /// let mut g: Graph = Graph::new(); - /// - /// g.insert(Node::new(0, ())); - /// g.insert(Node::new(1, ())); - /// g.insert(Node::new(2, ())); - /// g.insert(Node::new(3, ())); - /// g.insert(Node::new(4, ())); - /// g.insert(Node::new(5, ())); - /// g.insert(Node::new(6, ())); - /// g.insert(Node::new(7, ())); - /// g.insert(Node::new(8, ())); - /// g.insert(Node::new(9, ())); - /// - /// g[0].connect(&g[1], ()); // ---- C1 - /// g[1].connect(&g[2], ()); // - /// g[2].connect(&g[0], ()); // - /// g[3].connect(&g[4], ()); // ---- C2 - /// g[4].connect(&g[5], ()); // - /// g[5].connect(&g[3], ()); // - /// g[6].connect(&g[7], ()); // ---- C3 - /// g[7].connect(&g[8], ()); // - /// g[8].connect(&g[6], ()); // - /// g[9].connect(&g[9], ()); // ---- C4 - /// - /// let mut scc = g.scc(); - /// - /// // Since the graph container is a hash map, the order of the SCCs is - /// // not deterministic. We sort the SCCs by their size to make the test - /// // deterministic. - /// scc.sort_by(|a, b| a.len().cmp(&b.len())); - /// - /// assert!(scc.len() == 4); - /// assert!(scc[0].len() == 1); - /// assert!(scc[1].len() == 3); - /// assert!(scc[2].len() == 3); - /// assert!(scc[3].len() == 3); - /// ``` + /// Find the strongly connected components of the graph. Can be used to + /// find cycles in the graph and for topological sorting. + /// + /// # Examples + /// + /// ``` + /// use gdsl::digraph::*; + /// + /// let mut g: Graph = Graph::new(); + /// + /// g.insert(Node::new(0, ())); + /// g.insert(Node::new(1, ())); + /// g.insert(Node::new(2, ())); + /// g.insert(Node::new(3, ())); + /// g.insert(Node::new(4, ())); + /// g.insert(Node::new(5, ())); + /// g.insert(Node::new(6, ())); + /// g.insert(Node::new(7, ())); + /// g.insert(Node::new(8, ())); + /// g.insert(Node::new(9, ())); + /// + /// g[0].connect(&g[1], ()); // ---- C1 + /// g[1].connect(&g[2], ()); // + /// g[2].connect(&g[0], ()); // + /// g[3].connect(&g[4], ()); // ---- C2 + /// g[4].connect(&g[5], ()); // + /// g[5].connect(&g[3], ()); // + /// g[6].connect(&g[7], ()); // ---- C3 + /// g[7].connect(&g[8], ()); // + /// g[8].connect(&g[6], ()); // + /// g[9].connect(&g[9], ()); // ---- C4 + /// + /// let mut scc = g.scc(); + /// + /// // Since the graph container is a hash map, the order of the SCCs is + /// // not deterministic. We sort the SCCs by their size to make the test + /// // deterministic. + /// scc.sort_by(|a, b| a.len().cmp(&b.len())); + /// + /// assert!(scc.len() == 4); + /// assert!(scc[0].len() == 1); + /// assert!(scc[1].len() == 3); + /// assert!(scc[2].len() == 3); + /// assert!(scc[3].len() == 3); + /// ``` pub fn scc(&self) -> Vec>> { let mut invariant = HashSet::new(); let mut components = Vec::new(); @@ -404,7 +422,7 @@ where components } - fn scc_ordering(&self) -> Vec> { + fn scc_ordering(&self) -> Vec> { let mut visited = HashSet::new(); let mut ordering = Vec::new(); @@ -427,20 +445,20 @@ where let mut s = String::new(); s.push_str("digraph {\n"); for (u_key, node) in self.iter() { - s.push_str(&format!(" {}", u_key.clone())); + write!(&mut s, " {}", u_key.clone()).unwrap(); for Edge(_, v, _) in node { - s.push_str(&format!("\n {} -> {}", u_key, v.key())); + write!(&mut s, "\n {} -> {}", u_key, v.key()).unwrap(); } - s.push_str("\n"); + s.push('\n'); } - s.push_str("}"); + s.push('}'); s } fn fmt_attr(attrs: Vec<(String, String)>) -> String { let mut s = String::new(); for (k, v) in attrs { - s.push_str(&format!("[{}=\"{}\"]", k, v)); + write!(&mut s, "[{}=\"{}\"]", k, v).unwrap(); } s } @@ -463,7 +481,7 @@ where if let Some(nattr) = nattr(node) { s.push_str(&format!(" {}", Self::fmt_attr(nattr))); } - s.push_str("\n"); + s.push('\n'); } for (_, node) in self.iter() { for Edge(u, v, e) in node { @@ -471,10 +489,10 @@ where if let Some(eattrs) = eattr(&u, &v, &e) { s.push_str(&format!(" {}", Self::fmt_attr(eattrs))); } - s.push_str("\n"); + s.push('\n'); } } - s.push_str("}"); + s.push('}'); s } @@ -487,7 +505,7 @@ where } } -impl<'a, K, N, E> std::ops::Index for Graph +impl std::ops::Index for Graph where K: Clone + Hash + Display + Eq, N: Clone, @@ -512,3 +530,14 @@ where &self.nodes[key] } } + +impl Default for Graph +where + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, +{ + fn default() -> Self { + Self::new() + } +} diff --git a/src/digraph/node/adjacent.rs b/src/digraph/node/adjacent.rs index c49ff22..0e4ef06 100644 --- a/src/digraph/node/adjacent.rs +++ b/src/digraph/node/adjacent.rs @@ -1,30 +1,36 @@ use super::*; +use crate::error::Error; + +type InnerEdge = (WeakNode, E); +type RefInnerEdge<'a, K, N, E> = (&'a WeakNode, &'a E); +type NodeInner = (K, N, RefCell>); + #[derive(Clone)] pub struct WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - inner: Weak<(K, N, RefCell>)>, + inner: Weak>, } impl WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - pub fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Rc::downgrade(&node.inner) - } - } + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Rc::downgrade(&node.inner), + } + } } pub struct Adjacent @@ -33,8 +39,8 @@ where N: Clone, E: Clone, { - outbound: Vec<(WeakNode, E)>, - inbound: Vec<(WeakNode, E)>, + pub outbound: Vec>, + inbound: Vec>, } impl Adjacent @@ -50,21 +56,15 @@ where }) } - pub fn get_outbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.outbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - } + pub fn get_outbound(&self, idx: usize) -> Option> { + self.outbound.get(idx).map(|edge| (&edge.0, &edge.1)) } - pub fn get_inbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.inbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - } + pub fn get_inbound(&self, idx: usize) -> Option> { + self.inbound.get(idx).map(|edge| (&edge.0, &edge.1)) } - pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + pub fn find_outbound(&self, node: &K) -> Option> { for edge in self.outbound.iter() { if edge.0.upgrade().unwrap().key() == node { return Some((&edge.0, &edge.1)); @@ -73,7 +73,7 @@ where None } - pub fn find_inbound(&self, node: &K) -> Option<(&WeakNode, &E)> { + pub fn find_inbound(&self, node: &K) -> Option> { for edge in self.inbound.iter() { if edge.0.upgrade().unwrap().key() == node { return Some((&edge.0, &edge.1)); @@ -91,29 +91,29 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } - pub fn remove_inbound(&mut self, source: &K) -> Result { - for (idx, edge) in self.inbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == source { - return Ok(self.inbound.remove(idx).1); - } - } - Err(()) + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_outbound(&mut self, target: &K) -> Result { - for (idx, edge) in self.outbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == target { - return Ok(self.outbound.remove(idx).1); - } - } - Err(()) + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } pub fn clear_inbound(&mut self) { @@ -124,10 +124,10 @@ where self.outbound.clear(); } - pub fn sizeof(&self) -> usize { - self.inbound.len() + self.outbound.len() - * (std::mem::size_of::>() - + std::mem::size_of::()) - + std::mem::size_of::() - } -} \ No newline at end of file + pub fn sizeof(&self) -> usize { + self.inbound.len() + + self.outbound.len() + * (std::mem::size_of::>() + std::mem::size_of::()) + + std::mem::size_of::() + } +} diff --git a/src/digraph/node/algo/bfs.rs b/src/digraph/node/algo/bfs.rs index 0d69604..e49d111 100644 --- a/src/digraph/node/algo/bfs.rs +++ b/src/digraph/node/algo/bfs.rs @@ -1,216 +1,214 @@ -use std::{fmt::Display, hash::Hash, collections::VecDeque}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{collections::VecDeque, fmt::Display, hash::Hash}; -pub struct BFS<'a, K, N, E> +pub struct Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, } -impl<'a, K, N, E> BFS<'a, K, N, E> +impl<'a, K, N, E> Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - BFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - return self.loop_outbound_find(&mut visited, &mut queue); - } - Transposition::Inbound => { - return self.loop_inbound_find(&mut visited, &mut queue); - } - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - queue.push_back(self.root.clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.loop_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.loop_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - let target_found; - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.loop_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.loop_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - fn loop_outbound( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_inbound( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_outbound_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let Edge(_, v, _) = edge; - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } - - fn loop_inbound_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let Edge(_, v, _) = edge; - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Bfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => self.loop_outbound_find(&mut visited, &mut queue), + Transposition::Inbound => self.loop_inbound_find(&mut visited, &mut queue), + } + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push_back(self.root.clone()); + + match self.transpose { + Transposition::Outbound => { + match self.loop_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.loop_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => { + match self.loop_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.loop_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + fn loop_outbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v); + } + } + } + } + false + } + + fn loop_inbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v); + } + } + } + } + false + } + + fn loop_outbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v); + } + } + queue.push_back(v); + } + } + } + } + None + } + + fn loop_inbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v); + } + } + queue.push_back(v); + } + } + } + } + None + } +} diff --git a/src/digraph/node/algo/dfs.rs b/src/digraph/node/algo/dfs.rs index c4d16ff..da5c4cc 100644 --- a/src/digraph/node/algo/dfs.rs +++ b/src/digraph/node/algo/dfs.rs @@ -1,226 +1,228 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; -pub struct DFS<'a, K, N, E> +pub struct Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, } -impl<'a, K, N, E> DFS<'a, K, N, E> +impl<'a, K, N, E> Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - DFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - return self.recurse_outbound_find(&mut visited, &mut queue); - } - Transposition::Inbound => { - return self.recurse_inbound_find(&mut visited, &mut queue); - } - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - queue.push(self.root.clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.recurse_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.recurse_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - let target_found; - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.recurse_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.recurse_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - fn recurse_outbound(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_outbound(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_inbound(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_inbound(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_outbound_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_outbound_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } - - fn recurse_inbound_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_inbound_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Dfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => self.recurse_outbound_find(&mut visited, &mut queue), + Transposition::Inbound => self.recurse_inbound_find(&mut visited, &mut queue), + } + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push(self.root.clone()); + + match self.transpose { + Transposition::Outbound => { + match self.recurse_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.recurse_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => { + match self.recurse_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.recurse_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + fn recurse_outbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_outbound(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_inbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_inbound(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_outbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_outbound_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } + + fn recurse_inbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_inbound_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } +} diff --git a/src/digraph/node/algo/method.rs b/src/digraph/node/algo/method.rs index e552875..71a51db 100644 --- a/src/digraph/node/algo/method.rs +++ b/src/digraph/node/algo/method.rs @@ -5,26 +5,29 @@ pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); pub enum Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - NullMethod, - Filter(Filter<'a, K, N, E>), - ForEach(ForEach<'a, K, N, E>), + Empty, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), } impl<'a, K, N, E> Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn exec(&mut self, e: &Edge) -> bool { - match self { - Method::NullMethod => true, - Method::ForEach(f) => {f(e); true}, - Method::Filter(f) => f(e), - } - } -} \ No newline at end of file + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::Empty => true, + Method::ForEach(f) => { + f(e); + true + } + Method::Filter(f) => f(e), + } + } +} diff --git a/src/digraph/node/algo/mod.rs b/src/digraph/node/algo/mod.rs index ad8023c..f5c077d 100644 --- a/src/digraph/node/algo/mod.rs +++ b/src/digraph/node/algo/mod.rs @@ -2,8 +2,8 @@ use super::*; pub mod bfs; pub mod dfs; -pub mod pfs; pub mod order; +pub mod pfs; +mod method; mod path; -mod method; \ No newline at end of file diff --git a/src/digraph/node/algo/order.rs b/src/digraph/node/algo/order.rs index 5bb5a67..7e1f4cb 100644 --- a/src/digraph/node/algo/order.rs +++ b/src/digraph/node/algo/order.rs @@ -1,242 +1,213 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*}; +use super::{method::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; pub enum Ordering { - Pre, - Post, + Pre, + Post, } pub struct Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: &'a Node, - method: Method<'a, K, N, E>, - order: Ordering, - transpose: Transposition, + root: &'a Node, + method: Method<'a, K, N, E>, + order: Ordering, + transpose: Transposition, } - impl<'a, K, N, E> Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn preorder(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Pre, - transpose: Transposition::Outbound, - } - } - - pub fn postroder(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Post, - transpose: Transposition::Outbound, - } - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search_nodes(&mut self) -> Vec> { - let mut nodes = vec![]; - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - match self.order { - Ordering::Pre => { - self.preorder_forward(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.postorder_forward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - }, - Transposition::Inbound => { - match self.order { - Ordering::Pre => { - self.preorder_backward(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.postorder_backward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - }, - } - nodes - } - - pub fn search_edges(&mut self) -> Vec> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - match self.order { - Ordering::Pre => { - self.preorder_forward(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.postorder_forward(&mut edges, &mut visited, &mut queue); - }, - } - }, - Transposition::Inbound => { - match self.order { - Ordering::Pre => { - self.preorder_backward(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.postorder_backward(&mut edges, &mut visited, &mut queue); - }, - } - }, - } - edges - } - - fn preorder_forward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.preorder_forward( - result, - visited, - queue); - } - } - } - } - false - } - - fn preorder_backward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.preorder_forward( - result, - visited, - queue); - } - } - } - } - false - } - - fn postorder_forward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.postorder_forward( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } - - fn postorder_backward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.postorder_forward( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } -} \ No newline at end of file + pub fn preorder(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Pre, + transpose: Transposition::Outbound, + } + } + + pub fn postroder(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Post, + transpose: Transposition::Inbound, + } + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search_nodes(&mut self) -> Vec> { + let mut nodes = vec![]; + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => match self.order { + Ordering::Pre => { + self.preorder_forward(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.postorder_forward(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + }, + Transposition::Inbound => match self.order { + Ordering::Pre => { + self.preorder_backward(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.postorder_backward(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + }, + } + nodes + } + + pub fn search_edges(&mut self) -> Vec> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => match self.order { + Ordering::Pre => { + self.preorder_forward(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.postorder_forward(&mut edges, &mut visited, &mut queue); + } + }, + Transposition::Inbound => match self.order { + Ordering::Pre => { + self.preorder_backward(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.postorder_backward(&mut edges, &mut visited, &mut queue); + } + }, + } + edges + } + + fn preorder_forward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.preorder_forward(result, visited, queue); + } + } + } + false + } + + fn preorder_backward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.preorder_backward(result, visited, queue); + } + } + } + false + } + + fn postorder_forward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.postorder_forward(result, visited, queue); + } + } + } + false + } + + fn postorder_backward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.postorder_backward(result, visited, queue); + } + } + } + false + } +} diff --git a/src/digraph/node/algo/path.rs b/src/digraph/node/algo/path.rs index 6499b8d..21c6ca9 100644 --- a/src/digraph/node/algo/path.rs +++ b/src/digraph/node/algo/path.rs @@ -1,174 +1,176 @@ -use std::{fmt::Display, hash::Hash, ops::Index}; use super::*; +use std::{fmt::Display, hash::Hash, ops::Index}; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - let mut path = Vec::new(); - - if edge_tree.len() == 1 { - path.push(edge_tree[0].clone()); - return path; - } - let w = edge_tree.last().unwrap(); - path.push(w.clone()); - let mut i = 0; - for edge in edge_tree.iter().rev() { - let Edge(_, v, _) = edge; - let Edge(s, _, _) = &path[i]; - if s == v { - path.push(edge.clone()); - i += 1; - } - } - path.reverse(); - path + let mut path = Vec::new(); + + if edge_tree.len() == 1 { + path.push(edge_tree[0].clone()); + return path; + } + let w = edge_tree.last().unwrap(); + path.push(w.clone()); + let mut i = 0; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; + if s == v { + path.push(edge.clone()); + i += 1; + } + } + path.reverse(); + path } pub struct Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub edges: Vec>, + pub edges: Vec>, } impl Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn len(&self) -> usize { - // Conceptually a path always contains at least one node, - // the root node. The path containes edges, so the length - // of the path is the number of edges plus one. - self.edges.len() + 1 - } - - pub fn from_edge_tree(edge_tree: Vec>) -> Path { - Path { edges: backtrack_edge_tree(edge_tree) } - } - - pub fn iter_nodes(&self) -> PathNodeIterator { - PathNodeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn iter_edges(&self) -> PathEdgeIterator { - PathEdgeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn first_edge(&self) -> Option<&Edge> { - self.edges.first() - } - - pub fn first_node(&self) -> Option<&Node> { - self.edges.first().map(|e| &e.1) - } - - pub fn last_edge(&self) -> Option<&Edge> { - self.edges.last() - } - - pub fn last_node(&self) -> Option<&Node> { - self.edges.last().map(|e| &e.1) - } - - pub fn to_vec_nodes(&self) -> Vec> { - self.iter_nodes().map(|v| v).collect() - } - - pub fn to_vec_edges(&self) -> Vec> { - self.edges.clone() - } + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + + pub fn from_edge_tree(edge_tree: Vec>) -> Path { + Path { + edges: backtrack_edge_tree(edge_tree), + } + } + + pub fn iter_nodes(&self) -> PathNodeIterator { + PathNodeIterator { + path: self, + position: 0, + } + } + + pub fn iter_edges(&self) -> PathEdgeIterator { + PathEdgeIterator { + path: self, + position: 0, + } + } + + pub fn first_edge(&self) -> Option<&Edge> { + self.edges.first() + } + + pub fn first_node(&self) -> Option<&Node> { + self.edges.first().map(|e| &e.1) + } + + pub fn last_edge(&self) -> Option<&Edge> { + self.edges.last() + } + + pub fn last_node(&self) -> Option<&Node> { + self.edges.last().map(|e| &e.1) + } + + pub fn to_vec_nodes(&self) -> Vec> { + self.iter_nodes().collect() + } + + pub fn to_vec_edges(&self) -> Vec> { + self.edges.clone() + } } impl Index for Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Output = Edge; + type Output = Edge; - fn index(&self, index: usize) -> &Self::Output { - &self.edges[index] - } + fn index(&self, index: usize) -> &Self::Output { + &self.edges[index] + } } pub struct PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) + } + None => None, + } + } } pub struct PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Node; - - fn next(&mut self) -> Option { - if self.position == 0 { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - return Some(edge.0.clone()); - } - None => return None, - } - } - match self.path.edges.get(self.position - 1) { - Some(edge) => { - self.position += 1; - Some(edge.1.clone()) - } - None => None, - } - } -} \ No newline at end of file + type Item = Node; + + fn next(&mut self) -> Option { + if self.position == 0 { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + return Some(edge.0.clone()); + } + None => return None, + } + } + match self.path.edges.get(self.position - 1) { + Some(edge) => { + self.position += 1; + Some(edge.1.clone()) + } + None => None, + } + } +} diff --git a/src/digraph/node/algo/pfs.rs b/src/digraph/node/algo/pfs.rs index 42f71bf..f4d29af 100644 --- a/src/digraph/node/algo/pfs.rs +++ b/src/digraph/node/algo/pfs.rs @@ -1,276 +1,273 @@ -use std::{ - fmt::Display, - hash::Hash, - collections::BinaryHeap, - cmp::Reverse -}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; - +use std::{cmp::Reverse, collections::BinaryHeap, fmt::Display, hash::Hash}; enum Priority { - Min, - Max + Min, + Max, } -pub struct PFS<'a, K, N, E> +pub struct Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, - priority: Priority, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, + priority: Priority, } -impl<'a, K, N, E> PFS<'a, K, N, E> +impl<'a, K, N, E> Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone + Ord, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone + Ord, + E: Clone, { - pub fn new(root: &Node) -> Self { - PFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - priority: Priority::Min, - } - } + pub fn new(root: &Node) -> Self { + Pfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + priority: Priority::Min, + } + } - pub fn min(mut self) -> Self { - self.priority = Priority::Min; - self - } + pub fn min(mut self) -> Self { + self.priority = Priority::Min; + self + } - pub fn max(mut self) -> Self { - self.priority = Priority::Max; - self - } + pub fn max(mut self) -> Self { + self.priority = Priority::Max; + self + } - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } - fn loop_outbound_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(node) = queue.pop() { - let node = node.0; - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(Reverse(v.clone())); - } - } - } - } - false - } + fn loop_outbound_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(node) = queue.pop() { + let node = node.0; + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(Reverse(v.clone())); + } + } + } + } + false + } - fn loop_inbound_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(node) = queue.pop() { - let node = node.0; - for edge in node.iter_out() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(Reverse(v.clone())); - } - } - } - } - false - } + fn loop_inbound_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(node) = queue.pop() { + let node = node.0; + for edge in node.iter_out() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(Reverse(v.clone())); + } + } + } + } + false + } - fn loop_outbound_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - } - } - } - } - false - } + fn loop_outbound_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + } + } + } + } + false + } - fn loop_inbound_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - } - } - } - } - false - } + fn loop_inbound_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + } + } + } + } + false + } - pub fn search(&mut self) -> Option> { - let path = self.search_path(); - match path { - Some(path) => Some(path.last_node().unwrap().clone()), - None => None, - } - } + pub fn search(&mut self) -> Option> { + self.search_path() + .map(|path| path.last_node().unwrap().clone()) + } - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); - self.target = Some(self.root.key().clone()); + self.target = Some(self.root.key().clone()); - match self.transpose { - Transposition::Outbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - Transposition::Inbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } + match self.transpose { + Transposition::Outbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + Transposition::Inbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + } + } - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); - visited.insert(self.root.key().clone()); + visited.insert(self.root.key().clone()); - match self.transpose { - Transposition::Outbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - Transposition::Inbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } -} \ No newline at end of file + match self.transpose { + Transposition::Outbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + Transposition::Inbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_inbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_inbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + } + } +} diff --git a/src/digraph/node/mod.rs b/src/digraph/node/mod.rs index e2a212c..1aac1ff 100644 --- a/src/digraph/node/mod.rs +++ b/src/digraph/node/mod.rs @@ -34,25 +34,34 @@ mod adjacent; mod algo; -use self::{adjacent::*, algo::{bfs::*, dfs::*, order::*, pfs::*}}; -use std::{cell::RefCell, fmt::Display, hash::Hash, ops::Deref, rc::{Rc, Weak}}; +use crate::error::Error; + +use self::{ + adjacent::*, + algo::{bfs::*, dfs::*, order::*, pfs::*}, +}; +// use anyhow::{anyhow, Result}; +use std::{ + cell::RefCell, + fmt::Display, + hash::Hash, + ops::Deref, + rc::{Rc, Weak}, +}; enum Transposition { - Outbound, - Inbound, + Outbound, + Inbound, } /// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. -#[derive(Clone, PartialEq)] -pub struct Edge( - pub Node, - pub Node, - pub E, -) where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone; +#[derive(Clone)] +pub struct Edge(pub Node, pub Node, pub E) +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; impl Edge where @@ -81,6 +90,47 @@ where } } +impl PartialEq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 && self.1 == other.1 + } +} + +impl Eq for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, +{ +} + +impl PartialOrd for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.2.partial_cmp(&other.2) + } +} + +impl Ord for Edge +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + PartialOrd + Ord, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.2.cmp(&other.2) + } +} + /// A `Node` is a key value pair smart-pointer, which includes inbound /// and outbound connections to other nodes. Nodes can be created individually /// and they don't depend on a graph container. Generic parameters include `K` @@ -114,9 +164,11 @@ where N: Clone, E: Clone, { - inner: Rc<(K, N, RefCell>)>, + inner: NodeInner, } +type NodeInner = Rc<(K, N, RefCell>)>; + impl Node where K: Clone + Hash + PartialEq + Eq + Display, @@ -131,16 +183,16 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, 'A'); + /// let n1 = Node::::new(1, 'A'); /// - /// assert!(*n1.key() == 1); - /// assert!(*n1.value() == 'A'); + /// assert!(*n1.key() == 1); + /// assert!(*n1.value() == 'A'); /// ``` pub fn new(key: K, value: N) -> Self { Node { - inner: Rc::new((key, value, Adjacent::new())), + inner: NodeInner::new((key, value, Adjacent::new())), } } @@ -149,11 +201,11 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, ()); + /// let n1 = Node::::new(1, ()); /// - /// assert!(*n1.key() == 1); + /// assert!(*n1.key() == 1); /// ``` pub fn key(&self) -> &K { &self.inner.0 @@ -164,11 +216,11 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, 'A'); + /// let n1 = Node::::new(1, 'A'); /// - /// assert!(*n1.value() == 'A'); + /// assert!(*n1.value() == 'A'); /// ``` pub fn value(&self) -> &N { &self.inner.1 @@ -225,12 +277,12 @@ where /// ``` /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// n1.connect(&n2, 4.20); + /// n1.connect(&n2, 4.20); /// - /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n2.key())); /// ``` pub fn connect(&self, other: &Self, value: E) { self.inner @@ -253,24 +305,24 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => assert!(n1.is_connected(n2.key())), - /// Err(_) => panic!("n1 should be connected to n2"), - /// } + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => assert!(n1.is_connected(n2.key())), + /// Err(_) => panic!("n1 should be connected to n2"), + /// } /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => panic!("n1 should be connected to n2"), - /// Err(_) => assert!(n1.is_connected(n2.key())), - /// } + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => panic!("n1 should be connected to n2"), + /// Err(_) => assert!(n1.is_connected(n2.key())), + /// } /// ``` - pub fn try_connect(&self, other: &Self, value: E) -> Result<(), E> { + pub fn try_connect(&self, other: &Self, value: E) -> Result<(), Error> { if self.is_connected(other.key()) { - Err(value) + Err(Error::EdgeAlreadyExists) } else { self.connect(other, value); Ok(()) @@ -284,31 +336,31 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// n1.connect(&n2, ()); + /// n1.connect(&n2, ()); /// - /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n2.key())); /// - /// if n1.disconnect(n2.key()).is_err() { - /// panic!("n1 should be connected to n2"); - /// } + /// if n1.disconnect(n2.key()).is_err() { + /// panic!("n1 should be connected to n2"); + /// } /// - /// assert!(!n1.is_connected(n2.key())); + /// assert!(!n1.is_connected(n2.key())); /// ``` - pub fn disconnect(&self, other: &K) -> Result { + pub fn disconnect(&self, other: &K) -> Result { match self.find_outbound(other) { Some(other) => match self.inner.2.borrow_mut().remove_outbound(other.key()) { Ok(edge) => { other.inner.2.borrow_mut().remove_inbound(self.key())?; Ok(edge) } - Err(_) => Err(()), + Err(err) => Err(err), }, - None => Err(()), + None => Err(Error::EdgeNotFound), } } @@ -317,27 +369,27 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// let n4 = Node::new(4, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// let n4 = Node::new(4, ()); /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n1.connect(&n4, ()); - /// n2.connect(&n1, ()); - /// n3.connect(&n1, ()); - /// n4.connect(&n1, ()); + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n1.connect(&n4, ()); + /// n2.connect(&n1, ()); + /// n3.connect(&n1, ()); + /// n4.connect(&n1, ()); /// - /// assert!(n1.is_connected(n2.key())); - /// assert!(n1.is_connected(n3.key())); - /// assert!(n1.is_connected(n4.key())); + /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n3.key())); + /// assert!(n1.is_connected(n4.key())); /// - /// n1.isolate(); + /// n1.isolate(); /// - /// assert!(n1.is_orphan()); + /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { for Edge(_, v, _) in self.iter_out() { @@ -453,12 +505,8 @@ where /// ``` pub fn find_outbound(&self, other: &K) -> Option> { let edge = self.inner.2.borrow(); - let edge = edge.find_outbound(other); - if let Some(edge) = edge { - Some(edge.0.upgrade().unwrap().clone()) - } else { - None - } + let edge = edge.find_outbound(other); + edge.map(|edge| edge.0.upgrade().unwrap()) } /// Get a pointer to an adjacent node with a given key. Returns None if no @@ -483,12 +531,8 @@ where /// ``` pub fn find_inbound(&self, other: &K) -> Option> { let edge = self.inner.2.borrow(); - let edge = edge.find_inbound(other); - if let Some(edge) = edge { - Some(edge.0.upgrade().unwrap().clone()) - } else { - None - } + let edge = edge.find_inbound(other); + edge.map(|edge| edge.0.upgrade().unwrap()) } /// Returns an iterator-like object that can be used to map, filter and @@ -562,10 +606,10 @@ where /// n3.connect(&n1, ()); /// /// let path = n1 - /// .dfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); + /// .dfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); /// /// let mut iter = path.iter_nodes(); /// @@ -573,8 +617,8 @@ where /// assert!(iter.next().unwrap() == n2); /// assert!(iter.next().unwrap() == n3); /// ``` - pub fn dfs(&self) -> DFS { - DFS::new(self) + pub fn dfs(&self) -> Dfs { + Dfs::new(self) } /// Returns an iterator-like object that can be used to map, filter, @@ -595,10 +639,10 @@ where /// n3.connect(&n1, ()); /// /// let path = n1 - /// .bfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); + /// .bfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); /// /// let mut iter = path.iter_nodes(); /// @@ -606,8 +650,8 @@ where /// assert!(iter.next().unwrap() == n2); /// assert!(iter.next().unwrap() == n3); /// ``` - pub fn bfs(&self) -> BFS { - BFS::new(self) + pub fn bfs(&self) -> Bfs { + Bfs::new(self) } /// Returns an iterator-like object that can be used to map, filter, @@ -630,22 +674,22 @@ where /// n3.connect(&n4, ()); /// /// let path = n1 - /// .pfs() - /// .target(&'D') - /// .search_path() - /// .unwrap(); + /// .pfs() + /// .target(&'D') + /// .search_path() + /// .unwrap(); /// /// assert!(path[0] == Edge(n1, n3.clone(), ())); /// assert!(path[1] == Edge(n3, n4, ())); ///``` - pub fn pfs(&self) -> PFS + pub fn pfs(&self) -> Pfs where N: Ord, { - PFS::new(self) + Pfs::new(self) } - /// Returns an iterator over the node's outbound edges. + /// Returns an iterator over the node's outbound edges. /// /// # Example /// @@ -670,7 +714,7 @@ where } } - /// Returns an iterator over the node's inbound edges. + /// Returns an iterator over the node's inbound edges. /// /// # Example /// @@ -714,7 +758,7 @@ where { type Target = N; fn deref(&self) -> &Self::Target { - &self.value() + self.value() } } @@ -744,7 +788,7 @@ where E: Clone, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.value().cmp(&other.value())) + Some(self.value().cmp(other.value())) } } @@ -755,7 +799,7 @@ where E: Clone, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.value().cmp(&other.value()) + self.value().cmp(other.value()) } } @@ -779,18 +823,19 @@ where fn next(&mut self) -> Option { match self.node.inner.2.borrow().get_outbound(self.position) { - Some(current) => { - match current.0.upgrade() { - Some(node) => { - self.position += 1; - Some(Edge(self.node.clone(), node, current.1.clone())) - }, - None => { - panic!("Target node in the adjacency list of `node = {}` has been dropped.", self.node.key()); - } - } - } - None => None, + Some(current) => match current.0.upgrade() { + Some(node) => { + self.position += 1; + Some(Edge(self.node.clone(), node, current.1.clone())) + } + None => { + panic!( + "Target node in the adjacency list of `node = {}` has been dropped.", + self.node.key() + ); + } + }, + None => None, } } } @@ -815,18 +860,19 @@ where fn next(&mut self) -> Option { match self.node.inner.2.borrow().get_inbound(self.position) { - Some(current) => { - match current.0.upgrade() { - Some(node) => { - self.position += 1; - Some(Edge(node, self.node.clone(), current.1.clone())) - }, - None => { - panic!("Target node in the adjacency list of `node = {}` has been dropped.", self.node.key()); - } - } - } - None => None, + Some(current) => match current.0.upgrade() { + Some(node) => { + self.position += 1; + Some(Edge(node, self.node.clone(), current.1.clone())) + } + None => { + panic!( + "Target node in the adjacency list of `node = {}` has been dropped.", + self.node.key() + ); + } + }, + None => None, } } } @@ -846,4 +892,4 @@ where position: 0, } } -} \ No newline at end of file +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..9813a61 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Edge not found")] + EdgeNotFound, + #[error("Connection already exists")] + EdgeAlreadyExists, +} diff --git a/src/lib.rs b/src/lib.rs index 018acbd..22aa792 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,16 +53,16 @@ //! // `std::u64::MAX` to indicate that the node is not part of the shortest //! // path. //! let g = digraph![ -//! (char, Cell) => [u64] -//! ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] -//! ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] -//! ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] -//! ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] -//! ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] -//! ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] -//! ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] -//! ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] -//! ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] +//! (char, Cell) => [u64] +//! ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] +//! ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] +//! ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] +//! ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] +//! ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] +//! ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] +//! ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] +//! ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] +//! ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] //! ]; //! //! // In order to find the shortest path we need to specify the source node and @@ -70,12 +70,12 @@ //! g['A'].set(0); //! //! // In order to perform a dijkstra's we can use the priority first search or -//! // `pfs` for short. We determine a source node create a `PFS` search-object +//! // `pfs` for short. We determine a source node create a `Pfs` search-object //! // by calling the `pfs()` method on the node. //! // //! // If we find a shorter distance to a node we are traversing, we need to //! // update the distance of the node. We do this by using the `map()` method -//! // on the PFS search object. The `map()` method takes a closure as argument +//! // on the Pfs search object. The `map()` method takes a closure as argument //! // and calls it for each edge that is traversed. This way we can manipulate //! // the distance of the node. based on the edge that is traversed. //! // @@ -83,23 +83,25 @@ //! // executed when calling either `search()` or `search_path()`. //! g['A'].pfs().for_each(&mut |Edge(u, v, e)| { //! -//! // Since we are using a `Cell` to store the distance we use `get()` to -//! // read the distance values. -//! let (u_dist, v_dist) = (u.get(), v.get()); +//! // Since we are using a `Cell` to store the distance we use `get()` to +//! // read the distance values. +//! let (u_dist, v_dist) = (u.get(), v.get()); //! -//! // Now we check if the distance stored in the node `v` is smaller than -//! // the distance stored in the node `u` + the length (weight) of the -//! // edge `e`. If this is the case we update the distance stored in the -//! // node `v`. -//! if v_dist > u_dist + e { v.set(u_dist + e); } -//! }).search(); // pfs() is lazy, we need to call search() to execute the -//! // traversal. +//! // Now we check if the distance stored in the node `v` is smaller than +//! // the distance stored in the node `u` + the length (weight) of the +//! // edge `e`. If this is the case we update the distance stored in the +//! // node `v`. +//! if v_dist > u_dist + e { v.set(u_dist + e); } +//! }).search(); // pfs() is lazy, we need to call search() to execute the +//! // traversal. //! //! // We expect that the distance to the node `E` is 21. //! assert!(g['E'].take() == 21); //! ``` +#![allow(clippy::type_complexity)] pub mod digraph; -pub mod ungraph; pub mod sync_digraph; pub mod sync_ungraph; +pub mod ungraph; +pub mod error; diff --git a/src/sync_digraph/graph_macros.rs b/src/sync_digraph/graph_macros.rs index 7428432..f776e4a 100644 --- a/src/sync_digraph/graph_macros.rs +++ b/src/sync_digraph/graph_macros.rs @@ -3,46 +3,35 @@ /// Macro for creating a node. #[macro_export] macro_rules! sync_digraph_node { + // graph::Node + ( $key:expr ) => {{ + use gdsl::sync_digraph::*; - // graph::Node - ( $key:expr ) => { - { - use gdsl::sync_digraph::*; - - Node::new($key, ()) - } - }; - - // graph::Node - ( $key:expr, $param:expr ) => { - { - use gdsl::sync_digraph::*; + Node::new($key, ()) + }}; - Node::new($key, $param) - } - }; + // graph::Node + ( $key:expr, $param:expr ) => {{ + use gdsl::sync_digraph::*; + Node::new($key, $param) + }}; } /// Macro for connecting two nodes. #[macro_export] macro_rules! sync_digraph_connect { + ( $s:expr => $t:expr ) => {{ + use gdsl::sync_digraph::*; - ( $s:expr => $t:expr ) => { - { - use gdsl::sync_digraph::*; - - Node::connect($s, $t, ()) - } - }; + Node::connect($s, $t, ()) + }}; - ( $s:expr => $t:expr, $params:expr ) => { - { - use gdsl::sync_digraph::*; + ( $s:expr => $t:expr, $params:expr ) => {{ + use gdsl::sync_digraph::*; - Node::connect($s, $t, $params) - } - }; + Node::connect($s, $t, $params) + }}; } /// Macro for creating a graph. diff --git a/src/sync_digraph/graph_serde.rs b/src/sync_digraph/graph_serde.rs index f6b4956..b44c7e9 100644 --- a/src/sync_digraph/graph_serde.rs +++ b/src/sync_digraph/graph_serde.rs @@ -1,111 +1,121 @@ +use super::*; use serde::{ - Deserialize, - ser::{Serialize, Serializer, SerializeTuple}, - de::{self, Visitor}, + de::{self, Visitor}, + ser::{Serialize, SerializeTuple, Serializer}, + Deserialize, }; -use super::*; -fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) +fn graph_serde_decompose(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - let mut nodes = Vec::new(); - let mut edges = Vec::new(); + let mut nodes = Vec::new(); + let mut edges = Vec::new(); - for (_, n) in g.iter() { - nodes.push((n.key().clone(), n.value().clone())); + for (_, n) in g.iter() { + nodes.push((n.key().clone(), n.value().clone())); - for Edge(u, v, e) in n { - edges.push((u.key().clone(), v.key().clone(), e)); - } - } - (nodes, edges) + for Edge(u, v, e) in n { + edges.push((u.key().clone(), v.key().clone(), e)); + } + } + (nodes, edges) } impl Serialize for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tuple = serializer.serialize_tuple(2)?; - let (nodes, edges) = graph_serde_decompose(self); - tuple.serialize_element(&nodes)?; - tuple.serialize_element(&edges)?; - tuple.end() - } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(2)?; + let (nodes, edges) = graph_serde_decompose(self); + tuple.serialize_element(&nodes)?; + tuple.serialize_element(&edges)?; + tuple.end() + } } impl<'de, K, N, E> Deserialize<'de> for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, - { - _phantom: std::marker::PhantomData<(K, N, E)>, - } + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, + { + _phantom: std::marker::PhantomData<(K, N, E)>, + } - impl<'de, K, N, E> Visitor<'de> for GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, - { - type Value = Graph; + impl<'de, K, N, E> Visitor<'de> for GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, + { + type Value = Graph; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("node and edge lists") - } + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("node and edge lists") + } - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de> - { - let mut nodes = Vec::new(); - let mut edges: Vec<(K, K, E)> = Vec::new(); + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut nodes = Vec::new(); + let mut edges: Vec<(K, K, E)> = Vec::new(); - if let Some(node_seq) = seq.next_element()? { - nodes = node_seq; - } + if let Some(node_seq) = seq.next_element()? { + nodes = node_seq; + } - if let Some(edge_seq) = seq.next_element()? { - edges = edge_seq; - } + if let Some(edge_seq) = seq.next_element()? { + edges = edge_seq; + } - let mut g = Graph::new(); + let mut g = Graph::new(); - for (k, v) in nodes { - g.insert(Node::new(k, v)); - } + for (k, v) in nodes { + g.insert(Node::new(k, v)); + } - for (u, v, e) in edges { - let un = g.get(&u).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, u)))?; - let vn = g.get(&v).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, v)))?; - Node::connect(&un, &vn, e); - } + for (u, v, e) in edges { + let un = g.get(&u).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, u + )) + })?; + let vn = g.get(&v).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, v + )) + })?; + Node::connect(&un, &vn, e); + } - Ok(g) - } - } + Ok(g) + } + } - deserializer.deserialize_seq(GraphVisitor { - _phantom: std::marker::PhantomData, - }) - } -} \ No newline at end of file + deserializer.deserialize_seq(GraphVisitor { + _phantom: std::marker::PhantomData, + }) + } +} diff --git a/src/sync_digraph/mod.rs b/src/sync_digraph/mod.rs index b4c0781..86f8d00 100644 --- a/src/sync_digraph/mod.rs +++ b/src/sync_digraph/mod.rs @@ -27,13 +27,13 @@ //! g[1].connect(&g[3], ()); //! g[2].connect(&g[4], ()); //! g[3].connect(&g[2], ()); -//! g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle +//! g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle //! -//! let cycle = g[0] // We start at node 0 -//! .bfs() // We use a breadth-first search -//! .search_cycle() // We search for a cycle -//! .unwrap() // Returns `Option>` -//! .to_vec_nodes(); // Path is converted to a vector of nodes +//! let cycle = g[0] // We start at node 0 +//! .bfs() // We use a breadth-first search +//! .search_cycle() // We search for a cycle +//! .unwrap() // Returns `Option>` +//! .to_vec_nodes(); // Path is converted to a vector of nodes //! //! assert!(cycle[0] == g[0]); //! assert!(cycle[1] == g[3]); @@ -46,7 +46,10 @@ mod node; pub use self::node::*; use ahash::{AHashMap as HashMap, AHashSet as HashSet}; -use std::{fmt::Display, hash::Hash}; +use std::{ + fmt::{Display, Write}, + hash::Hash, +}; /// A directed graph containing nodes and edges. The graph is represented as a /// map of nodes, where each node is identified by a unique key. Each node @@ -62,7 +65,7 @@ where nodes: HashMap>, } -impl<'a, K, N, E> Graph +impl Graph where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, @@ -138,7 +141,7 @@ where /// assert!(node.key() == &"A"); /// ``` pub fn get(&self, key: &K) -> Option> { - self.nodes.get(key).map(|node| node.clone()) + self.nodes.get(key).cloned() } /// Check if Graph is empty @@ -219,7 +222,7 @@ where /// assert!(nodes.len() == 3); /// ``` pub fn to_vec(&self) -> Vec> { - self.nodes.values().map(|node| node.clone()).collect() + self.nodes.values().cloned().collect() } /// Collect roots into a vector @@ -247,7 +250,7 @@ where self.nodes .values() .filter(|node| node.is_root()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -275,7 +278,7 @@ where self.nodes .values() .filter(|node| node.is_leaf()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -303,7 +306,7 @@ where self.nodes .values() .filter(|node| node.is_orphan()) - .map(|node| node.clone()) + .cloned() .collect() } @@ -328,51 +331,51 @@ where self.nodes.iter() } - /// Find the strongly connected components of the graph. Can be used to - /// find cycles in the graph and for topological sorting. - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_digraph::*; - /// - /// let mut g: Graph = Graph::new(); - /// - /// g.insert(Node::new(0, ())); - /// g.insert(Node::new(1, ())); - /// g.insert(Node::new(2, ())); - /// g.insert(Node::new(3, ())); - /// g.insert(Node::new(4, ())); - /// g.insert(Node::new(5, ())); - /// g.insert(Node::new(6, ())); - /// g.insert(Node::new(7, ())); - /// g.insert(Node::new(8, ())); - /// g.insert(Node::new(9, ())); - /// - /// g[0].connect(&g[1], ()); // ---- C1 - /// g[1].connect(&g[2], ()); // - /// g[2].connect(&g[0], ()); // - /// g[3].connect(&g[4], ()); // ---- C2 - /// g[4].connect(&g[5], ()); // - /// g[5].connect(&g[3], ()); // - /// g[6].connect(&g[7], ()); // ---- C3 - /// g[7].connect(&g[8], ()); // - /// g[8].connect(&g[6], ()); // - /// g[9].connect(&g[9], ()); // ---- C4 - /// - /// let mut scc = g.scc(); - /// - /// // Since the graph container is a hash map, the order of the SCCs is - /// // not deterministic. We sort the SCCs by their size to make the test - /// // deterministic. - /// scc.sort_by(|a, b| a.len().cmp(&b.len())); - /// - /// assert!(scc.len() == 4); - /// assert!(scc[0].len() == 1); - /// assert!(scc[1].len() == 3); - /// assert!(scc[2].len() == 3); - /// assert!(scc[3].len() == 3); - /// ``` + /// Find the strongly connected components of the graph. Can be used to + /// find cycles in the graph and for topological sorting. + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_digraph::*; + /// + /// let mut g: Graph = Graph::new(); + /// + /// g.insert(Node::new(0, ())); + /// g.insert(Node::new(1, ())); + /// g.insert(Node::new(2, ())); + /// g.insert(Node::new(3, ())); + /// g.insert(Node::new(4, ())); + /// g.insert(Node::new(5, ())); + /// g.insert(Node::new(6, ())); + /// g.insert(Node::new(7, ())); + /// g.insert(Node::new(8, ())); + /// g.insert(Node::new(9, ())); + /// + /// g[0].connect(&g[1], ()); // ---- C1 + /// g[1].connect(&g[2], ()); // + /// g[2].connect(&g[0], ()); // + /// g[3].connect(&g[4], ()); // ---- C2 + /// g[4].connect(&g[5], ()); // + /// g[5].connect(&g[3], ()); // + /// g[6].connect(&g[7], ()); // ---- C3 + /// g[7].connect(&g[8], ()); // + /// g[8].connect(&g[6], ()); // + /// g[9].connect(&g[9], ()); // ---- C4 + /// + /// let mut scc = g.scc(); + /// + /// // Since the graph container is a hash map, the order of the SCCs is + /// // not deterministic. We sort the SCCs by their size to make the test + /// // deterministic. + /// scc.sort_by(|a, b| a.len().cmp(&b.len())); + /// + /// assert!(scc.len() == 4); + /// assert!(scc[0].len() == 1); + /// assert!(scc[1].len() == 3); + /// assert!(scc[2].len() == 3); + /// assert!(scc[3].len() == 3); + /// ``` pub fn scc(&self) -> Vec>> { let mut invariant = HashSet::new(); let mut components = Vec::new(); @@ -404,7 +407,7 @@ where components } - fn scc_ordering(&self) -> Vec> { + fn scc_ordering(&self) -> Vec> { let mut visited = HashSet::new(); let mut ordering = Vec::new(); @@ -427,20 +430,20 @@ where let mut s = String::new(); s.push_str("digraph {\n"); for (u_key, node) in self.iter() { - s.push_str(&format!(" {}", u_key.clone())); + write!(&mut s, " {}", u_key.clone()).unwrap(); for Edge(_, v, _) in node { - s.push_str(&format!("\n {} -> {}", u_key, v.key())); + write!(&mut s, "\n {} -> {}", u_key, v.key()).unwrap(); } - s.push_str("\n"); + s.push('\n'); } - s.push_str("}"); + s.push('}'); s } fn fmt_attr(attrs: Vec<(String, String)>) -> String { let mut s = String::new(); for (k, v) in attrs { - s.push_str(&format!("[{}=\"{}\"]", k, v)); + write!(&mut s, "[{}=\"{}\"]", k, v).unwrap(); } s } @@ -463,7 +466,7 @@ where if let Some(nattr) = nattr(node) { s.push_str(&format!(" {}", Self::fmt_attr(nattr))); } - s.push_str("\n"); + s.push('\n'); } for (_, node) in self.iter() { for Edge(u, v, e) in node { @@ -471,10 +474,10 @@ where if let Some(eattrs) = eattr(&u, &v, &e) { s.push_str(&format!(" {}", Self::fmt_attr(eattrs))); } - s.push_str("\n"); + s.push('\n'); } } - s.push_str("}"); + s.push('}'); s } @@ -487,7 +490,7 @@ where } } -impl<'a, K, N, E> std::ops::Index for Graph +impl std::ops::Index for Graph where K: Clone + Hash + Display + Eq, N: Clone, @@ -512,3 +515,14 @@ where &self.nodes[key] } } + +impl Default for Graph +where + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, +{ + fn default() -> Self { + Self::new() + } +} diff --git a/src/sync_digraph/node/adjacent.rs b/src/sync_digraph/node/adjacent.rs index 42d6577..5dc612a 100644 --- a/src/sync_digraph/node/adjacent.rs +++ b/src/sync_digraph/node/adjacent.rs @@ -1,30 +1,31 @@ use super::*; +use crate::error::Error; #[derive(Clone)] pub struct WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - inner: Weak<(K, N, RwLock>)>, + inner: Weak<(K, N, RwLock>)>, } impl WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - pub fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Arc::downgrade(&node.inner) - } - } + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Arc::downgrade(&node.inner), + } + } } pub struct Adjacent @@ -51,17 +52,11 @@ where } pub fn get_outbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.outbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - } + self.outbound.get(idx).map(|edge| (&edge.0, &edge.1)) } pub fn get_inbound(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.inbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - } + self.inbound.get(idx).map(|edge| (&edge.0, &edge.1)) } pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { @@ -91,29 +86,29 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } - pub fn remove_inbound(&mut self, source: &K) -> Result { - for (idx, edge) in self.inbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == source { - return Ok(self.inbound.remove(idx).1); - } - } - Err(()) + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_outbound(&mut self, target: &K) -> Result { - for (idx, edge) in self.outbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == target { - return Ok(self.outbound.remove(idx).1); - } - } - Err(()) + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } pub fn clear_inbound(&mut self) { @@ -124,10 +119,10 @@ where self.outbound.clear(); } - pub fn sizeof(&self) -> usize { - self.inbound.len() + self.outbound.len() - * (std::mem::size_of::>() - + std::mem::size_of::()) - + std::mem::size_of::() - } -} \ No newline at end of file + pub fn sizeof(&self) -> usize { + self.inbound.len() + + self.outbound.len() + * (std::mem::size_of::>() + std::mem::size_of::()) + + std::mem::size_of::() + } +} diff --git a/src/sync_digraph/node/algo/bfs.rs b/src/sync_digraph/node/algo/bfs.rs index 0d69604..63dc33c 100644 --- a/src/sync_digraph/node/algo/bfs.rs +++ b/src/sync_digraph/node/algo/bfs.rs @@ -1,216 +1,214 @@ -use std::{fmt::Display, hash::Hash, collections::VecDeque}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{collections::VecDeque, fmt::Display, hash::Hash}; -pub struct BFS<'a, K, N, E> +pub struct Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, } -impl<'a, K, N, E> BFS<'a, K, N, E> +impl<'a, K, N, E> Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - BFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - return self.loop_outbound_find(&mut visited, &mut queue); - } - Transposition::Inbound => { - return self.loop_inbound_find(&mut visited, &mut queue); - } - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - queue.push_back(self.root.clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.loop_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.loop_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - let target_found; - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.loop_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.loop_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - fn loop_outbound( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_inbound( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_outbound_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let Edge(_, v, _) = edge; - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } - - fn loop_inbound_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let Edge(_, v, _) = edge; - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Bfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => self.loop_outbound_find(&mut visited, &mut queue), + Transposition::Inbound => self.loop_inbound_find(&mut visited, &mut queue), + } + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push_back(self.root.clone()); + + match self.transpose { + Transposition::Outbound => { + match self.loop_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.loop_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => { + match self.loop_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.loop_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + fn loop_outbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v.clone()); + } + } + } + } + false + } + + fn loop_inbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v.clone()); + } + } + } + } + false + } + + fn loop_outbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v); + } + } + queue.push_back(v); + } + } + } + } + None + } + + fn loop_inbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let Edge(_, v, _) = edge; + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v); + } + } + queue.push_back(v); + } + } + } + } + None + } +} diff --git a/src/sync_digraph/node/algo/dfs.rs b/src/sync_digraph/node/algo/dfs.rs index c4d16ff..da5c4cc 100644 --- a/src/sync_digraph/node/algo/dfs.rs +++ b/src/sync_digraph/node/algo/dfs.rs @@ -1,226 +1,228 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; -pub struct DFS<'a, K, N, E> +pub struct Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, } -impl<'a, K, N, E> DFS<'a, K, N, E> +impl<'a, K, N, E> Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - DFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - return self.recurse_outbound_find(&mut visited, &mut queue); - } - Transposition::Inbound => { - return self.recurse_inbound_find(&mut visited, &mut queue); - } - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - queue.push(self.root.clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.recurse_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.recurse_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - let target_found; - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - target_found = self.recurse_outbound(&mut edges, &mut visited, &mut queue); - } - Transposition::Inbound => { - target_found = self.recurse_inbound(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - fn recurse_outbound(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_outbound(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_inbound(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_inbound(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_outbound_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_outbound_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } - - fn recurse_inbound_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_inbound_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Dfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => self.recurse_outbound_find(&mut visited, &mut queue), + Transposition::Inbound => self.recurse_inbound_find(&mut visited, &mut queue), + } + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push(self.root.clone()); + + match self.transpose { + Transposition::Outbound => { + match self.recurse_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.recurse_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => { + match self.recurse_outbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Transposition::Inbound => { + match self.recurse_inbound(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + fn recurse_outbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_outbound(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_inbound( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_inbound(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_outbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_outbound_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } + + fn recurse_inbound_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_inbound_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } +} diff --git a/src/sync_digraph/node/algo/method.rs b/src/sync_digraph/node/algo/method.rs index e552875..71a51db 100644 --- a/src/sync_digraph/node/algo/method.rs +++ b/src/sync_digraph/node/algo/method.rs @@ -5,26 +5,29 @@ pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); pub enum Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - NullMethod, - Filter(Filter<'a, K, N, E>), - ForEach(ForEach<'a, K, N, E>), + Empty, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), } impl<'a, K, N, E> Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn exec(&mut self, e: &Edge) -> bool { - match self { - Method::NullMethod => true, - Method::ForEach(f) => {f(e); true}, - Method::Filter(f) => f(e), - } - } -} \ No newline at end of file + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::Empty => true, + Method::ForEach(f) => { + f(e); + true + } + Method::Filter(f) => f(e), + } + } +} diff --git a/src/sync_digraph/node/algo/mod.rs b/src/sync_digraph/node/algo/mod.rs index ad8023c..f5c077d 100644 --- a/src/sync_digraph/node/algo/mod.rs +++ b/src/sync_digraph/node/algo/mod.rs @@ -2,8 +2,8 @@ use super::*; pub mod bfs; pub mod dfs; -pub mod pfs; pub mod order; +pub mod pfs; +mod method; mod path; -mod method; \ No newline at end of file diff --git a/src/sync_digraph/node/algo/order.rs b/src/sync_digraph/node/algo/order.rs index 5bb5a67..009aaa3 100644 --- a/src/sync_digraph/node/algo/order.rs +++ b/src/sync_digraph/node/algo/order.rs @@ -1,242 +1,213 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*}; +use super::{method::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; pub enum Ordering { - Pre, - Post, + Pre, + Post, } pub struct Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: &'a Node, - method: Method<'a, K, N, E>, - order: Ordering, - transpose: Transposition, + root: &'a Node, + method: Method<'a, K, N, E>, + order: Ordering, + transpose: Transposition, } - impl<'a, K, N, E> Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn preorder(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Pre, - transpose: Transposition::Outbound, - } - } - - pub fn postroder(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Post, - transpose: Transposition::Outbound, - } - } - - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search_nodes(&mut self) -> Vec> { - let mut nodes = vec![]; - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - match self.order { - Ordering::Pre => { - self.preorder_forward(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.postorder_forward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - }, - Transposition::Inbound => { - match self.order { - Ordering::Pre => { - self.preorder_backward(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.postorder_backward(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - }, - } - nodes - } - - pub fn search_edges(&mut self) -> Vec> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.transpose { - Transposition::Outbound => { - match self.order { - Ordering::Pre => { - self.preorder_forward(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.postorder_forward(&mut edges, &mut visited, &mut queue); - }, - } - }, - Transposition::Inbound => { - match self.order { - Ordering::Pre => { - self.preorder_backward(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.postorder_backward(&mut edges, &mut visited, &mut queue); - }, - } - }, - } - edges - } - - fn preorder_forward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.preorder_forward( - result, - visited, - queue); - } - } - } - } - false - } - - fn preorder_backward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.preorder_forward( - result, - visited, - queue); - } - } - } - } - false - } - - fn postorder_forward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_out() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.postorder_forward( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } - - fn postorder_backward( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.postorder_forward( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } -} \ No newline at end of file + pub fn preorder(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Pre, + transpose: Transposition::Outbound, + } + } + + pub fn postroder(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Post, + transpose: Transposition::Outbound, + } + } + + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search_nodes(&mut self) -> Vec> { + let mut nodes = vec![]; + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => match self.order { + Ordering::Pre => { + self.preorder_forward(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.postorder_forward(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + }, + Transposition::Inbound => match self.order { + Ordering::Pre => { + self.preorder_backward(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.postorder_backward(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + }, + } + nodes + } + + pub fn search_edges(&mut self) -> Vec> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.transpose { + Transposition::Outbound => match self.order { + Ordering::Pre => { + self.preorder_forward(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.postorder_forward(&mut edges, &mut visited, &mut queue); + } + }, + Transposition::Inbound => match self.order { + Ordering::Pre => { + self.preorder_backward(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.postorder_backward(&mut edges, &mut visited, &mut queue); + } + }, + } + edges + } + + fn preorder_forward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.preorder_forward(result, visited, queue); + } + } + } + false + } + + fn preorder_backward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.preorder_backward(result, visited, queue); + } + } + } + false + } + + fn postorder_forward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_out() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.postorder_forward(result, visited, queue); + } + } + } + false + } + + fn postorder_backward( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + result.push(edge); + self.postorder_backward(result, visited, queue); + } + } + } + false + } +} diff --git a/src/sync_digraph/node/algo/path.rs b/src/sync_digraph/node/algo/path.rs index 6499b8d..21c6ca9 100644 --- a/src/sync_digraph/node/algo/path.rs +++ b/src/sync_digraph/node/algo/path.rs @@ -1,174 +1,176 @@ -use std::{fmt::Display, hash::Hash, ops::Index}; use super::*; +use std::{fmt::Display, hash::Hash, ops::Index}; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - let mut path = Vec::new(); - - if edge_tree.len() == 1 { - path.push(edge_tree[0].clone()); - return path; - } - let w = edge_tree.last().unwrap(); - path.push(w.clone()); - let mut i = 0; - for edge in edge_tree.iter().rev() { - let Edge(_, v, _) = edge; - let Edge(s, _, _) = &path[i]; - if s == v { - path.push(edge.clone()); - i += 1; - } - } - path.reverse(); - path + let mut path = Vec::new(); + + if edge_tree.len() == 1 { + path.push(edge_tree[0].clone()); + return path; + } + let w = edge_tree.last().unwrap(); + path.push(w.clone()); + let mut i = 0; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; + if s == v { + path.push(edge.clone()); + i += 1; + } + } + path.reverse(); + path } pub struct Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub edges: Vec>, + pub edges: Vec>, } impl Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn len(&self) -> usize { - // Conceptually a path always contains at least one node, - // the root node. The path containes edges, so the length - // of the path is the number of edges plus one. - self.edges.len() + 1 - } - - pub fn from_edge_tree(edge_tree: Vec>) -> Path { - Path { edges: backtrack_edge_tree(edge_tree) } - } - - pub fn iter_nodes(&self) -> PathNodeIterator { - PathNodeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn iter_edges(&self) -> PathEdgeIterator { - PathEdgeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn first_edge(&self) -> Option<&Edge> { - self.edges.first() - } - - pub fn first_node(&self) -> Option<&Node> { - self.edges.first().map(|e| &e.1) - } - - pub fn last_edge(&self) -> Option<&Edge> { - self.edges.last() - } - - pub fn last_node(&self) -> Option<&Node> { - self.edges.last().map(|e| &e.1) - } - - pub fn to_vec_nodes(&self) -> Vec> { - self.iter_nodes().map(|v| v).collect() - } - - pub fn to_vec_edges(&self) -> Vec> { - self.edges.clone() - } + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + + pub fn from_edge_tree(edge_tree: Vec>) -> Path { + Path { + edges: backtrack_edge_tree(edge_tree), + } + } + + pub fn iter_nodes(&self) -> PathNodeIterator { + PathNodeIterator { + path: self, + position: 0, + } + } + + pub fn iter_edges(&self) -> PathEdgeIterator { + PathEdgeIterator { + path: self, + position: 0, + } + } + + pub fn first_edge(&self) -> Option<&Edge> { + self.edges.first() + } + + pub fn first_node(&self) -> Option<&Node> { + self.edges.first().map(|e| &e.1) + } + + pub fn last_edge(&self) -> Option<&Edge> { + self.edges.last() + } + + pub fn last_node(&self) -> Option<&Node> { + self.edges.last().map(|e| &e.1) + } + + pub fn to_vec_nodes(&self) -> Vec> { + self.iter_nodes().collect() + } + + pub fn to_vec_edges(&self) -> Vec> { + self.edges.clone() + } } impl Index for Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Output = Edge; + type Output = Edge; - fn index(&self, index: usize) -> &Self::Output { - &self.edges[index] - } + fn index(&self, index: usize) -> &Self::Output { + &self.edges[index] + } } pub struct PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) + } + None => None, + } + } } pub struct PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Node; - - fn next(&mut self) -> Option { - if self.position == 0 { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - return Some(edge.0.clone()); - } - None => return None, - } - } - match self.path.edges.get(self.position - 1) { - Some(edge) => { - self.position += 1; - Some(edge.1.clone()) - } - None => None, - } - } -} \ No newline at end of file + type Item = Node; + + fn next(&mut self) -> Option { + if self.position == 0 { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + return Some(edge.0.clone()); + } + None => return None, + } + } + match self.path.edges.get(self.position - 1) { + Some(edge) => { + self.position += 1; + Some(edge.1.clone()) + } + None => None, + } + } +} diff --git a/src/sync_digraph/node/algo/pfs.rs b/src/sync_digraph/node/algo/pfs.rs index 42f71bf..28f37b6 100644 --- a/src/sync_digraph/node/algo/pfs.rs +++ b/src/sync_digraph/node/algo/pfs.rs @@ -1,276 +1,273 @@ -use std::{ - fmt::Display, - hash::Hash, - collections::BinaryHeap, - cmp::Reverse -}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; - +use std::{cmp::Reverse, collections::BinaryHeap, fmt::Display, hash::Hash}; enum Priority { - Min, - Max + Min, + Max, } -pub struct PFS<'a, K, N, E> +pub struct Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - transpose: Transposition, - priority: Priority, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + transpose: Transposition, + priority: Priority, } -impl<'a, K, N, E> PFS<'a, K, N, E> +impl<'a, K, N, E> Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone + Ord, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone + Ord, + E: Clone, { - pub fn new(root: &Node) -> Self { - PFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - transpose: Transposition::Outbound, - priority: Priority::Min, - } - } + pub fn new(root: &Node) -> Self { + Pfs { + root: root.clone(), + target: None, + method: Method::Empty, + transpose: Transposition::Outbound, + priority: Priority::Min, + } + } - pub fn min(mut self) -> Self { - self.priority = Priority::Min; - self - } + pub fn min(mut self) -> Self { + self.priority = Priority::Min; + self + } - pub fn max(mut self) -> Self { - self.priority = Priority::Max; - self - } + pub fn max(mut self) -> Self { + self.priority = Priority::Max; + self + } - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } - pub fn transpose(mut self) -> Self { - self.transpose = Transposition::Inbound; - self - } + pub fn transpose(mut self) -> Self { + self.transpose = Transposition::Inbound; + self + } - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } - fn loop_outbound_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(node) = queue.pop() { - let node = node.0; - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(Reverse(v.clone())); - } - } - } - } - false - } + fn loop_outbound_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(node) = queue.pop() { + let node = node.0; + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(Reverse(v.clone())); + } + } + } + } + false + } - fn loop_inbound_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(node) = queue.pop() { - let node = node.0; - for edge in node.iter_out() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(Reverse(v.clone())); - } - } - } - } - false - } + fn loop_inbound_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(node) = queue.pop() { + let node = node.0; + for edge in node.iter_out() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(Reverse(v.clone())); + } + } + } + } + false + } - fn loop_outbound_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter_out() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - } - } - } - } - false - } + fn loop_outbound_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter_out() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + } + } + } + } + false + } - fn loop_inbound_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter_in() { - let edge = edge.reverse(); - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - } - } - } - } - false - } + fn loop_inbound_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter_in() { + let edge = edge.reverse(); + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + } + } + } + } + false + } - pub fn search(&mut self) -> Option> { - let path = self.search_path(); - match path { - Some(path) => Some(path.last_node().unwrap().clone()), - None => None, - } - } + pub fn search(&mut self) -> Option> { + let path = self.search_path(); + path.map(|path| path.last_node().unwrap().clone()) + } - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); - self.target = Some(self.root.key().clone()); + self.target = Some(self.root.key().clone()); - match self.transpose { - Transposition::Outbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - Transposition::Inbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } + match self.transpose { + Transposition::Outbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + Transposition::Inbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + } + } - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); - visited.insert(self.root.key().clone()); + visited.insert(self.root.key().clone()); - match self.transpose { - Transposition::Outbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_outbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_outbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - Transposition::Inbound => { - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_inbound_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_inbound_max(&mut edges, &mut visited, &mut queue); - } - } - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } -} \ No newline at end of file + match self.transpose { + Transposition::Outbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_outbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_outbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + Transposition::Inbound => match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_inbound_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_inbound_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + }, + } + } +} diff --git a/src/sync_digraph/node/mod.rs b/src/sync_digraph/node/mod.rs index d10224f..08741ae 100644 --- a/src/sync_digraph/node/mod.rs +++ b/src/sync_digraph/node/mod.rs @@ -34,25 +34,31 @@ mod adjacent; mod algo; -use self::{adjacent::*, algo::{bfs::*, dfs::*, order::*, pfs::*}}; -use std::{fmt::Display, hash::Hash, ops::Deref, sync::{Arc, Weak, RwLock}}; +use crate::error::Error; +use self::{ + adjacent::*, + algo::{bfs::*, dfs::*, order::*, pfs::*}, +}; +use std::{ + fmt::Display, + hash::Hash, + ops::Deref, + sync::{Arc, RwLock, Weak}, +}; enum Transposition { - Outbound, - Inbound, + Outbound, + Inbound, } /// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. #[derive(Clone, PartialEq)] -pub struct Edge( - pub Node, - pub Node, - pub E, -) where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone; +pub struct Edge(pub Node, pub Node, pub E) +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; impl Edge where @@ -131,12 +137,12 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, 'A'); + /// let n1 = Node::::new(1, 'A'); /// - /// assert!(*n1.key() == 1); - /// assert!(*n1.value() == 'A'); + /// assert!(*n1.key() == 1); + /// assert!(*n1.value() == 'A'); /// ``` pub fn new(key: K, value: N) -> Self { Node { @@ -149,11 +155,11 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, ()); + /// let n1 = Node::::new(1, ()); /// - /// assert!(*n1.key() == 1); + /// assert!(*n1.key() == 1); /// ``` pub fn key(&self) -> &K { &self.inner.0 @@ -164,11 +170,11 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::::new(1, 'A'); + /// let n1 = Node::::new(1, 'A'); /// - /// assert!(*n1.value() == 'A'); + /// assert!(*n1.value() == 'A'); /// ``` pub fn value(&self) -> &N { &self.inner.1 @@ -225,24 +231,24 @@ where /// ``` /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// n1.connect(&n2, 4.20); + /// n1.connect(&n2, 4.20); /// - /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n2.key())); /// ``` pub fn connect(&self, other: &Self, value: E) { self.inner .2 .write() - .unwrap() + .unwrap() .push_outbound((other.clone(), value.clone())); other .inner .2 .write() - .unwrap() + .unwrap() .push_inbound((self.clone(), value)); } @@ -255,24 +261,24 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => assert!(n1.is_connected(n2.key())), - /// Err(_) => panic!("n1 should be connected to n2"), - /// } + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => assert!(n1.is_connected(n2.key())), + /// Err(_) => panic!("n1 should be connected to n2"), + /// } /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => panic!("n1 should be connected to n2"), - /// Err(_) => assert!(n1.is_connected(n2.key())), - /// } + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => panic!("n1 should be connected to n2"), + /// Err(_) => assert!(n1.is_connected(n2.key())), + /// } /// ``` - pub fn try_connect(&self, other: &Self, value: E) -> Result<(), E> { + pub fn try_connect(&self, other: &Self, value: E) -> Result<(), Error> { if self.is_connected(other.key()) { - Err(value) + Err(Error::EdgeAlreadyExists) } else { self.connect(other, value); Ok(()) @@ -286,35 +292,31 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); /// - /// n1.connect(&n2, ()); + /// n1.connect(&n2, ()); /// - /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n2.key())); /// - /// if n1.disconnect(n2.key()).is_err() { - /// panic!("n1 should be connected to n2"); - /// } + /// if n1.disconnect(n2.key()).is_err() { + /// panic!("n1 should be connected to n2"); + /// } /// - /// assert!(!n1.is_connected(n2.key())); + /// assert!(!n1.is_connected(n2.key())); /// ``` - pub fn disconnect(&self, other: &K) -> Result { + pub fn disconnect(&self, other: &K) -> Result { match self.find_outbound(other) { - Some(other) => match self.inner.2 - .write() - .unwrap() - .remove_outbound(other.key()) { + Some(other) => match self.inner.2.write().unwrap().remove_outbound(other.key()) { Ok(edge) => { - other.inner.2.write() - .unwrap().remove_inbound(self.key())?; + other.inner.2.write().unwrap().remove_inbound(self.key())?; Ok(edge) } - Err(_) => Err(()), + Err(_) => Err(Error::EdgeNotFound), }, - None => Err(()), + None => Err(Error::EdgeNotFound), } } @@ -323,41 +325,47 @@ where /// # Example /// /// ``` - /// use gdsl::digraph::*; + /// use gdsl::digraph::*; /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// let n4 = Node::new(4, ()); + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// let n4 = Node::new(4, ()); /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n1.connect(&n4, ()); - /// n2.connect(&n1, ()); - /// n3.connect(&n1, ()); - /// n4.connect(&n1, ()); + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n1.connect(&n4, ()); + /// n2.connect(&n1, ()); + /// n3.connect(&n1, ()); + /// n4.connect(&n1, ()); /// - /// assert!(n1.is_connected(n2.key())); - /// assert!(n1.is_connected(n3.key())); - /// assert!(n1.is_connected(n4.key())); + /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n3.key())); + /// assert!(n1.is_connected(n4.key())); /// - /// n1.isolate(); + /// n1.isolate(); /// - /// assert!(n1.is_orphan()); + /// assert!(n1.is_orphan()); /// ``` pub fn isolate(&self) { for Edge(_, v, _) in self.iter_out() { - v.inner.2.write() - .unwrap().remove_inbound(self.key()).unwrap(); + v.inner + .2 + .write() + .unwrap() + .remove_inbound(self.key()) + .unwrap(); } for Edge(v, _, _) in self.iter_in() { - v.inner.2.write() - .unwrap().remove_outbound(self.key()).unwrap(); + v.inner + .2 + .write() + .unwrap() + .remove_outbound(self.key()) + .unwrap(); } - self.inner.2.write() - .unwrap().clear_outbound(); - self.inner.2.write() - .unwrap().clear_inbound(); + self.inner.2.write().unwrap().clear_outbound(); + self.inner.2.write().unwrap().clear_inbound(); } /// Returns true if the node is a root node. Root nodes are nodes that have @@ -463,12 +471,8 @@ where /// ``` pub fn find_outbound(&self, other: &K) -> Option> { let edge = self.inner.2.read().unwrap(); - let edge = edge.find_outbound(other); - if let Some(edge) = edge { - Some(edge.0.upgrade().unwrap().clone()) - } else { - None - } + let edge = edge.find_outbound(other); + edge.map(|edge| edge.0.upgrade().unwrap()) } /// Get a pointer to an adjacent node with a given key. Returns None if no @@ -493,12 +497,8 @@ where /// ``` pub fn find_inbound(&self, other: &K) -> Option> { let edge = self.inner.2.read().unwrap(); - let edge = edge.find_inbound(other); - if let Some(edge) = edge { - Some(edge.0.upgrade().unwrap().clone()) - } else { - None - } + let edge = edge.find_inbound(other); + edge.map(|edge| edge.0.upgrade().unwrap()) } /// Returns an iterator-like object that can be used to map, filter and @@ -572,10 +572,10 @@ where /// n3.connect(&n1, ()); /// /// let path = n1 - /// .dfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); + /// .dfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); /// /// let mut iter = path.iter_nodes(); /// @@ -583,8 +583,8 @@ where /// assert!(iter.next().unwrap() == n2); /// assert!(iter.next().unwrap() == n3); /// ``` - pub fn dfs(&self) -> DFS { - DFS::new(self) + pub fn dfs(&self) -> Dfs { + Dfs::new(self) } /// Returns an iterator-like object that can be used to map, filter, @@ -605,10 +605,10 @@ where /// n3.connect(&n1, ()); /// /// let path = n1 - /// .bfs() - /// .target(&3) - /// .search_path() - /// .unwrap(); + /// .bfs() + /// .target(&3) + /// .search_path() + /// .unwrap(); /// /// let mut iter = path.iter_nodes(); /// @@ -616,8 +616,8 @@ where /// assert!(iter.next().unwrap() == n2); /// assert!(iter.next().unwrap() == n3); /// ``` - pub fn bfs(&self) -> BFS { - BFS::new(self) + pub fn bfs(&self) -> Bfs { + Bfs::new(self) } /// Returns an iterator-like object that can be used to map, filter, @@ -640,22 +640,22 @@ where /// n3.connect(&n4, ()); /// /// let path = n1 - /// .pfs() - /// .target(&'D') - /// .search_path() - /// .unwrap(); + /// .pfs() + /// .target(&'D') + /// .search_path() + /// .unwrap(); /// /// assert!(path[0] == Edge(n1, n3.clone(), ())); /// assert!(path[1] == Edge(n3, n4, ())); ///``` - pub fn pfs(&self) -> PFS + pub fn pfs(&self) -> Pfs where N: Ord, { - PFS::new(self) + Pfs::new(self) } - /// Returns an iterator over the node's outbound edges. + /// Returns an iterator over the node's outbound edges. /// /// # Example /// @@ -680,7 +680,7 @@ where } } - /// Returns an iterator over the node's inbound edges. + /// Returns an iterator over the node's inbound edges. /// /// # Example /// @@ -724,7 +724,7 @@ where { type Target = N; fn deref(&self) -> &Self::Target { - &self.value() + self.value() } } @@ -754,7 +754,7 @@ where E: Clone, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.value().cmp(&other.value())) + Some(self.value().cmp(other.value())) } } @@ -765,7 +765,7 @@ where E: Clone, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.value().cmp(&other.value()) + self.value().cmp(other.value()) } } @@ -788,10 +788,21 @@ where type Item = Edge; fn next(&mut self) -> Option { - match self.node.inner.2.read().unwrap().get_outbound(self.position) { + match self + .node + .inner + .2 + .read() + .unwrap() + .get_outbound(self.position) + { Some(current) => { self.position += 1; - Some(Edge(self.node.clone(), current.0.upgrade().unwrap().clone(), current.1.clone())) + Some(Edge( + self.node.clone(), + current.0.upgrade().unwrap(), + current.1.clone(), + )) } None => None, } @@ -820,7 +831,11 @@ where match self.node.inner.2.read().unwrap().get_inbound(self.position) { Some(current) => { self.position += 1; - Some(Edge(current.0.upgrade().unwrap().clone(), self.node.clone(), current.1.clone())) + Some(Edge( + current.0.upgrade().unwrap(), + self.node.clone(), + current.1.clone(), + )) } None => None, } @@ -842,4 +857,20 @@ where position: 0, } } -} \ No newline at end of file +} + +unsafe impl Send for Node +where + K: Clone + Hash + Display + PartialEq + Eq + Send, + N: Clone + Send, + E: Clone + Send, +{ +} + +unsafe impl Sync for Node +where + K: Clone + Hash + Display + PartialEq + Eq + Sync, + N: Clone + Sync, + E: Clone + Sync, +{ +} diff --git a/src/sync_ungraph/graph_macros.rs b/src/sync_ungraph/graph_macros.rs index 45d73ae..63b6314 100644 --- a/src/sync_ungraph/graph_macros.rs +++ b/src/sync_ungraph/graph_macros.rs @@ -3,46 +3,35 @@ /// Macro for creating a node. #[macro_export] macro_rules! sync_ungraph_node { + // graph::Node + ( $key:expr ) => {{ + use gdsl::ungraph::*; - // graph::Node - ( $key:expr ) => { - { - use gdsl::ungraph::*; - - Node::new($key, ()) - } - }; - - // graph::Node - ( $key:expr, $param:expr ) => { - { - use gdsl::ungraph::*; + Node::new($key, ()) + }}; - Node::new($key, $param) - } - }; + // graph::Node + ( $key:expr, $param:expr ) => {{ + use gdsl::ungraph::*; + Node::new($key, $param) + }}; } /// Macro for connecting two nodes. #[macro_export] macro_rules! sync_ungraph_connect { + ( $s:expr => $t:expr ) => {{ + use gdsl::ungraph::*; - ( $s:expr => $t:expr ) => { - { - use gdsl::ungraph::*; - - Node::connect($s, $t, ()) - } - }; + Node::connect($s, $t, ()) + }}; - ( $s:expr => $t:expr, $params:expr ) => { - { - use gdsl::ungraph::*; + ( $s:expr => $t:expr, $params:expr ) => {{ + use gdsl::ungraph::*; - Node::connect($s, $t, $params) - } - }; + Node::connect($s, $t, $params) + }}; } /// Macro for creating a graph. diff --git a/src/sync_ungraph/graph_serde.rs b/src/sync_ungraph/graph_serde.rs index cd1c0fe..01e87ee 100644 --- a/src/sync_ungraph/graph_serde.rs +++ b/src/sync_ungraph/graph_serde.rs @@ -1,112 +1,124 @@ +use super::*; use serde::{ - Deserialize, - ser::{Serialize, Serializer, SerializeTuple}, - de::{self, Visitor}, + de::{self, Visitor}, + ser::{Serialize, SerializeTuple, Serializer}, + Deserialize, }; -use super::*; -fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) +type GraphDecomp = (Vec<(K, N)>, Vec<(K, K, E)>); + +fn graph_serde_decompose(g: &Graph) -> GraphDecomp where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - let mut nodes = Vec::new(); - let mut edges = Vec::new(); + let mut nodes = Vec::new(); + let mut edges = Vec::new(); - for (_, n) in g.iter() { - nodes.push((n.key().clone(), n.value().clone())); + for (_, n) in g.iter() { + nodes.push((n.key().clone(), n.value().clone())); - for Edge(u, v, e) in n.iter() { - edges.push((u.key().clone(), v.key().clone(), e)); - } - } + for Edge(u, v, e) in n.iter() { + edges.push((u.key().clone(), v.key().clone(), e)); + } + } - (nodes, edges) + (nodes, edges) } impl Serialize for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tuple = serializer.serialize_tuple(2)?; - let (nodes, edges) = graph_serde_decompose(self); - tuple.serialize_element(&nodes)?; - tuple.serialize_element(&edges)?; - tuple.end() - } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(2)?; + let (nodes, edges) = graph_serde_decompose(self); + tuple.serialize_element(&nodes)?; + tuple.serialize_element(&edges)?; + tuple.end() + } } impl<'de, K, N, E> Deserialize<'de> for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, - { - _phantom: std::marker::PhantomData<(K, N, E)>, - } - - impl<'de, K, N, E> Visitor<'de> for GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, - { - type Value = Graph; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("node and edge lists") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de> - { - let mut nodes = Vec::new(); - let mut edges: Vec<(K, K, E)> = Vec::new(); - - if let Some(node_seq) = seq.next_element()? { - nodes = node_seq; - } - - if let Some(edge_seq) = seq.next_element()? { - edges = edge_seq; - } - - let mut g = Graph::new(); - - for (k, v) in nodes { - g.insert(Node::new(k, v)); - } - - for (u, v, e) in edges { - let un = g.get(&u).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, u)))?; - let vn = g.get(&v).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, v)))?; - Node::connect(&un, &vn, e); - } - - Ok(g) - } - } - - deserializer.deserialize_seq(GraphVisitor { - _phantom: std::marker::PhantomData, - }) - } -} \ No newline at end of file + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, + { + _phantom: std::marker::PhantomData<(K, N, E)>, + } + + impl<'de, K, N, E> Visitor<'de> for GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, + { + type Value = Graph; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("node and edge lists") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut nodes = Vec::new(); + let mut edges: Vec<(K, K, E)> = Vec::new(); + + if let Some(node_seq) = seq.next_element()? { + nodes = node_seq; + } + + if let Some(edge_seq) = seq.next_element()? { + edges = edge_seq; + } + + let mut g = Graph::new(); + + for (k, v) in nodes { + g.insert(Node::new(k, v)); + } + + for (u, v, e) in edges { + let un = g.get(&u).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, u + )) + })?; + let vn = g.get(&v).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, v + )) + })?; + Node::connect(&un, &vn, e); + } + + Ok(g) + } + } + + deserializer.deserialize_seq(GraphVisitor { + _phantom: std::marker::PhantomData, + }) + } +} diff --git a/src/sync_ungraph/mod.rs b/src/sync_ungraph/mod.rs index 62c01df..62dc492 100644 --- a/src/sync_ungraph/mod.rs +++ b/src/sync_ungraph/mod.rs @@ -1,252 +1,275 @@ //! Undirected Graph -mod node; mod graph_macros; mod graph_serde; +mod node; use std::{ - fmt::Display, + fmt::{Display, Write}, hash::Hash, }; -use ahash::HashMap as HashMap; +use ahash::HashMap; pub use self::node::*; pub struct Graph where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - nodes: HashMap>, + nodes: HashMap>, } -impl<'a, K, N, E> Graph +impl Graph where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - /// Create a new Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// ``` - pub fn new() -> Self { Self { nodes: HashMap::default() } } - - /// Check if a node with the given key exists in the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// - /// assert!(g.contains(&"A")); - /// ``` - pub fn contains(&self, key: &K) -> bool { self.nodes.contains_key(key) } - - /// Get the length of the Graph (amount of nodes) - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// - /// let len = g.len(); - /// - /// assert!(len == 2); - /// ``` - pub fn len(&self) -> usize { self.nodes.len() } - - /// Get a node by key - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// let node = g.get(&"A").unwrap(); - /// - /// assert!(node.key() == &"A"); - /// ``` - pub fn get(&self, key: &K) -> Option> { self.nodes.get(key).map(|node| node.clone()) } - - /// Check if Graph is empty - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// assert!(g.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { self.nodes.is_empty() } - - /// Insert a node into the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// - /// assert!(g.contains(&"A")); - /// assert!(g.insert(Node::new("A", 0)) == false); - /// ``` - pub fn insert(&mut self, node: Node) -> bool { - if self.nodes.contains_key(node.key()) { - false - } else { - self.nodes.insert(node.key().clone(), node.clone()); - true - } - } - - /// Remove a node from the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// - /// assert!(g.contains(&"A")); - /// - /// g.remove(&"A"); - /// - /// assert!(g.contains(&"A") == false); - /// ``` - pub fn remove(&mut self, node: &K) -> Option> { - self.nodes.remove(node) - } - - /// Collect nodes into a vector - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// let nodes = g.to_vec(); - /// - /// assert!(nodes.len() == 3); - /// ``` - pub fn to_vec(&self) -> Vec> { - self.nodes.values().map(|node| node.clone()).collect() - } - - /// Collect orpahn nodes into a vector - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// g.insert(Node::new("D", 0)); - /// - /// g["A"].connect(&g["B"], 0x1); - /// - /// let orphans = g.orphans(); - /// - /// assert!(orphans.len() == 2); - /// ``` - pub fn orphans(&self) -> Vec> { - self.nodes - .values() - .filter(|node| node.is_orphan()) - .map(|node| node.clone()) - .collect() - } - - /// Iterate over nodes in the graph in random order - /// - /// # Examples - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// for (key, _)in g.iter() { - /// println!("{}", key); - /// } - /// ``` - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, Node> { - self.nodes.iter() - } - - pub fn to_dot(&self) -> String - where - N: Display, - E: Display, - { - let mut s = String::new(); - s.push_str("digraph {\n"); - for (u_key, node) in self.iter() { - s.push_str(&format!(" {}", u_key.clone())); - for Edge(_, v, _) in node { - s.push_str(&format!("\n {} -> {}", u_key, v.key())); - } - s.push_str("\n"); - } - s.push_str("}"); - s - } + /// Create a new Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// ``` + pub fn new() -> Self { + Self { + nodes: HashMap::default(), + } + } + + /// Check if a node with the given key exists in the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// + /// assert!(g.contains(&"A")); + /// ``` + pub fn contains(&self, key: &K) -> bool { + self.nodes.contains_key(key) + } + + /// Get the length of the Graph (amount of nodes) + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// + /// let len = g.len(); + /// + /// assert!(len == 2); + /// ``` + pub fn len(&self) -> usize { + self.nodes.len() + } + + /// Get a node by key + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// let node = g.get(&"A").unwrap(); + /// + /// assert!(node.key() == &"A"); + /// ``` + pub fn get(&self, key: &K) -> Option> { + self.nodes.get(key).cloned() + } + + /// Check if Graph is empty + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// assert!(g.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.nodes.is_empty() + } + + /// Insert a node into the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// + /// assert!(g.contains(&"A")); + /// assert!(g.insert(Node::new("A", 0)) == false); + /// ``` + pub fn insert(&mut self, node: Node) -> bool { + if self.nodes.contains_key(node.key()) { + false + } else { + self.nodes.insert(node.key().clone(), node.clone()); + true + } + } + + /// Remove a node from the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// + /// assert!(g.contains(&"A")); + /// + /// g.remove(&"A"); + /// + /// assert!(g.contains(&"A") == false); + /// ``` + pub fn remove(&mut self, node: &K) -> Option> { + self.nodes.remove(node) + } + + /// Collect nodes into a vector + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// let nodes = g.to_vec(); + /// + /// assert!(nodes.len() == 3); + /// ``` + pub fn to_vec(&self) -> Vec> { + self.nodes.values().cloned().collect() + } + + /// Collect orpahn nodes into a vector + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// g.insert(Node::new("D", 0)); + /// + /// g["A"].connect(&g["B"], 0x1); + /// + /// let orphans = g.orphans(); + /// + /// assert!(orphans.len() == 2); + /// ``` + pub fn orphans(&self) -> Vec> { + self.nodes + .values() + .filter(|node| node.is_orphan()) + .cloned() + .collect() + } + + /// Iterate over nodes in the graph in random order + /// + /// # Examples + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// for (key, _)in g.iter() { + /// println!("{}", key); + /// } + /// ``` + pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, Node> { + self.nodes.iter() + } + + pub fn to_dot(&self) -> String + where + N: Display, + E: Display, + { + let mut s = String::new(); + s.push_str("digraph {\n"); + for (u_key, node) in self.iter() { + write!(&mut s, " {}", u_key.clone()).unwrap(); + for Edge(_, v, _) in node { + write!(&mut s, "\n {} -> {}", u_key, v.key()).unwrap(); + } + s.push('\n'); + } + s.push('}'); + s + } } -impl<'a, K, N, E> std::ops::Index for Graph +impl std::ops::Index for Graph where - K: Clone + Hash + Display + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, { - type Output = Node; + type Output = Node; - fn index(&self, key: K) -> &Self::Output { - &self.nodes[&key] - } + fn index(&self, key: K) -> &Self::Output { + &self.nodes[&key] + } +} + +impl Default for Graph +where + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, +{ + fn default() -> Self { + Self::new() + } } diff --git a/src/sync_ungraph/node/adjacent.rs b/src/sync_ungraph/node/adjacent.rs index a00ea30..938bf41 100644 --- a/src/sync_ungraph/node/adjacent.rs +++ b/src/sync_ungraph/node/adjacent.rs @@ -1,30 +1,33 @@ use super::*; +use crate::error::Error; #[derive(Clone)] pub struct WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - inner: Weak<(K, N, RwLock>)>, + inner: WeakNodeInner, } +type WeakNodeInner = Weak<(K, N, RwLock>)>; + impl WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - pub fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Arc::downgrade(&node.inner) - } - } + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Arc::downgrade(&node.inner), + } + } } pub struct Adjacent @@ -50,15 +53,15 @@ where }) } - pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.outbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => match self.inbound.get(idx - self.outbound.len()) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - }, - } - } + pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { + match self.outbound.get(idx) { + Some(edge) => Some((&edge.0, &edge.1)), + None => self + .inbound + .get(idx - self.outbound.len()) + .map(|edge| (&edge.0, &edge.1)), + } + } pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.outbound.iter() { @@ -78,12 +81,12 @@ where None } - pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { - match self.find_outbound(node) { - Some(edge) => Some(edge), - None => self.find_inbound(node), - } - } + pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { + match self.find_outbound(node) { + Some(edge) => Some(edge), + None => self.find_inbound(node), + } + } pub fn len_outbound(&self) -> usize { self.outbound.len() @@ -94,37 +97,37 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } - pub fn remove_inbound(&mut self, source: &K) -> Result { - for (idx, edge) in self.inbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == source { - return Ok(self.inbound.remove(idx).1); - } - } - Err(()) + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_outbound(&mut self, target: &K) -> Result { - for (idx, edge) in self.outbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == target { - return Ok(self.outbound.remove(idx).1); - } - } - Err(()) + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_undirected(&mut self, node: &K) -> Result { - match self.remove_inbound(node) { - Ok(edge) => Ok(edge), - Err(_) => self.remove_outbound(node), - } - } + pub fn remove_undirected(&mut self, node: &K) -> Result { + match self.remove_inbound(node) { + Ok(edge) => Ok(edge), + Err(_) => self.remove_outbound(node), + } + } pub fn clear_inbound(&mut self) { self.inbound.clear(); @@ -134,10 +137,10 @@ where self.outbound.clear(); } - pub fn sizeof(&self) -> usize { - self.inbound.len() + self.outbound.len() - * (std::mem::size_of::>() - + std::mem::size_of::()) - + std::mem::size_of::() - } -} \ No newline at end of file + pub fn sizeof(&self) -> usize { + self.inbound.len() + + self.outbound.len() + * (std::mem::size_of::>() + std::mem::size_of::()) + + std::mem::size_of::() + } +} diff --git a/src/sync_ungraph/node/algo/bfs.rs b/src/sync_ungraph/node/algo/bfs.rs index 7518557..3a40d67 100644 --- a/src/sync_ungraph/node/algo/bfs.rs +++ b/src/sync_ungraph/node/algo/bfs.rs @@ -1,134 +1,134 @@ -use std::{fmt::Display, hash::Hash, collections::VecDeque}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{collections::VecDeque, fmt::Display, hash::Hash}; -pub struct BFS<'a, K, N, E> +pub struct Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, + root: Node, + target: Option, + method: Method<'a, K, N, E>, } -impl<'a, K, N, E> BFS<'a, K, N, E> +impl<'a, K, N, E> Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - BFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - } - } - - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn loop_adjacent( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_adjacent_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - return self.loop_adjacent_find(&mut visited, &mut queue); - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - self.target = Some(self.root.key().clone()); - queue.push_back(self.root.clone()); - - if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } + pub fn new(root: &Node) -> Self { + Bfs { + root: root.clone(), + target: None, + method: Method::Empty, + } + } + + pub fn target(mut self, target: &'a K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn loop_adjacent( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v.clone()); + } + } + } + } + false + } + + fn loop_adjacent_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push_back(v.clone()); + } + } + } + } + None + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + self.loop_adjacent_find(&mut visited, &mut queue) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push_back(self.root.clone()); + + if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } } diff --git a/src/sync_ungraph/node/algo/dfs.rs b/src/sync_ungraph/node/algo/dfs.rs index 523112f..680f3da 100644 --- a/src/sync_ungraph/node/algo/dfs.rs +++ b/src/sync_ungraph/node/algo/dfs.rs @@ -1,139 +1,141 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; -pub struct DFS<'a, K, N, E> +pub struct Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, + root: Node, + target: Option, + method: Method<'a, K, N, E>, } -impl<'a, K, N, E> DFS<'a, K, N, E> +impl<'a, K, N, E> Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - DFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn recurse_adjacent(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_adjacent(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_adjacent_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_adjacent_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - return self.recurse_adjacent_find(&mut visited, &mut queue); - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - self.target = Some(self.root.key().clone()); - queue.push(self.root.clone()); - - if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Dfs { + root: root.clone(), + target: None, + method: Method::Empty, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn recurse_adjacent( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_adjacent(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_adjacent_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_adjacent_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + self.recurse_adjacent_find(&mut visited, &mut queue) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push(self.root.clone()); + + if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } +} diff --git a/src/sync_ungraph/node/algo/method.rs b/src/sync_ungraph/node/algo/method.rs index c973f3b..3c0cd59 100644 --- a/src/sync_ungraph/node/algo/method.rs +++ b/src/sync_ungraph/node/algo/method.rs @@ -5,26 +5,29 @@ pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); pub enum Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - NullMethod, - Filter(Filter<'a, K, N, E>), - ForEach(ForEach<'a, K, N, E>), + Empty, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), } impl<'a, K, N, E> Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn exec(&mut self, e: &Edge) -> bool { - match self { - Method::NullMethod => true, - Method::Filter(f) => f(e), - Method::ForEach(f) => {f(e); true}, - } - } -} \ No newline at end of file + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::Empty => true, + Method::Filter(f) => f(e), + Method::ForEach(f) => { + f(e); + true + } + } + } +} diff --git a/src/sync_ungraph/node/algo/mod.rs b/src/sync_ungraph/node/algo/mod.rs index ad8023c..f5c077d 100644 --- a/src/sync_ungraph/node/algo/mod.rs +++ b/src/sync_ungraph/node/algo/mod.rs @@ -2,8 +2,8 @@ use super::*; pub mod bfs; pub mod dfs; -pub mod pfs; pub mod order; +pub mod pfs; +mod method; mod path; -mod method; \ No newline at end of file diff --git a/src/sync_ungraph/node/algo/order.rs b/src/sync_ungraph/node/algo/order.rs index eaa1b64..d914759 100644 --- a/src/sync_ungraph/node/algo/order.rs +++ b/src/sync_ungraph/node/algo/order.rs @@ -1,161 +1,147 @@ //==== Includes =============================================================== -use std::{ - fmt::Display, - hash::Hash, -}; +use std::{fmt::Display, hash::Hash}; -use ahash::HashSet as HashSet; +use ahash::HashSet; -use super::*; use super::method::*; +use super::*; //==== Ordering =============================================================== pub enum Ordering { - Pre, - Post, + Pre, + Post, } pub struct Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: &'a Node, - method: Method<'a, K, N, E>, - order: Ordering, + root: &'a Node, + method: Method<'a, K, N, E>, + order: Ordering, } - impl<'a, K, N, E> Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Pre, - } - } - - pub fn pre(mut self) -> Self { - self.order = Ordering::Pre; - self - } - - pub fn post(mut self) -> Self { - self.order = Ordering::Post; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search_nodes(&mut self) -> Vec> { - let mut nodes = vec![]; - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.order { - Ordering::Pre => { - self.recurse_preorder(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.recurse_postorder(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - nodes - } - - pub fn search_edges(&mut self) -> Vec> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.order { - Ordering::Pre => { - self.recurse_preorder(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.recurse_postorder(&mut edges, &mut visited, &mut queue); - }, - } - edges - } - - fn recurse_preorder( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.recurse_preorder( - result, - visited, - queue); - } - } - } - } - false - } - - fn recurse_postorder( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.recurse_postorder( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } + pub fn new(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Pre, + } + } + + pub fn pre(mut self) -> Self { + self.order = Ordering::Pre; + self + } + + pub fn post(mut self) -> Self { + self.order = Ordering::Post; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search_nodes(&mut self) -> Vec> { + let mut nodes = vec![]; + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.order { + Ordering::Pre => { + self.recurse_preorder(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.recurse_postorder(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + } + nodes + } + + pub fn search_edges(&mut self) -> Vec> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.order { + Ordering::Pre => { + self.recurse_preorder(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.recurse_postorder(&mut edges, &mut visited, &mut queue); + } + } + edges + } + + fn recurse_preorder( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + self.recurse_preorder(result, visited, queue); + result.push(edge); + } + } + } + false + } + + fn recurse_postorder( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + self.recurse_postorder(result, visited, queue); + result.push(edge); + } + } + } + false + } } diff --git a/src/sync_ungraph/node/algo/path.rs b/src/sync_ungraph/node/algo/path.rs index 6499b8d..21c6ca9 100644 --- a/src/sync_ungraph/node/algo/path.rs +++ b/src/sync_ungraph/node/algo/path.rs @@ -1,174 +1,176 @@ -use std::{fmt::Display, hash::Hash, ops::Index}; use super::*; +use std::{fmt::Display, hash::Hash, ops::Index}; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - let mut path = Vec::new(); - - if edge_tree.len() == 1 { - path.push(edge_tree[0].clone()); - return path; - } - let w = edge_tree.last().unwrap(); - path.push(w.clone()); - let mut i = 0; - for edge in edge_tree.iter().rev() { - let Edge(_, v, _) = edge; - let Edge(s, _, _) = &path[i]; - if s == v { - path.push(edge.clone()); - i += 1; - } - } - path.reverse(); - path + let mut path = Vec::new(); + + if edge_tree.len() == 1 { + path.push(edge_tree[0].clone()); + return path; + } + let w = edge_tree.last().unwrap(); + path.push(w.clone()); + let mut i = 0; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; + if s == v { + path.push(edge.clone()); + i += 1; + } + } + path.reverse(); + path } pub struct Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub edges: Vec>, + pub edges: Vec>, } impl Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn len(&self) -> usize { - // Conceptually a path always contains at least one node, - // the root node. The path containes edges, so the length - // of the path is the number of edges plus one. - self.edges.len() + 1 - } - - pub fn from_edge_tree(edge_tree: Vec>) -> Path { - Path { edges: backtrack_edge_tree(edge_tree) } - } - - pub fn iter_nodes(&self) -> PathNodeIterator { - PathNodeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn iter_edges(&self) -> PathEdgeIterator { - PathEdgeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn first_edge(&self) -> Option<&Edge> { - self.edges.first() - } - - pub fn first_node(&self) -> Option<&Node> { - self.edges.first().map(|e| &e.1) - } - - pub fn last_edge(&self) -> Option<&Edge> { - self.edges.last() - } - - pub fn last_node(&self) -> Option<&Node> { - self.edges.last().map(|e| &e.1) - } - - pub fn to_vec_nodes(&self) -> Vec> { - self.iter_nodes().map(|v| v).collect() - } - - pub fn to_vec_edges(&self) -> Vec> { - self.edges.clone() - } + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + + pub fn from_edge_tree(edge_tree: Vec>) -> Path { + Path { + edges: backtrack_edge_tree(edge_tree), + } + } + + pub fn iter_nodes(&self) -> PathNodeIterator { + PathNodeIterator { + path: self, + position: 0, + } + } + + pub fn iter_edges(&self) -> PathEdgeIterator { + PathEdgeIterator { + path: self, + position: 0, + } + } + + pub fn first_edge(&self) -> Option<&Edge> { + self.edges.first() + } + + pub fn first_node(&self) -> Option<&Node> { + self.edges.first().map(|e| &e.1) + } + + pub fn last_edge(&self) -> Option<&Edge> { + self.edges.last() + } + + pub fn last_node(&self) -> Option<&Node> { + self.edges.last().map(|e| &e.1) + } + + pub fn to_vec_nodes(&self) -> Vec> { + self.iter_nodes().collect() + } + + pub fn to_vec_edges(&self) -> Vec> { + self.edges.clone() + } } impl Index for Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Output = Edge; + type Output = Edge; - fn index(&self, index: usize) -> &Self::Output { - &self.edges[index] - } + fn index(&self, index: usize) -> &Self::Output { + &self.edges[index] + } } pub struct PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) + } + None => None, + } + } } pub struct PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Node; - - fn next(&mut self) -> Option { - if self.position == 0 { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - return Some(edge.0.clone()); - } - None => return None, - } - } - match self.path.edges.get(self.position - 1) { - Some(edge) => { - self.position += 1; - Some(edge.1.clone()) - } - None => None, - } - } -} \ No newline at end of file + type Item = Node; + + fn next(&mut self) -> Option { + if self.position == 0 { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + return Some(edge.0.clone()); + } + None => return None, + } + } + match self.path.edges.get(self.position - 1) { + Some(edge) => { + self.position += 1; + Some(edge.1.clone()) + } + None => None, + } + } +} diff --git a/src/sync_ungraph/node/algo/pfs.rs b/src/sync_ungraph/node/algo/pfs.rs index eadf25e..26dd43c 100644 --- a/src/sync_ungraph/node/algo/pfs.rs +++ b/src/sync_ungraph/node/algo/pfs.rs @@ -1,176 +1,170 @@ -use std::{ - fmt::Display, - hash::Hash, - collections::BinaryHeap, - cmp::Reverse -}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{cmp::Reverse, collections::BinaryHeap, fmt::Display, hash::Hash}; enum Priority { - Min, - Max + Min, + Max, } -pub struct PFS<'a, K, N, E> +pub struct Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - priority: Priority, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + priority: Priority, } -impl<'a, K, N, E> PFS<'a, K, N, E> +impl<'a, K, N, E> Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone + Ord, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone + Ord, + E: Clone, { - pub fn new(root: &Node) -> Self { - PFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - priority: Priority::Min, - } - } - - pub fn min(mut self) -> Self { - self.priority = Priority::Min; - self - } - - pub fn max(mut self) -> Self { - self.priority = Priority::Max; - self - } - - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn loop_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(Reverse(node)) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - visited.insert(v.key().clone()); - result.push(edge); - queue.push(Reverse(v)); - } - } - } - } - false - } - - fn loop_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - visited.insert(v.key().clone()); - result.push(edge); - queue.push(v); - } - } - } - } - false - } - - pub fn search(&mut self) -> Option> { - let path = self.search_path(); - match path { - Some(path) => Some(path.last_node().unwrap().clone()), - None => None, - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_max(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; - - visited.insert(self.root.key().clone()); - - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_max(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Pfs { + root: root.clone(), + target: None, + method: Method::Empty, + priority: Priority::Min, + } + } + + pub fn min(mut self) -> Self { + self.priority = Priority::Min; + self + } + + pub fn max(mut self) -> Self { + self.priority = Priority::Max; + self + } + + pub fn target(mut self, target: &'a K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn loop_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(Reverse(node)) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + visited.insert(v.key().clone()); + result.push(edge); + queue.push(Reverse(v)); + } + } + } + } + false + } + + fn loop_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + visited.insert(v.key().clone()); + result.push(edge); + queue.push(v); + } + } + } + } + false + } + + pub fn search(&mut self) -> Option> { + self.search_path() + .map(|path| path.last_node().unwrap().clone()) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + + match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); + + visited.insert(self.root.key().clone()); + + match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } +} diff --git a/src/sync_ungraph/node/mod.rs b/src/sync_ungraph/node/mod.rs index 7ba1e94..b9551ef 100644 --- a/src/sync_ungraph/node/mod.rs +++ b/src/sync_ungraph/node/mod.rs @@ -31,39 +31,32 @@ //! //! This node uses `Arc` for reference counting, thus it is thread-safe. -mod algo; mod adjacent; +mod algo; +use crate::error::Error; use std::{ fmt::Display, hash::Hash, ops::Deref, - sync::{Arc, Weak, RwLock}, + sync::{Arc, RwLock, Weak}, }; use self::{ - algo::{ - pfs::*, - dfs::*, - bfs::*, - order::*, - }, - adjacent::*, + adjacent::*, + algo::{bfs::*, dfs::*, order::*, pfs::*}, }; /// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. #[derive(Clone)] -pub struct Edge( - pub Node, - pub Node, - pub E, -) where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone; - - impl Edge +pub struct Edge(pub Node, pub Node, pub E) +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; + +impl Edge where K: Clone + Hash + PartialEq + Eq + Display, N: Clone, @@ -92,42 +85,43 @@ where impl PartialEq for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn eq(&self, other: &Edge) -> bool { - self.2 == other.2 - } + fn eq(&self, other: &Edge) -> bool { + self.2 == other.2 + } } impl Eq for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord -{} + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, +{ +} impl PartialOrd for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn partial_cmp(&self, other: &Edge) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Edge) -> Option { + Some(self.cmp(other)) + } } impl Ord for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn cmp(&self, other: &Edge) -> std::cmp::Ordering { - self.2.cmp(&other.2) - } + fn cmp(&self, other: &Edge) -> std::cmp::Ordering { + self.2.cmp(&other.2) + } } /// A `Node` is a key value pair smart-pointer, which includes inbound and @@ -163,67 +157,69 @@ where N: Clone, E: Clone, { - inner: Arc<(K, N, RwLock>)>, + inner: NodeInner, } +type NodeInner = Arc<(K, N, RwLock>)>; + impl Node where K: Clone + Hash + PartialEq + Eq + Display, N: Clone, E: Clone, { - /// Creates a new node with a given key and value. The key is used to - /// identify the node in the graph. Two nodes with the same key are - /// considered equal. Value is optional, node use's `()` as default - /// value type. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::::new(1, 'A'); - /// - /// assert!(*n1.key() == 1); - /// assert!(*n1.value() == 'A'); - /// ``` + /// Creates a new node with a given key and value. The key is used to + /// identify the node in the graph. Two nodes with the same key are + /// considered equal. Value is optional, node use's `()` as default + /// value type. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::::new(1, 'A'); + /// + /// assert!(*n1.key() == 1); + /// assert!(*n1.value() == 'A'); + /// ``` pub fn new(key: K, value: N) -> Self { Node { - inner: Arc::new((key, value, Adjacent::new())), + inner: NodeInner::new((key, value, Adjacent::new())), } } - /// Returns a reference to the node's key. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::::new(1, ()); - /// - /// assert!(*n1.key() == 1); - /// ``` + /// Returns a reference to the node's key. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::::new(1, ()); + /// + /// assert!(*n1.key() == 1); + /// ``` pub fn key(&self) -> &K { &self.inner.0 } - /// Returns a reference to the node's value. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::::new(1, 'A'); - /// - /// assert!(*n1.value() == 'A'); - /// ``` + /// Returns a reference to the node's value. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::::new(1, 'A'); + /// + /// assert!(*n1.value() == 'A'); + /// ``` pub fn value(&self) -> &N { &self.inner.1 } - /// Returns the degree of the node. The degree is the number of + /// Returns the degree of the node. The degree is the number of /// adjacent edges. /// /// # Example @@ -241,197 +237,208 @@ where /// assert!(a.out_degree() == 2); /// ``` pub fn degree(&self) -> usize { - self.inner.2.read().unwrap().len_outbound() - + self.inner.2.read().unwrap().len_inbound() + self.inner.2.read().unwrap().len_outbound() + self.inner.2.read().unwrap().len_inbound() } - /// Connects this node to another node. The connection is created in both - /// directions. The connection is created with the given edge value and - /// defaults to `()`. This function allows for creating multiple - /// connections between the same nodes. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, 4.20); - /// - /// assert!(n1.is_connected(n2.key())); - /// ``` - pub fn connect(&self, other: &Self, value: E) { + /// Connects this node to another node. The connection is created in both + /// directions. The connection is created with the given edge value and + /// defaults to `()`. This function allows for creating multiple + /// connections between the same nodes. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, 4.20); + /// + /// assert!(n1.is_connected(n2.key())); + /// ``` + pub fn connect(&self, other: &Self, value: E) { self.inner .2 .write() - .unwrap() + .unwrap() .push_outbound((other.clone(), value.clone())); other .inner .2 .write() - .unwrap() + .unwrap() .push_inbound((self.clone(), value)); } - /// Connects this node to another node. The connection is created in both - /// directions. The connection is created with the given edge value and - /// defaults to `()`. This function doesn't allow for creating multiple - /// connections between the same nodes. Returns Ok(()) if the connection - /// was created, Err(EdgeValue) if the connection already exists. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => assert!(n1.is_connected(n2.key())), - /// Err(_) => panic!("n1 should be connected to n2"), - /// } - /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => panic!("n1 should be connected to n2"), - /// Err(_) => assert!(n1.is_connected(n2.key())), - /// } - /// ``` - pub fn try_connect(&self, other: &Node, value: E) -> Result<(), E> { - if self.is_connected(other.key()) { - Err(value) - } else { - self.connect(other, value); - Ok(()) - } - } - - /// Disconnect two nodes from each other. The connection is removed in both - /// directions. Returns Ok(EdgeValue) if the connection was removed, Err(()) - /// if the connection doesn't exist. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// - /// if n1.disconnect(n2.key()).is_err() { - /// panic!("n1 should be connected to n2"); - /// } - /// - /// assert!(!n1.is_connected(n2.key())); - /// ``` - pub fn disconnect(&self, other: &K) -> Result { - self.inner.2.write() - .unwrap().remove_undirected(other) - } - - /// Removes all inbound and outbound connections to and from the node. - /// - /// # Example - /// - /// ``` - /// use gdsl::sync_ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// let n4 = Node::new(4, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n1.connect(&n4, ()); - /// n2.connect(&n1, ()); - /// n3.connect(&n1, ()); - /// n4.connect(&n1, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// assert!(n1.is_connected(n3.key())); - /// assert!(n1.is_connected(n4.key())); - /// - /// n1.isolate(); - /// - /// assert!(n1.is_orphan()); - /// ``` - pub fn isolate(&self) { - for Edge(_, v, _) in self.iter() { - if v.inner.2.write() - .unwrap().remove_inbound(self.key()).is_err() { - v.inner.2.write() - .unwrap().remove_outbound(self.key()).unwrap(); - } - } - self.inner.2.write() - .unwrap().clear_outbound(); - self.inner.2.write() - .unwrap().clear_inbound(); - } - - /// Returns true if the node is an oprhan. Orphan nodes are nodes that have - /// no connections. - pub fn is_orphan(&self) -> bool { - self.inner.2.read().unwrap().len_outbound() == 0 && self.inner.2.read().unwrap().len_inbound() == 0 - } - - /// Returns true if the node is connected to another node with a given key. - pub fn is_connected(&self, other: &K) -> bool { - self.find_adjacent(other).is_some() - } - - /// Get a pointer to an adjacent node with a given key. Returns None if no - /// node with the given key is found from the node's adjacency list. - pub fn find_adjacent(&self, other: &K) -> Option> { - match self.inner.2.read().unwrap().find_adjacent(other) { - Some((n, _)) => Some(n.upgrade().unwrap()), - None => None, - } - } - - /// Returns an iterator-like object that can be used to map, filter and - /// collect reachable nodes or edges in different orderings such as - /// postorder or preorder. - pub fn order(&self) -> Order { - Order::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a depth-first search. - pub fn dfs(&self) -> DFS { - DFS::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a breadth-first search. - pub fn bfs(&self) -> BFS { - BFS::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a - /// priotity-first search. - pub fn pfs(&self) -> PFS - where - N: Ord - { - PFS::new(self) - } - - /// Returns an iterator over the node's adjacent edges. - pub fn iter(&self) -> NodeIterator { - NodeIterator { node: self, position: 0 } - } - - pub fn sizeof(&self) -> usize { + /// Connects this node to another node. The connection is created in both + /// directions. The connection is created with the given edge value and + /// defaults to `()`. This function doesn't allow for creating multiple + /// connections between the same nodes. Returns Ok(()) if the connection + /// was created, Err(EdgeValue) if the connection already exists. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => assert!(n1.is_connected(n2.key())), + /// Err(_) => panic!("n1 should be connected to n2"), + /// } + /// + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => panic!("n1 should be connected to n2"), + /// Err(_) => assert!(n1.is_connected(n2.key())), + /// } + /// ``` + pub fn try_connect(&self, other: &Node, value: E) -> Result<(), Error> { + if self.is_connected(other.key()) { + Err(Error::EdgeAlreadyExists) + } else { + self.connect(other, value); + Ok(()) + } + } + + /// Disconnect two nodes from each other. The connection is removed in both + /// directions. Returns Ok(EdgeValue) if the connection was removed, Err(()) + /// if the connection doesn't exist. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// + /// if n1.disconnect(n2.key()).is_err() { + /// panic!("n1 should be connected to n2"); + /// } + /// + /// assert!(!n1.is_connected(n2.key())); + /// ``` + pub fn disconnect(&self, other: &K) -> Result { + self.inner.2.write().unwrap().remove_undirected(other) + } + + /// Removes all inbound and outbound connections to and from the node. + /// + /// # Example + /// + /// ``` + /// use gdsl::sync_ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// let n4 = Node::new(4, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n1.connect(&n4, ()); + /// n2.connect(&n1, ()); + /// n3.connect(&n1, ()); + /// n4.connect(&n1, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n3.key())); + /// assert!(n1.is_connected(n4.key())); + /// + /// n1.isolate(); + /// + /// assert!(n1.is_orphan()); + /// ``` + pub fn isolate(&self) { + for Edge(_, v, _) in self.iter() { + if v.inner + .2 + .write() + .unwrap() + .remove_inbound(self.key()) + .is_err() + { + v.inner + .2 + .write() + .unwrap() + .remove_outbound(self.key()) + .unwrap(); + } + } + self.inner.2.write().unwrap().clear_outbound(); + self.inner.2.write().unwrap().clear_inbound(); + } + + /// Returns true if the node is an oprhan. Orphan nodes are nodes that have + /// no connections. + pub fn is_orphan(&self) -> bool { + self.inner.2.read().unwrap().len_outbound() == 0 + && self.inner.2.read().unwrap().len_inbound() == 0 + } + + /// Returns true if the node is connected to another node with a given key. + pub fn is_connected(&self, other: &K) -> bool { + self.find_adjacent(other).is_some() + } + + /// Get a pointer to an adjacent node with a given key. Returns None if no + /// node with the given key is found from the node's adjacency list. + pub fn find_adjacent(&self, other: &K) -> Option> { + self.inner + .2 + .read() + .unwrap() + .find_adjacent(other) + .map(|(n, _)| n.upgrade().unwrap()) + } + + /// Returns an iterator-like object that can be used to map, filter and + /// collect reachable nodes or edges in different orderings such as + /// postorder or preorder. + pub fn order(&self) -> Order { + Order::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a depth-first search. + pub fn dfs(&self) -> Dfs { + Dfs::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a breadth-first search. + pub fn bfs(&self) -> Bfs { + Bfs::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a + /// priotity-first search. + pub fn pfs(&self) -> Pfs + where + N: Ord, + { + Pfs::new(self) + } + + /// Returns an iterator over the node's adjacent edges. + pub fn iter(&self) -> NodeIterator { + NodeIterator { + node: self, + position: 0, + } + } + + pub fn sizeof(&self) -> usize { std::mem::size_of::>() + std::mem::size_of::() + std::mem::size_of::() @@ -450,7 +457,7 @@ where { type Target = N; fn deref(&self) -> &Self::Target { - &self.value() + self.value() } } @@ -470,7 +477,8 @@ where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, E: Clone, -{} +{ +} impl PartialOrd for Node where @@ -479,7 +487,7 @@ where E: Clone, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.value().cmp(&other.value())) + Some(self.value().cmp(other.value())) } } @@ -490,50 +498,53 @@ where E: Clone, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.value().cmp(&other.value()) + self.value().cmp(other.value()) } } pub struct NodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - node: &'a Node, - position: usize, + node: &'a Node, + position: usize, } impl<'a, K, N, E> Iterator for NodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - let adjacent = &self.node.inner.2.read().unwrap(); - match adjacent.get_adjacent(self.position) { - Some((n, e)) => { - self.position += 1; - Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + let adjacent = &self.node.inner.2.read().unwrap(); + match adjacent.get_adjacent(self.position) { + Some((n, e)) => { + self.position += 1; + Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) + } + None => None, + } + } } impl<'a, K, N, E> IntoIterator for &'a Node where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - type IntoIter = NodeIterator<'a, K, N, E>; + type Item = Edge; + type IntoIter = NodeIterator<'a, K, N, E>; - fn into_iter(self) -> Self::IntoIter { - NodeIterator { node: self, position: 0 } - } -} \ No newline at end of file + fn into_iter(self) -> Self::IntoIter { + NodeIterator { + node: self, + position: 0, + } + } +} diff --git a/src/ungraph/graph_macros.rs b/src/ungraph/graph_macros.rs index 0d679e2..e1e5c78 100644 --- a/src/ungraph/graph_macros.rs +++ b/src/ungraph/graph_macros.rs @@ -3,46 +3,35 @@ /// Macro for creating a node. #[macro_export] macro_rules! ungraph_node { + // graph::Node + ( $key:expr ) => {{ + use gdsl::ungraph::*; - // graph::Node - ( $key:expr ) => { - { - use gdsl::ungraph::*; - - Node::new($key, ()) - } - }; - - // graph::Node - ( $key:expr, $param:expr ) => { - { - use gdsl::ungraph::*; + Node::new($key, ()) + }}; - Node::new($key, $param) - } - }; + // graph::Node + ( $key:expr, $param:expr ) => {{ + use gdsl::ungraph::*; + Node::new($key, $param) + }}; } /// Macro for connecting two nodes. #[macro_export] macro_rules! ungraph_connect { + ( $s:expr => $t:expr ) => {{ + use gdsl::ungraph::*; - ( $s:expr => $t:expr ) => { - { - use gdsl::ungraph::*; - - Node::connect($s, $t, ()) - } - }; + Node::connect($s, $t, ()) + }}; - ( $s:expr => $t:expr, $params:expr ) => { - { - use gdsl::ungraph::*; + ( $s:expr => $t:expr, $params:expr ) => {{ + use gdsl::ungraph::*; - Node::connect($s, $t, $params) - } - }; + Node::connect($s, $t, $params) + }}; } /// Macro for creating a graph. diff --git a/src/ungraph/graph_serde.rs b/src/ungraph/graph_serde.rs index cd1c0fe..69d7838 100644 --- a/src/ungraph/graph_serde.rs +++ b/src/ungraph/graph_serde.rs @@ -1,112 +1,122 @@ +use super::*; use serde::{ - Deserialize, - ser::{Serialize, Serializer, SerializeTuple}, - de::{self, Visitor}, + de::{self, Visitor}, + ser::{Serialize, SerializeTuple, Serializer}, + Deserialize, }; -use super::*; -fn graph_serde_decompose<'de, K, N, E>(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) +fn graph_serde_decompose(g: &Graph) -> (Vec<(K, N)>, Vec<(K, K, E)>) where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - let mut nodes = Vec::new(); - let mut edges = Vec::new(); + let mut nodes = Vec::new(); + let mut edges = Vec::new(); - for (_, n) in g.iter() { - nodes.push((n.key().clone(), n.value().clone())); + for (_, n) in g.iter() { + nodes.push((n.key().clone(), n.value().clone())); - for Edge(u, v, e) in n.iter() { - edges.push((u.key().clone(), v.key().clone(), e)); - } - } + for Edge(u, v, e) in n.iter() { + edges.push((u.key().clone(), v.key().clone(), e)); + } + } - (nodes, edges) + (nodes, edges) } impl Serialize for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Serialize, - N: Clone + Serialize, - E: Clone + Serialize, + K: Clone + Hash + PartialEq + Eq + Display + Serialize, + N: Clone + Serialize, + E: Clone + Serialize, { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut tuple = serializer.serialize_tuple(2)?; - let (nodes, edges) = graph_serde_decompose(self); - tuple.serialize_element(&nodes)?; - tuple.serialize_element(&edges)?; - tuple.end() - } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(2)?; + let (nodes, edges) = graph_serde_decompose(self); + tuple.serialize_element(&nodes)?; + tuple.serialize_element(&edges)?; + tuple.end() + } } impl<'de, K, N, E> Deserialize<'de> for Graph where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone, - { - _phantom: std::marker::PhantomData<(K, N, E)>, - } - - impl<'de, K, N, E> Visitor<'de> for GraphVisitor - where - K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, - N: Clone + Deserialize<'de>, - E: Clone + Deserialize<'de>, - { - type Value = Graph; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("node and edge lists") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: de::SeqAccess<'de> - { - let mut nodes = Vec::new(); - let mut edges: Vec<(K, K, E)> = Vec::new(); - - if let Some(node_seq) = seq.next_element()? { - nodes = node_seq; - } - - if let Some(edge_seq) = seq.next_element()? { - edges = edge_seq; - } - - let mut g = Graph::new(); - - for (k, v) in nodes { - g.insert(Node::new(k, v)); - } - - for (u, v, e) in edges { - let un = g.get(&u).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, u)))?; - let vn = g.get(&v).ok_or_else(|| de::Error::custom(&format!("Can't connect {} => {} because {} doesn't exist!", u, v, v)))?; - Node::connect(&un, &vn, e); - } - - Ok(g) - } - } - - deserializer.deserialize_seq(GraphVisitor { - _phantom: std::marker::PhantomData, - }) - } -} \ No newline at end of file + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone, + { + _phantom: std::marker::PhantomData<(K, N, E)>, + } + + impl<'de, K, N, E> Visitor<'de> for GraphVisitor + where + K: Clone + Hash + PartialEq + Eq + Display + Deserialize<'de>, + N: Clone + Deserialize<'de>, + E: Clone + Deserialize<'de>, + { + type Value = Graph; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("node and edge lists") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut nodes = Vec::new(); + let mut edges: Vec<(K, K, E)> = Vec::new(); + + if let Some(node_seq) = seq.next_element()? { + nodes = node_seq; + } + + if let Some(edge_seq) = seq.next_element()? { + edges = edge_seq; + } + + let mut g = Graph::new(); + + for (k, v) in nodes { + g.insert(Node::new(k, v)); + } + + for (u, v, e) in edges { + let un = g.get(&u).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, u + )) + })?; + let vn = g.get(&v).ok_or_else(|| { + de::Error::custom(format!( + "Can't connect {} => {} because {} doesn't exist!", + u, v, v + )) + })?; + Node::connect(&un, &vn, e); + } + + Ok(g) + } + } + + deserializer.deserialize_seq(GraphVisitor { + _phantom: std::marker::PhantomData, + }) + } +} diff --git a/src/ungraph/mod.rs b/src/ungraph/mod.rs index 7751d09..a37703b 100644 --- a/src/ungraph/mod.rs +++ b/src/ungraph/mod.rs @@ -1,252 +1,320 @@ //! Undirected Graph -mod node; mod graph_macros; mod graph_serde; +mod node; use std::{ - fmt::Display, + fmt::{Display, Write}, hash::Hash, }; -use ahash::HashMap as HashMap; +use ahash::HashMap; pub use self::node::*; pub struct Graph where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - nodes: HashMap>, + nodes: HashMap>, } -impl<'a, K, N, E> Graph +impl Graph where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - /// Create a new Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// ``` - pub fn new() -> Self { Self { nodes: HashMap::default() } } - - /// Check if a node with the given key exists in the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// - /// assert!(g.contains(&"A")); - /// ``` - pub fn contains(&self, key: &K) -> bool { self.nodes.contains_key(key) } - - /// Get the length of the Graph (amount of nodes) - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// - /// let len = g.len(); - /// - /// assert!(len == 2); - /// ``` - pub fn len(&self) -> usize { self.nodes.len() } - - /// Get a node by key - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// let node = g.get(&"A").unwrap(); - /// - /// assert!(node.key() == &"A"); - /// ``` - pub fn get(&self, key: &K) -> Option> { self.nodes.get(key).map(|node| node.clone()) } - - /// Check if Graph is empty - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// assert!(g.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { self.nodes.is_empty() } - - /// Insert a node into the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// - /// assert!(g.contains(&"A")); - /// assert!(g.insert(Node::new("A", 0)) == false); - /// ``` - pub fn insert(&mut self, node: Node) -> bool { - if self.nodes.contains_key(node.key()) { - false - } else { - self.nodes.insert(node.key().clone(), node.clone()); - true - } - } - - /// Remove a node from the Graph - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// - /// assert!(g.contains(&"A")); - /// - /// g.remove(&"A"); - /// - /// assert!(g.contains(&"A") == false); - /// ``` - pub fn remove(&mut self, node: &K) -> Option> { - self.nodes.remove(node) - } - - /// Collect nodes into a vector - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// let nodes = g.to_vec(); - /// - /// assert!(nodes.len() == 3); - /// ``` - pub fn to_vec(&self) -> Vec> { - self.nodes.values().map(|node| node.clone()).collect() - } - - /// Collect orpahn nodes into a vector - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// g.insert(Node::new("D", 0)); - /// - /// g["A"].connect(&g["B"], 0x1); - /// - /// let orphans = g.orphans(); - /// - /// assert!(orphans.len() == 2); - /// ``` - pub fn orphans(&self) -> Vec> { - self.nodes - .values() - .filter(|node| node.is_orphan()) - .map(|node| node.clone()) - .collect() - } - - /// Iterate over nodes in the graph in random order - /// - /// # Examples - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let mut g = Graph::<&str, u64, u64>::new(); - /// - /// g.insert(Node::new("A", 0)); - /// g.insert(Node::new("B", 0)); - /// g.insert(Node::new("C", 0)); - /// - /// for (key, _)in g.iter() { - /// println!("{}", key); - /// } - /// ``` - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, Node> { - self.nodes.iter() - } - - pub fn to_dot(&self) -> String - where - N: Display, - E: Display, - { - let mut s = String::new(); - s.push_str("digraph {\n"); - for (u_key, node) in self.iter() { - s.push_str(&format!(" {}", u_key.clone())); - for Edge(_, v, _) in node { - s.push_str(&format!("\n {} -> {}", u_key, v.key())); - } - s.push_str("\n"); - } - s.push_str("}"); - s - } + /// Create a new Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// ``` + pub fn new() -> Self { + Self { + nodes: HashMap::default(), + } + } + + /// Check if a node with the given key exists in the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// + /// assert!(g.contains(&"A")); + /// ``` + pub fn contains(&self, key: &K) -> bool { + self.nodes.contains_key(key) + } + + /// Get the length of the Graph (amount of nodes) + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// + /// let len = g.len(); + /// + /// assert!(len == 2); + /// ``` + pub fn len(&self) -> usize { + self.nodes.len() + } + + /// Get a node by key + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// let node = g.get(&"A").unwrap(); + /// + /// assert!(node.key() == &"A"); + /// ``` + pub fn get(&self, key: &K) -> Option> { + self.nodes.get(key).cloned() + } + + /// Check if Graph is empty + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// assert!(g.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.nodes.is_empty() + } + + /// Insert a node into the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// + /// assert!(g.contains(&"A")); + /// assert!(g.insert(Node::new("A", 0)) == false); + /// ``` + pub fn insert(&mut self, node: Node) -> bool { + if self.nodes.contains_key(node.key()) { + false + } else { + self.nodes.insert(node.key().clone(), node.clone()); + true + } + } + + /// Remove a node from the Graph + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// + /// assert!(g.contains(&"A")); + /// + /// g.remove(&"A"); + /// + /// assert!(g.contains(&"A") == false); + /// ``` + pub fn remove(&mut self, node: &K) -> Option> { + self.nodes.remove(node) + } + + /// Collect nodes into a vector + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// let nodes = g.to_vec(); + /// + /// assert!(nodes.len() == 3); + /// ``` + pub fn to_vec(&self) -> Vec> { + self.nodes.values().cloned().collect() + } + + /// Collect orpahn nodes into a vector + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// g.insert(Node::new("D", 0)); + /// + /// g["A"].connect(&g["B"], 0x1); + /// + /// let orphans = g.orphans(); + /// + /// assert!(orphans.len() == 2); + /// ``` + pub fn orphans(&self) -> Vec> { + self.nodes + .values() + .filter(|node| node.is_orphan()) + .cloned() + .collect() + } + + /// Iterate over nodes in the graph in random order + /// + /// # Examples + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let mut g = Graph::<&str, u64, u64>::new(); + /// + /// g.insert(Node::new("A", 0)); + /// g.insert(Node::new("B", 0)); + /// g.insert(Node::new("C", 0)); + /// + /// for (key, _)in g.iter() { + /// println!("{}", key); + /// } + /// ``` + pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, Node> { + self.nodes.iter() + } + + pub fn to_dot(&self) -> String { + let mut s = String::new(); + s.push_str("digraph {\n"); + for (u_key, node) in self.iter() { + write!(&mut s, " {}", u_key.clone()).unwrap(); + for Edge(_, v, _) in node { + write!(&mut s, "\n {} -> {}", u_key, v.key()).unwrap(); + } + s.push('\n'); + } + s.push('}'); + s + } + + fn fmt_attr(attrs: Vec<(String, String)>) -> String { + let mut s = String::new(); + for (k, v) in attrs { + write!(&mut s, "[{}=\"{}\"]", k, v).unwrap(); + } + s + } + + pub fn to_dot_with_attr( + &self, + gattr: &dyn Fn(&Self) -> Option>, + nattr: &dyn Fn(&Node) -> Option>, + eattr: &dyn Fn(&Node, &Node, &E) -> Option>, + ) -> String { + let mut s = String::new(); + s.push_str("digraph {\n"); + if let Some(gattrs) = gattr(self) { + for (k, v) in gattrs { + s.push_str(&format!("\t{}=\"{}\"\n", k, v)); + } + } + for (u_key, node) in self.iter() { + s.push_str(&format!("\t{}", u_key.clone())); + if let Some(nattr) = nattr(node) { + s.push_str(&format!(" {}", Self::fmt_attr(nattr))); + } + s.push('\n'); + } + for (_, node) in self.iter() { + for Edge(u, v, e) in node { + s.push_str(&format!("\t{} -> {}", u.key(), v.key())); + if let Some(eattrs) = eattr(&u, &v, &e) { + s.push_str(&format!(" {}", Self::fmt_attr(eattrs))); + } + s.push('\n'); + } + } + s.push('}'); + s + } + + pub fn sizeof(&self) -> usize { + let mut size = 0; + for (k, node) in self.iter() { + size += node.sizeof() + std::mem::size_of_val(k); + } + size + } } -impl<'a, K, N, E> std::ops::Index for Graph +impl std::ops::Index for Graph where - K: Clone + Hash + Display + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, { - type Output = Node; + type Output = Node; - fn index(&self, key: K) -> &Self::Output { - &self.nodes[&key] - } + fn index(&self, key: K) -> &Self::Output { + &self.nodes[&key] + } +} + +impl Default for Graph +where + K: Clone + Hash + Display + Eq, + N: Clone, + E: Clone, +{ + fn default() -> Self { + Self::new() + } } diff --git a/src/ungraph/node/adjacent.rs b/src/ungraph/node/adjacent.rs index 8090030..77f7748 100644 --- a/src/ungraph/node/adjacent.rs +++ b/src/ungraph/node/adjacent.rs @@ -1,30 +1,31 @@ use super::*; +use crate::error::Error; #[derive(Clone)] pub struct WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - inner: Weak<(K, N, RefCell>)>, + inner: Weak<(K, N, RefCell>)>, } impl WeakNode where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn upgrade(&self) -> Option> { - self.inner.upgrade().map(|inner| Node { inner }) - } - - pub fn downgrade(node: &Node) -> Self { - WeakNode { - inner: Rc::downgrade(&node.inner) - } - } + pub fn upgrade(&self) -> Option> { + self.inner.upgrade().map(|inner| Node { inner }) + } + + pub fn downgrade(node: &Node) -> Self { + WeakNode { + inner: Rc::downgrade(&node.inner), + } + } } pub struct Adjacent @@ -50,15 +51,15 @@ where }) } - pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { - match self.outbound.get(idx) { - Some(edge) => Some((&edge.0, &edge.1)), - None => match self.inbound.get(idx - self.outbound.len()) { - Some(edge) => Some((&edge.0, &edge.1)), - None => None, - }, - } - } + pub fn get_adjacent(&self, idx: usize) -> Option<(&WeakNode, &E)> { + match self.outbound.get(idx) { + Some(edge) => Some((&edge.0, &edge.1)), + None => self + .inbound + .get(idx - self.outbound.len()) + .map(|edge| (&edge.0, &edge.1)), + } + } pub fn find_outbound(&self, node: &K) -> Option<(&WeakNode, &E)> { for edge in self.outbound.iter() { @@ -78,12 +79,12 @@ where None } - pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { - match self.find_outbound(node) { - Some(edge) => Some(edge), - None => self.find_inbound(node), - } - } + pub fn find_adjacent(&self, node: &K) -> Option<(&WeakNode, &E)> { + match self.find_outbound(node) { + Some(edge) => Some(edge), + None => self.find_inbound(node), + } + } pub fn len_outbound(&self) -> usize { self.outbound.len() @@ -94,37 +95,37 @@ where } pub fn push_inbound(&mut self, edge: (Node, E)) { - self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); + self.inbound.push((WeakNode::downgrade(&edge.0), edge.1)); } pub fn push_outbound(&mut self, edge: (Node, E)) { self.outbound.push((WeakNode::downgrade(&edge.0), edge.1)); } - pub fn remove_inbound(&mut self, source: &K) -> Result { - for (idx, edge) in self.inbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == source { - return Ok(self.inbound.remove(idx).1); - } - } - Err(()) + pub fn remove_inbound(&mut self, source: &K) -> Result { + for (idx, edge) in self.inbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == source { + return Ok(self.inbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_outbound(&mut self, target: &K) -> Result { - for (idx, edge) in self.outbound.iter().enumerate() { - if edge.0.upgrade().unwrap().key() == target { - return Ok(self.outbound.remove(idx).1); - } - } - Err(()) + pub fn remove_outbound(&mut self, target: &K) -> Result { + for (idx, edge) in self.outbound.iter().enumerate() { + if edge.0.upgrade().unwrap().key() == target { + return Ok(self.outbound.remove(idx).1); + } + } + Err(Error::EdgeNotFound) } - pub fn remove_undirected(&mut self, node: &K) -> Result { - match self.remove_inbound(node) { - Ok(edge) => Ok(edge), - Err(_) => self.remove_outbound(node), - } - } + pub fn remove_undirected(&mut self, node: &K) -> Result { + match self.remove_inbound(node) { + Ok(edge) => Ok(edge), + Err(_) => self.remove_outbound(node), + } + } pub fn clear_inbound(&mut self) { self.inbound.clear(); @@ -134,10 +135,10 @@ where self.outbound.clear(); } - pub fn sizeof(&self) -> usize { - self.inbound.len() + self.outbound.len() - * (std::mem::size_of::>() - + std::mem::size_of::()) - + std::mem::size_of::() - } -} \ No newline at end of file + pub fn sizeof(&self) -> usize { + self.inbound.len() + + self.outbound.len() + * (std::mem::size_of::>() + std::mem::size_of::()) + + std::mem::size_of::() + } +} diff --git a/src/ungraph/node/algo/bfs.rs b/src/ungraph/node/algo/bfs.rs index 7518557..3a40d67 100644 --- a/src/ungraph/node/algo/bfs.rs +++ b/src/ungraph/node/algo/bfs.rs @@ -1,134 +1,134 @@ -use std::{fmt::Display, hash::Hash, collections::VecDeque}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{collections::VecDeque, fmt::Display, hash::Hash}; -pub struct BFS<'a, K, N, E> +pub struct Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, + root: Node, + target: Option, + method: Method<'a, K, N, E>, } -impl<'a, K, N, E> BFS<'a, K, N, E> +impl<'a, K, N, E> Bfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - BFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - } - } - - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn loop_adjacent( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> bool { - while let Some(node) = queue.pop_front() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push_back(v.clone()); - } - } - } - } - false - } - - fn loop_adjacent_find( - &mut self, - visited: &mut HashSet, - queue: &mut VecDeque>, - ) -> Option> { - while let Some(node) = queue.pop_front() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target(); - if !visited.contains(v.key()) { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push_back(v.clone()); - } - } - } - } - None - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - return self.loop_adjacent_find(&mut visited, &mut queue); - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - self.target = Some(self.root.key().clone()); - queue.push_back(self.root.clone()); - - if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = VecDeque::new(); - let mut visited = HashSet::default(); - - queue.push_back(self.root.clone()); - visited.insert(self.root.key().clone()); - - if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } + pub fn new(root: &Node) -> Self { + Bfs { + root: root.clone(), + target: None, + method: Method::Empty, + } + } + + pub fn target(mut self, target: &'a K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn loop_adjacent( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> bool { + while let Some(node) = queue.pop_front() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push_back(v.clone()); + } + } + } + } + false + } + + fn loop_adjacent_find( + &mut self, + visited: &mut HashSet, + queue: &mut VecDeque>, + ) -> Option> { + while let Some(node) = queue.pop_front() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push_back(v.clone()); + } + } + } + } + None + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + self.loop_adjacent_find(&mut visited, &mut queue) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push_back(self.root.clone()); + + if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = VecDeque::new(); + let mut visited = HashSet::default(); + + queue.push_back(self.root.clone()); + visited.insert(self.root.key().clone()); + + if self.loop_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } } diff --git a/src/ungraph/node/algo/dfs.rs b/src/ungraph/node/algo/dfs.rs index 523112f..680f3da 100644 --- a/src/ungraph/node/algo/dfs.rs +++ b/src/ungraph/node/algo/dfs.rs @@ -1,139 +1,141 @@ -use std::{fmt::Display, hash::Hash}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{fmt::Display, hash::Hash}; -pub struct DFS<'a, K, N, E> +pub struct Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, + root: Node, + target: Option, + method: Method<'a, K, N, E>, } -impl<'a, K, N, E> DFS<'a, K, N, E> +impl<'a, K, N, E> Dfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &Node) -> Self { - DFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - } - } - - pub fn target(mut self, target: &K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn recurse_adjacent(&mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target().clone(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - result.push(edge); - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - queue.push(v.clone()); - if self.recurse_adjacent(result, visited, queue) { - return true; - } - } - } - } - } - false - } - - fn recurse_adjacent_find(&mut self, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> Option> { - if let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.target(); - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - if let Some(ref t) = self.target { - if v.key() == t { - return Some(v.clone()); - } - } - queue.push(v.clone()); - match self.recurse_adjacent_find(visited, queue) { - Some(t) => return Some(t), - None => continue, - } - } - } - } - } - None - } - - pub fn search(&'a mut self) -> Option> { - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - return self.recurse_adjacent_find(&mut visited, &mut queue); - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - self.target = Some(self.root.key().clone()); - queue.push(self.root.clone()); - - if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { - Some(Path::from_edge_tree(edges)) - } else { - None - } - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Dfs { + root: root.clone(), + target: None, + method: Method::Empty, + } + } + + pub fn target(mut self, target: &K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn recurse_adjacent( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target().clone(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + result.push(edge); + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + queue.push(v.clone()); + if self.recurse_adjacent(result, visited, queue) { + return true; + } + } + } + } + } + false + } + + fn recurse_adjacent_find( + &mut self, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> Option> { + if let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.target(); + if !visited.contains(v.key()) { + visited.insert(v.key().clone()); + if let Some(ref t) = self.target { + if v.key() == t { + return Some(v.clone()); + } + } + queue.push(v.clone()); + match self.recurse_adjacent_find(visited, queue) { + Some(t) => return Some(t), + None => continue, + } + } + } + } + } + None + } + + pub fn search(&'a mut self) -> Option> { + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + self.recurse_adjacent_find(&mut visited, &mut queue) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + queue.push(self.root.clone()); + + if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + if self.recurse_adjacent(&mut edges, &mut visited, &mut queue) { + Some(Path::from_edge_tree(edges)) + } else { + None + } + } +} diff --git a/src/ungraph/node/algo/method.rs b/src/ungraph/node/algo/method.rs index c973f3b..3c0cd59 100644 --- a/src/ungraph/node/algo/method.rs +++ b/src/ungraph/node/algo/method.rs @@ -5,26 +5,29 @@ pub type ForEach<'a, K, N, E> = &'a mut dyn FnMut(&Edge); pub enum Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - NullMethod, - Filter(Filter<'a, K, N, E>), - ForEach(ForEach<'a, K, N, E>), + Empty, + Filter(Filter<'a, K, N, E>), + ForEach(ForEach<'a, K, N, E>), } impl<'a, K, N, E> Method<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn exec(&mut self, e: &Edge) -> bool { - match self { - Method::NullMethod => true, - Method::Filter(f) => f(e), - Method::ForEach(f) => {f(e); true}, - } - } -} \ No newline at end of file + pub fn exec(&mut self, e: &Edge) -> bool { + match self { + Method::Empty => true, + Method::Filter(f) => f(e), + Method::ForEach(f) => { + f(e); + true + } + } + } +} diff --git a/src/ungraph/node/algo/mod.rs b/src/ungraph/node/algo/mod.rs index ad8023c..f5c077d 100644 --- a/src/ungraph/node/algo/mod.rs +++ b/src/ungraph/node/algo/mod.rs @@ -2,8 +2,8 @@ use super::*; pub mod bfs; pub mod dfs; -pub mod pfs; pub mod order; +pub mod pfs; +mod method; mod path; -mod method; \ No newline at end of file diff --git a/src/ungraph/node/algo/order.rs b/src/ungraph/node/algo/order.rs index eaa1b64..d914759 100644 --- a/src/ungraph/node/algo/order.rs +++ b/src/ungraph/node/algo/order.rs @@ -1,161 +1,147 @@ //==== Includes =============================================================== -use std::{ - fmt::Display, - hash::Hash, -}; +use std::{fmt::Display, hash::Hash}; -use ahash::HashSet as HashSet; +use ahash::HashSet; -use super::*; use super::method::*; +use super::*; //==== Ordering =============================================================== pub enum Ordering { - Pre, - Post, + Pre, + Post, } pub struct Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: &'a Node, - method: Method<'a, K, N, E>, - order: Ordering, + root: &'a Node, + method: Method<'a, K, N, E>, + order: Ordering, } - impl<'a, K, N, E> Order<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn new(root: &'a Node) -> Self { - Self { - root, - method: Method::NullMethod, - order: Ordering::Pre, - } - } - - pub fn pre(mut self) -> Self { - self.order = Ordering::Pre; - self - } - - pub fn post(mut self) -> Self { - self.order = Ordering::Post; - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - pub fn search_nodes(&mut self) -> Vec> { - let mut nodes = vec![]; - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.order { - Ordering::Pre => { - self.recurse_preorder(&mut edges, &mut visited, &mut queue); - nodes.push(self.root.clone()); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - }, - Ordering::Post => { - self.recurse_postorder(&mut edges, &mut visited, &mut queue); - let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); - nodes.append(&mut coll); - nodes.push(self.root.clone()); - }, - } - nodes - } - - pub fn search_edges(&mut self) -> Vec> { - let mut edges = vec![]; - let mut queue = vec![]; - let mut visited = HashSet::default(); - - queue.push(self.root.clone()); - visited.insert(self.root.key().clone()); - - match self.order { - Ordering::Pre => { - self.recurse_preorder(&mut edges, &mut visited, &mut queue); - }, - Ordering::Post => { - self.recurse_postorder(&mut edges, &mut visited, &mut queue); - }, - } - edges - } - - fn recurse_preorder( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - let edge = edge.reverse(); - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - result.push(edge); - self.recurse_preorder( - result, - visited, - queue); - } - } - } - } - false - } - - fn recurse_postorder( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut Vec>, - ) -> bool { - if let Some(node) = queue.pop() { - for edge in node.iter() { - let v = edge.1.clone(); - if self.method.exec(&edge) { - if visited.contains(v.key()) == false { - visited.insert(v.key().clone()); - queue.push(v.clone()); - self.recurse_postorder( - result, - visited, - queue); - result.push(edge); - } - } - } - } - false - } + pub fn new(root: &'a Node) -> Self { + Self { + root, + method: Method::Empty, + order: Ordering::Pre, + } + } + + pub fn pre(mut self) -> Self { + self.order = Ordering::Pre; + self + } + + pub fn post(mut self) -> Self { + self.order = Ordering::Post; + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + pub fn search_nodes(&mut self) -> Vec> { + let mut nodes = vec![]; + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.order { + Ordering::Pre => { + self.recurse_preorder(&mut edges, &mut visited, &mut queue); + nodes.push(self.root.clone()); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + } + Ordering::Post => { + self.recurse_postorder(&mut edges, &mut visited, &mut queue); + let mut coll = edges.iter().map(|Edge(_, v, _)| v.clone()).collect(); + nodes.append(&mut coll); + nodes.push(self.root.clone()); + } + } + nodes + } + + pub fn search_edges(&mut self) -> Vec> { + let mut edges = vec![]; + let mut queue = vec![]; + let mut visited = HashSet::default(); + + queue.push(self.root.clone()); + visited.insert(self.root.key().clone()); + + match self.order { + Ordering::Pre => { + self.recurse_preorder(&mut edges, &mut visited, &mut queue); + } + Ordering::Post => { + self.recurse_postorder(&mut edges, &mut visited, &mut queue); + } + } + edges + } + + fn recurse_preorder( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + let edge = edge.reverse(); + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + self.recurse_preorder(result, visited, queue); + result.push(edge); + } + } + } + false + } + + fn recurse_postorder( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut Vec>, + ) -> bool { + if let Some(node) = queue.pop() { + for edge in node.iter() { + let v = edge.1.clone(); + if self.method.exec(&edge) && !visited.contains(v.key()) { + visited.insert(v.key().clone()); + queue.push(v.clone()); + self.recurse_postorder(result, visited, queue); + result.push(edge); + } + } + } + false + } } diff --git a/src/ungraph/node/algo/path.rs b/src/ungraph/node/algo/path.rs index 6499b8d..21c6ca9 100644 --- a/src/ungraph/node/algo/path.rs +++ b/src/ungraph/node/algo/path.rs @@ -1,174 +1,176 @@ -use std::{fmt::Display, hash::Hash, ops::Index}; use super::*; +use std::{fmt::Display, hash::Hash, ops::Index}; pub fn backtrack_edge_tree(edge_tree: Vec>) -> Vec> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - let mut path = Vec::new(); - - if edge_tree.len() == 1 { - path.push(edge_tree[0].clone()); - return path; - } - let w = edge_tree.last().unwrap(); - path.push(w.clone()); - let mut i = 0; - for edge in edge_tree.iter().rev() { - let Edge(_, v, _) = edge; - let Edge(s, _, _) = &path[i]; - if s == v { - path.push(edge.clone()); - i += 1; - } - } - path.reverse(); - path + let mut path = Vec::new(); + + if edge_tree.len() == 1 { + path.push(edge_tree[0].clone()); + return path; + } + let w = edge_tree.last().unwrap(); + path.push(w.clone()); + let mut i = 0; + for edge in edge_tree.iter().rev() { + let Edge(_, v, _) = edge; + let Edge(s, _, _) = &path[i]; + if s == v { + path.push(edge.clone()); + i += 1; + } + } + path.reverse(); + path } pub struct Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub edges: Vec>, + pub edges: Vec>, } impl Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - pub fn len(&self) -> usize { - // Conceptually a path always contains at least one node, - // the root node. The path containes edges, so the length - // of the path is the number of edges plus one. - self.edges.len() + 1 - } - - pub fn from_edge_tree(edge_tree: Vec>) -> Path { - Path { edges: backtrack_edge_tree(edge_tree) } - } - - pub fn iter_nodes(&self) -> PathNodeIterator { - PathNodeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn iter_edges(&self) -> PathEdgeIterator { - PathEdgeIterator { - path: self.clone(), - position: 0, - } - } - - pub fn first_edge(&self) -> Option<&Edge> { - self.edges.first() - } - - pub fn first_node(&self) -> Option<&Node> { - self.edges.first().map(|e| &e.1) - } - - pub fn last_edge(&self) -> Option<&Edge> { - self.edges.last() - } - - pub fn last_node(&self) -> Option<&Node> { - self.edges.last().map(|e| &e.1) - } - - pub fn to_vec_nodes(&self) -> Vec> { - self.iter_nodes().map(|v| v).collect() - } - - pub fn to_vec_edges(&self) -> Vec> { - self.edges.clone() - } + pub fn len(&self) -> usize { + // Conceptually a path always contains at least one node, + // the root node. The path containes edges, so the length + // of the path is the number of edges plus one. + self.edges.len() + 1 + } + + pub fn from_edge_tree(edge_tree: Vec>) -> Path { + Path { + edges: backtrack_edge_tree(edge_tree), + } + } + + pub fn iter_nodes(&self) -> PathNodeIterator { + PathNodeIterator { + path: self, + position: 0, + } + } + + pub fn iter_edges(&self) -> PathEdgeIterator { + PathEdgeIterator { + path: self, + position: 0, + } + } + + pub fn first_edge(&self) -> Option<&Edge> { + self.edges.first() + } + + pub fn first_node(&self) -> Option<&Node> { + self.edges.first().map(|e| &e.1) + } + + pub fn last_edge(&self) -> Option<&Edge> { + self.edges.last() + } + + pub fn last_node(&self) -> Option<&Node> { + self.edges.last().map(|e| &e.1) + } + + pub fn to_vec_nodes(&self) -> Vec> { + self.iter_nodes().collect() + } + + pub fn to_vec_edges(&self) -> Vec> { + self.edges.clone() + } } impl Index for Path where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Output = Edge; + type Output = Edge; - fn index(&self, index: usize) -> &Self::Output { - &self.edges[index] - } + fn index(&self, index: usize) -> &Self::Output { + &self.edges[index] + } } pub struct PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathEdgeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + Some(Edge(edge.0.clone(), edge.1.clone(), edge.2.clone())) + } + None => None, + } + } } pub struct PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - path: &'a Path, - position: usize, + path: &'a Path, + position: usize, } impl<'a, K, N, E> Iterator for PathNodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Node; - - fn next(&mut self) -> Option { - if self.position == 0 { - match self.path.edges.get(self.position) { - Some(edge) => { - self.position += 1; - return Some(edge.0.clone()); - } - None => return None, - } - } - match self.path.edges.get(self.position - 1) { - Some(edge) => { - self.position += 1; - Some(edge.1.clone()) - } - None => None, - } - } -} \ No newline at end of file + type Item = Node; + + fn next(&mut self) -> Option { + if self.position == 0 { + match self.path.edges.get(self.position) { + Some(edge) => { + self.position += 1; + return Some(edge.0.clone()); + } + None => return None, + } + } + match self.path.edges.get(self.position - 1) { + Some(edge) => { + self.position += 1; + Some(edge.1.clone()) + } + None => None, + } + } +} diff --git a/src/ungraph/node/algo/pfs.rs b/src/ungraph/node/algo/pfs.rs index eadf25e..26dd43c 100644 --- a/src/ungraph/node/algo/pfs.rs +++ b/src/ungraph/node/algo/pfs.rs @@ -1,176 +1,170 @@ -use std::{ - fmt::Display, - hash::Hash, - collections::BinaryHeap, - cmp::Reverse -}; -use super::{*, method::*, path::*}; +use super::{method::*, path::*, *}; use ahash::AHashSet as HashSet; +use std::{cmp::Reverse, collections::BinaryHeap, fmt::Display, hash::Hash}; enum Priority { - Min, - Max + Min, + Max, } -pub struct PFS<'a, K, N, E> +pub struct Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - root: Node, - target: Option, - method: Method<'a, K, N, E>, - priority: Priority, + root: Node, + target: Option, + method: Method<'a, K, N, E>, + priority: Priority, } -impl<'a, K, N, E> PFS<'a, K, N, E> +impl<'a, K, N, E> Pfs<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone + Ord, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone + Ord, + E: Clone, { - pub fn new(root: &Node) -> Self { - PFS { - root: root.clone(), - target: None, - method: Method::NullMethod, - priority: Priority::Min, - } - } - - pub fn min(mut self) -> Self { - self.priority = Priority::Min; - self - } - - pub fn max(mut self) -> Self { - self.priority = Priority::Max; - self - } - - pub fn target(mut self, target: &'a K) -> Self { - self.target = Some(target.clone()); - self - } - - pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { - self.method = Method::ForEach(f); - self - } - - pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { - self.method = Method::Filter(f); - self - } - - fn loop_min( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>>, - ) -> bool { - while let Some(Reverse(node)) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - visited.insert(v.key().clone()); - result.push(edge); - queue.push(Reverse(v)); - } - } - } - } - false - } - - fn loop_max( - &mut self, - result: &mut Vec>, - visited: &mut HashSet, - queue: &mut BinaryHeap>, - ) -> bool { - while let Some(node) = queue.pop() { - for edge in node.iter() { - if self.method.exec(&edge) { - let v = edge.1.clone(); - if !visited.contains(v.key()) { - if let Some(ref t) = self.target { - if v.key() == t { - return true; - } - } - visited.insert(v.key().clone()); - result.push(edge); - queue.push(v); - } - } - } - } - false - } - - pub fn search(&mut self) -> Option> { - let path = self.search_path(); - match path { - Some(path) => Some(path.last_node().unwrap().clone()), - None => None, - } - } - - pub fn search_cycle(&'a mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; - - self.target = Some(self.root.key().clone()); - - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_max(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } - - pub fn search_path(&mut self) -> Option> { - let mut edges = vec![]; - let mut visited = HashSet::default(); - let target_found; - - visited.insert(self.root.key().clone()); - - match self.priority { - Priority::Min => { - let mut queue = BinaryHeap::new(); - queue.push(Reverse(self.root.clone())); - target_found = self.loop_min(&mut edges, &mut visited, &mut queue); - } - Priority::Max => { - let mut queue = BinaryHeap::new(); - queue.push(self.root.clone()); - target_found = self.loop_max(&mut edges, &mut visited, &mut queue); - } - } - if target_found { - return Some(Path::from_edge_tree(edges)); - } - None - } -} \ No newline at end of file + pub fn new(root: &Node) -> Self { + Pfs { + root: root.clone(), + target: None, + method: Method::Empty, + priority: Priority::Min, + } + } + + pub fn min(mut self) -> Self { + self.priority = Priority::Min; + self + } + + pub fn max(mut self) -> Self { + self.priority = Priority::Max; + self + } + + pub fn target(mut self, target: &'a K) -> Self { + self.target = Some(target.clone()); + self + } + + pub fn for_each(mut self, f: ForEach<'a, K, N, E>) -> Self { + self.method = Method::ForEach(f); + self + } + + pub fn filter(mut self, f: Filter<'a, K, N, E>) -> Self { + self.method = Method::Filter(f); + self + } + + fn loop_min( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>>, + ) -> bool { + while let Some(Reverse(node)) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + visited.insert(v.key().clone()); + result.push(edge); + queue.push(Reverse(v)); + } + } + } + } + false + } + + fn loop_max( + &mut self, + result: &mut Vec>, + visited: &mut HashSet, + queue: &mut BinaryHeap>, + ) -> bool { + while let Some(node) = queue.pop() { + for edge in node.iter() { + if self.method.exec(&edge) { + let v = edge.1.clone(); + if !visited.contains(v.key()) { + if let Some(ref t) = self.target { + if v.key() == t { + return true; + } + } + visited.insert(v.key().clone()); + result.push(edge); + queue.push(v); + } + } + } + } + false + } + + pub fn search(&mut self) -> Option> { + self.search_path() + .map(|path| path.last_node().unwrap().clone()) + } + + pub fn search_cycle(&'a mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); + + self.target = Some(self.root.key().clone()); + + match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } + + pub fn search_path(&mut self) -> Option> { + let mut edges = vec![]; + let mut visited = HashSet::default(); + + visited.insert(self.root.key().clone()); + + match self.priority { + Priority::Min => { + let mut queue = BinaryHeap::new(); + queue.push(Reverse(self.root.clone())); + match self.loop_min(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + Priority::Max => { + let mut queue = BinaryHeap::new(); + queue.push(self.root.clone()); + match self.loop_max(&mut edges, &mut visited, &mut queue) { + true => Some(Path::from_edge_tree(edges)), + false => None, + } + } + } + } +} diff --git a/src/ungraph/node/mod.rs b/src/ungraph/node/mod.rs index 8cac122..f24f8e1 100644 --- a/src/ungraph/node/mod.rs +++ b/src/ungraph/node/mod.rs @@ -31,40 +31,33 @@ //! //! This node uses `Rc` for reference counting, thus it is not thread-safe. -mod algo; mod adjacent; +mod algo; +use crate::error::Error; use std::{ + cell::RefCell, fmt::Display, hash::Hash, - cell::RefCell, ops::Deref, rc::{Rc, Weak}, }; use self::{ - algo::{ - pfs::*, - dfs::*, - bfs::*, - order::*, - }, - adjacent::*, + adjacent::*, + algo::{bfs::*, dfs::*, order::*, pfs::*}, }; /// An edge between nodes is a tuple struct `Edge(u, v, e)` where `u` is the /// source node, `v` is the target node, and `e` is the edge's value. #[derive(Clone)] -pub struct Edge( - pub Node, - pub Node, - pub E, -) where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone; - - impl Edge +pub struct Edge(pub Node, pub Node, pub E) +where + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone; + +impl Edge where K: Clone + Hash + PartialEq + Eq + Display, N: Clone, @@ -93,42 +86,43 @@ where impl PartialEq for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn eq(&self, other: &Edge) -> bool { - self.2 == other.2 - } + fn eq(&self, other: &Edge) -> bool { + self.2 == other.2 + } } impl Eq for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord -{} + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, +{ +} impl PartialOrd for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn partial_cmp(&self, other: &Edge) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Edge) -> Option { + Some(self.cmp(other)) + } } impl Ord for Edge where - K: Clone + Hash + PartialEq + Eq + Display, - N: Clone, - E: Clone + Ord + K: Clone + Hash + PartialEq + Eq + Display, + N: Clone, + E: Clone + Ord, { - fn cmp(&self, other: &Edge) -> std::cmp::Ordering { - self.2.cmp(&other.2) - } + fn cmp(&self, other: &Edge) -> std::cmp::Ordering { + self.2.cmp(&other.2) + } } /// A `Node` is a key value pair smart-pointer, which includes inbound and @@ -173,58 +167,58 @@ where N: Clone, E: Clone, { - /// Creates a new node with a given key and value. The key is used to - /// identify the node in the graph. Two nodes with the same key are - /// considered equal. Value is optional, node use's `()` as default - /// value type. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::::new(1, 'A'); - /// - /// assert!(*n1.key() == 1); - /// assert!(*n1.value() == 'A'); - /// ``` + /// Creates a new node with a given key and value. The key is used to + /// identify the node in the graph. Two nodes with the same key are + /// considered equal. Value is optional, node use's `()` as default + /// value type. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::::new(1, 'A'); + /// + /// assert!(*n1.key() == 1); + /// assert!(*n1.value() == 'A'); + /// ``` pub fn new(key: K, value: N) -> Self { Node { inner: Rc::new((key, value, Adjacent::new())), } } - /// Returns a reference to the node's key. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::::new(1, ()); - /// - /// assert!(*n1.key() == 1); - /// ``` + /// Returns a reference to the node's key. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::::new(1, ()); + /// + /// assert!(*n1.key() == 1); + /// ``` pub fn key(&self) -> &K { &self.inner.0 } - /// Returns a reference to the node's value. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::::new(1, 'A'); - /// - /// assert!(*n1.value() == 'A'); - /// ``` + /// Returns a reference to the node's value. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::::new(1, 'A'); + /// + /// assert!(*n1.value() == 'A'); + /// ``` pub fn value(&self) -> &N { &self.inner.1 } - /// Returns the degree of the node. The degree is the number of + /// Returns the degree of the node. The degree is the number of /// adjacent edges. /// /// # Example @@ -242,28 +236,27 @@ where /// assert!(a.out_degree() == 2); /// ``` pub fn degree(&self) -> usize { - self.inner.2.borrow().len_outbound() - + self.inner.2.borrow().len_inbound() + self.inner.2.borrow().len_outbound() + self.inner.2.borrow().len_inbound() } - /// Connects this node to another node. The connection is created in both - /// directions. The connection is created with the given edge value and - /// defaults to `()`. This function allows for creating multiple - /// connections between the same nodes. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, 4.20); - /// - /// assert!(n1.is_connected(n2.key())); - /// ``` - pub fn connect(&self, other: &Self, value: E) { + /// Connects this node to another node. The connection is created in both + /// directions. The connection is created with the given edge value and + /// defaults to `()`. This function allows for creating multiple + /// connections between the same nodes. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, 4.20); + /// + /// assert!(n1.is_connected(n2.key())); + /// ``` + pub fn connect(&self, other: &Self, value: E) { self.inner .2 .borrow_mut() @@ -275,157 +268,161 @@ where .push_inbound((self.clone(), value)); } - /// Connects this node to another node. The connection is created in both - /// directions. The connection is created with the given edge value and - /// defaults to `()`. This function doesn't allow for creating multiple - /// connections between the same nodes. Returns Ok(()) if the connection - /// was created, Err(EdgeValue) if the connection already exists. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => assert!(n1.is_connected(n2.key())), - /// Err(_) => panic!("n1 should be connected to n2"), - /// } - /// - /// match n1.try_connect(&n2, ()) { - /// Ok(_) => panic!("n1 should be connected to n2"), - /// Err(_) => assert!(n1.is_connected(n2.key())), - /// } - /// ``` - pub fn try_connect(&self, other: &Node, value: E) -> Result<(), E> { - if self.is_connected(other.key()) { - Err(value) - } else { - self.connect(other, value); - Ok(()) - } - } - - /// Disconnect two nodes from each other. The connection is removed in both - /// directions. Returns Ok(EdgeValue) if the connection was removed, Err(()) - /// if the connection doesn't exist. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// - /// n1.connect(&n2, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// - /// if n1.disconnect(n2.key()).is_err() { - /// panic!("n1 should be connected to n2"); - /// } - /// - /// assert!(!n1.is_connected(n2.key())); - /// ``` - pub fn disconnect(&self, other: &K) -> Result { - self.inner.2.borrow_mut().remove_undirected(other) - } - - /// Removes all inbound and outbound connections to and from the node. - /// - /// # Example - /// - /// ``` - /// use gdsl::ungraph::*; - /// - /// let n1 = Node::new(1, ()); - /// let n2 = Node::new(2, ()); - /// let n3 = Node::new(3, ()); - /// let n4 = Node::new(4, ()); - /// - /// n1.connect(&n2, ()); - /// n1.connect(&n3, ()); - /// n1.connect(&n4, ()); - /// n2.connect(&n1, ()); - /// n3.connect(&n1, ()); - /// n4.connect(&n1, ()); - /// - /// assert!(n1.is_connected(n2.key())); - /// assert!(n1.is_connected(n3.key())); - /// assert!(n1.is_connected(n4.key())); - /// - /// n1.isolate(); - /// - /// assert!(n1.is_orphan()); - /// ``` - pub fn isolate(&self) { - for Edge(_, v, _) in self.iter() { - if v.inner.2.borrow_mut().remove_inbound(self.key()).is_err() { - v.inner.2.borrow_mut().remove_outbound(self.key()).unwrap(); - } - } - self.inner.2.borrow_mut().clear_outbound(); - self.inner.2.borrow_mut().clear_inbound(); - } - - /// Returns true if the node is an oprhan. Orphan nodes are nodes that have - /// no connections. - pub fn is_orphan(&self) -> bool { - self.inner.2.borrow().len_outbound() == 0 && self.inner.2.borrow().len_inbound() == 0 - } - - /// Returns true if the node is connected to another node with a given key. - pub fn is_connected(&self, other: &K) -> bool { - self.find_adjacent(other).is_some() - } - - /// Get a pointer to an adjacent node with a given key. Returns None if no - /// node with the given key is found from the node's adjacency list. - pub fn find_adjacent(&self, other: &K) -> Option> { - match self.inner.2.borrow().find_adjacent(other) { - Some((n, _)) => Some(n.upgrade().unwrap()), - None => None, - } - } - - /// Returns an iterator-like object that can be used to map, filter and - /// collect reachable nodes or edges in different orderings such as - /// postorder or preorder. - pub fn order(&self) -> Order { - Order::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a depth-first search. - pub fn dfs(&self) -> DFS { - DFS::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a breadth-first search. - pub fn bfs(&self) -> BFS { - BFS::new(self) - } - - /// Returns an iterator-like object that can be used to map, filter, - /// search and collect nodes or edges resulting from a - /// priotity-first search. - pub fn pfs(&self) -> PFS - where - N: Ord - { - PFS::new(self) - } - - /// Returns an iterator over the node's adjacent edges. - pub fn iter(&self) -> NodeIterator { - NodeIterator { node: self, position: 0 } - } - - pub fn sizeof(&self) -> usize { + /// Connects this node to another node. The connection is created in both + /// directions. The connection is created with the given edge value and + /// defaults to `()`. This function doesn't allow for creating multiple + /// connections between the same nodes. Returns Ok(()) if the connection + /// was created, Err(EdgeValue) if the connection already exists. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => assert!(n1.is_connected(n2.key())), + /// Err(_) => panic!("n1 should be connected to n2"), + /// } + /// + /// match n1.try_connect(&n2, ()) { + /// Ok(_) => panic!("n1 should be connected to n2"), + /// Err(_) => assert!(n1.is_connected(n2.key())), + /// } + /// ``` + pub fn try_connect(&self, other: &Node, value: E) -> Result<(), Error> { + if self.is_connected(other.key()) { + Err(Error::EdgeAlreadyExists) + } else { + self.connect(other, value); + Ok(()) + } + } + + /// Disconnect two nodes from each other. The connection is removed in both + /// directions. Returns Ok(EdgeValue) if the connection was removed, Err(()) + /// if the connection doesn't exist. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// + /// n1.connect(&n2, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// + /// if n1.disconnect(n2.key()).is_err() { + /// panic!("n1 should be connected to n2"); + /// } + /// + /// assert!(!n1.is_connected(n2.key())); + /// ``` + pub fn disconnect(&self, other: &K) -> Result { + self.inner.2.borrow_mut().remove_undirected(other) + } + + /// Removes all inbound and outbound connections to and from the node. + /// + /// # Example + /// + /// ``` + /// use gdsl::ungraph::*; + /// + /// let n1 = Node::new(1, ()); + /// let n2 = Node::new(2, ()); + /// let n3 = Node::new(3, ()); + /// let n4 = Node::new(4, ()); + /// + /// n1.connect(&n2, ()); + /// n1.connect(&n3, ()); + /// n1.connect(&n4, ()); + /// n2.connect(&n1, ()); + /// n3.connect(&n1, ()); + /// n4.connect(&n1, ()); + /// + /// assert!(n1.is_connected(n2.key())); + /// assert!(n1.is_connected(n3.key())); + /// assert!(n1.is_connected(n4.key())); + /// + /// n1.isolate(); + /// + /// assert!(n1.is_orphan()); + /// ``` + pub fn isolate(&self) { + for Edge(_, v, _) in self.iter() { + if v.inner.2.borrow_mut().remove_inbound(self.key()).is_err() { + v.inner.2.borrow_mut().remove_outbound(self.key()).unwrap(); + } + } + self.inner.2.borrow_mut().clear_outbound(); + self.inner.2.borrow_mut().clear_inbound(); + } + + /// Returns true if the node is an oprhan. Orphan nodes are nodes that have + /// no connections. + pub fn is_orphan(&self) -> bool { + self.inner.2.borrow().len_outbound() == 0 && self.inner.2.borrow().len_inbound() == 0 + } + + /// Returns true if the node is connected to another node with a given key. + pub fn is_connected(&self, other: &K) -> bool { + self.find_adjacent(other).is_some() + } + + /// Get a pointer to an adjacent node with a given key. Returns None if no + /// node with the given key is found from the node's adjacency list. + pub fn find_adjacent(&self, other: &K) -> Option> { + self.inner + .2 + .borrow() + .find_adjacent(other) + .map(|(n, _)| n.upgrade().unwrap()) + } + + /// Returns an iterator-like object that can be used to map, filter and + /// collect reachable nodes or edges in different orderings such as + /// postorder or preorder. + pub fn order(&self) -> Order { + Order::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a depth-first search. + pub fn dfs(&self) -> Dfs { + Dfs::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a breadth-first search. + pub fn bfs(&self) -> Bfs { + Bfs::new(self) + } + + /// Returns an iterator-like object that can be used to map, filter, + /// search and collect nodes or edges resulting from a + /// priotity-first search. + pub fn pfs(&self) -> Pfs + where + N: Ord, + { + Pfs::new(self) + } + + /// Returns an iterator over the node's adjacent edges. + pub fn iter(&self) -> NodeIterator { + NodeIterator { + node: self, + position: 0, + } + } + + pub fn sizeof(&self) -> usize { std::mem::size_of::>() + std::mem::size_of::() + std::mem::size_of::() @@ -444,7 +441,7 @@ where { type Target = N; fn deref(&self) -> &Self::Target { - &self.value() + self.value() } } @@ -464,7 +461,8 @@ where K: Clone + Hash + Display + PartialEq + Eq, N: Clone, E: Clone, -{} +{ +} impl PartialOrd for Node where @@ -473,7 +471,7 @@ where E: Clone, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.value().cmp(&other.value())) + Some(self.value().cmp(other.value())) } } @@ -484,50 +482,53 @@ where E: Clone, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.value().cmp(&other.value()) + self.value().cmp(other.value()) } } pub struct NodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - node: &'a Node, - position: usize, + node: &'a Node, + position: usize, } impl<'a, K, N, E> Iterator for NodeIterator<'a, K, N, E> where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - - fn next(&mut self) -> Option { - let adjacent = &self.node.inner.2.borrow(); - match adjacent.get_adjacent(self.position) { - Some((n, e)) => { - self.position += 1; - Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) - } - None => None, - } - } + type Item = Edge; + + fn next(&mut self) -> Option { + let adjacent = &self.node.inner.2.borrow(); + match adjacent.get_adjacent(self.position) { + Some((n, e)) => { + self.position += 1; + Some(Edge(self.node.clone(), n.upgrade().unwrap(), e.clone())) + } + None => None, + } + } } impl<'a, K, N, E> IntoIterator for &'a Node where - K: Clone + Hash + Display + PartialEq + Eq, - N: Clone, - E: Clone, + K: Clone + Hash + Display + PartialEq + Eq, + N: Clone, + E: Clone, { - type Item = Edge; - type IntoIter = NodeIterator<'a, K, N, E>; + type Item = Edge; + type IntoIter = NodeIterator<'a, K, N, E>; - fn into_iter(self) -> Self::IntoIter { - NodeIterator { node: self, position: 0 } - } -} \ No newline at end of file + fn into_iter(self) -> Self::IntoIter { + NodeIterator { + node: self, + position: 0, + } + } +} diff --git a/tests/digraph_tests.rs b/tests/digraph_tests.rs index faabe6e..b5107a8 100644 --- a/tests/digraph_tests.rs +++ b/tests/digraph_tests.rs @@ -1,577 +1,584 @@ #[test] -fn ut_digraph_manual_bfs() -{ - use gdsl::digraph::*; - use std::collections::{HashSet, VecDeque}; - - let g = vec![ - Node::new(0, ()), - Node::new(1, ()), - Node::new(2, ()), - Node::new(3, ()), - Node::new(4, ()), - Node::new(5, ()), - ]; - - g[0].connect(&g[1], ()); - g[0].connect(&g[2], ()); - g[0].connect(&g[3], ()); - g[1].connect(&g[4], ()); - g[2].connect(&g[5], ()); - g[3].connect(&g[4], ()); - g[3].connect(&g[5], ()); - - let mut visited = HashSet::new(); - let mut queue = VecDeque::new(); - - queue.push_back(g[0].clone()); - visited.insert(g[0].key().clone()); - - while let Some(node) = queue.pop_front() { - for Edge(_, v, _) in &node { - if !visited.contains(v.key()) { - if v == g[4] { - return; - } - visited.insert(v.key().clone()); - queue.push_back(v); - } - } - } - panic!(); +fn ut_digraph_manual_bfs() { + use gdsl::digraph::*; + use std::collections::{HashSet, VecDeque}; + + let g = vec![ + Node::new(0, ()), + Node::new(1, ()), + Node::new(2, ()), + Node::new(3, ()), + Node::new(4, ()), + Node::new(5, ()), + ]; + + g[0].connect(&g[1], ()); + g[0].connect(&g[2], ()); + g[0].connect(&g[3], ()); + g[1].connect(&g[4], ()); + g[2].connect(&g[5], ()); + g[3].connect(&g[4], ()); + g[3].connect(&g[5], ()); + + let mut visited = HashSet::new(); + let mut queue = VecDeque::new(); + + queue.push_back(g[0].clone()); + visited.insert(g[0].key().clone()); + + while let Some(node) = queue.pop_front() { + for Edge(_, v, _) in &node { + if !visited.contains(v.key()) { + if v == g[4] { + return; + } + visited.insert(v.key().clone()); + queue.push_back(v); + } + } + } + panic!(); } #[test] fn ut_digraph_bfs() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2] - (4) => [] - ]; - - let path = g[0] - .bfs() - .target(&4) - .search_path() - .unwrap() - .to_vec_nodes(); - - assert!(path[0] == g[0]); - assert!(path[1] == g[2]); - assert!(path[2] == g[4]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2] + (4) => [] + ]; + + let path = g[0].bfs().target(&4).search_path().unwrap().to_vec_nodes(); + + assert!(path[0] == g[0]); + assert!(path[1] == g[2]); + assert!(path[2] == g[4]); } #[test] -fn ut_digraph() -{ - use gdsl::digraph::*; +fn ut_digraph() { + use gdsl::digraph::*; - let a = Node::new(0x1, "A"); - let b = Node::new(0x2, "B"); - let c = Node::new(0x4, "C"); + let a = Node::new(0x1, "A"); + let b = Node::new(0x2, "B"); + let c = Node::new(0x4, "C"); - a.connect(&b, 0.42); - a.connect(&c, 1.7); - b.connect(&c, 0.09); - c.connect(&b, 12.9); + a.connect(&b, 0.42); + a.connect(&c, 1.7); + b.connect(&c, 0.09); + c.connect(&b, 12.9); - let Edge(u, v, e) = a.iter_out().next().unwrap(); + let Edge(u, v, e) = a.iter_out().next().unwrap(); - assert!(u == a); - assert!(v == b); - assert!(e == 0.42); + assert!(u == a); + assert!(v == b); + assert!(e == 0.42); } #[test] -fn ut_digraph_new() -{ - use gdsl::digraph::*; +fn ut_digraph_new() { + use gdsl::digraph::*; - let n1 = Node::::new(1, 'A'); + let n1 = Node::::new(1, 'A'); - assert!(*n1.key() == 1); - assert!(*n1.value() == 'A'); + assert!(*n1.key() == 1); + assert!(*n1.value() == 'A'); } #[test] -fn ut_digraph_connect() -{ - use gdsl::digraph::*; +fn ut_digraph_connect() { + use gdsl::digraph::*; - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); - n1.connect(&n2, 4.20); + n1.connect(&n2, 4.20); - assert!(n1.is_connected(n2.key())); + assert!(n1.is_connected(n2.key())); } #[test] -fn ut_digraph_try_connect() -{ - use gdsl::digraph::*; - - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); - - match n1.try_connect(&n2, ()) { - Ok(_) => assert!(n1.is_connected(n2.key())), - Err(_) => panic!("n1 should be connected to n2"), - } - - match n1.try_connect(&n2, ()) { - Ok(_) => panic!("n1 should be connected to n2"), - Err(_) => assert!(n1.is_connected(n2.key())), - } +fn ut_digraph_try_connect() { + use gdsl::digraph::*; + + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + + match n1.try_connect(&n2, ()) { + Ok(_) => assert!(n1.is_connected(n2.key())), + Err(_) => panic!("n1 should be connected to n2"), + } + + match n1.try_connect(&n2, ()) { + Ok(_) => panic!("n1 should be connected to n2"), + Err(_) => assert!(n1.is_connected(n2.key())), + } } #[test] -fn ut_digraph_disconnect() -{ - use gdsl::digraph::*; +fn ut_digraph_disconnect() { + use gdsl::digraph::*; - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); - n1.connect(&n2, ()); + n1.connect(&n2, ()); - assert!(n1.is_connected(n2.key())); + assert!(n1.is_connected(n2.key())); - if n1.disconnect(n2.key()).is_err() { - panic!("n1 should be connected to n2"); - } + if n1.disconnect(n2.key()).is_err() { + panic!("n1 should be connected to n2"); + } - assert!(!n1.is_connected(n2.key())); + assert!(!n1.is_connected(n2.key())); } #[test] fn ut_digraph_isolate() { - use gdsl::digraph::*; - - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); - let n3 = Node::new(3, ()); - let n4 = Node::new(4, ()); - - n1.connect(&n2, ()); - n1.connect(&n3, ()); - n2.connect(&n1, ()); - n3.connect(&n1, ()); - n4.connect(&n3, ()); - n3.connect(&n2, ()); - - n1.isolate(); - - assert!(n3.is_connected(n2.key())); - assert!(n4.is_connected(n3.key())); - assert!(!n1.is_connected(n2.key())); - assert!(!n1.is_connected(n3.key())); - assert!(n1.is_orphan()); + use gdsl::digraph::*; + + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + let n3 = Node::new(3, ()); + let n4 = Node::new(4, ()); + + n1.connect(&n2, ()); + n1.connect(&n3, ()); + n2.connect(&n1, ()); + n3.connect(&n1, ()); + n4.connect(&n3, ()); + n3.connect(&n2, ()); + + n1.isolate(); + + assert!(n3.is_connected(n2.key())); + assert!(n4.is_connected(n3.key())); + assert!(!n1.is_connected(n2.key())); + assert!(!n1.is_connected(n3.key())); + assert!(n1.is_orphan()); } -// TEST DFS +// TEST Dfs #[test] fn ut_digraph_dfs_find_1() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let target = g[0] - .dfs() - .target(&4) - .search() - .unwrap(); - - let source = g[4] - .dfs() - .target(&0) - .transpose() - .search() - .unwrap(); - - assert!(target == g[4]); - assert!(source == g[0]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let target = g[0].dfs().target(&4).search().unwrap(); + + let source = g[4].dfs().target(&0).transpose().search().unwrap(); + + assert!(target == g[4]); + assert!(source == g[0]); } #[test] fn ut_digraph_dfs_cycle_1() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [0, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .dfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle[1] == g[0]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [0, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].dfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle[1] == g[0]); } #[test] fn ut_digraph_dfs_cycle_2() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .dfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle.last().unwrap() == &g[0]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].dfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle.last().unwrap() == &g[0]); } -// TEST BFS +// TEST Bfs #[test] fn ut_digraph_bfs_find_1() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let target = g[0] - .bfs() - .target(&4) - .search() - .unwrap(); - - let source = g[4] - .bfs() - .target(&0) - .transpose() - .search() - .unwrap(); - - assert!(target == g[4]); - assert!(source == g[0]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let target = g[0].bfs().target(&4).search().unwrap(); + + let source = g[4].bfs().target(&0).transpose().search().unwrap(); + + assert!(target == g[4]); + assert!(source == g[0]); } #[test] fn ut_digraph_bfs_cycle_1() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .bfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle[1] == g[3]); - assert!(cycle[2] == g[0]); + use gdsl::*; + + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].bfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle[1] == g[3]); + assert!(cycle[2] == g[0]); } #[test] fn ut_digraph_bfs_cycle_2() { - use gdsl::*; - - let g = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .bfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle.last().unwrap() == &g[0]); -} + use gdsl::*; + let g = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].bfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle.last().unwrap() == &g[0]); +} #[test] fn ut_digraph_sizes() { - use gdsl::digraph::*; - - type N1 = Node; - type N2 = Node; - type N3 = Node; - type N4 = Node; - - let n1 = N1::new(1, ()); - let n2 = N2::new(2, ()); - let n3 = N3::new(3, 42); - let n4 = N4::new(4, 42); - - assert!(n1.sizeof() == 72); - assert!(n2.sizeof() == 72); - assert!(n3.sizeof() == 80); - assert!(n4.sizeof() == 80); + use gdsl::digraph::*; + + type N1 = Node; + type N2 = Node; + type N3 = Node; + type N4 = Node; + + let n1 = N1::new(1, ()); + let n2 = N2::new(2, ()); + let n3 = N3::new(3, 42); + let n4 = N4::new(4, 42); + + assert!(n1.sizeof() == 72); + assert!(n2.sizeof() == 72); + assert!(n3.sizeof() == 80); + assert!(n4.sizeof() == 80); } #[test] fn ut_digraph_deref_node() { - use gdsl::digraph::*; + use gdsl::digraph::*; - let n1 = Node::::new('A', 42); - let n2 = Node::::new('B', 6); + let n1 = Node::::new('A', 42); + let n2 = Node::::new('B', 6); - n1.connect(&n2, 0.5); + n1.connect(&n2, 0.5); - assert!(*n1 == 42); - assert!(n2.key() == &'B'); + assert!(*n1 == 42); + assert!(n2.key() == &'B'); - let Edge(u, v, e) = n1.iter_out().next().unwrap(); + let Edge(u, v, e) = n1.iter_out().next().unwrap(); - assert!(u.key() == &'A'); - assert!(v == n2); - assert!(e == 0.5); + assert!(u.key() == &'A'); + assert!(v == n2); + assert!(e == 0.5); } #[test] fn ut_serde_json() { - use gdsl::*; - use gdsl::digraph::*; - - let graph = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2] - (4) => [] - ]; - - let json = serde_json::to_string(&graph).unwrap(); - - let de: Graph = serde_json::from_str(&json).unwrap(); - - let mut graph_vec = graph.to_vec(); - let mut de_vec = de.to_vec(); - - graph_vec.sort_by(|a, b| a.key().cmp(b.key())); - de_vec.sort_by(|a, b| a.key().cmp(b.key())); - - for (a, b) in graph_vec.iter().zip(de_vec.iter()) { - assert!(a == b); - for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { - assert!(u == u2); - assert!(v == v2); - assert!(e == e2); - } - } + use gdsl::digraph::*; + use gdsl::*; + + let graph = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2] + (4) => [] + ]; + + let json = serde_json::to_string(&graph).unwrap(); + + let de: Graph = serde_json::from_str(&json).unwrap(); + + let mut graph_vec = graph.to_vec(); + let mut de_vec = de.to_vec(); + + graph_vec.sort_by(|a, b| a.key().cmp(b.key())); + de_vec.sort_by(|a, b| a.key().cmp(b.key())); + + for (a, b) in graph_vec.iter().zip(de_vec.iter()) { + assert!(a == b); + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + assert!(u == u2); + assert!(v == v2); + assert!(e == e2); + } + } } #[test] fn ut_serde_cbor() { - use gdsl::*; - use gdsl::digraph::*; - - let graph = digraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2] - (4) => [] - ]; - - let cbor = serde_cbor::to_vec(&graph).unwrap(); - - let de: Graph = serde_cbor::from_slice(&cbor).unwrap(); - - let mut graph_vec = graph.to_vec(); - let mut de_vec = de.to_vec(); - - graph_vec.sort_by(|a, b| a.key().cmp(b.key())); - de_vec.sort_by(|a, b| a.key().cmp(b.key())); - - for (a, b) in graph_vec.iter().zip(de_vec.iter()) { - assert!(a == b); - for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { - assert!(u == u2); - assert!(v == v2); - assert!(e == e2); - } - } + use gdsl::digraph::*; + use gdsl::*; + + let graph = digraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2] + (4) => [] + ]; + + let cbor = serde_cbor::to_vec(&graph).unwrap(); + + let de: Graph = serde_cbor::from_slice(&cbor).unwrap(); + + let mut graph_vec = graph.to_vec(); + let mut de_vec = de.to_vec(); + + graph_vec.sort_by(|a, b| a.key().cmp(b.key())); + de_vec.sort_by(|a, b| a.key().cmp(b.key())); + + for (a, b) in graph_vec.iter().zip(de_vec.iter()) { + assert!(a == b); + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + assert!(u == u2); + assert!(v == v2); + assert!(e == e2); + } + } } #[test] fn ut_serde_cbor_big() { - use gdsl::*; - use gdsl::digraph::*; - use std::cell::Cell; - - let graph = digraph![ - (char, Cell) => [u64] - ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] - ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] - ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] - ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] - ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] - ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] - ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] - ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] - ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] - ]; - - let cbor = serde_cbor::to_vec(&graph).unwrap(); - - let de: Graph, u64> = serde_cbor::from_slice(&cbor).unwrap(); - - let mut graph_vec = graph.to_vec(); - let mut de_vec = de.to_vec(); - - graph_vec.sort_by(|a, b| a.key().cmp(b.key())); - de_vec.sort_by(|a, b| a.key().cmp(b.key())); - - for (a, b) in graph_vec.iter().zip(de_vec.iter()) { - assert!(a == b); - for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { - assert!(u == u2); - assert!(v == v2); - assert!(e == e2); - } - } + use gdsl::digraph::*; + use gdsl::*; + use std::cell::Cell; + + let graph = digraph![ + (char, Cell) => [u64] + ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] + ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] + ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] + ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] + ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] + ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] + ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] + ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] + ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] + ]; + + let cbor = serde_cbor::to_vec(&graph).unwrap(); + + let de: Graph, u64> = serde_cbor::from_slice(&cbor).unwrap(); + + let mut graph_vec = graph.to_vec(); + let mut de_vec = de.to_vec(); + + graph_vec.sort_by(|a, b| a.key().cmp(b.key())); + de_vec.sort_by(|a, b| a.key().cmp(b.key())); + + for (a, b) in graph_vec.iter().zip(de_vec.iter()) { + assert!(a == b); + for (Edge(u, v, e), Edge(u2, v2, e2)) in a.iter_out().zip(b.iter_out()) { + assert!(u == u2); + assert!(v == v2); + assert!(e == e2); + } + } } #[test] fn ut_digraph_order() { - use gdsl::digraph::*; + use gdsl::digraph::*; - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); - let n3 = Node::new(3, ()); + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + let n3 = Node::new(3, ()); - n1.connect(&n2, ()); - n2.connect(&n3, ()); - n3.connect(&n1, ()); + n1.connect(&n2, ()); + n2.connect(&n3, ()); + n3.connect(&n1, ()); - let order = n1.preorder().search_nodes(); + let order = n1.preorder().search_nodes(); - assert!(order[0] == n1); - assert!(order[1] == n2); - assert!(order[2] == n3); + assert!(order[0] == n1); + assert!(order[1] == n2); + assert!(order[2] == n3); - let order = n1.postorder().search_nodes(); + let order = n1.postorder().search_nodes(); - assert!(order[0] == n3); - assert!(order[1] == n2); - assert!(order[2] == n1); + assert!(order[0] == n3); + assert!(order[1] == n2); + assert!(order[2] == n1); } #[test] fn doc_header_digraph() { - use gdsl::digraph::*; - - let mut g: Graph = Graph::new(); - - g.insert(Node::new(0, ())); - g.insert(Node::new(1, ())); - g.insert(Node::new(2, ())); - g.insert(Node::new(3, ())); - g.insert(Node::new(4, ())); - - g[0].connect(&g[1], ()); - g[0].connect(&g[2], ()); - g[0].connect(&g[3], ()); - g[1].connect(&g[3], ()); - g[2].connect(&g[4], ()); - g[3].connect(&g[2], ()); - g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle - - let cycle = g[0] // We start at node 0 - .bfs() // We use a breadth-first search - .search_cycle() // We search for a cycle - .unwrap() // Returns `Option>` - .to_vec_nodes(); // Path is converted to a vector of nodes - - assert!(cycle[0] == g[0]); - assert!(cycle[1] == g[3]); - assert!(cycle[2] == g[0]); + use gdsl::digraph::*; + + let mut g: Graph = Graph::new(); + + g.insert(Node::new(0, ())); + g.insert(Node::new(1, ())); + g.insert(Node::new(2, ())); + g.insert(Node::new(3, ())); + g.insert(Node::new(4, ())); + + g[0].connect(&g[1], ()); + g[0].connect(&g[2], ()); + g[0].connect(&g[3], ()); + g[1].connect(&g[3], ()); + g[2].connect(&g[4], ()); + g[3].connect(&g[2], ()); + g[3].connect(&g[0], ()); // 3 points back to 0 creating a cycle + + let cycle = g[0] // We start at node 0 + .bfs() // We use a breadth-first search + .search_cycle() // We search for a cycle + .unwrap() // Returns `Option>` + .to_vec_nodes(); // Path is converted to a vector of nodes + + assert!(cycle[0] == g[0]); + assert!(cycle[1] == g[3]); + assert!(cycle[2] == g[0]); } #[test] fn ut_digraph_scc() { - use gdsl::digraph::*; - - let mut g: Graph = Graph::new(); - - g.insert(Node::new(0, ())); - g.insert(Node::new(1, ())); - g.insert(Node::new(2, ())); - g.insert(Node::new(3, ())); - g.insert(Node::new(4, ())); - g.insert(Node::new(5, ())); - g.insert(Node::new(6, ())); - g.insert(Node::new(7, ())); - g.insert(Node::new(8, ())); - g.insert(Node::new(9, ())); - - g[0].connect(&g[1], ()); // ---- C1 - g[1].connect(&g[2], ()); // - g[2].connect(&g[0], ()); // - g[3].connect(&g[4], ()); // ---- C2 - g[4].connect(&g[5], ()); // - g[5].connect(&g[3], ()); // - g[6].connect(&g[7], ()); // ---- C3 - g[7].connect(&g[8], ()); // - g[8].connect(&g[6], ()); // - g[9].connect(&g[9], ()); // ---- C4 - - let mut scc = g.scc(); - - // Since the graph container is a hash map, the order of the SCCs is not - // deterministic. We sort the SCCs by their size to make the test - // deterministic. - scc.sort_by(|a, b| a.len().cmp(&b.len())); - - assert!(scc.len() == 4); - assert!(scc[0].len() == 1); - assert!(scc[1].len() == 3); - assert!(scc[2].len() == 3); - assert!(scc[3].len() == 3); -} \ No newline at end of file + use gdsl::digraph::*; + + let mut g: Graph = Graph::new(); + + g.insert(Node::new(0, ())); + g.insert(Node::new(1, ())); + g.insert(Node::new(2, ())); + g.insert(Node::new(3, ())); + g.insert(Node::new(4, ())); + g.insert(Node::new(5, ())); + g.insert(Node::new(6, ())); + g.insert(Node::new(7, ())); + g.insert(Node::new(8, ())); + g.insert(Node::new(9, ())); + + g[0].connect(&g[1], ()); // ---- C1 + g[1].connect(&g[2], ()); // + g[2].connect(&g[0], ()); // + g[3].connect(&g[4], ()); // ---- C2 + g[4].connect(&g[5], ()); // + g[5].connect(&g[3], ()); // + g[6].connect(&g[7], ()); // ---- C3 + g[7].connect(&g[8], ()); // + g[8].connect(&g[6], ()); // + g[9].connect(&g[9], ()); // ---- C4 + + let mut scc = g.scc(); + + // Since the graph container is a hash map, the order of the SCCs is not + // deterministic. We sort the SCCs by their size to make the test + // deterministic. + scc.sort_by(|a, b| a.len().cmp(&b.len())); + + assert!(scc.len() == 4); + assert!(scc[0].len() == 1); + assert!(scc[1].len() == 3); + assert!(scc[2].len() == 3); + assert!(scc[3].len() == 3); +} + +#[test] +fn ut_digraph_dijkstra() { + use gdsl::*; + use std::cell::Cell; + + // https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/ + let g = digraph![ + (char, Cell) => [u64] + ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] + ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] + ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] + ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] + ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] + ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] + ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] + ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] + ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] + ]; + + g['A'].set(0); + g['A'] + .pfs() + .for_each(&mut |digraph::Edge(u, v, e)| { + if v.get() > u.get() + e { + v.set(u.get() + e); + } + }) + .search(); + + assert!(g['A'].get() == 0); + assert!(g['B'].get() == 4); + assert!(g['C'].get() == 12); + assert!(g['D'].get() == 19); + assert!(g['E'].get() == 21); + assert!(g['F'].get() == 11); + assert!(g['G'].get() == 9); + assert!(g['H'].get() == 8); + assert!(g['I'].get() == 15); +} + +#[test] +fn ttt() { + use gdsl::digraph::*; + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + let n3 = Node::new(3, ()); + n1.connect(&n2, ()); + n1.connect(&n3, ()); + let mut iter = n2.iter_in(); + assert!(iter.next().unwrap() == Edge(n1.clone(), n2.clone(), ())); + assert!(iter.next().is_none()); +} diff --git a/tests/ungraph_tests.rs b/tests/ungraph_tests.rs index 2363bca..70344d9 100644 --- a/tests/ungraph_tests.rs +++ b/tests/ungraph_tests.rs @@ -1,360 +1,358 @@ #[test] -fn ut_ungraph_manual_bfs() -{ - use gdsl::ungraph::*; - use std::collections::{HashSet, VecDeque}; - - let g = vec![ - Node::new(0, ()), - Node::new(1, ()), - Node::new(2, ()), - Node::new(3, ()), - Node::new(4, ()), - Node::new(5, ()), - ]; - - g[0].connect(&g[1], ()); - g[0].connect(&g[2], ()); - g[0].connect(&g[3], ()); - g[1].connect(&g[4], ()); - g[2].connect(&g[5], ()); - g[3].connect(&g[4], ()); - g[3].connect(&g[5], ()); - - let mut visited = HashSet::new(); - let mut queue = VecDeque::new(); - - queue.push_back(g[0].clone()); - visited.insert(g[0].key().clone()); - - while let Some(node) = queue.pop_front() { - for Edge(_, v, _) in &node { - if !visited.contains(v.key()) { - if v == g[4] { - return; - } - visited.insert(v.key().clone()); - queue.push_back(v); - } - } - } - panic!(); +fn ut_ungraph_manual_bfs() { + use gdsl::ungraph::*; + use std::collections::{HashSet, VecDeque}; + + let g = vec![ + Node::new(0, ()), + Node::new(1, ()), + Node::new(2, ()), + Node::new(3, ()), + Node::new(4, ()), + Node::new(5, ()), + ]; + + g[0].connect(&g[1], ()); + g[0].connect(&g[2], ()); + g[0].connect(&g[3], ()); + g[1].connect(&g[4], ()); + g[2].connect(&g[5], ()); + g[3].connect(&g[4], ()); + g[3].connect(&g[5], ()); + + let mut visited = HashSet::new(); + let mut queue = VecDeque::new(); + + queue.push_back(g[0].clone()); + visited.insert(g[0].key().clone()); + + while let Some(node) = queue.pop_front() { + for Edge(_, v, _) in &node { + if !visited.contains(v.key()) { + if v == g[4] { + return; + } + visited.insert(v.key().clone()); + queue.push_back(v); + } + } + } + panic!(); } #[test] fn ut_ungraph_bfs() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2] - (4) => [] - ]; - - let path = g[0] - .bfs() - .target(&4) - .search_path() - .unwrap() - .to_vec_nodes(); - - assert!(path[0] == g[0]); - assert!(path[1] == g[2]); - assert!(path[2] == g[4]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2] + (4) => [] + ]; + + let path = g[0].bfs().target(&4).search_path().unwrap().to_vec_nodes(); + + assert!(path[0] == g[0]); + assert!(path[1] == g[2]); + assert!(path[2] == g[4]); } #[test] -fn ut_ungraph() -{ - use gdsl::ungraph::*; +fn ut_ungraph() { + use gdsl::ungraph::*; - let a = Node::new(0x1, "A"); - let b = Node::new(0x2, "B"); - let c = Node::new(0x4, "C"); + let a = Node::new(0x1, "A"); + let b = Node::new(0x2, "B"); + let c = Node::new(0x4, "C"); - a.connect(&b, 0.42); - a.connect(&c, 1.7); - b.connect(&c, 0.09); - c.connect(&b, 12.9); + a.connect(&b, 0.42); + a.connect(&c, 1.7); + b.connect(&c, 0.09); + c.connect(&b, 12.9); - let Edge(u, v, e) = a.iter().next().unwrap(); + let Edge(u, v, e) = a.iter().next().unwrap(); - assert!(u == a); - assert!(v == b); - assert!(e == 0.42); + assert!(u == a); + assert!(v == b); + assert!(e == 0.42); } #[test] -fn ut_ungraph_new() -{ - use gdsl::ungraph::*; +fn ut_ungraph_new() { + use gdsl::ungraph::*; - let n1 = Node::::new(1, 'A'); + let n1 = Node::::new(1, 'A'); - assert!(*n1.key() == 1); - assert!(*n1.value() == 'A'); + assert!(*n1.key() == 1); + assert!(*n1.value() == 'A'); } #[test] -fn ut_ungraph_connect() -{ - use gdsl::ungraph::*; +fn ut_ungraph_connect() { + use gdsl::ungraph::*; - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); - n1.connect(&n2, 4.20); + n1.connect(&n2, 4.20); - assert!(n1.is_connected(n2.key())); + assert!(n1.is_connected(n2.key())); } #[test] -fn ut_ungraph_try_connect() -{ - use gdsl::ungraph::*; - - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); - - match n1.try_connect(&n2, ()) { - Ok(_) => assert!(n1.is_connected(n2.key())), - Err(_) => panic!("n1 should be connected to n2"), - } - - match n1.try_connect(&n2, ()) { - Ok(_) => panic!("n1 should be connected to n2"), - Err(_) => assert!(n1.is_connected(n2.key())), - } +fn ut_ungraph_try_connect() { + use gdsl::ungraph::*; + + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + + match n1.try_connect(&n2, ()) { + Ok(_) => assert!(n1.is_connected(n2.key())), + Err(_) => panic!("n1 should be connected to n2"), + } + + match n1.try_connect(&n2, ()) { + Ok(_) => panic!("n1 should be connected to n2"), + Err(_) => assert!(n1.is_connected(n2.key())), + } } #[test] -fn ut_ungraph_disconnect() -{ - use gdsl::ungraph::*; +fn ut_ungraph_disconnect() { + use gdsl::ungraph::*; - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); - n1.connect(&n2, ()); + n1.connect(&n2, ()); - assert!(n1.is_connected(n2.key())); + assert!(n1.is_connected(n2.key())); - if n1.disconnect(n2.key()).is_err() { - panic!("n1 should be connected to n2"); - } + if n1.disconnect(n2.key()).is_err() { + panic!("n1 should be connected to n2"); + } - assert!(!n1.is_connected(n2.key())); + assert!(!n1.is_connected(n2.key())); } #[test] fn ut_ungraph_isolate() { - use gdsl::ungraph::*; - - let n1 = Node::new(1, ()); - let n2 = Node::new(2, ()); - let n3 = Node::new(3, ()); - let n4 = Node::new(4, ()); - - n1.connect(&n2, ()); - n1.connect(&n3, ()); - n2.connect(&n1, ()); - n3.connect(&n1, ()); - n4.connect(&n3, ()); - n3.connect(&n2, ()); - - n1.isolate(); - - assert!(n3.is_connected(n2.key())); - assert!(n4.is_connected(n3.key())); - assert!(!n1.is_connected(n2.key())); - assert!(!n1.is_connected(n3.key())); - assert!(n1.is_orphan()); + use gdsl::ungraph::*; + + let n1 = Node::new(1, ()); + let n2 = Node::new(2, ()); + let n3 = Node::new(3, ()); + let n4 = Node::new(4, ()); + + n1.connect(&n2, ()); + n1.connect(&n3, ()); + n2.connect(&n1, ()); + n3.connect(&n1, ()); + n4.connect(&n3, ()); + n3.connect(&n2, ()); + + n1.isolate(); + + assert!(n3.is_connected(n2.key())); + assert!(n4.is_connected(n3.key())); + assert!(!n1.is_connected(n2.key())); + assert!(!n1.is_connected(n3.key())); + assert!(n1.is_orphan()); } -// TEST DFS +// TEST Dfs #[test] fn ut_ungraph_dfs_find_1() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let target = g[0] - .dfs() - .target(&4) - .search() - .unwrap(); - - let source = g[4] - .dfs() - .target(&0) - .search() - .unwrap(); - - assert!(target == g[4]); - assert!(source == g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let target = g[0].dfs().target(&4).search().unwrap(); + + let source = g[4].dfs().target(&0).search().unwrap(); + + assert!(target == g[4]); + assert!(source == g[0]); } #[test] fn ut_ungraph_dfs_cycle_1() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [0, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .dfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle[1] == g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [0, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].dfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle[1] == g[0]); } #[test] fn ut_ungraph_dfs_cycle_2() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .dfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle.last().unwrap() == &g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].dfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle.last().unwrap() == &g[0]); } -// TEST BFS +// TEST Bfs #[test] fn ut_ungraph_bfs_find_1() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let target = g[0] - .bfs() - .target(&4) - .search() - .unwrap(); - - let source = g[4] - .bfs() - .target(&0) - .search() - .unwrap(); - - assert!(target == g[4]); - assert!(source == g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let target = g[0].bfs().target(&4).search().unwrap(); + + let source = g[4].bfs().target(&0).search().unwrap(); + + assert!(target == g[4]); + assert!(source == g[0]); } #[test] fn ut_ungraph_bfs_cycle_1() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [0, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .bfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle[1] == g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [0, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].bfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle[1] == g[0]); } #[test] fn ut_ungraph_bfs_cycle_2() { - use gdsl::*; - - let g = ungraph![ - (usize) - (0) => [1, 2, 3] - (1) => [3] - (2) => [4] - (3) => [2, 0] - (4) => [] - ]; - - let cycle = g[0] - .bfs() - .search_cycle() - .unwrap() - .to_vec_nodes(); - - assert!(cycle[0] == g[0]); - assert!(cycle.last().unwrap() == &g[0]); + use gdsl::*; + + let g = ungraph![ + (usize) + (0) => [1, 2, 3] + (1) => [3] + (2) => [4] + (3) => [2, 0] + (4) => [] + ]; + + let cycle = g[0].bfs().search_cycle().unwrap().to_vec_nodes(); + + assert!(cycle[0] == g[0]); + assert!(cycle.last().unwrap() == &g[0]); } #[test] fn ut_ungraph_sizes() { - use gdsl::ungraph::*; - - type N1 = Node; - type N2 = Node; - type N3 = Node; - type N4 = Node; - - let n1 = N1::new(1, ()); - let n2 = N2::new(2, ()); - let n3 = N3::new(3, 42); - let n4 = N4::new(4, 42); - - assert!(n1.sizeof() == 72); - assert!(n2.sizeof() == 72); - assert!(n3.sizeof() == 80); - assert!(n4.sizeof() == 80); - - let n1t1 = N1::new(1, ()); - let n1t2 = N1::new(1, ()); - let n1t3 = N1::new(1, ()); - - n1.connect(&n1t1, ()); - n1.connect(&n1t2, ()); - n1.connect(&n1t3, ()); - - assert!(n1.sizeof() == 96); - assert!(n1t1.sizeof() == 73); -} \ No newline at end of file + use gdsl::ungraph::*; + + type N1 = Node; + type N2 = Node; + type N3 = Node; + type N4 = Node; + + let n1 = N1::new(1, ()); + let n2 = N2::new(2, ()); + let n3 = N3::new(3, 42); + let n4 = N4::new(4, 42); + + assert!(n1.sizeof() == 72); + assert!(n2.sizeof() == 72); + assert!(n3.sizeof() == 80); + assert!(n4.sizeof() == 80); + + let n1t1 = N1::new(1, ()); + let n1t2 = N1::new(1, ()); + let n1t3 = N1::new(1, ()); + + n1.connect(&n1t1, ()); + n1.connect(&n1t2, ()); + n1.connect(&n1t3, ()); + + assert!(n1.sizeof() == 96); + assert!(n1t1.sizeof() == 73); +} + +#[test] +fn ut_ungraph_dijkstra() { + use gdsl::ungraph::*; + use gdsl::*; + use std::cell::Cell; + + // https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/ + let g = ungraph![ + (char, Cell) => [u64] + ('A', Cell::new(u64::MAX)) => [ ('B', 4), ('H', 8) ] + ('B', Cell::new(u64::MAX)) => [ ('A', 4), ('H', 11), ('C', 8) ] + ('C', Cell::new(u64::MAX)) => [ ('B', 8), ('C', 2), ('F', 4), ('D', 7) ] + ('D', Cell::new(u64::MAX)) => [ ('C', 7), ('F', 14), ('E', 9) ] + ('E', Cell::new(u64::MAX)) => [ ('D', 9), ('F', 10) ] + ('F', Cell::new(u64::MAX)) => [ ('G', 2), ('C', 4), ('D', 14), ('E', 10) ] + ('G', Cell::new(u64::MAX)) => [ ('H', 1), ('I', 6), ('F', 2) ] + ('H', Cell::new(u64::MAX)) => [ ('A', 8), ('B', 11), ('I', 7), ('G', 1) ] + ('I', Cell::new(u64::MAX)) => [ ('H', 7), ('C', 2), ('G', 6) ] + ]; + + g['A'].set(0); + g['A'] + .pfs() + .for_each(&mut |Edge(u, v, e)| { + if v.get() > u.get() + e { + v.set(u.get() + e); + } + }) + .search(); + + assert!(g['A'].get() == 0); + assert!(g['B'].get() == 4); + assert!(g['C'].get() == 12); + assert!(g['D'].get() == 19); + assert!(g['E'].get() == 21); + assert!(g['F'].get() == 11); + assert!(g['G'].get() == 9); + assert!(g['H'].get() == 8); + assert!(g['I'].get() == 14); +}