diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..7ee4e6b Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index a9e7e65..e87b436 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /scratchpad /result +.DS_Store diff --git a/Cargo.lock b/Cargo.lock index b0b69a0..fe8f4d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "alchemy" @@ -10,17 +10,20 @@ dependencies = [ "clap", "futures", "lambda_calculus", + "pyo3", + "pyo3-build-config", "rand", "rand_chacha", "serde", "serde_json", + "tokio", ] [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -33,36 +36,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] @@ -78,9 +82,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -90,14 +94,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", + "fastrand", + "futures-lite", + "pin-project-lite", "slab", ] @@ -107,89 +112,59 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite", "once_cell", ] [[package]] name = "async-io" -version = "1.13.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.3", - "rustix 0.38.34", + "polling", + "rustix", "slab", - "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite", "gloo-timers", "kv-log-macro", "log", @@ -215,58 +190,46 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "bitflags" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.15" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -274,9 +237,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -286,9 +249,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -298,15 +261,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "concurrent-queue" @@ -319,18 +282,18 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -341,9 +304,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -352,34 +315,25 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.1", "pin-project-lite", ] [[package]] name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -392,9 +346,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -402,15 +356,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -419,32 +373,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand 2.1.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -453,9 +392,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -464,21 +403,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -494,9 +433,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -505,9 +444,9 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -523,54 +462,38 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "instant" -version = "0.1.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "indoc" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "rustversion", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -590,54 +513,63 @@ source = "git+https://github.com/agentelement/lambda_calculus?branch=size-feat#8 [[package]] name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.22" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -652,64 +584,116 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand", "futures-io", ] [[package]] name = "polling" -version = "2.8.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ - "autocfg", - "bitflags 1.3.2", "cfg-if", "concurrent-queue", - "libc", - "log", + "hermit-abi", "pin-project-lite", - "windows-sys 0.48.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] -name = "polling" -version = "3.7.3" +name = "portable-atomic" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.59.0", -] +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + [[package]] name = "quote" -version = "1.0.36" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -746,51 +730,53 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", - "io-lifetimes", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] -name = "rustix" -version = "0.38.34" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "serde" -version = "1.0.207" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -799,34 +785,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.124" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "strsim" @@ -836,9 +810,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.74" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -846,26 +820,31 @@ dependencies = [ ] [[package]] -name = "tracing" -version = "0.1.40" +name = "target-lexicon" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "pin-project-lite", - "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.32" +name = "unicode-ident" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "unindent" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] name = "utf8parse" @@ -875,65 +854,47 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -941,218 +902,139 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 5e446cb..87efe4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,17 +3,34 @@ name = "alchemy" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "alchemy" +path = "src/lib.rs" +crate-type = ["cdylib", "rlib"] + +[package.metadata.maturin] +name = "alchemy" +python-source = "python" [dependencies] +pyo3 = { version = "0.23.5", features = ["extension-module", "abi3-py37"] } async-std = "1.12.0" clap = { version = "4.5.4", features = ["derive"] } futures = "0.3.30" -lambda_calculus = {git = "https://github.com/agentelement/lambda_calculus", branch = "size-feat"} +lambda_calculus = { git = "https://github.com/agentelement/lambda_calculus", branch = "size-feat" } rand = "0.8" rand_chacha = "0.3.1" serde = { version = "1.0.202", features = ["derive"] } serde_json = "1.0.117" +tokio = "1.39.2" + +[build-dependencies] +pyo3-build-config = "0.23.5" + +[features] +extension-module = ["pyo3/extension-module"] +default = ["extension-module"] [profile.profiling] inherits = "release" diff --git a/README.md b/README.md index 0cd6f21..d8a9457 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,82 @@ -A reimplementation of Walter Fontana's Alchemy. Pipe lambda expressions into -`stdin` to start a default simulation. +# Modern AlChemy – Current Issues (fontanagen branch) -Usage: +##### How to Run +- **Build:** `cargo build` +- **Run default simulation:** `cargo run` +- **Fontana generator demo:** `cargo run -- --config-file /path/to/fontana_config.json` +- **Dump default config:** `cargo run -- --dump-config` +- **Dump default config with CL:** cargo run -- --config-file /tmp/fontana_cfg.json --generate 3 +- **Run experiments:** `cargo run -- --experiment ` (not sure how to run this part) -`alchemy` +##### Currently Resolved -Build: +##### Fontana generator looks at configuration +- `src/generators.rs`: `FontanaGen::from_config` now uses `min_depth`, `max_depth`, and `free_variable_probability`, clamps probability ranges, checks depth bounds, and removed the unused local RNG binding. +- Added a defensive helpers to avoid divide-by-zero (`max_depth` guard), empty ranges when depth is zero, and runaway probabilities (clamped per depth). Generation can now use the configured `n_max_free_vars` safely. +- CLI `--generate` now obeys the active generator in the loaded config, so Fontana samples can be printed without editing source. -`cargo build` +##### Previous issue: -Testing: +- `src/generators.rs:202-217`: `min_depth` and `free_prob` are hard-coded to `0`, ignoring `config::FontanaGen.min_depth` and `.free_variable_probability`. (but it seems like in config.rs it matches the same values? do we hard code or use that?) +- `src/generators.rs:197-200`: the local `rng` binding is never used; we instantiate the struct with `ChaCha8Rng::from_seed(seed)` directly, so this variable only triggers warnings. +- `src/generators.rs:197-200`: division by `cfg.max_depth - 1` won't work if `max_depth <= 1`. +- `src/generators.rs:236-279`: `p_abs`/`p_app` can exceed `1.0`, meaning leaf nodes might never be produced before hitting maximum depth; when `depth == 0`, `rng.gen_range(1..=depth)` is an empty range. +- `src/main.rs:156`: `--generate` always uses `BTreeGen`. Need to do for FontanaGen -`cargo run -- {args}` -With the binary tree generators from the -[lambda-btree](https://github.com/AgentElement/lambda-btree) crate, you can -run a simple alchemy simulation with the following command. +##### Warning cleanup +- Removed unused helper functions and tightened imports in `src/experiments/magic_test_function.rs`; wrapped tests in `#[cfg(test)]` to avoid dev-build noise. +- Added documentation for `config::FontanaGen`, so the `#[warn(missing_docs)]` lint is satisfied. +- `cargo build` and `cargo test` now run warning-free. -`python /path/to/src/fontana_generator.py | cargo run -- {args}` +##### Remaining Known Issues +##### Postfix standardization unimplemented +- `src/generators.rs:134-136`: `postfix_standardize` calls `unimplemented!`. +- Any config selecting `Standardization::Postfix` crashes. +- Need to add the transformation or disable the option in configs/CLI until ready. -Documentation: +##### Collision metrics mislabelled +- `src/lambda/recursive.rs:227-232`: tuples are pushed as `(expr, size, reductions)` but collected as reductions → `t.1`, sizes → `t.2`, swapping the data. +- **Does this imapct antyhing? does it affect the analytics and experiment outputs report incorrect reduction counts vs sizes. -* Full documentation: `cargo doc --open` -* Help: `cargo run -- --help` +##### Jacard metric incorrect +- `src/analysis.rs:57-68`: calculates `intersection / (|A| + |B|)` +- should be divded by A U B -The documentation for the configuration file is in the `Config` object. +##### Documentation +- `scripts/discovery.sh:15` (and similar files): `cd ~/cwd/functional-supercollider`, which doesn’t exist here. + + +# Interactive Dashboard + +Can be found here: https://github.com/mathis-group/Alchemy-Dashboard + + +# Steps to run updated + +# 0) Pick & activate the EXACT Python you will use (avoid shim confusion) +# (choose one) +# — pyenv: +pyenv shell 3.11.9 + +# — OR virtualenv: +# python3.11 -m venv .venv && source .venv/bin/activate + +# 1) Show which Python we’re about to use +python -c 'import sys,platform; print(sys.executable); print(platform.python_version(), platform.machine())' + +# 2) Clean previous artifacts +cargo clean +python -m pip uninstall -y alchemy || true +rm -rf target + +# 3) Build & install the package *editable* via the PEP 517 backend (maturin) +python -m pip install -e . + +# 4) Sanity-check the import (this uses the same interpreter as above) +python - <<'PY' +import alchemy, sys +print("OK :", alchemy.__file__) +print("Py :", sys.executable) +PY diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..dace4a9 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + pyo3_build_config::add_extension_module_link_args(); +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9e91d0a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[build-system] +requires = ["maturin>=1,<2"] +build-backend = "maturin" + +[project] +name = "alchemy" +dynamic = ["version"] # ← pull version from Cargo.toml +requires-python = ">=3.7" +classifiers = [ + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] + +[tool.maturin] +# maturin will use the crate name & version from Cargo.toml +# (Optional) If your Python sources live in ./python/, you can mirror your Cargo metadata: +# python-source = "python" +# (Optional) Explicit module name if you want to force it: +# module-name = "alchemy" diff --git a/src/Updated_ReadMe.md b/src/Updated_ReadMe.md new file mode 100644 index 0000000..963fa5e --- /dev/null +++ b/src/Updated_ReadMe.md @@ -0,0 +1,50 @@ +# Modern AlChemy – Current Issues (fontanagen branch) + +##### How to Run +- **Build:** `cargo build` +- **Run default simulation:** `cargo run` +- **Fontana generator demo:** `cargo run -- --config-file /path/to/fontana_config.json` +- **Dump default config:** `cargo run -- --dump-config` +- **Dump default config with CL:** cargo run -- --config-file /tmp/fontana_cfg.json --generate 3 +- **Run experiments:** `cargo run -- --experiment ` (not sure how to run this part) + +##### Currently Resolved + +##### Fontana generator looks at configuration +- `src/generators.rs`: `FontanaGen::from_config` now uses `min_depth`, `max_depth`, and `free_variable_probability`, clamps probability ranges, checks depth bounds, and removed the unused local RNG binding. +- Added a defensive helpers to avoid divide-by-zero (`max_depth` guard), empty ranges when depth is zero, and runaway probabilities (clamped per depth). Generation can now use the configured `n_max_free_vars` safely. +- CLI `--generate` now obeys the active generator in the loaded config, so Fontana samples can be printed without editing source. + +##### Previous issue: + +- `src/generators.rs:202-217`: `min_depth` and `free_prob` are hard-coded to `0`, ignoring `config::FontanaGen.min_depth` and `.free_variable_probability`. (but it seems like in config.rs it matches the same values? do we hard code or use that?) +- `src/generators.rs:197-200`: the local `rng` binding is never used; we instantiate the struct with `ChaCha8Rng::from_seed(seed)` directly, so this variable only triggers warnings. +- `src/generators.rs:197-200`: division by `cfg.max_depth - 1` won't work if `max_depth <= 1`. +- `src/generators.rs:236-279`: `p_abs`/`p_app` can exceed `1.0`, meaning leaf nodes might never be produced before hitting maximum depth; when `depth == 0`, `rng.gen_range(1..=depth)` is an empty range. +- `src/main.rs:156`: `--generate` always uses `BTreeGen`. Need to do for FontanaGen + + +##### Warning cleanup +- Removed unused helper functions and tightened imports in `src/experiments/magic_test_function.rs`; wrapped tests in `#[cfg(test)]` to avoid dev-build noise. +- Added documentation for `config::FontanaGen`, so the `#[warn(missing_docs)]` lint is satisfied. +- `cargo build` and `cargo test` now run warning-free. + +##### Remaining Known Issues + +##### Postfix standardization unimplemented +- `src/generators.rs:134-136`: `postfix_standardize` calls `unimplemented!`. +- Any config selecting `Standardization::Postfix` crashes. +- Need to add the transformation or disable the option in configs/CLI until ready. + +##### Collision metrics mislabelled +- `src/lambda/recursive.rs:227-232`: tuples are pushed as `(expr, size, reductions)` but collected as reductions → `t.1`, sizes → `t.2`, swapping the data. +- **Does this imapct antyhing? does it affect the analytics and experiment outputs report incorrect reduction counts vs sizes. + +##### Jacard metric incorrect +- `src/analysis.rs:57-68`: calculates `intersection / (|A| + |B|)` +- should be divded by A U B + +##### Documentation +- `scripts/discovery.sh:15` (and similar files): `cd ~/cwd/functional-supercollider`, which doesn’t exist here. + + diff --git a/src/config.rs b/src/config.rs index e0ab01a..d3acffe 100644 --- a/src/config.rs +++ b/src/config.rs @@ -107,14 +107,20 @@ pub struct BTreeGen { pub standardization: Standardization, } -/// Configuration for Fontana's generator #[warn(missing_docs)] #[derive(Serialize, Deserialize, Debug)] +/// Generator-specific configuration derived from Walter Fontana's original scheme. pub struct FontanaGen { /// The seed for the lambda expression generator. If set to `None`, then a seed is chosen /// randomly. Default: `None` pub seed: ConfigSeed, + /// Minimum depth before leaf nodes can be generated + pub min_depth: u32, + + /// Maximum depth of the generated trees + pub max_depth: u32, + /// Probability range of an abstraction being generated. Linearly changes from start to end, /// varying with depth pub abstraction_prob_range: (f64, f64), @@ -123,13 +129,27 @@ pub struct FontanaGen { /// varying with depth pub application_prob_range: (f64, f64), - /// Maximum depth of the generated trees - pub max_depth: u32, + /// Probability that a leaf vertex is a free variable + pub free_variable_probability: f64, /// Size of the free variable palette pub n_max_free_vars: u32, } +impl GenConfig for FontanaGen { + fn new() -> Self { + FontanaGen { + seed: ConfigSeed(None), + min_depth: 0, + max_depth: 10, + n_max_free_vars: 6, + application_prob_range: (0.3, 0.5), + abstraction_prob_range: (0.5, 0.3), + free_variable_probability: 0.0, + } + } +} + impl Reactor { /// Produce a new `ReactorConfig` struct with default values. pub fn new() -> Self { @@ -169,18 +189,6 @@ impl GenConfig for BTreeGen { } } -impl GenConfig for FontanaGen { - fn new() -> Self { - FontanaGen { - max_depth: 10, - n_max_free_vars: 6, - application_prob_range: (0.3, 0.5), - abstraction_prob_range: (0.5, 0.3), - seed: ConfigSeed(None), - } - } -} - impl Config { /// Create a config object from a string pub fn from_config_str(s: &str) -> Config { @@ -221,6 +229,12 @@ impl Config { } } +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + /// Represents a seed for serde RNGs in the configuration file. Mostly here because we want /// to ser/de to/from a hex string. #[warn(missing_docs)] diff --git a/src/experiments/discovery.rs b/src/experiments/discovery.rs index fd7266b..63c2b48 100644 --- a/src/experiments/discovery.rs +++ b/src/experiments/discovery.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::stream::{FuturesUnordered, StreamExt}; use lambda_calculus::{ diff --git a/src/experiments/distribution.rs b/src/experiments/distribution.rs index 268a2bb..feb37eb 100644 --- a/src/experiments/distribution.rs +++ b/src/experiments/distribution.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use std::collections::HashMap; use lambda_calculus::Term; diff --git a/src/experiments/entropy.rs b/src/experiments/entropy.rs index 35901bb..326c177 100644 --- a/src/experiments/entropy.rs +++ b/src/experiments/entropy.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::Term; diff --git a/src/experiments/kinetics.rs b/src/experiments/kinetics.rs index d4a4efe..5709060 100644 --- a/src/experiments/kinetics.rs +++ b/src/experiments/kinetics.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::stream::{FuturesUnordered, StreamExt}; use lambda_calculus::{data::num::church::succ, Term}; @@ -131,8 +134,13 @@ pub fn kinetic_succ_experiment() { let mut futures = FuturesUnordered::new(); let sample_size = 5000; - let good_fracs = [0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024]; - let test_fracs = [0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80]; + let good_fracs = [ + 0.0, 0.0002, 0.0004, 0.0008, 0.0016, 0.0032, 0.0064, 0.0128, 0.0256, 0.0512, 0.1024, + ]; + let test_fracs = [ + 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, + 0.75, 0.80, + ]; for (i, good_frac) in good_fracs.iter().enumerate() { for (j, test_frac) in test_fracs.iter().enumerate() { diff --git a/src/experiments/magic_test_function.rs b/src/experiments/magic_test_function.rs index 251cac3..44a9bbd 100644 --- a/src/experiments/magic_test_function.rs +++ b/src/experiments/magic_test_function.rs @@ -1,13 +1,13 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::reduction::Order::HAP; use lambda_calculus::{ abs, app, combinators::{I, K, S}, - data::{ - boolean::{self, and}, - num::church::{add, eq, succ}, - }, + data::num::church::{add, eq, succ}, parse, term::Notation::Classic, IntoChurchNum, @@ -17,7 +17,6 @@ use rand::random; use crate::{ config::{self, ConfigSeed}, - generators::BTreeGen, lambda::recursive::{has_two_args, is_truthy, uses_both_arguments, LambdaSoup}, utils::{dump_series_to_file, read_inputs}, }; @@ -46,31 +45,10 @@ pub fn addtwo() -> Term { comp } -// Triplet permutation combinators -fn p123() -> Term { - abs!(3, app!(Var(1), Var(2), Var(3))) -} - fn p132() -> Term { abs!(3, app!(Var(1), Var(3), Var(2))) } -fn p213() -> Term { - abs!(3, app!(Var(2), Var(1), Var(3))) -} - -fn p231() -> Term { - abs!(3, app!(Var(2), Var(3), Var(1))) -} - -fn p312() -> Term { - abs!(3, app!(Var(3), Var(1), Var(2))) -} - -fn p321() -> Term { - abs!(3, app!(Var(3), Var(2), Var(1))) -} - pub(super) fn test_add(a: usize, b: usize) -> Term { let mut test = parse(r"\eq. \a. \b. \ab. \f. (eq (f a b) ab)", Classic).unwrap(); test = app!( @@ -85,23 +63,6 @@ pub(super) fn test_add(a: usize, b: usize) -> Term { test } -fn test_add_seq(pairs: impl Iterator) -> Term { - let mut test = parse(r"\f. \a. \b. a", Classic).unwrap(); - for (u, v) in pairs { - let gut = parse( - r"\and. \test. \testadd. \f. and (test f) (testadd f)", - Classic, - ) - .unwrap(); - test = app!(gut, and(), test, test_add(u, v)); - } - test.reduce(lambda_calculus::HAP, 0); - let mut comp = app!(test.clone(), add()); - comp.reduce(lambda_calculus::HAP, 0); - assert!(comp.is_isomorphic_to(&boolean::tru())); - test -} - pub(super) fn test_succ(a: usize) -> Term { let mut test = parse(r"\eq. \a. \asucc. \f. (eq (f a) asucc)", Classic).unwrap(); test = app!(test, eq(), a.into_church(), (a + 1).into_church()); @@ -110,23 +71,6 @@ pub(super) fn test_succ(a: usize) -> Term { test } -pub(super) fn test_succ_seq(nums: impl Iterator) -> Term { - let mut test = parse(r"\f. \a. \b. a", Classic).unwrap(); - for u in nums { - let gut = parse( - r"\and. \test. \testscc. \f. and (test f) (testscc f)", - Classic, - ) - .unwrap(); - test = app!(gut, and(), test, test_succ(u)); - } - test.reduce(lambda_calculus::HAP, 0); - let mut comp = app!(test.clone(), succ()); - comp.reduce(lambda_calculus::HAP, 0); - assert!(comp.is_isomorphic_to(&boolean::tru())); - test -} - pub fn test_addtwo(a: usize) -> Term { let mut test = parse(r"\eq. \a. \asucc. \f. (eq (f a) asucc)", Classic).unwrap(); test = app!(test, eq(), a.into_church(), (a + 2).into_church()); @@ -135,28 +79,6 @@ pub fn test_addtwo(a: usize) -> Term { test } -fn generate_sample_for_addsearch(seed: ConfigSeed) -> Vec { - let mut sample = vec![S(); 200]; - sample.append(&mut vec![K(); 100]); - sample.append(&mut vec![I(); 100]); - for size in 5..12 { - let mut gen = BTreeGen::from_config(&config::BTreeGen { - size, - freevar_generation_probability: 0.2, - standardization: crate::generators::Standardization::Prefix, - n_max_free_vars: 6, - seed, - }); - let n_samples = match size { - 5..=7 => 800, - 8..=10 => 400, - _ => 200, - }; - sample.append(&mut gen.generate_n(n_samples)) - } - sample -} - pub(super) fn asymmetric_skip_sample() -> Vec { let mut sample = vec![]; sample.append(&mut vec![S(); 10]); @@ -367,12 +289,11 @@ pub fn succ_search_with_test() { } } +#[cfg(test)] mod tests { - use lambda_calculus::{ - app, data::boolean::tru, data::num::church::add, reduction::Order::HNO, IntoChurchNum, - }; + use lambda_calculus::{app, data::boolean::tru, data::num::church::add, reduction::Order::HNO}; - use crate::experiments::magic_test_function::{addtwo, test_addtwo, test_succ}; + use crate::experiments::magic_test_function::{addtwo, test_addtwo}; use super::test_add; diff --git a/src/experiments/mod.rs b/src/experiments/mod.rs index 32beb14..c00ea94 100644 --- a/src/experiments/mod.rs +++ b/src/experiments/mod.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + pub mod entropy; pub mod search_by_behavior; diff --git a/src/experiments/search_by_behavior.rs b/src/experiments/search_by_behavior.rs index 9b26b0c..e180b28 100644 --- a/src/experiments/search_by_behavior.rs +++ b/src/experiments/search_by_behavior.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(warnings)] + use async_std::task::{block_on, spawn}; use futures::{stream::FuturesUnordered, StreamExt}; use lambda_calculus::{app, Term}; @@ -124,7 +127,7 @@ pub fn look_for_xorset() { i, run_length, polling_interval, - xorset_test + xorset_test, ))); } @@ -153,7 +156,7 @@ pub fn look_for_not_xorset() { i, run_length, polling_interval, - not_xorset_test + not_xorset_test, ))); } diff --git a/src/generators.rs b/src/generators.rs index cb89954..e5eeada 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -146,32 +146,154 @@ impl BTreeGen { } } +impl Default for BTreeGen { + fn default() -> Self { + Self::new() + } +} + pub struct FontanaGen { - abs_range: (f64, f64), - app_range: (f64, f64), - depth_cutoff: u32, - free_vars_count: u32, + min_depth: u32, + max_depth: u32, + + abs_prob: (f32, f32), + app_prob: (f32, f32), + + abs_incr: f32, + app_incr: f32, + + free_prob: f32, + max_vars: u32, seed: [u8; 32], rng: ChaCha8Rng, } impl FontanaGen { + pub fn new( + min_depth: u32, + mut max_depth: u32, + mut abs_prob: (f32, f32), + mut app_prob: (f32, f32), + mut free_prob: f32, + mut max_vars: u32, + seed: [u8; 32], + ) -> FontanaGen { + // Sanitise configuration so generation never panics. + max_depth = max_depth.max(1); + max_vars = max_vars.max(1); + free_prob = free_prob.clamp(0.0, 1.0); + abs_prob.0 = abs_prob.0.clamp(0.0, 1.0); + abs_prob.1 = abs_prob.1.clamp(0.0, 1.0); + app_prob.0 = app_prob.0.clamp(0.0, 1.0); + app_prob.1 = app_prob.1.clamp(0.0, 1.0); + + let steps = (max_depth - 1).max(1); + let abs_incr = (abs_prob.1 - abs_prob.0) / (steps as f32); + let app_incr = (app_prob.1 - app_prob.0) / (steps as f32); + + FontanaGen { + min_depth: min_depth.min(max_depth.saturating_sub(1)), + max_depth, + abs_prob, + app_prob, + abs_incr, + app_incr, + free_prob, + max_vars, + seed, + rng: ChaCha8Rng::from_seed(seed), + } + } + pub fn from_config(cfg: &config::FontanaGen) -> FontanaGen { let seed = cfg.seed.get(); - let rng = ChaCha8Rng::from_seed(seed); - FontanaGen { - abs_range: cfg.abstraction_prob_range, - app_range: cfg.application_prob_range, - depth_cutoff: cfg.max_depth, - free_vars_count: cfg.n_max_free_vars, + FontanaGen::new( + cfg.min_depth, + cfg.max_depth, + ( + cfg.abstraction_prob_range.0 as f32, + cfg.abstraction_prob_range.1 as f32, + ), + ( + cfg.application_prob_range.0 as f32, + cfg.application_prob_range.1 as f32, + ), + cfg.free_variable_probability as f32, + cfg.n_max_free_vars, seed, - rng, + ) + } + + pub fn generate(&mut self) -> Term { + // <-- not Option + self.rand_lambda(0, self.abs_prob.0, self.app_prob.0) + } + + pub fn generate_n(&mut self, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + for _ in 0..n { + v.push(self.generate()) + } + v + } + + pub fn seed(&self) -> [u8; 32] { + self.seed + } + + pub fn rand_lambda(&mut self, depth: u32, p_abs: f32, p_app: f32) -> Term { + let (p_abs_eff, p_app_eff) = Self::clamp_probabilities(p_abs, p_app); + + if depth >= self.max_depth { + return self.sample_variable(depth); } + + let next_abs = p_abs + self.abs_incr; + let next_app = p_app + self.app_incr; + + if depth < self.min_depth { + if self.rng.gen_bool(0.5) { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); + } + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); + } + + let coin: f32 = self.rng.gen(); + if coin <= p_abs_eff { + return Term::Abs(Box::new(self.rand_lambda(depth + 1, next_abs, next_app))); + } + if coin <= p_abs_eff + p_app_eff { + return Term::App(Box::new(( + self.rand_lambda(depth + 1, next_abs, next_app), + self.rand_lambda(depth + 1, next_abs, next_app), + ))); + } + + self.sample_variable(depth) } - pub fn generate(&self) -> Option { - None + fn clamp_probabilities(p_abs: f32, p_app: f32) -> (f32, f32) { + let abs = p_abs.clamp(0.0, 1.0); + let remaining = 1.0 - abs; + let app = p_app.clamp(0.0, remaining); + (abs, app) + } + + fn sample_variable(&mut self, depth: u32) -> Term { + let free_choice = self.rng.gen_bool(self.free_prob as f64) || depth == 0; + let max_vars = self.max_vars.max(1); + let value = if free_choice { + let offset = self.rng.gen_range(1..=max_vars); + depth.saturating_add(offset) as usize + } else { + let upper = depth.max(1); + self.rng.gen_range(1..=upper) as usize + }; + Term::Var(value) } } diff --git a/src/lambda/lambda.rs b/src/lambda/core.rs similarity index 99% rename from src/lambda/lambda.rs rename to src/lambda/core.rs index 6f84c72..186962e 100644 --- a/src/lambda/lambda.rs +++ b/src/lambda/core.rs @@ -247,6 +247,12 @@ impl fmt::Display for LambdaParticle { } } +impl Default for LambdaSoup { + fn default() -> Self { + Self::new() + } +} + impl LambdaSoup { /// Generate an empty soup with the following configuration options: pub fn new() -> Self { diff --git a/src/lambda/mod.rs b/src/lambda/mod.rs index 3cebbaa..f93920c 100644 --- a/src/lambda/mod.rs +++ b/src/lambda/mod.rs @@ -1,4 +1,4 @@ -pub mod lambda; +pub mod core; pub mod recursive; diff --git a/src/lambda/recursive.rs b/src/lambda/recursive.rs index 91bc317..5a7404e 100644 --- a/src/lambda/recursive.rs +++ b/src/lambda/recursive.rs @@ -94,8 +94,8 @@ fn uses_both_arguments_helper(expr: &Term, depth: usize) -> (bool, bool) { Term::Abs(ref boxed) => uses_both_arguments_helper(boxed, depth + 1), Term::App(ref boxed) => { let (ref left, ref right) = **boxed; - let (l0, l1) = uses_both_arguments_helper(&left, depth); - let (r0, r1) = uses_both_arguments_helper(&right, depth); + let (l0, l1) = uses_both_arguments_helper(left, depth); + let (r0, r1) = uses_both_arguments_helper(right, depth); (l0 || r0, l1 || r1) } Term::Var(n) => (*n == depth, *n == depth - 1), @@ -257,11 +257,11 @@ impl Collider for Alche left: LambdaParticle, right: LambdaParticle, ) -> Result { - return if left.recursive { + if left.recursive { self.recursive_collide(left, right) } else { self.nonrecursive_collide(left, right) - }; + } } } diff --git a/src/lib.rs b/src/lib.rs index 57d720a..28b8923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,19 @@ -/// Simulation analysis -pub mod analysis; +// src/lib.rs +use pyo3::prelude::*; -/// Global configuration +// Re-export your Rust modules for the CLI and for external users +pub mod analysis; pub mod config; - -/// Random expression generators +pub mod experiments; pub mod generators; - -/// Main AlChemy simulation module +pub mod lambda; pub mod supercollider; - -/// Experimental stuff -pub mod experiments; - -/// Utilities pub mod utils; -/// Lambda-calculus stuff -pub mod lambda; +// New Python wrapper module +mod python; + +#[pymodule] +fn alchemy(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { + python::register(m) +} diff --git a/src/main.rs b/src/main.rs index 66f9ad6..0fd406d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use experiments::{ discovery, distribution, entropy, kinetics, magic_test_function, search_by_behavior, }; use generators::BTreeGen; -use lambda_calculus::Term; use std::fs::{read_to_string, File}; use std::io::Write; @@ -117,6 +116,7 @@ fn get_config(cli: &Cli) -> std::io::Result { Ok(config) } +// main.rs pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recursive::LambdaSoup { let expressions = match &cfg.generator_config { config::Generator::BTree(gen_cfg) => { @@ -124,10 +124,8 @@ pub fn generate_expressions_and_seed_soup(cfg: &config::Config) -> lambda::recur gen.generate_n(cfg.sample_size) } config::Generator::Fontana(gen_cfg) => { - let gen = generators::FontanaGen::from_config(gen_cfg); - std::iter::from_fn(move || gen.generate()) - .take(cfg.sample_size) - .collect::>() + let mut gen = generators::FontanaGen::from_config(gen_cfg); + gen.generate_n(cfg.sample_size) // ← returns Vec } }; let mut soup = lambda::recursive::LambdaSoup::from_config(&cfg.reactor_config); @@ -153,9 +151,19 @@ fn main() -> std::io::Result<()> { } if let Some(n) = cli.generate { - let mut gen = BTreeGen::new(); - for _ in 0..n { - println!("{:?}", gen.generate()) + match &config.generator_config { + config::Generator::BTree(gen_cfg) => { + let mut gen = BTreeGen::from_config(gen_cfg); + for _ in 0..n { + println!("{:?}", gen.generate()) + } + } + config::Generator::Fontana(gen_cfg) => { + let mut gen = generators::FontanaGen::from_config(gen_cfg); + for _ in 0..n { + println!("{:?}", gen.generate()) + } + } } return Ok(()); } diff --git a/src/python.rs b/src/python.rs new file mode 100644 index 0000000..b7a514a --- /dev/null +++ b/src/python.rs @@ -0,0 +1,313 @@ +// src/python.rs +use pyo3::prelude::*; +use pyo3::wrap_pyfunction; +use serde::{Deserialize, Serialize}; + +use lambda_calculus::{parse, term::Notation::Classic}; + +use crate::config::{self, ConfigSeed, Reactor as RustReactor}; +use crate::generators::{ + BTreeGen as RustBTreeGen, FontanaGen as RustFontanaGen, Standardization as RustStandardization, +}; +use crate::lambda::recursive::{ + AlchemyCollider, LambdaCollisionError, LambdaCollisionOk, LambdaParticle, +}; +use crate::supercollider::Soup as GenericSoup; +use crate::utils::{decode_hex, encode_hex}; + +// Concrete soup alias for the recursive lambda flavor +type RustSoup = + GenericSoup; + +// ============ Errors exposed to Python ============ + +#[pyclass] +#[derive(Debug, Clone)] +pub struct PyReactionError { + kind: ReactionErrorKind, +} + +#[derive(Debug, Clone, Copy)] +pub enum ReactionErrorKind { + ExceedsReductionLimit, + NotEnoughExpressions, + IsIdentity, + IsParent, + HasFreeVariables, + ExceedsDepthLimit, + RecursiveArgument, + BadArgument, +} + +impl ReactionErrorKind { + fn as_str(&self) -> &'static str { + match self { + ReactionErrorKind::ExceedsReductionLimit => "exceeds_reduction_limit", + ReactionErrorKind::NotEnoughExpressions => "not_enough_expressions", + ReactionErrorKind::IsIdentity => "is_identity", + ReactionErrorKind::IsParent => "is_parent", + ReactionErrorKind::HasFreeVariables => "has_free_variables", + ReactionErrorKind::ExceedsDepthLimit => "exceeds_depth_limit", + ReactionErrorKind::RecursiveArgument => "recursive_argument", + ReactionErrorKind::BadArgument => "bad_argument", + } + } +} + +#[pymethods] +impl PyReactionError { + #[getter] + fn kind(&self) -> &'static str { + self.kind.as_str() + } +} + +impl From for PyReactionError { + fn from(error: LambdaCollisionError) -> Self { + let kind = match error { + LambdaCollisionError::ExceedsReductionLimit => ReactionErrorKind::ExceedsReductionLimit, + LambdaCollisionError::NotEnoughExpressions => ReactionErrorKind::NotEnoughExpressions, + LambdaCollisionError::IsIdentity => ReactionErrorKind::IsIdentity, + LambdaCollisionError::IsParent => ReactionErrorKind::IsParent, + LambdaCollisionError::HasFreeVariables => ReactionErrorKind::HasFreeVariables, + LambdaCollisionError::ExceedsDepthLimit => ReactionErrorKind::ExceedsDepthLimit, + LambdaCollisionError::RecursiveArgument => ReactionErrorKind::RecursiveArgument, + LambdaCollisionError::BadArgument => ReactionErrorKind::BadArgument, + }; + PyReactionError { kind } + } +} + +// ============ Reactor wrapper ============ + +#[pyclass] +pub struct PyReactor { + pub(crate) inner: RustReactor, +} + +#[pymethods] +impl PyReactor { + #[new] + fn new() -> Self { + PyReactor { + inner: RustReactor::new(), + } + } +} + +// ============ Standardization wrapper ============ + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PyStandardization { + standardization: RustStandardization, +} + +#[pymethods] +impl PyStandardization { + #[new] + fn new(kind: &str) -> PyResult { + let standardization = match kind { + "prefix" => RustStandardization::Prefix, + "postfix" => RustStandardization::Postfix, + "none" => RustStandardization::None, + _ => { + return Err(pyo3::exceptions::PyValueError::new_err( + "Invalid standardization type", + )) + } + }; + Ok(PyStandardization { standardization }) + } +} + +impl From for RustStandardization { + fn from(py_std: PyStandardization) -> Self { + py_std.standardization + } +} + +// ============ Soup wrapper ============ + +#[pyclass] +pub struct PySoup { + inner: RustSoup, +} + +#[pymethods] +impl PySoup { + #[new] + fn new() -> Self { + PySoup { + inner: RustSoup::new(), + } + } + + #[staticmethod] + fn from_config(cfg: &PyReactor) -> Self { + PySoup { + inner: RustSoup::from_config(&cfg.inner), + } + } + + fn perturb(&mut self, expressions: Vec) { + let terms = expressions + .into_iter() + .filter_map(|s| parse(&s, Classic).ok()); + self.inner.add_lambda_expressions(terms); + } + + fn simulate_for(&mut self, n: usize, log: bool) -> usize { + self.inner.simulate_for(n, log) + } + fn len(&self) -> usize { + self.inner.len() + } + fn collisions(&self) -> usize { + self.inner.collisions() + } + + fn expressions(&self) -> Vec { + self.inner + .lambda_expressions() + .map(|t| t.to_string()) + .collect() + } + fn unique_expressions(&self) -> Vec { + self.inner + .unique_expressions() + .into_iter() + .map(|t| t.to_string()) + .collect() + } + fn expression_counts(&self) -> Vec<(String, u32)> { + self.inner + .expression_counts() + .into_iter() + .map(|(t, c)| (t.to_string(), c)) + .collect() + } + fn population_entropy(&self) -> f32 { + self.inner.population_entropy() + } +} + +// ============ Generators ============ + +#[pyclass] +pub struct PyBTreeGen { + inner: RustBTreeGen, +} + +#[pymethods] +impl PyBTreeGen { + #[new] + fn new() -> Self { + PyBTreeGen { + inner: RustBTreeGen::new(), + } + } + + #[staticmethod] + fn from_config( + size: u32, + freevar_generation_probability: f64, + max_free_vars: u32, + std: PyStandardization, + ) -> Self { + let cfg = config::BTreeGen { + size, + freevar_generation_probability, + n_max_free_vars: max_free_vars, + standardization: std.into(), + seed: ConfigSeed::new([0; 32]), + }; + PyBTreeGen { + inner: RustBTreeGen::from_config(&cfg), + } + } + + fn generate(&mut self) -> String { + self.inner.generate().to_string() + } + + fn generate_n(&mut self, n: usize) -> Vec { + self.inner + .generate_n(n) + .into_iter() + .map(|t| t.to_string()) + .collect() + } +} + +#[pyclass] +pub struct PyFontanaGen { + inner: RustFontanaGen, +} + +#[pymethods] +impl PyFontanaGen { + /// Build a Fontana generator from config values (matches the new struct) + #[staticmethod] + pub fn from_config( + abs_range: (f64, f64), + app_range: (f64, f64), + min_depth: u32, + max_depth: u32, + free_variable_probability: f64, + max_free_vars: u32, + ) -> Self { + let cfg = config::FontanaGen { + abstraction_prob_range: abs_range, + application_prob_range: app_range, + min_depth, + max_depth, + free_variable_probability, + n_max_free_vars: max_free_vars, + seed: ConfigSeed::new([0; 32]), + }; + PyFontanaGen { + inner: RustFontanaGen::from_config(&cfg), + } + } + + /// Generate a single lambda term (now always returns a term) + pub fn generate(&mut self) -> String { + self.inner.generate().to_string() + } + + /// Convenience: generate N terms + pub fn generate_n(&mut self, n: usize) -> Vec { + self.inner + .generate_n(n) + .into_iter() + .map(|t| t.to_string()) + .collect() + } +} + +// ============ Utilities ============ + +#[pyfunction] +fn decode_hex_py(hex_string: &str) -> PyResult> { + decode_hex(hex_string).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string())) +} + +#[pyfunction] +fn encode_hex_py(bytes: Vec) -> String { + encode_hex(&bytes) +} + +// ============ Public registration hook ============ + +pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_function(wrap_pyfunction!(decode_hex_py, m)?)?; + m.add_function(wrap_pyfunction!(encode_hex_py, m)?)?; + Ok(()) +} diff --git a/src/supercollider.rs b/src/supercollider.rs index 31fb7f4..772177d 100644 --- a/src/supercollider.rs +++ b/src/supercollider.rs @@ -223,6 +223,10 @@ where self.expressions.len() } + pub fn is_empty(&self) -> bool { + self.expressions.is_empty() + } + /// Get the number of successful collisions pub fn collisions(&self) -> usize { self.n_collisions diff --git a/src/utils.rs b/src/utils.rs index c8b3544..d844fe2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,7 +8,7 @@ use std::io::{self, BufRead, BufReader, Write}; // This was shamelessly stolen from // https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=e241493d100ecaadac3c99f37d0f766f pub fn decode_hex(s: &str) -> Result, DecodeHexError> { - if s.len() % 2 != 0 { + if s.len() & 1 == 1 { Err(DecodeHexError::OddLength) } else { (0..s.len()) @@ -97,7 +97,7 @@ where U: Ord, { fn partial_cmp(&self, other: &Self) -> Option { - Some(self.priority.cmp(&other.priority)) + Some(self.cmp(other)) } } @@ -144,6 +144,6 @@ where for i in series { write!(file, "{:?}; ", i)?; } - write!(file, "\n")?; + writeln!(file)?; Ok(()) } diff --git a/test_alchemy.py b/test_alchemy.py new file mode 100644 index 0000000..9f1f03d --- /dev/null +++ b/test_alchemy.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# test_alchemy.py + +import sys +import traceback + + +def die(msg: str): + print(msg) + sys.exit(1) + + +def main(): + # ---------- Import ---------- + try: + import alchemy + import inspect + print("✅ Imported alchemy") + print(" module:", getattr(alchemy, "__file__", "")) + print(" PyFontanaGen.from_config signature:", + inspect.signature(alchemy.PyFontanaGen.from_config)) + except Exception: + die("❌ Failed to import 'alchemy'\n" + traceback.format_exc()) + + # ---------- Utilities ---------- + try: + raw = b"\x00\x01\xab\xcd" + hx = alchemy.decode_hex_py("0001abcd") + assert bytes(hx) == raw, f"decode_hex_py mismatch: {hx}" + re_hx = alchemy.encode_hex_py(list(raw)) + assert re_hx.lower() == "0001abcd", f"encode_hex_py mismatch: {re_hx}" + print("✅ Utilities OK (decode_hex_py / encode_hex_py)") + except Exception: + die("❌ Utilities failed\n" + traceback.format_exc()) + + # ---------- Standardization ---------- + try: + std_prefix = alchemy.PyStandardization("prefix") + std_postfix = alchemy.PyStandardization("postfix") + std_none = alchemy.PyStandardization("none") + for s in (std_prefix, std_postfix, std_none): + assert s is not None + print("✅ PyStandardization constructed (prefix/postfix/none)") + except Exception: + die("❌ PyStandardization construction failed\n" + traceback.format_exc()) + + # ---------- Generators: BTreeGen ---------- + try: + bt = alchemy.PyBTreeGen.from_config( + size=6, + freevar_generation_probability=0.3, + max_free_vars=3, + std=std_prefix, + ) + one = bt.generate() + many = bt.generate_n(5) + assert isinstance(one, str) and len(one) > 0, "BTreeGen.generate must return a non-empty string" + assert isinstance(many, list) and len(many) == 5 and all(isinstance(x, str) and x for x in many) + print("✅ PyBTreeGen.generate / generate_n OK") + except Exception: + die("❌ PyBTreeGen tests failed\n" + traceback.format_exc()) + + # ---------- Soup lifecycle ---------- + try: + soup1 = alchemy.PySoup() + assert soup1.len() == 0, "New soup should be empty" + + reactor = alchemy.PyReactor() + soup2 = alchemy.PySoup.from_config(reactor) + assert soup2.len() == 0, "Soup.from_config should start empty" + + exprs = bt.generate_n(10) + soup2.perturb(exprs) + assert soup2.len() == 10, f"After perturb, expected 10 expressions, got {soup2.len()}" + + steps = soup2.simulate_for(25, False) + assert isinstance(steps, int) + + all_exprs = soup2.expressions() + uniq = soup2.unique_expressions() + counts = soup2.expression_counts() + ent = soup2.population_entropy() + col = soup2.collisions() + ln = soup2.len() + + assert isinstance(all_exprs, list) + assert isinstance(uniq, list) + assert isinstance(counts, list) and all( + isinstance(p, (tuple, list)) and len(p) == 2 and isinstance(p[0], str) and isinstance(p[1], int) + for p in counts + ) + assert isinstance(ent, float) + assert isinstance(col, int) + assert isinstance(ln, int) + print(f"✅ PySoup lifecycle OK | len={ln}, uniq={len(uniq)}, collisions={col}, entropy={ent:.4f}") + except Exception: + die("❌ PySoup tests failed\n" + traceback.format_exc()) + + # ---------- FontanaGen (new API + always returns str) ---------- + try: + fg = alchemy.PyFontanaGen.from_config( + abs_range=(0.2, 0.6), + app_range=(0.2, 0.6), + min_depth=1, # test minimum nesting before allowing variables + max_depth=5, # cap depth growth + free_variable_probability=0.25, + max_free_vars=3, + ) + term = fg.generate() + assert isinstance(term, str) and term, "FontanaGen.generate must return a non-empty string" + terms = fg.generate_n(5) + assert isinstance(terms, list) and len(terms) == 5 and all(isinstance(t, str) and t for t in terms) + print("✅ PyFontanaGen.from_config / generate / generate_n OK") + except Exception: + die("❌ PyFontanaGen tests failed\n" + traceback.format_exc()) + + print("\n🎉 All python.rs bindings exercised successfully.") + + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..7c4d26c --- /dev/null +++ b/uv.lock @@ -0,0 +1,7 @@ +version = 1 +revision = 3 +requires-python = ">=3.7" + +[[package]] +name = "alchemy" +source = { editable = "." }