From 319080af05dcd75938ad663ae0183c482a51d1c8 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 11 Aug 2025 14:04:20 -0600 Subject: [PATCH 01/28] v1 --- .gitignore | 1 + Cargo.lock | 4362 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 + src/main.rs | 383 +++++ src/mirror.rs | 48 + 5 files changed, 4807 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs create mode 100644 src/mirror.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..77f2eccf2 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4362 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ammonia" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b346764dd0814805de8abf899fe03065bcee69bb1a4771c785817e39f3978f" +dependencies = [ + "cssparser", + "html5ever", + "maplit", + "tendril", + "url", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "atomic_float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +dependencies = [ + "serde", +] + +[[package]] +name = "blanket" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56791e4bd64c99fc361e01008f45c984baa93f12a0957d1b3c51dd2c6baab453" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "burn" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c652ab5d2d1a4b3f5781ea4a3b907cecc09b8bc9fa93ca934f12e13bbbc96" +dependencies = [ + "burn-autodiff", + "burn-candle", + "burn-core", + "burn-cuda", + "burn-ndarray", + "burn-rocm", + "burn-router", + "burn-wgpu", +] + +[[package]] +name = "burn-autodiff" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cfe012cffcf0f3700a1fccc8f78db08c63ba772d63a4d11687da58afa220e13" +dependencies = [ + "burn-common", + "burn-tensor", + "derive-new", + "hashbrown 0.15.5", + "log", + "num-traits", + "portable-atomic", + "spin", +] + +[[package]] +name = "burn-candle" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb052e5c240b7fc3265a3d8137a53b7c29b678f6b7613cc5ca315217e4a8d627" +dependencies = [ + "burn-common", + "burn-tensor", + "candle-core", + "derive-new", + "half", +] + +[[package]] +name = "burn-common" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99029e20e31124a48fd9ed7a56898a878df224f7030940d40a88cc36a086cc9" +dependencies = [ + "cubecl-common", + "rayon", + "serde", +] + +[[package]] +name = "burn-core" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f7a4166dfa0d7b30f5caa583d9bf01366052537f8cbd522c8a415125fe4592" +dependencies = [ + "ahash", + "bincode", + "burn-common", + "burn-derive", + "burn-tensor", + "data-encoding", + "derive-new", + "flate2", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "portable-atomic-util", + "rand 0.9.2", + "rmp-serde", + "serde", + "serde_json", + "spin", + "uuid", +] + +[[package]] +name = "burn-cubecl" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec89330675dabf02ba979ddf6874c2bd38d17d398a446e83a8c7b586536a940" +dependencies = [ + "burn-common", + "burn-cubecl-fusion", + "burn-fusion", + "burn-ir", + "burn-tensor", + "bytemuck", + "cubecl", + "derive-new", + "futures-lite", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "rand 0.9.2", + "serde", + "spin", + "text_placeholder", +] + +[[package]] +name = "burn-cubecl-fusion" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823fdd0fc98a5a2adcfa5fb6ff0791652db07aa72d68c0ab9cedd31188f01b0e" +dependencies = [ + "burn-common", + "burn-fusion", + "burn-ir", + "burn-tensor", + "cubecl", + "derive-new", + "half", + "serde", +] + +[[package]] +name = "burn-cuda" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0d9909ff711c13a416a5212111a6c85defce9a5e194752a012e79b27a107f9" +dependencies = [ + "burn-cubecl", + "burn-tensor", + "bytemuck", + "cubecl", + "derive-new", + "half", + "log", +] + +[[package]] +name = "burn-derive" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e901ae21fa532d237168fe963db9bf2ff1d73c8fbde2c7cffe1cdbae107499" +dependencies = [ + "derive-new", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "burn-fusion" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97673bcc1f574d23d505605af943a9f84a495d8abd0af48b496927a004912c7" +dependencies = [ + "burn-common", + "burn-ir", + "burn-tensor", + "derive-new", + "half", + "hashbrown 0.15.5", + "log", + "serde", + "spin", +] + +[[package]] +name = "burn-ir" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf45587016162b5ec6764dd4b79ee43c85d1d04bb4850fccce97fe672c4e6fbb" +dependencies = [ + "burn-tensor", + "hashbrown 0.15.5", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "burn-ndarray" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6518dc3956cba8f6c8a747e498029e93b22727720c0bc4ebebef35fe447dfe02" +dependencies = [ + "atomic_float", + "burn-autodiff", + "burn-common", + "burn-ir", + "burn-tensor", + "derive-new", + "libm", + "macerator", + "matrixmultiply", + "ndarray", + "num-traits", + "paste", + "portable-atomic-util", + "rand 0.9.2", + "spin", +] + +[[package]] +name = "burn-rocm" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2e74851c0e2fc600a0362544cd4cfccf0519ba11ab530734be30a79683c0ff" +dependencies = [ + "burn-cubecl", + "burn-tensor", + "bytemuck", + "cubecl", + "derive-new", + "half", + "log", +] + +[[package]] +name = "burn-router" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b0566c0414f63b7353c222231f075ed29bc55eb0fed9f4123edfd3a1ed4ac3" +dependencies = [ + "burn-common", + "burn-ir", + "burn-tensor", + "hashbrown 0.15.5", + "log", + "spin", +] + +[[package]] +name = "burn-tensor" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5719aec856f198aea8ac6bd859d2a9e88a626bafbb343a558614ec9ec9fb8605" +dependencies = [ + "burn-common", + "bytemuck", + "colored", + "cubecl", + "derive-new", + "half", + "hashbrown 0.15.5", + "num-traits", + "rand 0.9.2", + "rand_distr", + "serde", + "serde_bytes", +] + +[[package]] +name = "burn-wgpu" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59fcb1d419fe44700cac10b59e5dda0e1512e8f8d7199073c172d88ba964b8f" +dependencies = [ + "burn-cubecl", + "burn-tensor", + "cubecl", +] + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cached" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801927ee168e17809ab8901d9f01f700cd7d8d6a6527997fee44e4b0327a253c" +dependencies = [ + "ahash", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown 0.15.5", + "once_cell", + "thiserror 2.0.12", + "web-time", +] + +[[package]] +name = "cached_proc_macro" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9225bdcf4e4a9a4c08bf16607908eb2fbf746828d5e0b5e019726dbf6571f201" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + +[[package]] +name = "candle-core" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ccf5ee3532e66868516d9b315f73aec9f34ea1a37ae98514534d458915dbf1" +dependencies = [ + "byteorder", + "gemm 0.17.1", + "half", + "memmap2", + "num-traits", + "num_cpus", + "rand 0.9.2", + "rand_distr", + "rayon", + "safetensors", + "thiserror 1.0.69", + "ug", + "yoke 0.7.5", + "zip", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clap" +version = "4.5.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "cubecl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418aabe526efb2d2714b9282a583bccbc555fe2e42546101259b2042bc133fa" +dependencies = [ + "cubecl-convolution", + "cubecl-core", + "cubecl-cuda", + "cubecl-hip", + "cubecl-matmul", + "cubecl-random", + "cubecl-reduce", + "cubecl-runtime", + "cubecl-std", + "cubecl-wgpu", + "half", +] + +[[package]] +name = "cubecl-common" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2bed7d9aa1a2fe640696067cab6b0b1b40dd30cdb8d12f91ae43ca6392498e" +dependencies = [ + "bytemuck", + "cfg-if", + "derive-new", + "derive_more 2.0.1", + "dirs", + "embassy-futures", + "embassy-time", + "futures-lite", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "portable-atomic", + "rand 0.9.2", + "sanitize-filename", + "serde", + "serde_json", + "spin", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "cubecl-convolution" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a324c7e684c627a2746fb4700a29b5881970c7f93cc06c66bcf3c2c5184af97b" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-matmul", + "cubecl-random", + "cubecl-reduce", + "cubecl-runtime", + "cubecl-std", + "half", + "serde", +] + +[[package]] +name = "cubecl-core" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4c683bb3ed715eed12cfeca6599dc554efb9371e85f783eb7c3ae0d3781274" +dependencies = [ + "bitflags 2.9.1", + "bytemuck", + "cubecl-common", + "cubecl-ir", + "cubecl-macros", + "cubecl-runtime", + "derive-new", + "derive_more 2.0.1", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "paste", + "serde", + "serde_json", + "variadics_please", +] + +[[package]] +name = "cubecl-cpp" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d06ed3e34f0a9f0a1ca225fc3351865a2ddf66966c73a7953dd27f1bbaed9b9" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-runtime", + "derive-new", + "half", + "log", +] + +[[package]] +name = "cubecl-cuda" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf8898be518bd3df9f7d0df8c25e95f07cfc087c6485dda42e99add432e3463b" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-runtime", + "cudarc", + "derive-new", + "half", + "log", + "serde", +] + +[[package]] +name = "cubecl-hip" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9afb1c085f8d715fd8686ad77ada69e364c9cc16a51cf10a7d65ad88d760b6b" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-hip-sys", + "cubecl-runtime", + "derive-new", + "half", + "log", + "paste", +] + +[[package]] +name = "cubecl-hip-sys" +version = "6.4.4348201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678a20e5e38ce9c772bdd53596f2801ef210ae735ec2d7d46b5d5b675c09d929" +dependencies = [ + "libc", + "regex", +] + +[[package]] +name = "cubecl-ir" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb72454fb17da66e60f98a011cce199ff0bb78c4e465236459af619039b6cd5" +dependencies = [ + "cubecl-common", + "cubecl-macros-internal", + "derive_more 2.0.1", + "float-ord", + "fnv", + "half", + "hashbrown 0.15.5", + "num-traits", + "portable-atomic", + "serde", + "variadics_please", +] + +[[package]] +name = "cubecl-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d61316b8a2ec26bb554745591174022bb048dbcc508091b15dd4f6fcb4793a" +dependencies = [ + "cubecl-common", + "darling 0.21.1", + "derive-new", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cubecl-macros-internal" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c27cf02393d78a41ad125ef6d6274cd3930385f6945779f4f21a2c66e718db" +dependencies = [ + "darling 0.21.1", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cubecl-matmul" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66af2716f458eed3bd14d810d9a90bc43dd35c5464b2fe4630a711a074892fb8" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-random", + "cubecl-reduce", + "cubecl-runtime", + "cubecl-std", + "half", + "serde", +] + +[[package]] +name = "cubecl-random" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648731639463df215c01ee209477a2f233fb5168fb50e8df755e658ddaaf29f4" +dependencies = [ + "cubecl-common", + "cubecl-core", + "cubecl-runtime", + "cubecl-std", + "half", + "num-traits", + "rand 0.9.2", + "serde", +] + +[[package]] +name = "cubecl-reduce" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729e3de15783aed5c617c8c4de633765c6d0cf4b9564bb51d21dd67b4fdeeebf" +dependencies = [ + "cubecl-core", + "cubecl-runtime", + "cubecl-std", + "half", + "num-traits", + "serde", +] + +[[package]] +name = "cubecl-runtime" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab7c56cbb83e43fd1b52ee3d521bcb816068e0bb6f4aeb56c9bd63218b1147" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-ir", + "derive-new", + "dirs", + "foldhash", + "hashbrown 0.15.5", + "log", + "md5", + "serde", + "serde_json", + "spin", + "toml", + "variadics_please", + "wasm-bindgen-futures", +] + +[[package]] +name = "cubecl-std" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3536c4c1c878bd77ceda959a3f157bbb69f957269e3f138c7edd72d9deb533fd" +dependencies = [ + "cubecl-core", + "cubecl-runtime", + "half", + "serde", +] + +[[package]] +name = "cubecl-wgpu" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3f068c9a81201f43cdd3f6385201b330f2499f6c24d688d82a70d705261a32" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-core", + "cubecl-runtime", + "derive-new", + "derive_more 2.0.1", + "half", + "hashbrown 0.15.5", + "log", + "wgpu", +] + +[[package]] +name = "cudarc" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17200eb07e7d85a243aa1bf4569a7aa998385ba98d14833973a817a63cc86e92" +dependencies = [ + "libloading", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b136475da5ef7b6ac596c0e956e37bad51b85b987ff3d5e230e964936736b2" +dependencies = [ + "darling_core 0.21.1", + "darling_macro 0.21.1", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b44ad32f92b75fb438b04b68547e521a548be8acc339a6dacc4a7121488f53e6" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5be8a7a562d315a5b92a630c30cec6bcf663e6673f00fbb69cca66a6f521b9" +dependencies = [ + "darling_core 0.21.1", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.60.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dyn-stack" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e53799688f5632f364f8fb387488dd05db9fe45db7011be066fc20e7027f8b" +dependencies = [ + "bytemuck", + "reborrow", +] + +[[package]] +name = "dyn-stack" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embassy-futures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" + +[[package]] +name = "embassy-time" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d45f5d833b6d98bd2aab0c2de70b18bfaa10faf661a1578fd8e5dfb15eb7eba" +dependencies = [ + "document-features", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gemm" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab24cc62135b40090e31a76a9b2766a501979f3070fa27f689c27ec04377d32" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-c32 0.17.1", + "gemm-c64 0.17.1", + "gemm-common 0.17.1", + "gemm-f16 0.17.1", + "gemm-f32 0.17.1", + "gemm-f64 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-c32 0.18.2", + "gemm-c64 0.18.2", + "gemm-common 0.18.2", + "gemm-f16 0.18.2", + "gemm-f32 0.18.2", + "gemm-f64 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c030d0b983d1e34a546b86e08f600c11696fde16199f971cd46c12e67512c0" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb5f2e79fefb9693d18e1066a557b4546cd334b226beadc68b11a8f9431852a" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" +dependencies = [ + "bytemuck", + "dyn-stack 0.10.0", + "half", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.18.22", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", + "sysctl 0.5.5", +] + +[[package]] +name = "gemm-common" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" +dependencies = [ + "bytemuck", + "dyn-stack 0.13.0", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.21.5", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", + "sysctl 0.6.0", +] + +[[package]] +name = "gemm-f16" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca4c06b9b11952071d317604acb332e924e817bd891bec8dfb494168c7cedd4" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "gemm-f32 0.17.1", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f16" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "gemm-f32 0.18.2", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a69f51aaefbd9cf12d18faf273d3e982d9d711f60775645ed5c8047b4ae113" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa397a48544fadf0b81ec8741e5c0fba0043008113f71f2034def1935645d2b0" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "getopts" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.9.1", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.9.1", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", + "num-traits", + "rand 0.9.2", + "rand_distr", + "serde", +] + +[[package]] +name = "harper-brill" +version = "0.56.0" +dependencies = [ + "harper-pos-utils", + "lazy_static", + "rs-conllu", + "serde", + "serde_json", +] + +[[package]] +name = "harper-core" +version = "0.56.0" +dependencies = [ + "ammonia", + "bitflags 2.9.1", + "blanket", + "cached", + "foldhash", + "fst", + "harper-brill", + "hashbrown 0.15.5", + "is-macro", + "itertools", + "lazy_static", + "levenshtein_automata", + "lru", + "ordered-float 5.0.0", + "paste", + "pulldown-cmark", + "serde", + "serde_json", + "smallvec", + "strum 0.27.2", + "strum_macros 0.27.2", + "thiserror 2.0.12", + "unicode-blocks", + "unicode-script", + "unicode-width", +] + +[[package]] +name = "harper-pos-utils" +version = "0.56.0" +dependencies = [ + "burn", + "burn-ndarray", + "hashbrown 0.15.5", + "is-macro", + "itertools", + "lru", + "rs-conllu", + "serde", + "serde_json", + "strum 0.27.2", + "strum_macros 0.27.2", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "html5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" +dependencies = [ + "log", + "markup5ever", + "match_token", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke 0.8.0", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke 0.8.0", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.5", +] + +[[package]] +name = "is-macro" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" +dependencies = [ + "fst", +] + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.1", + "libc", +] + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "macerator" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ac9c19702c37bae1a53d130a326b1c4f58cb17d472538cf547d44b46dbbe3aa" +dependencies = [ + "bytemuck", + "cfg_aliases", + "half", + "macerator-macros", + "moddef", + "num-traits", + "paste", + "rustc_version", +] + +[[package]] +name = "macerator-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd48b535b9b37a25a2589ab8d4f997886a2c68f59960ce06588525f38dd4944" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "markup5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", +] + +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.9.1", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "moddef" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0b3262dc837d2513fe2ef31ff8461352ef932dcca31ba0c0abe33547cf6b9b" + +[[package]] +name = "naga" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.9.1", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.15.5", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "once_cell", + "rustc-hash", + "spirv", + "strum 0.26.3", + "thiserror 2.0.12", + "unicode-ident", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", + "rayon", +] + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-float" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" +dependencies = [ + "num-traits", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +dependencies = [ + "serde", +] + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + +[[package]] +name = "pulldown-cmark" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +dependencies = [ + "bitflags 2.9.1", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + +[[package]] +name = "pulp" +version = "0.18.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" +dependencies = [ + "bytemuck", + "libm", + "num-complex", + "reborrow", +] + +[[package]] +name = "pulp" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "reborrow", + "version_check", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "serde", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "range-alloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.12", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "ripper" +version = "0.1.0" +dependencies = [ + "harper-brill", + "harper-core", + "rand 0.9.2", + "rayon", + "serde", + "serde_json", + "strum 0.27.2", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rs-conllu" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6de5aecf17f8fff1b35d59a12e2b8c908cad4d67208805166483655554f9169" +dependencies = [ + "clap", + "derive_more 1.0.0", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "safetensors" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sanitize-filename" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" +dependencies = [ + "regex", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", + "portable-atomic", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sysctl" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" +dependencies = [ + "bitflags 2.9.1", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.9.1", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "text_placeholder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5008f74a09742486ef0047596cf35df2b914e2a8dca5727fcb6ba6842a766b" +dependencies = [ + "hashbrown 0.13.2", + "serde", + "serde_json", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "toml_datetime 0.6.11", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "ug" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03719c61a91b51541f076dfdba45caacf750b230cefaa4b32d6f5411c3f7f437" +dependencies = [ + "gemm 0.18.2", + "half", + "libloading", + "memmap2", + "num", + "num-traits", + "num_cpus", + "rayon", + "safetensors", + "serde", + "thiserror 1.0.69", + "tracing", + "yoke 0.7.5", +] + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-blocks" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b12e05d9e06373163a9bb6bb8c263c261b396643a99445fe6b9811fd376581b" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" + +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "wgpu" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9" +dependencies = [ + "arrayvec", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "js-sys", + "log", + "naga", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500" +dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror 2.0.12", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core-deps-apple" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd488b3239b6b7b185c3b045c39ca6bf8af34467a4c5de4e0b1a564135d093d" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09ad7aceb3818e52539acc679f049d3475775586f3f4e311c30165cf2c00445" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba5fb5f7f9c98baa7c889d444f63ace25574833df56f5b817985f641af58e46" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f968767fe4d3d33747bbd1473ccd55bf0f6451f55d733b5597e67b5deab4ad17" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.9.1", + "block", + "bytemuck", + "cfg-if", + "cfg_aliases", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.15.5", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "ordered-float 4.6.0", + "parking_lot", + "portable-atomic", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.12", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows", + "windows-core", +] + +[[package]] +name = "wgpu-types" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc" +dependencies = [ + "bitflags 2.9.1", + "bytemuck", + "js-sys", + "log", + "thiserror 2.0.12", + "web-sys", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "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", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[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_i686_gnullvm 0.52.6", + "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", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "xml-rs" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.8.0", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke 0.8.0", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke 0.8.0", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "indexmap", + "num_enum", + "thiserror 1.0.69", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..49d4c7d0a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ripper" +version = "0.1.0" +edition = "2024" + +[dependencies] +harper-brill = { version = "0.56.0", path = "../harper/harper-brill" } +harper-core = { version = "0.56.0", path = "../harper/harper-core" } +rand = "0.9.2" +rayon = "1.10.0" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.142" +strum = "0.27.2" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 000000000..7e4caa6f7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,383 @@ +mod mirror; + +use std::collections::HashSet; + +use harper_brill::UPOS; +use harper_core::Document; +use harper_core::expr::{ExprExt, SequenceExpr}; +use harper_core::patterns::{UPOSSet, WordSet}; +use harper_core::spell::{Dictionary, FstDictionary}; +use rand::seq::IndexedRandom; +use rand::{Rng, seq::SliceRandom}; +use rayon::slice::ParallelSliceMut; +use serde_json::to_string; +use strum::IntoEnumIterator; + +use self::mirror::{Mirror, MirrorAtom}; + +fn main() { + let child_ratio = 10000; + let min_pop = 10; + let dict = FstDictionary::curated(); + + let mut mirs = vec![Mirror { + seq: vec![MirrorAtom::AllowedWords(vec!["too".to_string()])], + }]; + + for i in 0..200 { + mirs.par_sort_by_cached_key(|s| usize::MAX - score(&s.to_seq_expr())); + + for i in 0..3.min(mirs.len()) { + dbg!( + &mirs[i], + score(&mirs[i].to_seq_expr()), + problems().len() + clean().len() + ); + } + + mirs.truncate(min_pop); + + let mut perm_mirs = Vec::new(); + + for mir in &mirs { + perm_mirs.append(&mut permute_mirror_unique(mir, child_ratio, &dict)); + } + + mirs.append(&mut perm_mirs); + mirs.shuffle(&mut rand::rng()); + } +} + +fn build_word_pool(dict: Option<&D>, rng: &mut impl Rng) -> Vec { + match dict { + Some(d) => { + let cap = d.word_count().min(5_000); + let mut pool = Vec::with_capacity(cap); + for w in d.words_iter().take(cap) { + let s: String = w.iter().collect(); + if !s.chars().any(|c| c.is_whitespace()) { + pool.push(s); + } + } + pool.shuffle(rng); + if pool.is_empty() { + fallback_words() + } else { + pool + } + } + None => fallback_words(), + } +} + +fn choose_words(pool: &[String], k: usize, rng: &mut impl Rng) -> Vec { + if pool.is_empty() { + return fallback_words() + .choose_multiple(rng, k) + .cloned() + .map(|s| s.to_string()) + .collect(); + } + pool.choose_multiple(rng, k).cloned().collect() +} + +fn fallback_words() -> Vec { + [ + "alpha", "brisk", "candle", "delta", "ember", "flora", "glyph", "harbor", "ionic", + "juniper", "keystone", "lumen", "modest", "nylon", "opal", "quartz", "rivet", "spruce", + "topaz", "umber", "vivid", "willow", "xenon", "yonder", "zephyr", + ] + .iter() + .map(|s| s.to_string()) + .collect() +} + +pub fn permute_mirror_unique(base: &Mirror, n: usize, dict: &D) -> Vec { + let mut rng = rand::thread_rng(); + let word_pool = build_word_pool(Some(dict), &mut rng); + + let mut out = Vec::with_capacity(n); + + let mut attempts = 0usize; + while out.len() < n && attempts < n * 80 { + attempts += 1; + + let mut m = Mirror { + seq: base.seq.clone(), + }; + if rng.gen_bool(0.35) { + m.seq.push(random_non_ws_atom(&word_pool, &mut rng)); + } else { + apply_random_edit(&mut m, &word_pool, &mut rng); + } + + if rng.gen_bool(0.80) { + m.seq.push(MirrorAtom::Whitespace); + } + + out.push(m); + } + + out +} + +fn apply_random_edit(m: &mut Mirror, pool: &[String], rng: &mut impl Rng) { + for _ in 0..6 { + let i = rng.gen_range(0..m.seq.len()); + match &mut m.seq[i] { + MirrorAtom::AllowedWords(words) => { + if rng.gen_bool(0.65) { + *words = distinct_words(pool, words.len(), rng, Some(words)); + } else { + m.seq[i] = flip_from_words(words.len(), pool, rng); + } + } + MirrorAtom::DisallowedWords(words) => { + if rng.gen_bool(0.65) { + *words = distinct_words(pool, words.len(), rng, Some(words)); + } else { + m.seq[i] = flip_from_words(words.len(), pool, rng); + } + } + MirrorAtom::UPOS(_) => { + if rng.gen_bool(0.65) { + m.seq[i] = MirrorAtom::UPOS(random_upos_set(rng)); + } else { + m.seq[i] = flip_from_upos(pool, rng); + } + } + MirrorAtom::Whitespace => { + m.seq[i] = if rng.gen_bool(0.55) { + random_non_ws_atom(pool, rng) + } else { + MirrorAtom::UPOS(random_upos_set(rng)) + }; + } + } + } +} + +fn flip_from_words(len: usize, pool: &[String], rng: &mut impl Rng) -> MirrorAtom { + match rng.gen_range(0..=2) { + 0 => MirrorAtom::DisallowedWords(distinct_words(pool, len.max(1), rng, None)), + 1 => MirrorAtom::UPOS(random_upos_set(rng)), + _ => MirrorAtom::Whitespace, + } +} + +fn flip_from_upos(pool: &[String], rng: &mut impl Rng) -> MirrorAtom { + match rng.gen_range(0..=2) { + 0 => MirrorAtom::AllowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), + 1 => MirrorAtom::DisallowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), + _ => MirrorAtom::Whitespace, + } +} + +fn random_non_ws_atom(pool: &[String], rng: &mut impl Rng) -> MirrorAtom { + match rng.gen_range(0..=2) { + 0 => MirrorAtom::AllowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), + 1 => MirrorAtom::DisallowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), + _ => MirrorAtom::UPOS(random_upos_set(rng)), + } +} + +fn random_upos_set(rng: &mut impl Rng) -> UPOSSet { + let k = rng.gen_range(1..=3); + let mut v: Vec = UPOS::iter() + .collect::>() + .choose_multiple(rng, k) + .cloned() + .collect(); + v.sort_unstable(); + UPOSSet::new(&v) +} + +fn distinct_words( + pool: &[String], + k: usize, + rng: &mut impl Rng, + avoid: Option<&Vec>, +) -> Vec { + let mut out: Vec = pool.choose_multiple(rng, k.max(1)).cloned().collect(); + out.sort_unstable(); + out.dedup(); + if let Some(orig) = avoid { + let mut a = orig.clone(); + a.sort_unstable(); + a.dedup(); + if a == out { + return distinct_words(pool, k, rng, avoid); + } + } + out +} + +fn problems() -> &'static [&'static str] { + &[ + "I need too finish this report before noon.", + "She went too the grocery store after work.", + "We decided too postpone the meeting.", + "He forgot too send the invitation.", + "Remember too lock the door.", + "They plan too travel next spring.", + "I tried too explain the discrepancy.", + "Please add this file too the repository.", + "He refused too apologize for the oversight.", + "I'm happy too help with debugging.", + "Set the thermostat back too sixty-eight at night.", + "We need too align our objectives.", + "She learned how too solder the components.", + "The CEO chose too prioritize profitability.", + "Use the adapter too connect the cable.", + "He ran from end too end of the field.", + "It's critical too verify each assumption.", + "Attach the label too the container.", + "I meant too forward you the email.", + "They drove too Denver before sunrise.", + "Tap here too continue.", + "I neglected too charge the laptop.", + "We hope too avoid scope creep.", + "Click 'Build' too compile the project.", + "The change needs too propagate across services.", + "I'm going too grab lunch.", + "She agreed too mentor the interns.", + "He promised too follow up tomorrow.", + "Use this form too request access.", + "I prefer too work asynchronously.", + "The team aims too reduce latency.", + "Press Esc too cancel.", + "Switch lanes from left too right safely.", + "We're moving from draft too production.", + "I waited an hour just too speak with support.", + "Route the packet too the primary gateway.", + "This needs to adhere too the spec.", + "According too our records, your payment cleared.", + "Due too network congestion, the upload stalled.", + "We intend too deprecate this endpoint.", + ] +} + +fn clean() -> &'static [&'static str] { + &[ + "I need to finish this report before noon.", + "She went to the grocery store after work.", + "We decided to postpone the meeting.", + "He forgot to send the invitation.", + "Remember to lock the door.", + "They plan to travel next spring.", + "I tried to explain the discrepancy.", + "Please add this file to the repository.", + "He refused to apologize for the oversight.", + "I'm happy to help with debugging.", + "Set the thermostat back to sixty-eight at night.", + "We need to align our objectives.", + "She learned how to solder the components.", + "The CEO chose to prioritize profitability.", + "Use the adapter to connect the cable.", + "He ran from end to end of the field.", + "It's critical to verify each assumption.", + "Attach the label to the container.", + "I meant to forward you the email.", + "They drove to Denver before sunrise.", + "Tap here to continue.", + "I neglected to charge the laptop.", + "We hope to avoid scope creep.", + "Click 'Build' to compile the project.", + "The change needs to propagate across services.", + "I'm going to grab lunch.", + "She agreed to mentor the interns.", + "He promised to follow up tomorrow.", + "Use this form to request access.", + "I prefer to work asynchronously.", + "The team aims to reduce latency.", + "Press Esc to cancel.", + "Switch lanes from left to right safely.", + "We're moving from draft to production.", + "I waited an hour just to speak with support.", + "Route the packet to the primary gateway.", + "This needs to adhere to the spec.", + "According to our records, your payment cleared.", + "Due to network congestion, the upload stalled.", + "We intend to deprecate this endpoint.", + "It was far too late to salvage the schedule.", + "The espresso tasted too bitter for my palate.", + "She is joining the expedition too, despite the warnings.", + "Your proposal is too vague for the board.", + "The server grew too hot under sustained load.", + "He spoke too quickly to be understood.", + "I found the contract too onerous to sign.", + "They arrived too early and waited in silence.", + "This dataset is too noisy for reliable inference.", + "The film was too long yet strangely compelling.", + "The cliff looked too sheer for novice climbers.", + "Her apology felt too rehearsed to be sincere.", + "That price is too steep for a prototype.", + "He ate too much and regretted it.", + "The room grew too quiet to ignore.", + "Your tone is too abrasive for diplomacy.", + "The deadline is too tight for thorough testing.", + "She laughed too hard at the misprint.", + "The instructions are too convoluted for speed.", + "I, too, questioned the methodology.", + "He goes too far with bets.", + "Just be prepared to occasionally troubleshoot the debugger itself.", + "It takes a great deal of energy to consistently operate under that kind of pressure.", + "I am too hungry.", + "Please remember to eat your vegetables.", + "I’m going to Nashville next week.", + "Talk to you later.", + "The coffee is too hot to drink.", + "The music was too loud, making it hard to hear.", + "He's too shy to speak in public.", + "The cake is too sweet for my taste.", + "It's too expensive for me to buy right now.", + "She worked too hard and ended up getting sick.", + "The instructions were too complicated to understand.", + "I like apples, and my brother does too.", + "She's coming to the party, and he is too.", + "I want to go to the beach, and you do too?", + "He's a talented musician, and a great friend too.", + "The movie was good, and the popcorn was delicious too.", + "The problem is too difficult, and the deadline is too close.", + "He's too good at the game, and he's too nice to win.", + "Bringing Hope and Opportunity to Young Musicians", + "Attendees can look forward to:", + "We're empowering them to build brighter futures.", + "I’d like you to consciously delegate one task", + "Soundscapes are not merely environmental features; they are integral to human identity and cultural expression.", + "Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions.", + "Attempted to explicitly cast the result back to a string", + "They felt buried under the data, unable to proactively address emerging threats.", + "Familiarize yourself with these resources to learn how to effectively utilize the plugin’s features.", + "It takes a great deal of energy to consistently operate under that kind of pressure.", + "Just be prepared to occasionally troubleshoot the debugger itself.", + "He goes too far with bets.", + ] +} + +fn score(candidate: &SequenceExpr) -> usize { + let mut correct = 0; + + let mut matches = Vec::new(); + + for problem in problems() { + let doc = Document::new_plain_english_curated(&problem); + + matches.clear(); + matches.extend(candidate.iter_matches_in_doc(&doc)); + + if matches.len() == 1 { + correct += 1; + } + } + + for clean in clean() { + let doc = Document::new_plain_english_curated(&clean); + + if candidate.iter_matches_in_doc(&doc).count() == 0 { + correct += 1; + } + } + + correct +} diff --git a/src/mirror.rs b/src/mirror.rs new file mode 100644 index 000000000..500240ab1 --- /dev/null +++ b/src/mirror.rs @@ -0,0 +1,48 @@ +use harper_core::expr::SequenceExpr; +use harper_core::patterns::{UPOSSet, WordSet}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Mirror { + pub seq: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum MirrorAtom { + AllowedWords(Vec), + DisallowedWords(Vec), + UPOS(UPOSSet), + Whitespace, +} + +impl Mirror { + pub fn to_seq_expr(&self) -> SequenceExpr { + let mut seq = SequenceExpr::default(); + for atom in &self.seq { + match atom { + MirrorAtom::AllowedWords(items) => { + let mut set = WordSet::default(); + + for item in items { + set.add(&item); + } + + seq = seq.then(set) + } + MirrorAtom::DisallowedWords(items) => { + let mut set = WordSet::default(); + + for item in items { + set.add(&item); + } + + seq = seq.then_unless(set) + } + MirrorAtom::UPOS(uposset) => seq = seq.then(uposset.clone()), + MirrorAtom::Whitespace => seq = seq.t_ws(), + }; + } + + seq + } +} From 8c68a1c40f59855884304b17dee1cd3d523d6d50 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 11 Aug 2025 14:40:57 -0600 Subject: [PATCH 02/28] allow more UPOS --- src/main.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7e4caa6f7..6cc2549ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ mod mirror; -use std::collections::HashSet; - use harper_brill::UPOS; use harper_core::Document; use harper_core::expr::{ExprExt, SequenceExpr}; @@ -10,7 +8,6 @@ use harper_core::spell::{Dictionary, FstDictionary}; use rand::seq::IndexedRandom; use rand::{Rng, seq::SliceRandom}; use rayon::slice::ParallelSliceMut; -use serde_json::to_string; use strum::IntoEnumIterator; use self::mirror::{Mirror, MirrorAtom}; @@ -182,12 +179,9 @@ fn random_non_ws_atom(pool: &[String], rng: &mut impl Rng) -> MirrorAtom { } fn random_upos_set(rng: &mut impl Rng) -> UPOSSet { - let k = rng.gen_range(1..=3); - let mut v: Vec = UPOS::iter() - .collect::>() - .choose_multiple(rng, k) - .cloned() - .collect(); + let v = UPOS::iter().collect::>(); + let k = rng.gen_range(1..v.len()); + let mut v: Vec = v.choose_multiple(rng, k).cloned().collect(); v.sort_unstable(); UPOSSet::new(&v) } From 79095fac2ddc6d75a586779b42f2a710114d88ac Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 11 Aug 2025 14:47:12 -0600 Subject: [PATCH 03/28] feat: add clap and configure parameters --- Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 25 +++++++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77f2eccf2..aeee3db68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3053,6 +3053,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" name = "ripper" version = "0.1.0" dependencies = [ + "clap", "harper-brill", "harper-core", "rand 0.9.2", diff --git a/Cargo.toml b/Cargo.toml index 49d4c7d0a..43071d098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +clap = { version = "4.5.4", features = ["derive"] } harper-brill = { version = "0.56.0", path = "../harper/harper-brill" } harper-core = { version = "0.56.0", path = "../harper/harper-core" } rand = "0.9.2" diff --git a/src/main.rs b/src/main.rs index 6cc2549ab..0fc90566c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod mirror; +use clap::Parser; use harper_brill::UPOS; use harper_core::Document; use harper_core::expr::{ExprExt, SequenceExpr}; @@ -12,9 +13,21 @@ use strum::IntoEnumIterator; use self::mirror::{Mirror, MirrorAtom}; +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// The ratio of children to generate for each generation + #[arg(short, long, default_value_t = 10000)] + child_ratio: usize, + + /// The minimum population size to maintain + #[arg(short, long, default_value_t = 10)] + min_pop: usize, +} + fn main() { - let child_ratio = 10000; - let min_pop = 10; + let args = Args::parse(); + let dict = FstDictionary::curated(); let mut mirs = vec![Mirror { @@ -32,12 +45,16 @@ fn main() { ); } - mirs.truncate(min_pop); + mirs.truncate(args.min_pop); let mut perm_mirs = Vec::new(); for mir in &mirs { - perm_mirs.append(&mut permute_mirror_unique(mir, child_ratio, &dict)); + perm_mirs.append(&mut permute_mirror_unique( + mir, + args.child_ratio, + &dict, + )); } mirs.append(&mut perm_mirs); From 686b0d6aaa2eea161a2eb289713db61dc179acf7 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 11 Aug 2025 15:17:03 -0600 Subject: [PATCH 04/28] feat: parameterize clean and problematic sentences --- clean.txt | 93 ++++++++++++++++++++++++++ problems.txt | 40 +++++++++++ src/main.rs | 184 +++++++++------------------------------------------ 3 files changed, 163 insertions(+), 154 deletions(-) create mode 100644 clean.txt create mode 100644 problems.txt diff --git a/clean.txt b/clean.txt new file mode 100644 index 000000000..0be890557 --- /dev/null +++ b/clean.txt @@ -0,0 +1,93 @@ +I need to finish this report before noon. +She went to the grocery store after work. +We decided to postpone the meeting. +He forgot to send the invitation. +Remember to lock the door. +They plan to travel next spring. +I tried to explain the discrepancy. +Please add this file to the repository. +He refused to apologize for the oversight. +I'm happy to help with debugging. +Set the thermostat back to sixty-eight at night. +We need to align our objectives. +She learned how to solder the components. +The CEO chose to prioritize profitability. +Use the adapter to connect the cable. +He ran from end to end of the field. +It's critical to verify each assumption. +Attach the label to the container. +I meant to forward you the email. +They drove to Denver before sunrise. +Tap here to continue. +I neglected to charge the laptop. +We hope to avoid scope creep. +Click 'Build' to compile the project. +The change needs to propagate across services. +I'm going to grab lunch. +She agreed to mentor the interns. +He promised to follow up tomorrow. +Use this form to request access. +I prefer to work asynchronously. +The team aims to reduce latency. +Press Esc to cancel. +Switch lanes from left to right safely. +We're moving from draft to production. +I waited an hour just to speak with support. +Route the packet to the primary gateway. +This needs to adhere to the spec. +According to our records, your payment cleared. +Due to network congestion, the upload stalled. +We intend to deprecate this endpoint. +It was far too late to salvage the schedule. +The espresso tasted too bitter for my palate. +She is joining the expedition too, despite the warnings. +Your proposal is too vague for the board. +The server grew too hot under sustained load. +He spoke too quickly to be understood. +I found the contract too onerous to sign. +They arrived too early and waited in silence. +This dataset is too noisy for reliable inference. +The film was too long yet strangely compelling. +The cliff looked too sheer for novice climbers. +Her apology felt too rehearsed to be sincere. +That price is too steep for a prototype. +He ate too much and regretted it. +The room grew too quiet to ignore. +Your tone is too abrasive for diplomacy. +The deadline is too tight for thorough testing. +She laughed too hard at the misprint. +The instructions are too convoluted for speed. +I, too, questioned the methodology. +He goes too far with bets. +Just be prepared to occasionally troubleshoot the debugger itself. +It takes a great deal of energy to consistently operate under that kind of pressure. +I am too hungry. +Please remember to eat your vegetables. +I’m going to Nashville next week. +Talk to you later. +The coffee is too hot to drink. +The music was too loud, making it hard to hear. +He's too shy to speak in public. +The cake is too sweet for my taste. +It's too expensive for me to buy right now. +She worked too hard and ended up getting sick. +The instructions were too complicated to understand. +I like apples, and my brother does too. +She's coming to the party, and he is too. +I want to go to the beach, and you do too?. +He's a talented musician, and a great friend too. +The movie was good, and the popcorn was delicious too. +The problem is too difficult, and the deadline is too close. +He's too good at the game, and he's too nice to win. +Bringing Hope and Opportunity to Young Musicians +Attendees can look forward to: +We're empowering them to build brighter futures. +I’d like you to consciously delegate one task +Soundscapes are not merely environmental features; they are integral to human identity and cultural expression. +Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. +Attempted to explicitly cast the result back to a string +They felt buried under the data, unable to proactively address emerging threats. +Familiarize yourself with these resources to learn how to effectively utilize the plugin’s features. +It takes a great deal of energy to consistently operate under that kind of pressure. +Just be prepared to occasionally troubleshoot the debugger itself. +He goes too far with bets. \ No newline at end of file diff --git a/problems.txt b/problems.txt new file mode 100644 index 000000000..9b3ab6801 --- /dev/null +++ b/problems.txt @@ -0,0 +1,40 @@ +I need too finish this report before noon. +She went too the grocery store after work. +We decided too postpone the meeting. +He forgot too send the invitation. +Remember too lock the door. +They plan too travel next spring. +I tried too explain the discrepancy. +Please add this file too the repository. +He refused too apologize for the oversight. +I'm happy too help with debugging. +Set the thermostat back too sixty-eight at night. +We need too align our objectives. +She learned how too solder the components. +The CEO chose too prioritize profitability. +Use the adapter too connect the cable. +He ran from end too end of the field. +It's critical too verify each assumption. +Attach the label too the container. +I meant too forward you the email. +They drove too Denver before sunrise. +Tap here too continue. +I neglected too charge the laptop. +We hope too avoid scope creep. +Click 'Build' too compile the project. +The change needs too propagate across services. +I'm going too grab lunch. +She agreed too mentor the interns. +He promised too follow up tomorrow. +Use this form too request access. +I prefer too work asynchronously. +The team aims too reduce latency. +Press Esc too cancel. +Switch lanes from left too right safely. +We're moving from draft too production. +I waited an hour just too speak with support. +Route the packet too the primary gateway. +This needs to adhere too the spec. +According too our records, your payment cleared. +Due too network congestion, the upload stalled. +We intend too deprecate this endpoint. \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0fc90566c..f265d3556 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,12 @@ use clap::Parser; use harper_brill::UPOS; use harper_core::Document; use harper_core::expr::{ExprExt, SequenceExpr}; -use harper_core::patterns::{UPOSSet, WordSet}; +use harper_core::patterns::UPOSSet; use harper_core::spell::{Dictionary, FstDictionary}; use rand::seq::IndexedRandom; use rand::{Rng, seq::SliceRandom}; use rayon::slice::ParallelSliceMut; +use std::fs; use strum::IntoEnumIterator; use self::mirror::{Mirror, MirrorAtom}; @@ -23,11 +24,22 @@ struct Args { /// The minimum population size to maintain #[arg(short, long, default_value_t = 10)] min_pop: usize, + + /// A file containing newline-separated sentences that should be flagged + #[arg(long)] + problem_file: String, + + /// A file containing newline-separated sentences that should not be flagged + #[arg(long)] + clean_file: String, } fn main() { let args = Args::parse(); + let problems = load_sentences(&args.problem_file); + let clean = load_sentences(&args.clean_file); + let dict = FstDictionary::curated(); let mut mirs = vec![Mirror { @@ -35,13 +47,16 @@ fn main() { }]; for i in 0..200 { - mirs.par_sort_by_cached_key(|s| usize::MAX - score(&s.to_seq_expr())); + mirs.par_sort_by_cached_key(|s| { + let score = score(&s.to_seq_expr(), &problems, &clean); + usize::MAX - score + }); for i in 0..3.min(mirs.len()) { dbg!( &mirs[i], - score(&mirs[i].to_seq_expr()), - problems().len() + clean().len() + score(&mirs[i].to_seq_expr(), &problems, &clean), + problems.len() + clean.len() ); } @@ -50,11 +65,7 @@ fn main() { let mut perm_mirs = Vec::new(); for mir in &mirs { - perm_mirs.append(&mut permute_mirror_unique( - mir, - args.child_ratio, - &dict, - )); + perm_mirs.append(&mut permute_mirror_unique(mir, args.child_ratio, &dict)); } mirs.append(&mut perm_mirs); @@ -223,155 +234,20 @@ fn distinct_words( out } -fn problems() -> &'static [&'static str] { - &[ - "I need too finish this report before noon.", - "She went too the grocery store after work.", - "We decided too postpone the meeting.", - "He forgot too send the invitation.", - "Remember too lock the door.", - "They plan too travel next spring.", - "I tried too explain the discrepancy.", - "Please add this file too the repository.", - "He refused too apologize for the oversight.", - "I'm happy too help with debugging.", - "Set the thermostat back too sixty-eight at night.", - "We need too align our objectives.", - "She learned how too solder the components.", - "The CEO chose too prioritize profitability.", - "Use the adapter too connect the cable.", - "He ran from end too end of the field.", - "It's critical too verify each assumption.", - "Attach the label too the container.", - "I meant too forward you the email.", - "They drove too Denver before sunrise.", - "Tap here too continue.", - "I neglected too charge the laptop.", - "We hope too avoid scope creep.", - "Click 'Build' too compile the project.", - "The change needs too propagate across services.", - "I'm going too grab lunch.", - "She agreed too mentor the interns.", - "He promised too follow up tomorrow.", - "Use this form too request access.", - "I prefer too work asynchronously.", - "The team aims too reduce latency.", - "Press Esc too cancel.", - "Switch lanes from left too right safely.", - "We're moving from draft too production.", - "I waited an hour just too speak with support.", - "Route the packet too the primary gateway.", - "This needs to adhere too the spec.", - "According too our records, your payment cleared.", - "Due too network congestion, the upload stalled.", - "We intend too deprecate this endpoint.", - ] -} - -fn clean() -> &'static [&'static str] { - &[ - "I need to finish this report before noon.", - "She went to the grocery store after work.", - "We decided to postpone the meeting.", - "He forgot to send the invitation.", - "Remember to lock the door.", - "They plan to travel next spring.", - "I tried to explain the discrepancy.", - "Please add this file to the repository.", - "He refused to apologize for the oversight.", - "I'm happy to help with debugging.", - "Set the thermostat back to sixty-eight at night.", - "We need to align our objectives.", - "She learned how to solder the components.", - "The CEO chose to prioritize profitability.", - "Use the adapter to connect the cable.", - "He ran from end to end of the field.", - "It's critical to verify each assumption.", - "Attach the label to the container.", - "I meant to forward you the email.", - "They drove to Denver before sunrise.", - "Tap here to continue.", - "I neglected to charge the laptop.", - "We hope to avoid scope creep.", - "Click 'Build' to compile the project.", - "The change needs to propagate across services.", - "I'm going to grab lunch.", - "She agreed to mentor the interns.", - "He promised to follow up tomorrow.", - "Use this form to request access.", - "I prefer to work asynchronously.", - "The team aims to reduce latency.", - "Press Esc to cancel.", - "Switch lanes from left to right safely.", - "We're moving from draft to production.", - "I waited an hour just to speak with support.", - "Route the packet to the primary gateway.", - "This needs to adhere to the spec.", - "According to our records, your payment cleared.", - "Due to network congestion, the upload stalled.", - "We intend to deprecate this endpoint.", - "It was far too late to salvage the schedule.", - "The espresso tasted too bitter for my palate.", - "She is joining the expedition too, despite the warnings.", - "Your proposal is too vague for the board.", - "The server grew too hot under sustained load.", - "He spoke too quickly to be understood.", - "I found the contract too onerous to sign.", - "They arrived too early and waited in silence.", - "This dataset is too noisy for reliable inference.", - "The film was too long yet strangely compelling.", - "The cliff looked too sheer for novice climbers.", - "Her apology felt too rehearsed to be sincere.", - "That price is too steep for a prototype.", - "He ate too much and regretted it.", - "The room grew too quiet to ignore.", - "Your tone is too abrasive for diplomacy.", - "The deadline is too tight for thorough testing.", - "She laughed too hard at the misprint.", - "The instructions are too convoluted for speed.", - "I, too, questioned the methodology.", - "He goes too far with bets.", - "Just be prepared to occasionally troubleshoot the debugger itself.", - "It takes a great deal of energy to consistently operate under that kind of pressure.", - "I am too hungry.", - "Please remember to eat your vegetables.", - "I’m going to Nashville next week.", - "Talk to you later.", - "The coffee is too hot to drink.", - "The music was too loud, making it hard to hear.", - "He's too shy to speak in public.", - "The cake is too sweet for my taste.", - "It's too expensive for me to buy right now.", - "She worked too hard and ended up getting sick.", - "The instructions were too complicated to understand.", - "I like apples, and my brother does too.", - "She's coming to the party, and he is too.", - "I want to go to the beach, and you do too?", - "He's a talented musician, and a great friend too.", - "The movie was good, and the popcorn was delicious too.", - "The problem is too difficult, and the deadline is too close.", - "He's too good at the game, and he's too nice to win.", - "Bringing Hope and Opportunity to Young Musicians", - "Attendees can look forward to:", - "We're empowering them to build brighter futures.", - "I’d like you to consciously delegate one task", - "Soundscapes are not merely environmental features; they are integral to human identity and cultural expression.", - "Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions.", - "Attempted to explicitly cast the result back to a string", - "They felt buried under the data, unable to proactively address emerging threats.", - "Familiarize yourself with these resources to learn how to effectively utilize the plugin’s features.", - "It takes a great deal of energy to consistently operate under that kind of pressure.", - "Just be prepared to occasionally troubleshoot the debugger itself.", - "He goes too far with bets.", - ] +fn load_sentences(path: &str) -> Vec { + fs::read_to_string(path) + .expect("Unable to read file") + .lines() + .map(|s| s.to_string()) + .collect() } -fn score(candidate: &SequenceExpr) -> usize { +fn score(candidate: &SequenceExpr, problems: &[String], clean: &[String]) -> usize { let mut correct = 0; let mut matches = Vec::new(); - for problem in problems() { + for problem in problems { let doc = Document::new_plain_english_curated(&problem); matches.clear(); @@ -382,7 +258,7 @@ fn score(candidate: &SequenceExpr) -> usize { } } - for clean in clean() { + for clean in clean { let doc = Document::new_plain_english_curated(&clean); if candidate.iter_matches_in_doc(&doc).count() == 0 { @@ -391,4 +267,4 @@ fn score(candidate: &SequenceExpr) -> usize { } correct -} +} \ No newline at end of file From f9c1a958a42589d5af4af12582e205baf2910ff6 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Tue, 12 Aug 2025 12:17:56 -0600 Subject: [PATCH 05/28] feat: make generations configurable --- problems.txt | 41 ++++++++++++++++++++++++++++++++++++++++- src/main.rs | 6 +++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/problems.txt b/problems.txt index 9b3ab6801..76d213cdf 100644 --- a/problems.txt +++ b/problems.txt @@ -37,4 +37,43 @@ Route the packet too the primary gateway. This needs to adhere too the spec. According too our records, your payment cleared. Due too network congestion, the upload stalled. -We intend too deprecate this endpoint. \ No newline at end of file +We intend too deprecate this endpoint. +We struggled too reconcile the budget. +Make sure too water the plants before leaving. +The request failed too return any results. +I stayed late too finish the presentation. +They hesitated too escalate the issue. +This feature allows you too override defaults. +Be sure too back up your data. +The board voted too delay the launch. +I forgot too renew the subscription. +They invited us too join the pilot program. +We worked overtime too meet the deadline. +Don't forget too update the changelog. +She intends too publish her findings. +I started too refactor the legacy code. +We need too coordinate with the vendor. +The script failed too execute properly. +Take time too review the proposal. +He decided too withdraw from the project. +I paused too consider the implications. +They chose too merge the branches. +Remember too submit your timesheet. +The system began too slow down under load. +She offered too host the meeting. +Please remember too clear the cache. +We attempted too reproduce the error. +I logged in too check the status. +They are preparing too scale the service. +He volunteered too take on the extra work. +We stopped too admire the scenery. +Be careful not too overwrite existing files. +The committee resolved too adopt the policy. +It's best too follow the documented steps. +I waited too see if the alert would trigger. +She learned too troubleshoot the issue. +They forgot too enable the firewall. +We opted too archive the old records. +It's important too clarify the scope. +Use the wizard too configure the settings. +I need too verify the checksum. diff --git a/src/main.rs b/src/main.rs index f265d3556..5d7d32bf0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,10 @@ struct Args { /// A file containing newline-separated sentences that should not be flagged #[arg(long)] clean_file: String, + + /// The number of generations to run + #[arg(short, long)] + generations: usize, } fn main() { @@ -46,7 +50,7 @@ fn main() { seq: vec![MirrorAtom::AllowedWords(vec!["too".to_string()])], }]; - for i in 0..200 { + for _i in 0..args.generations { mirs.par_sort_by_cached_key(|s| { let score = score(&s.to_seq_expr(), &problems, &clean); usize::MAX - score From 4a53c17e915f99d82e63d0f4ae9381a1c440704d Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 14 Aug 2025 15:18:00 -0600 Subject: [PATCH 06/28] feat: replaced mutation functions --- Cargo.lock | 45 +++++++------ Cargo.toml | 5 +- src/main.rs | 173 ++------------------------------------------------ src/mirror.rs | 85 +++++++++++++++++++------ 4 files changed, 101 insertions(+), 207 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aeee3db68..01e2727a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] @@ -518,7 +518,7 @@ dependencies = [ "cached_proc_macro_types", "hashbrown 0.15.5", "once_cell", - "thiserror 2.0.12", + "thiserror 2.0.14", "web-time", ] @@ -1155,9 +1155,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", @@ -1880,7 +1880,9 @@ dependencies = [ [[package]] name = "harper-brill" -version = "0.56.0" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d74a75befdd0ded2ef9c45ecb0b6050ba1b317a8ac8003a06e4f75740c543233" dependencies = [ "harper-pos-utils", "lazy_static", @@ -1891,7 +1893,9 @@ dependencies = [ [[package]] name = "harper-core" -version = "0.56.0" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e8918b1400fc36699739ba5b9ce64a6e87f8755d9e249eb47e3c1f19da780c" dependencies = [ "ammonia", "bitflags 2.9.1", @@ -1914,7 +1918,7 @@ dependencies = [ "smallvec", "strum 0.27.2", "strum_macros 0.27.2", - "thiserror 2.0.12", + "thiserror 2.0.14", "unicode-blocks", "unicode-script", "unicode-width", @@ -1922,7 +1926,9 @@ dependencies = [ [[package]] name = "harper-pos-utils" -version = "0.56.0" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26043b4b3366b3db550f7b467a82ea08607628378787ae160baab0f4829def1a" dependencies = [ "burn", "burn-ndarray", @@ -2417,7 +2423,7 @@ dependencies = [ "rustc-hash", "spirv", "strum 0.26.3", - "thiserror 2.0.12", + "thiserror 2.0.14", "unicode-ident", ] @@ -3011,7 +3017,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.14", ] [[package]] @@ -3060,6 +3066,7 @@ dependencies = [ "rayon", "serde", "serde_json", + "smallvec", "strum 0.27.2", ] @@ -3438,11 +3445,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.14", ] [[package]] @@ -3458,9 +3465,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" dependencies = [ "proc-macro2", "quote", @@ -3873,7 +3880,7 @@ dependencies = [ "raw-window-handle", "rustc-hash", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.14", "wgpu-core-deps-apple", "wgpu-core-deps-emscripten", "wgpu-core-deps-windows-linux-android", @@ -3947,7 +3954,7 @@ dependencies = [ "raw-window-handle", "renderdoc-sys", "smallvec", - "thiserror 2.0.12", + "thiserror 2.0.14", "wasm-bindgen", "web-sys", "wgpu-types", @@ -3965,7 +3972,7 @@ dependencies = [ "bytemuck", "js-sys", "log", - "thiserror 2.0.12", + "thiserror 2.0.14", "web-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 43071d098..45d0809ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,11 @@ edition = "2024" [dependencies] clap = { version = "4.5.4", features = ["derive"] } -harper-brill = { version = "0.56.0", path = "../harper/harper-brill" } -harper-core = { version = "0.56.0", path = "../harper/harper-core" } +harper-brill = "0.57.0" +harper-core = "0.57.0" rand = "0.9.2" rayon = "1.10.0" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.142" +smallvec = "1.15.1" strum = "0.27.2" diff --git a/src/main.rs b/src/main.rs index 5d7d32bf0..b5be13b4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,10 +44,8 @@ fn main() { let problems = load_sentences(&args.problem_file); let clean = load_sentences(&args.clean_file); - let dict = FstDictionary::curated(); - let mut mirs = vec![Mirror { - seq: vec![MirrorAtom::AllowedWords(vec!["too".to_string()])], + seq: vec![MirrorAtom::Word("too".to_string())], }]; for _i in 0..args.generations { @@ -56,7 +54,7 @@ fn main() { usize::MAX - score }); - for i in 0..3.min(mirs.len()) { + for i in 0..4.min(mirs.len()) { dbg!( &mirs[i], score(&mirs[i].to_seq_expr(), &problems, &clean), @@ -69,7 +67,9 @@ fn main() { let mut perm_mirs = Vec::new(); for mir in &mirs { - perm_mirs.append(&mut permute_mirror_unique(mir, args.child_ratio, &dict)); + perm_mirs.append( + &mut mir.create_children_with_mutations(args.child_ratio, &mut rand::rng()), + ); } mirs.append(&mut perm_mirs); @@ -77,167 +77,6 @@ fn main() { } } -fn build_word_pool(dict: Option<&D>, rng: &mut impl Rng) -> Vec { - match dict { - Some(d) => { - let cap = d.word_count().min(5_000); - let mut pool = Vec::with_capacity(cap); - for w in d.words_iter().take(cap) { - let s: String = w.iter().collect(); - if !s.chars().any(|c| c.is_whitespace()) { - pool.push(s); - } - } - pool.shuffle(rng); - if pool.is_empty() { - fallback_words() - } else { - pool - } - } - None => fallback_words(), - } -} - -fn choose_words(pool: &[String], k: usize, rng: &mut impl Rng) -> Vec { - if pool.is_empty() { - return fallback_words() - .choose_multiple(rng, k) - .cloned() - .map(|s| s.to_string()) - .collect(); - } - pool.choose_multiple(rng, k).cloned().collect() -} - -fn fallback_words() -> Vec { - [ - "alpha", "brisk", "candle", "delta", "ember", "flora", "glyph", "harbor", "ionic", - "juniper", "keystone", "lumen", "modest", "nylon", "opal", "quartz", "rivet", "spruce", - "topaz", "umber", "vivid", "willow", "xenon", "yonder", "zephyr", - ] - .iter() - .map(|s| s.to_string()) - .collect() -} - -pub fn permute_mirror_unique(base: &Mirror, n: usize, dict: &D) -> Vec { - let mut rng = rand::thread_rng(); - let word_pool = build_word_pool(Some(dict), &mut rng); - - let mut out = Vec::with_capacity(n); - - let mut attempts = 0usize; - while out.len() < n && attempts < n * 80 { - attempts += 1; - - let mut m = Mirror { - seq: base.seq.clone(), - }; - if rng.gen_bool(0.35) { - m.seq.push(random_non_ws_atom(&word_pool, &mut rng)); - } else { - apply_random_edit(&mut m, &word_pool, &mut rng); - } - - if rng.gen_bool(0.80) { - m.seq.push(MirrorAtom::Whitespace); - } - - out.push(m); - } - - out -} - -fn apply_random_edit(m: &mut Mirror, pool: &[String], rng: &mut impl Rng) { - for _ in 0..6 { - let i = rng.gen_range(0..m.seq.len()); - match &mut m.seq[i] { - MirrorAtom::AllowedWords(words) => { - if rng.gen_bool(0.65) { - *words = distinct_words(pool, words.len(), rng, Some(words)); - } else { - m.seq[i] = flip_from_words(words.len(), pool, rng); - } - } - MirrorAtom::DisallowedWords(words) => { - if rng.gen_bool(0.65) { - *words = distinct_words(pool, words.len(), rng, Some(words)); - } else { - m.seq[i] = flip_from_words(words.len(), pool, rng); - } - } - MirrorAtom::UPOS(_) => { - if rng.gen_bool(0.65) { - m.seq[i] = MirrorAtom::UPOS(random_upos_set(rng)); - } else { - m.seq[i] = flip_from_upos(pool, rng); - } - } - MirrorAtom::Whitespace => { - m.seq[i] = if rng.gen_bool(0.55) { - random_non_ws_atom(pool, rng) - } else { - MirrorAtom::UPOS(random_upos_set(rng)) - }; - } - } - } -} - -fn flip_from_words(len: usize, pool: &[String], rng: &mut impl Rng) -> MirrorAtom { - match rng.gen_range(0..=2) { - 0 => MirrorAtom::DisallowedWords(distinct_words(pool, len.max(1), rng, None)), - 1 => MirrorAtom::UPOS(random_upos_set(rng)), - _ => MirrorAtom::Whitespace, - } -} - -fn flip_from_upos(pool: &[String], rng: &mut impl Rng) -> MirrorAtom { - match rng.gen_range(0..=2) { - 0 => MirrorAtom::AllowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), - 1 => MirrorAtom::DisallowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), - _ => MirrorAtom::Whitespace, - } -} - -fn random_non_ws_atom(pool: &[String], rng: &mut impl Rng) -> MirrorAtom { - match rng.gen_range(0..=2) { - 0 => MirrorAtom::AllowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), - 1 => MirrorAtom::DisallowedWords(distinct_words(pool, rng.gen_range(1..=3), rng, None)), - _ => MirrorAtom::UPOS(random_upos_set(rng)), - } -} - -fn random_upos_set(rng: &mut impl Rng) -> UPOSSet { - let v = UPOS::iter().collect::>(); - let k = rng.gen_range(1..v.len()); - let mut v: Vec = v.choose_multiple(rng, k).cloned().collect(); - v.sort_unstable(); - UPOSSet::new(&v) -} - -fn distinct_words( - pool: &[String], - k: usize, - rng: &mut impl Rng, - avoid: Option<&Vec>, -) -> Vec { - let mut out: Vec = pool.choose_multiple(rng, k.max(1)).cloned().collect(); - out.sort_unstable(); - out.dedup(); - if let Some(orig) = avoid { - let mut a = orig.clone(); - a.sort_unstable(); - a.dedup(); - if a == out { - return distinct_words(pool, k, rng, avoid); - } - } - out -} - fn load_sentences(path: &str) -> Vec { fs::read_to_string(path) .expect("Unable to read file") @@ -271,4 +110,4 @@ fn score(candidate: &SequenceExpr, problems: &[String], clean: &[String]) -> usi } correct -} \ No newline at end of file +} diff --git a/src/mirror.rs b/src/mirror.rs index 500240ab1..cb0447008 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -1,6 +1,12 @@ +use harper_brill::UPOS; use harper_core::expr::SequenceExpr; -use harper_core::patterns::{UPOSSet, WordSet}; +use harper_core::patterns::{UPOSSet, Word, WordSet}; +use harper_core::spell::Dictionary; +use rand::seq::{IndexedRandom, SliceRandom}; +use rand::{Rng, random_bool}; use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use strum::IntoEnumIterator; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Mirror { @@ -9,9 +15,8 @@ pub struct Mirror { #[derive(Debug, Serialize, Deserialize, Clone)] pub enum MirrorAtom { - AllowedWords(Vec), - DisallowedWords(Vec), - UPOS(UPOSSet), + Word(String), + UPOS(SmallVec<[UPOS; 16]>), Whitespace, } @@ -20,29 +25,71 @@ impl Mirror { let mut seq = SequenceExpr::default(); for atom in &self.seq { match atom { - MirrorAtom::AllowedWords(items) => { + MirrorAtom::UPOS(uposset) => seq = seq.then(UPOSSet::new(&uposset)), + MirrorAtom::Whitespace => seq = seq.t_ws(), + MirrorAtom::Word(word) => { let mut set = WordSet::default(); - - for item in items { - set.add(&item); - } + set.add_chars(&word.chars().collect::>()); seq = seq.then(set) } - MirrorAtom::DisallowedWords(items) => { - let mut set = WordSet::default(); + }; + } + + seq + } + + /// Creates children with random mutations. + pub fn create_children_with_mutations( + &self, + child_count: usize, + rng: &mut impl Rng, + ) -> Vec { + let mut children = Vec::with_capacity(child_count); + + for _ in 0..child_count { + let mut child = self.clone(); + child.mutate(rng); + children.push(child); + } - for item in items { - set.add(&item); - } + children + } + + pub fn mutate(&mut self, rng: &mut impl Rng) { + if !self.seq.is_empty() && rng.random_bool(0.5) { + let i = rng.random_range(0..self.seq.len()); + let step = &mut self.seq[i]; + Self::mutate_step(step, rng); + } else { + let i = rng.random_range(0..self.seq.len()); + self.seq.insert(i, Self::create_random_step(rng)); + } + } - seq = seq.then_unless(set) + fn mutate_step(atom: &mut MirrorAtom, rng: &mut impl Rng) { + match atom { + MirrorAtom::UPOS(uposset) => { + if !uposset.is_empty() && rng.random_bool(0.5) { + uposset.remove(rng.random_range(0..uposset.len())); } - MirrorAtom::UPOS(uposset) => seq = seq.then(uposset.clone()), - MirrorAtom::Whitespace => seq = seq.t_ws(), - }; + + if rng.random_bool(0.5) { + uposset.push(UPOS::iter().nth(rng.random_range(0..16)).unwrap()); + } + } + _ => (), } + } - seq + fn create_random_step(rng: &mut impl Rng) -> MirrorAtom { + if random_bool(0.5) { + let mut all_upos: SmallVec<[UPOS; 16]> = UPOS::iter().collect(); + all_upos.shuffle(rng); + all_upos.truncate(rng.random_range(0..all_upos.len())); + MirrorAtom::UPOS(all_upos) + } else { + MirrorAtom::Whitespace + } } } From fcecbbb62d2fad9c345de5bd4b8a020b1f9c27f1 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 14 Aug 2025 15:33:46 -0600 Subject: [PATCH 07/28] feat: move Document construction out of the loop --- Cargo.toml | 2 +- src/main.rs | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 45d0809ba..8f5f05ed8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] clap = { version = "4.5.4", features = ["derive"] } harper-brill = "0.57.0" -harper-core = "0.57.0" +harper-core = { version = "0.57.0", features = ["concurrent"] } rand = "0.9.2" rayon = "1.10.0" serde = { version = "1.0.219", features = ["derive"] } diff --git a/src/main.rs b/src/main.rs index b5be13b4c..7b43f2d80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,8 +41,8 @@ struct Args { fn main() { let args = Args::parse(); - let problems = load_sentences(&args.problem_file); - let clean = load_sentences(&args.clean_file); + let problems = load_documents(&args.problem_file); + let clean = load_documents(&args.clean_file); let mut mirs = vec![Mirror { seq: vec![MirrorAtom::Word("too".to_string())], @@ -77,24 +77,22 @@ fn main() { } } -fn load_sentences(path: &str) -> Vec { +fn load_documents(path: &str) -> Vec { fs::read_to_string(path) .expect("Unable to read file") .lines() - .map(|s| s.to_string()) + .map(|s| Document::new_plain_english_curated(s)) .collect() } -fn score(candidate: &SequenceExpr, problems: &[String], clean: &[String]) -> usize { +fn score(candidate: &SequenceExpr, problems: &[Document], clean: &[Document]) -> usize { let mut correct = 0; let mut matches = Vec::new(); for problem in problems { - let doc = Document::new_plain_english_curated(&problem); - matches.clear(); - matches.extend(candidate.iter_matches_in_doc(&doc)); + matches.extend(candidate.iter_matches_in_doc(problem)); if matches.len() == 1 { correct += 1; @@ -102,9 +100,7 @@ fn score(candidate: &SequenceExpr, problems: &[String], clean: &[String]) -> usi } for clean in clean { - let doc = Document::new_plain_english_curated(&clean); - - if candidate.iter_matches_in_doc(&doc).count() == 0 { + if candidate.iter_matches_in_doc(clean).count() == 0 { correct += 1; } } From b69a9339850b73c8ac9765868d3b063cbe8844e2 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 14 Aug 2025 15:46:18 -0600 Subject: [PATCH 08/28] feat: allow variable mutation count --- src/main.rs | 14 ++++++++++---- src/mirror.rs | 8 +++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7b43f2d80..519230209 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,10 @@ struct Args { /// The number of generations to run #[arg(short, long)] generations: usize, + + /// The maximum number of mutations to apply to a child + #[arg(long, default_value_t = 5)] + max_mutations: usize, } fn main() { @@ -67,9 +71,11 @@ fn main() { let mut perm_mirs = Vec::new(); for mir in &mirs { - perm_mirs.append( - &mut mir.create_children_with_mutations(args.child_ratio, &mut rand::rng()), - ); + perm_mirs.append(&mut mir.create_children_with_mutations( + args.child_ratio, + args.max_mutations, + &mut rand::thread_rng(), + )); } mirs.append(&mut perm_mirs); @@ -79,7 +85,7 @@ fn main() { fn load_documents(path: &str) -> Vec { fs::read_to_string(path) - .expect("Unable to read file") + .expect("Unable to read file.") .lines() .map(|s| Document::new_plain_english_curated(s)) .collect() diff --git a/src/mirror.rs b/src/mirror.rs index cb0447008..a7fb6c681 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -43,13 +43,19 @@ impl Mirror { pub fn create_children_with_mutations( &self, child_count: usize, + max_mutations: usize, rng: &mut impl Rng, ) -> Vec { let mut children = Vec::with_capacity(child_count); for _ in 0..child_count { let mut child = self.clone(); - child.mutate(rng); + let mutation_count = rng.gen_range(1..=max_mutations); + + for _ in 0..mutation_count { + child.mutate(rng); + } + children.push(child); } From 2a22a2829bbd1ba7d0c66268b912a173b42b9672 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 18 Aug 2025 09:45:05 -0600 Subject: [PATCH 09/28] feat: favor simpler patterns --- clean.txt | 3 ++- src/main.rs | 63 +++++++++++++++++++++++++++++++++++++++------------ src/mirror.rs | 2 +- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/clean.txt b/clean.txt index 0be890557..6de172bca 100644 --- a/clean.txt +++ b/clean.txt @@ -90,4 +90,5 @@ They felt buried under the data, unable to proactively address emerging threats. Familiarize yourself with these resources to learn how to effectively utilize the plugin’s features. It takes a great deal of energy to consistently operate under that kind of pressure. Just be prepared to occasionally troubleshoot the debugger itself. -He goes too far with bets. \ No newline at end of file +He goes too far with bets. +In Mediterranean and Middle Eastern dishes, yoghurt often accompanies savoury meals, acting as a refreshing complement to spicy flavours. diff --git a/src/main.rs b/src/main.rs index 519230209..19ceaaab6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,15 +54,15 @@ fn main() { for _i in 0..args.generations { mirs.par_sort_by_cached_key(|s| { - let score = score(&s.to_seq_expr(), &problems, &clean); + let score = score(&s, &problems, &clean); usize::MAX - score }); - for i in 0..4.min(mirs.len()) { + for i in 0..1.min(mirs.len()) { dbg!( &mirs[i], - score(&mirs[i].to_seq_expr(), &problems, &clean), - problems.len() + clean.len() + score(&mirs[i], &problems, &clean), + max_possible_score(&problems, &clean), ); } @@ -91,25 +91,60 @@ fn load_documents(path: &str) -> Vec { .collect() } -fn score(candidate: &SequenceExpr, problems: &[Document], clean: &[Document]) -> usize { - let mut correct = 0; +// Treat correctness as the dominant term and use simplicity as a tiebreaker. +// "Simpler" = fewer non-whitespace atoms and smaller UPOS sets. +fn mirror_complexity(m: &Mirror) -> usize { + use MirrorAtom::*; + let mut cost = 0usize; + + for atom in &m.seq { + match atom { + Whitespace => {} // free + Word(_w) => { + cost += 1; + } + UPOS(set) => { + cost += set.len().max(1); + } + } + } + + cost +} - let mut matches = Vec::new(); +fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize { + let seq = candidate.to_seq_expr(); - for problem in problems { - matches.clear(); - matches.extend(candidate.iter_matches_in_doc(problem)); + let mut correct = 0usize; - if matches.len() == 1 { + for problem in problems { + if seq.iter_matches_in_doc(problem).count() == 1 { correct += 1; } } for clean in clean { - if candidate.iter_matches_in_doc(clean).count() == 0 { - correct += 1; + if seq.iter_matches_in_doc(clean).count() == 0 { + correct += 100; } } - correct + const TIE_SCALE: usize = 1_000; + let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); + + correct.saturating_mul(TIE_SCALE) + simplicity_bonus +} + +pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { + const TIE_SCALE: usize = 1_000; + let per_problem = 1usize; + let per_clean = 100usize; + + let correctness = per_problem + .saturating_mul(problems.len()) + .saturating_add(per_clean.saturating_mul(clean.len())); + + correctness + .saturating_mul(TIE_SCALE) + .saturating_add(TIE_SCALE) } diff --git a/src/mirror.rs b/src/mirror.rs index a7fb6c681..763090e67 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -68,7 +68,7 @@ impl Mirror { let step = &mut self.seq[i]; Self::mutate_step(step, rng); } else { - let i = rng.random_range(0..self.seq.len()); + let i = rng.random_range(0..=self.seq.len()); self.seq.insert(i, Self::create_random_step(rng)); } } From 0c65c821c21629d6da753d11e8d6a67cddf93deb Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 18 Aug 2025 09:46:48 -0600 Subject: [PATCH 10/28] fix: make simplicity less valuable --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 19ceaaab6..3db18b9de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,14 +129,14 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize } } - const TIE_SCALE: usize = 1_000; + const TIE_SCALE: usize = 500; let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); correct.saturating_mul(TIE_SCALE) + simplicity_bonus } pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { - const TIE_SCALE: usize = 1_000; + const TIE_SCALE: usize = 500; let per_problem = 1usize; let per_clean = 100usize; From c38c0c2245c2aadfa4862165b977a8399fa2a4dd Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 18 Aug 2025 13:38:46 -0600 Subject: [PATCH 11/28] feat: change target --- clean.txt | 113 +++++++++++++++------------------------------- problems.txt | 123 ++++++++++++++++++--------------------------------- src/main.rs | 9 ++-- 3 files changed, 83 insertions(+), 162 deletions(-) diff --git a/clean.txt b/clean.txt index 6de172bca..2b826ccfc 100644 --- a/clean.txt +++ b/clean.txt @@ -1,70 +1,34 @@ -I need to finish this report before noon. -She went to the grocery store after work. -We decided to postpone the meeting. -He forgot to send the invitation. -Remember to lock the door. -They plan to travel next spring. -I tried to explain the discrepancy. -Please add this file to the repository. -He refused to apologize for the oversight. -I'm happy to help with debugging. -Set the thermostat back to sixty-eight at night. -We need to align our objectives. -She learned how to solder the components. -The CEO chose to prioritize profitability. -Use the adapter to connect the cable. -He ran from end to end of the field. -It's critical to verify each assumption. -Attach the label to the container. -I meant to forward you the email. -They drove to Denver before sunrise. -Tap here to continue. -I neglected to charge the laptop. -We hope to avoid scope creep. -Click 'Build' to compile the project. -The change needs to propagate across services. -I'm going to grab lunch. -She agreed to mentor the interns. -He promised to follow up tomorrow. -Use this form to request access. -I prefer to work asynchronously. -The team aims to reduce latency. -Press Esc to cancel. -Switch lanes from left to right safely. -We're moving from draft to production. -I waited an hour just to speak with support. -Route the packet to the primary gateway. -This needs to adhere to the spec. -According to our records, your payment cleared. -Due to network congestion, the upload stalled. -We intend to deprecate this endpoint. -It was far too late to salvage the schedule. -The espresso tasted too bitter for my palate. -She is joining the expedition too, despite the warnings. -Your proposal is too vague for the board. -The server grew too hot under sustained load. -He spoke too quickly to be understood. -I found the contract too onerous to sign. -They arrived too early and waited in silence. -This dataset is too noisy for reliable inference. -The film was too long yet strangely compelling. -The cliff looked too sheer for novice climbers. -Her apology felt too rehearsed to be sincere. -That price is too steep for a prototype. -He ate too much and regretted it. -The room grew too quiet to ignore. -Your tone is too abrasive for diplomacy. -The deadline is too tight for thorough testing. -She laughed too hard at the misprint. -The instructions are too convoluted for speed. -I, too, questioned the methodology. -He goes too far with bets. -Just be prepared to occasionally troubleshoot the debugger itself. -It takes a great deal of energy to consistently operate under that kind of pressure. +I ate way too much pizza last night. +She runs too fast for me to catch up. +This shirt is too big for me. +He was too tired to continue. +The movie was too long and boring. +It’s too hot outside to go for a walk. +They were talking too loudly in the library. +This problem is too complicated for beginners. +She’s too busy to answer her phone. +The bag is too heavy for me to lift. +I want to go shopping, but it's too late now. +She was too tired to finish her homework. +The soup is too hot to eat right now. +You're standing too close to the fire. +He runs too fast for me to keep up. +That joke was too funny to ignore. +The music is too loud in this room. +She was dressed too nicely for the occasion. +It's too bad you missed the concert. +He’s too young to drive a car. +The bag is too heavy for me to carry. +You’re talking too much during the movie. +It’s too cold outside for a picnic. +He was driving too quickly down the street. +She’s too busy to answer the phone right now. +The cake is too sweet for my taste. +I ate too many cookies after dinner. +That shirt is too small for you. +You’re being too hard on yourself. +The movie was too long and boring. I am too hungry. -Please remember to eat your vegetables. -I’m going to Nashville next week. -Talk to you later. The coffee is too hot to drink. The music was too loud, making it hard to hear. He's too shy to speak in public. @@ -74,21 +38,14 @@ She worked too hard and ended up getting sick. The instructions were too complicated to understand. I like apples, and my brother does too. She's coming to the party, and he is too. -I want to go to the beach, and you do too?. +I want to go to the beach, and you do too? He's a talented musician, and a great friend too. The movie was good, and the popcorn was delicious too. The problem is too difficult, and the deadline is too close. He's too good at the game, and he's too nice to win. -Bringing Hope and Opportunity to Young Musicians -Attendees can look forward to: -We're empowering them to build brighter futures. -I’d like you to consciously delegate one task -Soundscapes are not merely environmental features; they are integral to human identity and cultural expression. -Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. -Attempted to explicitly cast the result back to a string -They felt buried under the data, unable to proactively address emerging threats. -Familiarize yourself with these resources to learn how to effectively utilize the plugin’s features. -It takes a great deal of energy to consistently operate under that kind of pressure. Just be prepared to occasionally troubleshoot the debugger itself. +You're 7 years too late +The project scope is too ambitious He goes too far with bets. -In Mediterranean and Middle Eastern dishes, yoghurt often accompanies savoury meals, acting as a refreshing complement to spicy flavours. +Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. +It's not too easy, is it? diff --git a/problems.txt b/problems.txt index 76d213cdf..850c62716 100644 --- a/problems.txt +++ b/problems.txt @@ -1,79 +1,44 @@ -I need too finish this report before noon. -She went too the grocery store after work. -We decided too postpone the meeting. -He forgot too send the invitation. -Remember too lock the door. -They plan too travel next spring. -I tried too explain the discrepancy. -Please add this file too the repository. -He refused too apologize for the oversight. -I'm happy too help with debugging. -Set the thermostat back too sixty-eight at night. -We need too align our objectives. -She learned how too solder the components. -The CEO chose too prioritize profitability. -Use the adapter too connect the cable. -He ran from end too end of the field. -It's critical too verify each assumption. -Attach the label too the container. -I meant too forward you the email. -They drove too Denver before sunrise. -Tap here too continue. -I neglected too charge the laptop. -We hope too avoid scope creep. -Click 'Build' too compile the project. -The change needs too propagate across services. -I'm going too grab lunch. -She agreed too mentor the interns. -He promised too follow up tomorrow. -Use this form too request access. -I prefer too work asynchronously. -The team aims too reduce latency. -Press Esc too cancel. -Switch lanes from left too right safely. -We're moving from draft too production. -I waited an hour just too speak with support. -Route the packet too the primary gateway. -This needs to adhere too the spec. -According too our records, your payment cleared. -Due too network congestion, the upload stalled. -We intend too deprecate this endpoint. -We struggled too reconcile the budget. -Make sure too water the plants before leaving. -The request failed too return any results. -I stayed late too finish the presentation. -They hesitated too escalate the issue. -This feature allows you too override defaults. -Be sure too back up your data. -The board voted too delay the launch. -I forgot too renew the subscription. -They invited us too join the pilot program. -We worked overtime too meet the deadline. -Don't forget too update the changelog. -She intends too publish her findings. -I started too refactor the legacy code. -We need too coordinate with the vendor. -The script failed too execute properly. -Take time too review the proposal. -He decided too withdraw from the project. -I paused too consider the implications. -They chose too merge the branches. -Remember too submit your timesheet. -The system began too slow down under load. -She offered too host the meeting. -Please remember too clear the cache. -We attempted too reproduce the error. -I logged in too check the status. -They are preparing too scale the service. -He volunteered too take on the extra work. -We stopped too admire the scenery. -Be careful not too overwrite existing files. -The committee resolved too adopt the policy. -It's best too follow the documented steps. -I waited too see if the alert would trigger. -She learned too troubleshoot the issue. -They forgot too enable the firewall. -We opted too archive the old records. -It's important too clarify the scope. -Use the wizard too configure the settings. -I need too verify the checksum. +I ate way to much pizza last night. +She runs to fast for me to catch up. +This shirt is to big for me. +He was to tired to continue. +The movie was to long and boring. +It’s to hot outside to go for a walk. +They were talking to loudly in the library. +This problem is to complicated for beginners. +She’s to busy to answer her phone. +The bag is to heavy for me to lift. +I want to go shopping, but it's to late now. +She was to tired to finish her homework. +The soup is to hot to eat right now. +You're standing to close to the fire. +He runs to fast for me to keep up. +That joke was to funny to ignore. +The music is to loud in this room. +She was dressed to nicely for the occasion. +It's to bad you missed the concert. +He’s to young to drive a car. +The bag is to heavy for me to carry. +You’re talking to much during the movie. +It’s to cold outside for a picnic. +He was driving to quickly down the street. +She’s to busy to answer the phone right now. +The cake is to sweet for my taste. +I ate to many cookies after dinner. +That shirt is to small for you. +You’re being to hard on yourself. +The movie was to long and boring. +She wanted to join us for dinner, but she was to nervous to ask if it was okay. +The kids were playing to roughly in the living room, and they almost broke the lamp. +I tried to stay awake during the lecture, but it was to boring for me to concentrate. +He wanted to buy the shoes, but they were to expensive for his budget at the time. +The dog barked to loudly last night, and none of us could get any sleep because of it. +She studied for hours, but she felt to tired to remember anything during the exam. +It was raining to heavily outside, so we decided to cancel our plans and stay home. +The directions were to confusing for anyone to understand clearly, so we got lost. +He laughed to hard at the joke, and everyone else in the café turned to look at him. +The sweater was to itchy for her to wear, even though it looked really nice. +You're 7 years to late +The project scope is to ambitious +He goes to far with bets. +It's not to easy, is it? diff --git a/src/main.rs b/src/main.rs index 3db18b9de..a467f10c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,9 @@ use harper_core::expr::{ExprExt, SequenceExpr}; use harper_core::patterns::UPOSSet; use harper_core::spell::{Dictionary, FstDictionary}; use rand::seq::IndexedRandom; -use rand::{Rng, seq::SliceRandom}; +use rand::seq::SliceRandom; use rayon::slice::ParallelSliceMut; use std::fs; -use strum::IntoEnumIterator; use self::mirror::{Mirror, MirrorAtom}; @@ -49,7 +48,7 @@ fn main() { let clean = load_documents(&args.clean_file); let mut mirs = vec![Mirror { - seq: vec![MirrorAtom::Word("too".to_string())], + seq: vec![MirrorAtom::Word("to".to_string())], }]; for _i in 0..args.generations { @@ -119,7 +118,7 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize for problem in problems { if seq.iter_matches_in_doc(problem).count() == 1 { - correct += 1; + correct += 50; } } @@ -137,7 +136,7 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { const TIE_SCALE: usize = 500; - let per_problem = 1usize; + let per_problem = 50usize; let per_clean = 100usize; let correctness = per_problem From 87411f547adb053e3b32b983272cccdf9fe94549 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 18 Aug 2025 14:20:54 -0600 Subject: [PATCH 12/28] feat: add layers --- Cargo.toml | 2 +- clean.txt | 2 + src/main.rs | 32 ++++++++----- src/mirror.rs | 130 +++++++++++++++++++++++++++++++++++++------------- 4 files changed, 120 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8f5f05ed8..47051a10a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" clap = { version = "4.5.4", features = ["derive"] } harper-brill = "0.57.0" harper-core = { version = "0.57.0", features = ["concurrent"] } -rand = "0.9.2" +rand = { version = "0.9.2", features = ["small_rng"] } rayon = "1.10.0" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.142" diff --git a/clean.txt b/clean.txt index 2b826ccfc..43ec19df1 100644 --- a/clean.txt +++ b/clean.txt @@ -49,3 +49,5 @@ The project scope is too ambitious He goes too far with bets. Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. It's not too easy, is it? +Soundscapes are not merely environmental features; they are integral to human identity and cultural expression. +Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. diff --git a/src/main.rs b/src/main.rs index a467f10c6..04463e0a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,10 +8,11 @@ use harper_core::patterns::UPOSSet; use harper_core::spell::{Dictionary, FstDictionary}; use rand::seq::IndexedRandom; use rand::seq::SliceRandom; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::slice::ParallelSliceMut; use std::fs; -use self::mirror::{Mirror, MirrorAtom}; +use self::mirror::{Mirror, MirrorAtom, MirrorLayer}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -48,7 +49,9 @@ fn main() { let clean = load_documents(&args.clean_file); let mut mirs = vec![Mirror { - seq: vec![MirrorAtom::Word("to".to_string())], + layers: vec![MirrorLayer { + seq: vec![MirrorAtom::Word("to".to_string())], + }], }]; for _i in 0..args.generations { @@ -78,6 +81,7 @@ fn main() { } mirs.append(&mut perm_mirs); + mirs.shuffle(&mut rand::rng()); } } @@ -96,14 +100,16 @@ fn mirror_complexity(m: &Mirror) -> usize { use MirrorAtom::*; let mut cost = 0usize; - for atom in &m.seq { - match atom { - Whitespace => {} // free - Word(_w) => { - cost += 1; - } - UPOS(set) => { - cost += set.len().max(1); + for layer in &m.layers { + for atom in &layer.seq { + match atom { + Whitespace => {} // free + Word(_w) => { + cost += 1; + } + UPOS(set) => { + cost += set.len().max(1); + } } } } @@ -112,18 +118,18 @@ fn mirror_complexity(m: &Mirror) -> usize { } fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize { - let seq = candidate.to_seq_expr(); + let expr = candidate.to_expr(); let mut correct = 0usize; for problem in problems { - if seq.iter_matches_in_doc(problem).count() == 1 { + if expr.iter_matches_in_doc(problem).count() == 1 { correct += 50; } } for clean in clean { - if seq.iter_matches_in_doc(clean).count() == 0 { + if expr.iter_matches_in_doc(clean).count() == 0 { correct += 100; } } diff --git a/src/mirror.rs b/src/mirror.rs index 763090e67..85465e719 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -1,7 +1,6 @@ use harper_brill::UPOS; -use harper_core::expr::SequenceExpr; -use harper_core::patterns::{UPOSSet, Word, WordSet}; -use harper_core::spell::Dictionary; +use harper_core::expr::{All, LongestMatchOf, SequenceExpr}; +use harper_core::patterns::{UPOSSet, WordSet}; use rand::seq::{IndexedRandom, SliceRandom}; use rand::{Rng, random_bool}; use serde::{Deserialize, Serialize}; @@ -10,6 +9,11 @@ use strum::IntoEnumIterator; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Mirror { + pub layers: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MirrorLayer { pub seq: Vec, } @@ -20,7 +24,7 @@ pub enum MirrorAtom { Whitespace, } -impl Mirror { +impl MirrorLayer { pub fn to_seq_expr(&self) -> SequenceExpr { let mut seq = SequenceExpr::default(); for atom in &self.seq { @@ -30,36 +34,11 @@ impl Mirror { MirrorAtom::Word(word) => { let mut set = WordSet::default(); set.add_chars(&word.chars().collect::>()); - seq = seq.then(set) } - }; - } - - seq - } - - /// Creates children with random mutations. - pub fn create_children_with_mutations( - &self, - child_count: usize, - max_mutations: usize, - rng: &mut impl Rng, - ) -> Vec { - let mut children = Vec::with_capacity(child_count); - - for _ in 0..child_count { - let mut child = self.clone(); - let mutation_count = rng.gen_range(1..=max_mutations); - - for _ in 0..mutation_count { - child.mutate(rng); } - - children.push(child); } - - children + seq } pub fn mutate(&mut self, rng: &mut impl Rng) { @@ -71,6 +50,11 @@ impl Mirror { let i = rng.random_range(0..=self.seq.len()); self.seq.insert(i, Self::create_random_step(rng)); } + + if !self.seq.is_empty() && rng.random_bool(0.1) { + let i = rng.random_range(0..self.seq.len()); + self.seq.remove(i); + } } fn mutate_step(atom: &mut MirrorAtom, rng: &mut impl Rng) { @@ -79,12 +63,19 @@ impl Mirror { if !uposset.is_empty() && rng.random_bool(0.5) { uposset.remove(rng.random_range(0..uposset.len())); } - if rng.random_bool(0.5) { uposset.push(UPOS::iter().nth(rng.random_range(0..16)).unwrap()); } } - _ => (), + MirrorAtom::Word(w) => { + if rng.random_bool(0.2) && !w.is_empty() { + let chars: Vec = w.chars().collect(); + let take = rng.random_range(1..=chars.len()); + let new_w: String = chars.into_iter().take(take).collect(); + *w = new_w; + } + } + MirrorAtom::Whitespace => {} } } @@ -94,8 +85,83 @@ impl Mirror { all_upos.shuffle(rng); all_upos.truncate(rng.random_range(0..all_upos.len())); MirrorAtom::UPOS(all_upos) + } else if random_bool(0.2) { + MirrorAtom::Word(String::from("the")) } else { MirrorAtom::Whitespace } } + + fn create_random_layer(rng: &mut impl Rng) -> Self { + let len = rng.random_range(1..=3); + let mut seq = Vec::with_capacity(len); + for _ in 0..len { + seq.push(Self::create_random_step(rng)); + } + Self { seq } + } +} + +impl Mirror { + pub fn to_expr(&self) -> All { + let mut all = All::default(); + for layer in &self.layers { + all.add(layer.to_seq_expr()); + } + all + } + + pub fn create_children_with_mutations( + &self, + child_count: usize, + max_mutations: usize, + rng: &mut impl Rng, + ) -> Vec { + let mut children = Vec::with_capacity(child_count); + for _ in 0..child_count { + let mut child = self.clone(); + let mutation_count = rng.gen_range(1..=max_mutations); + for _ in 0..mutation_count { + child.mutate(rng); + } + children.push(child); + } + children + } + + pub fn mutate(&mut self, rng: &mut impl Rng) { + if self.layers.is_empty() || rng.random_bool(0.2) { + let i = rng.random_range(0..=self.layers.len()); + self.layers.insert(i, MirrorLayer::create_random_layer(rng)); + return; + } + + if rng.random_bool(0.1) && !self.layers.is_empty() { + let i = rng.random_range(0..self.layers.len()); + self.layers.remove(i); + return; + } + + if rng.random_bool(0.1) && self.layers.len() >= 2 { + self.layers.shuffle(rng); + return; + } + + let i = rng.random_range(0..self.layers.len()); + let layer = &mut self.layers[i]; + + if rng.random_bool(0.6) { + layer.mutate(rng); + } else { + if rng.random_bool(0.5) { + let insert_at = rng.random_range(0..=layer.seq.len()); + layer + .seq + .insert(insert_at, MirrorLayer::create_random_step(rng)); + } else if !layer.seq.is_empty() { + let remove_at = rng.random_range(0..layer.seq.len()); + layer.seq.remove(remove_at); + } + } + } } From 873998f3f26fb7bb0b76e075b4333c8c443e8688 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 18 Aug 2025 15:42:24 -0600 Subject: [PATCH 13/28] feat: improve scoring and reporting --- src/main.rs | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 04463e0a9..5a1b8183f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,20 +54,36 @@ fn main() { }], }]; - for _i in 0..args.generations { + let mut last_best_score = 0; + + for i in 0..args.generations { mirs.par_sort_by_cached_key(|s| { let score = score(&s, &problems, &clean); usize::MAX - score }); - for i in 0..1.min(mirs.len()) { - dbg!( - &mirs[i], - score(&mirs[i], &problems, &clean), - max_possible_score(&problems, &clean), - ); + let best_score = if let Some(best_mir) = mirs.first() { + score(best_mir, &problems, &clean) + } else { + 0 + }; + + let delta = best_score as i64 - last_best_score as i64; + + println!( + "Generation {:<4} | Best Score: {:<10} | Max Score: {:<10} | Delta: {:<+10}", + i, + best_score, + max_possible_score(&problems, &clean), + delta + ); + + if let Some(best_mir) = mirs.first() { + println!("Best mirror: {:#?}", best_mir); } + last_best_score = best_score; + mirs.truncate(args.min_pop); let mut perm_mirs = Vec::new(); @@ -82,7 +98,7 @@ fn main() { mirs.append(&mut perm_mirs); - mirs.shuffle(&mut rand::rng()); + mirs.shuffle(&mut rand::thread_rng()); } } @@ -134,14 +150,14 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize } } - const TIE_SCALE: usize = 500; + const TIE_SCALE: usize = 25; let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); correct.saturating_mul(TIE_SCALE) + simplicity_bonus } pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { - const TIE_SCALE: usize = 500; + const TIE_SCALE: usize = 25; let per_problem = 50usize; let per_clean = 100usize; From 301258503c0c06dc370e0b97177b149acdfa9d0a Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Tue, 19 Aug 2025 09:54:21 -0600 Subject: [PATCH 14/28] feat: optimize and report speed --- Cargo.toml | 7 +++++++ src/main.rs | 10 ++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 47051a10a..c12ea366d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,10 @@ serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.142" smallvec = "1.15.1" strum = "0.27.2" + +[profile.release] +opt-level = 3 +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = true diff --git a/src/main.rs b/src/main.rs index 5a1b8183f..d5b30a8c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use rand::seq::SliceRandom; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::slice::ParallelSliceMut; use std::fs; +use std::time::Instant; use self::mirror::{Mirror, MirrorAtom, MirrorLayer}; @@ -57,6 +58,8 @@ fn main() { let mut last_best_score = 0; for i in 0..args.generations { + let start_time = Instant::now(); + mirs.par_sort_by_cached_key(|s| { let score = score(&s, &problems, &clean); usize::MAX - score @@ -69,13 +72,16 @@ fn main() { }; let delta = best_score as i64 - last_best_score as i64; + let elapsed = start_time.elapsed(); + let candidates_per_second = (mirs.len() as f64 / elapsed.as_secs_f64()) as usize; println!( - "Generation {:<4} | Best Score: {:<10} | Max Score: {:<10} | Delta: {:<+10}", + "Generation {:<4} | Best Score: {:<10} | Max Score: {:<10} | Delta: {:<+10} | Candidates/sec: {:<10}", i, best_score, max_possible_score(&problems, &clean), - delta + delta, + candidates_per_second ); if let Some(best_mir) = mirs.first() { From 03edbf70ec0ec2391361740dc46e2a73a559e8f4 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Tue, 19 Aug 2025 10:08:26 -0600 Subject: [PATCH 15/28] feat: make core-count configurable --- src/main.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main.rs b/src/main.rs index d5b30a8c5..2c53ac5cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,11 +41,23 @@ struct Args { /// The maximum number of mutations to apply to a child #[arg(long, default_value_t = 5)] max_mutations: usize, + + /// The number of jobs (threads) to use for parallel processing. + /// If not specified, Rayon will use the default number of threads. + #[arg(short, long)] + jobs: Option, } fn main() { let args = Args::parse(); + if let Some(jobs) = args.jobs { + rayon::ThreadPoolBuilder::new() + .num_threads(jobs) + .build_global() + .unwrap(); + } + let problems = load_documents(&args.problem_file); let clean = load_documents(&args.clean_file); From 6caffc635c8be44d69a69472e101d60240bbea54 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Tue, 19 Aug 2025 13:36:01 -0600 Subject: [PATCH 16/28] fix: more logical ordering --- src/main.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2c53ac5cb..06625c881 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,6 +72,22 @@ fn main() { for i in 0..args.generations { let start_time = Instant::now(); + mirs.truncate(args.min_pop); + + let mut perm_mirs = Vec::new(); + + for mir in &mirs { + perm_mirs.append(&mut mir.create_children_with_mutations( + args.child_ratio, + args.max_mutations, + &mut rand::thread_rng(), + )); + } + + mirs.append(&mut perm_mirs); + + mirs.shuffle(&mut rand::thread_rng()); + mirs.par_sort_by_cached_key(|s| { let score = score(&s, &problems, &clean); usize::MAX - score @@ -101,22 +117,6 @@ fn main() { } last_best_score = best_score; - - mirs.truncate(args.min_pop); - - let mut perm_mirs = Vec::new(); - - for mir in &mirs { - perm_mirs.append(&mut mir.create_children_with_mutations( - args.child_ratio, - args.max_mutations, - &mut rand::thread_rng(), - )); - } - - mirs.append(&mut perm_mirs); - - mirs.shuffle(&mut rand::thread_rng()); } } From 543171532e54a98989c25cff084d9e55a2e33418 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Tue, 19 Aug 2025 15:57:16 -0600 Subject: [PATCH 17/28] tree --- problems.txt | 33 +++++++++ src/main.rs | 53 ++++++++------- src/mirror.rs | 185 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 212 insertions(+), 59 deletions(-) diff --git a/problems.txt b/problems.txt index 850c62716..ef178fde5 100644 --- a/problems.txt +++ b/problems.txt @@ -42,3 +42,36 @@ You're 7 years to late The project scope is to ambitious He goes to far with bets. It's not to easy, is it? +She was to late. +The bag is to heavy. +He runs to fast. +That coffee is to hot. +The dress is to small. +They are to busy. +The noise is to loud. +The shoes are to tight. +This movie is to boring. +The test was to hard. +It feels to cold. +The dog is to big. +You speak to quickly. +She eats to much. +The room is to dark. +The car is to slow. +He drives to recklessly. +The hill is to steep. +The water is to deep. +That song is to sad. +The box is to heavy. +She works to hard. +He talks to loudly. +The game is to easy. +This bread is to stale. +The kids are to noisy. +Her dress is to long. +The road is to narrow. +That joke was to mean. +The apple is to sour. +It's not to easy, is it? +You're 7 years to late? +It's not to hard, is it? diff --git a/src/main.rs b/src/main.rs index 06625c881..15003a3fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,14 @@ mod mirror; use clap::Parser; -use harper_brill::UPOS; use harper_core::Document; -use harper_core::expr::{ExprExt, SequenceExpr}; -use harper_core::patterns::UPOSSet; -use harper_core::spell::{Dictionary, FstDictionary}; -use rand::seq::IndexedRandom; +use harper_core::expr::ExprExt; use rand::seq::SliceRandom; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::slice::ParallelSliceMut; use std::fs; use std::time::Instant; -use self::mirror::{Mirror, MirrorAtom, MirrorLayer}; +use self::mirror::{Mirror, MirrorAtom, MirrorLayer, MirrorNode}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -62,9 +57,9 @@ fn main() { let clean = load_documents(&args.clean_file); let mut mirs = vec![Mirror { - layers: vec![MirrorLayer { - seq: vec![MirrorAtom::Word("to".to_string())], - }], + root: MirrorNode::Leaf(MirrorLayer { + seq: vec![MirrorAtom::Word("to".to_owned())], + }), }]; let mut last_best_score = 0; @@ -103,6 +98,10 @@ fn main() { let elapsed = start_time.elapsed(); let candidates_per_second = (mirs.len() as f64 / elapsed.as_secs_f64()) as usize; + if let Some(best_mir) = mirs.first() { + println!("Best mirror: {:#?}", best_mir); + } + println!( "Generation {:<4} | Best Score: {:<10} | Max Score: {:<10} | Delta: {:<+10} | Candidates/sec: {:<10}", i, @@ -112,10 +111,6 @@ fn main() { candidates_per_second ); - if let Some(best_mir) = mirs.first() { - println!("Best mirror: {:#?}", best_mir); - } - last_best_score = best_score; } } @@ -131,24 +126,34 @@ fn load_documents(path: &str) -> Vec { // Treat correctness as the dominant term and use simplicity as a tiebreaker. // "Simpler" = fewer non-whitespace atoms and smaller UPOS sets. fn mirror_complexity(m: &Mirror) -> usize { - use MirrorAtom::*; - let mut cost = 0usize; - - for layer in &m.layers { + fn layer_cost(layer: &MirrorLayer) -> usize { + let mut cost = 0usize; for atom in &layer.seq { match atom { - Whitespace => {} // free - Word(_w) => { + MirrorAtom::Whitespace => { + cost += 1; + } + MirrorAtom::Word(_) => { cost += 1; } - UPOS(set) => { + MirrorAtom::UPOS(set) => { cost += set.len().max(1); } } } + cost + } + + fn node_cost(node: &MirrorNode) -> usize { + match node { + MirrorNode::Leaf(layer) => layer_cost(layer), + MirrorNode::And(children) | MirrorNode::Or(children) => { + children.iter().map(node_cost).sum::() + 2 + } + } } - cost + node_cost(&m.root) } fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize { @@ -168,14 +173,14 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize } } - const TIE_SCALE: usize = 25; + const TIE_SCALE: usize = 40; let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); correct.saturating_mul(TIE_SCALE) + simplicity_bonus } pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { - const TIE_SCALE: usize = 25; + const TIE_SCALE: usize = 40; let per_problem = 50usize; let per_clean = 100usize; diff --git a/src/mirror.rs b/src/mirror.rs index 85465e719..a225df44f 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -1,5 +1,5 @@ use harper_brill::UPOS; -use harper_core::expr::{All, LongestMatchOf, SequenceExpr}; +use harper_core::expr::{All, Expr, LongestMatchOf, SequenceExpr}; use harper_core::patterns::{UPOSSet, WordSet}; use rand::seq::{IndexedRandom, SliceRandom}; use rand::{Rng, random_bool}; @@ -7,9 +7,35 @@ use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use strum::IntoEnumIterator; +/// A tree of expressions. +/// - `And`: every child must match (logical AND). +/// - `Or`: at least one child must match (logical OR, longest-match semantics). +/// - `Leaf`: a concrete `SequenceExpr` built from a `MirrorLayer`. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum MirrorNode { + And(Vec), + Or(Vec), + Leaf(MirrorLayer), +} + +impl Default for MirrorNode { + fn default() -> Self { + Self::Leaf(MirrorLayer { seq: vec![] }) + } +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Mirror { - pub layers: Vec, + pub root: MirrorNode, +} + +/// Back-compat constructor for callers that still think in “layers = AND of sequences”. +impl From> for Mirror { + fn from(layers: Vec) -> Self { + Mirror { + root: MirrorNode::And(layers.into_iter().map(MirrorNode::Leaf).collect()), + } + } } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -92,7 +118,7 @@ impl MirrorLayer { } } - fn create_random_layer(rng: &mut impl Rng) -> Self { + pub fn create_random_layer(rng: &mut impl Rng) -> Self { let len = rng.random_range(1..=3); let mut seq = Vec::with_capacity(len); for _ in 0..len { @@ -102,13 +128,113 @@ impl MirrorLayer { } } +impl MirrorNode { + /// Build a boxed `Expr` for this subtree. + /// AND => `All`, OR => `LongestMatchOf`, Leaf => `SequenceExpr`. + pub fn to_owned_expr(&self) -> Box { + match self { + MirrorNode::Leaf(layer) => Box::new(layer.to_seq_expr()), + MirrorNode::And(children) => { + let mut v: Vec> = Vec::with_capacity(children.len().max(1)); + for c in children { + v.push(c.to_owned_expr()); + } + Box::new(All::new(v)) + } + MirrorNode::Or(children) => { + let mut v: Vec> = Vec::with_capacity(children.len().max(1)); + for c in children { + v.push(c.to_owned_expr()); + } + Box::new(LongestMatchOf::new(v)) + } + } + } + + /// Randomly mutate the tree: + /// - Recurse into a child and mutate it + /// - Insert/remove a child + /// - Flip AND <-> OR + /// - Wrap/unwrap a leaf to introduce structure + pub fn mutate(&mut self, rng: &mut impl Rng) { + match self { + MirrorNode::Leaf(layer) => { + // 70%: tweak the leaf; 30%: promote to a tiny AND/OR subtree + if rng.random_bool(0.7) { + layer.mutate(rng); + } else { + let new_leaf = MirrorNode::Leaf(MirrorLayer::create_random_layer(rng)); + if rng.random_bool(0.5) { + *self = MirrorNode::And(vec![MirrorNode::Leaf(layer.clone()), new_leaf]); + } else { + *self = MirrorNode::Or(vec![MirrorNode::Leaf(layer.clone()), new_leaf]); + } + } + } + MirrorNode::And(children) | MirrorNode::Or(children) => { + let len = children.len(); + + // Occasionally flip operator + if rng.random_bool(0.1) { + let swapped = match std::mem::take(self) { + MirrorNode::And(c) => MirrorNode::Or(c), + MirrorNode::Or(c) => MirrorNode::And(c), + MirrorNode::Leaf(_) => unreachable!(), + }; + *self = swapped; + return; + } + + // Sometimes reorder for variety + if len >= 2 && rng.random_bool(0.1) { + children.shuffle(rng); + } + + // Insert / remove + if rng.random_bool(0.25) { + let idx = rng.random_range(0..=len); + children.insert(idx, MirrorNode::Leaf(MirrorLayer::create_random_layer(rng))); + } else if len > 1 && rng.random_bool(0.15) { + let idx = rng.random_range(0..len); + children.remove(idx); + } else if !children.is_empty() { + // Recurse into a child + let idx = rng.random_range(0..children.len()); + children[idx].mutate(rng); + } + + // Occasionally collapse a singleton (unwrap) or wrap a pair + if children.len() == 1 && rng.random_bool(0.15) { + // Replace this node with its only child + let only = children.remove(0); + *self = only; + } else if children.len() >= 2 && rng.random_bool(0.15) { + // Wrap two adjacent children into a new AND/OR group + let idx = rng.random_range(0..children.len() - 1); + let a = children.remove(idx); + let b = children.remove(idx); // same idx: list shrank + let wrapped = if rng.random_bool(0.5) { + MirrorNode::And(vec![a, b]) + } else { + MirrorNode::Or(vec![a, b]) + }; + children.insert(idx, wrapped); + } + } + } + } +} + impl Mirror { + /// Legacy API: keep returning an `All`, but place the whole tree as a single child. + /// This preserves older call sites that expect `All` while allowing OR inside. pub fn to_expr(&self) -> All { - let mut all = All::default(); - for layer in &self.layers { - all.add(layer.to_seq_expr()); - } - all + All::new(vec![self.root.to_owned_expr()]) + } + + /// New API: get the actual tree as a single `Expr`. + pub fn to_owned_expr(&self) -> Box { + self.root.to_owned_expr() } pub fn create_children_with_mutations( @@ -130,38 +256,27 @@ impl Mirror { } pub fn mutate(&mut self, rng: &mut impl Rng) { - if self.layers.is_empty() || rng.random_bool(0.2) { - let i = rng.random_range(0..=self.layers.len()); - self.layers.insert(i, MirrorLayer::create_random_layer(rng)); - return; - } - - if rng.random_bool(0.1) && !self.layers.is_empty() { - let i = rng.random_range(0..self.layers.len()); - self.layers.remove(i); + // 20%: wrap root to add a new level (AND/OR); 10%: replace root with a fresh leaf; otherwise recurse. + if rng.random_bool(0.2) { + let wrapper_is_and = rng.random_bool(0.5); + let sibling = MirrorNode::Leaf(MirrorLayer::create_random_layer(rng)); + let old = std::mem::replace( + &mut self.root, + MirrorNode::Leaf(MirrorLayer::create_random_layer(rng)), + ); + self.root = if wrapper_is_and { + MirrorNode::And(vec![old, sibling]) + } else { + MirrorNode::Or(vec![old, sibling]) + }; return; } - if rng.random_bool(0.1) && self.layers.len() >= 2 { - self.layers.shuffle(rng); + if rng.random_bool(0.1) { + self.root = MirrorNode::Leaf(MirrorLayer::create_random_layer(rng)); return; } - let i = rng.random_range(0..self.layers.len()); - let layer = &mut self.layers[i]; - - if rng.random_bool(0.6) { - layer.mutate(rng); - } else { - if rng.random_bool(0.5) { - let insert_at = rng.random_range(0..=layer.seq.len()); - layer - .seq - .insert(insert_at, MirrorLayer::create_random_step(rng)); - } else if !layer.seq.is_empty() { - let remove_at = rng.random_range(0..layer.seq.len()); - layer.seq.remove(remove_at); - } - } + self.root.mutate(rng); } } From eb230e9ff981a5cf5123c12438b4e6f7e7c80226 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Wed, 20 Aug 2025 12:27:16 -0600 Subject: [PATCH 18/28] fix: remove pointer --- src/mirror.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/mirror.rs b/src/mirror.rs index a225df44f..52a8f17a2 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -226,14 +226,7 @@ impl MirrorNode { } impl Mirror { - /// Legacy API: keep returning an `All`, but place the whole tree as a single child. - /// This preserves older call sites that expect `All` while allowing OR inside. - pub fn to_expr(&self) -> All { - All::new(vec![self.root.to_owned_expr()]) - } - - /// New API: get the actual tree as a single `Expr`. - pub fn to_owned_expr(&self) -> Box { + pub fn to_expr(&self) -> Box { self.root.to_owned_expr() } From a43b574319326a10f14e35f6503d1a187ca96b81 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Wed, 20 Aug 2025 13:06:38 -0600 Subject: [PATCH 19/28] fix: score --- src/main.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 15003a3fa..41f3800b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -156,6 +156,10 @@ fn mirror_complexity(m: &Mirror) -> usize { node_cost(&m.root) } +const TIE_SCALE: usize = 400; +const PROBLEM_REWARD: usize = 500; +const CLEAN_REWARD: usize = 1000; + fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize { let expr = candidate.to_expr(); @@ -163,30 +167,25 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize for problem in problems { if expr.iter_matches_in_doc(problem).count() == 1 { - correct += 50; + correct += PROBLEM_REWARD; } } for clean in clean { if expr.iter_matches_in_doc(clean).count() == 0 { - correct += 100; + correct += CLEAN_REWARD; } } - const TIE_SCALE: usize = 40; let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); correct.saturating_mul(TIE_SCALE) + simplicity_bonus } pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { - const TIE_SCALE: usize = 40; - let per_problem = 50usize; - let per_clean = 100usize; - - let correctness = per_problem + let correctness = PROBLEM_REWARD .saturating_mul(problems.len()) - .saturating_add(per_clean.saturating_mul(clean.len())); + .saturating_add(CLEAN_REWARD.saturating_mul(clean.len())); correctness .saturating_mul(TIE_SCALE) From cdfa5fea1d2f524b529fccedeef7cc7949f3e70a Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 21 Aug 2025 11:36:04 -0600 Subject: [PATCH 20/28] feat: add early-exits to speed things up --- src/main.rs | 17 ++++++++++++----- src/mirror.rs | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 41f3800b2..9b3fef24e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use clap::Parser; use harper_core::Document; use harper_core::expr::ExprExt; use rand::seq::SliceRandom; +use rayon::iter::ParallelIterator; use rayon::slice::ParallelSliceMut; use std::fs; use std::time::Instant; @@ -70,18 +71,19 @@ fn main() { mirs.truncate(args.min_pop); let mut perm_mirs = Vec::new(); + let mut rng = rand::rng(); for mir in &mirs { perm_mirs.append(&mut mir.create_children_with_mutations( args.child_ratio, args.max_mutations, - &mut rand::thread_rng(), + &mut rng, )); } mirs.append(&mut perm_mirs); - mirs.shuffle(&mut rand::thread_rng()); + mirs.shuffle(&mut rand::rng()); mirs.par_sort_by_cached_key(|s| { let score = score(&s, &problems, &clean); @@ -119,7 +121,7 @@ fn load_documents(path: &str) -> Vec { fs::read_to_string(path) .expect("Unable to read file.") .lines() - .map(|s| Document::new_plain_english_curated(s)) + .map(Document::new_plain_english_curated) .collect() } @@ -165,14 +167,19 @@ fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize let mut correct = 0usize; + // Early-exit counting: avoid scanning entire document when not necessary. for problem in problems { - if expr.iter_matches_in_doc(problem).count() == 1 { + let mut it = expr.iter_matches_in_doc(problem); + let first = it.next().is_some(); + let second = it.next().is_none(); + if first && second { + // Exactly one match correct += PROBLEM_REWARD; } } for clean in clean { - if expr.iter_matches_in_doc(clean).count() == 0 { + if expr.iter_matches_in_doc(clean).next().is_none() { correct += CLEAN_REWARD; } } diff --git a/src/mirror.rs b/src/mirror.rs index 52a8f17a2..21be8bc9c 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -1,7 +1,7 @@ use harper_brill::UPOS; use harper_core::expr::{All, Expr, LongestMatchOf, SequenceExpr}; use harper_core::patterns::{UPOSSet, WordSet}; -use rand::seq::{IndexedRandom, SliceRandom}; +use rand::seq::SliceRandom; use rand::{Rng, random_bool}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; @@ -55,7 +55,7 @@ impl MirrorLayer { let mut seq = SequenceExpr::default(); for atom in &self.seq { match atom { - MirrorAtom::UPOS(uposset) => seq = seq.then(UPOSSet::new(&uposset)), + MirrorAtom::UPOS(uposset) => seq = seq.then(UPOSSet::new(uposset)), MirrorAtom::Whitespace => seq = seq.t_ws(), MirrorAtom::Word(word) => { let mut set = WordSet::default(); @@ -239,7 +239,7 @@ impl Mirror { let mut children = Vec::with_capacity(child_count); for _ in 0..child_count { let mut child = self.clone(); - let mutation_count = rng.gen_range(1..=max_mutations); + let mutation_count = rng.random_range(1..=max_mutations); for _ in 0..mutation_count { child.mutate(rng); } From ca5be037024615084592b655ad0f79f22a6a0b18 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 21 Aug 2025 12:08:26 -0600 Subject: [PATCH 21/28] feat: add NP membership to search --- src/main.rs | 4 ++++ src/mirror.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main.rs b/src/main.rs index 9b3fef24e..bae40841f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,6 +141,10 @@ fn mirror_complexity(m: &Mirror) -> usize { MirrorAtom::UPOS(set) => { cost += set.len().max(1); } + MirrorAtom::NPMember => { + // Simple boolean check; treat similar to a basic atom + cost += 1; + } } } cost diff --git a/src/mirror.rs b/src/mirror.rs index 21be8bc9c..89f350545 100644 --- a/src/mirror.rs +++ b/src/mirror.rs @@ -1,4 +1,5 @@ use harper_brill::UPOS; +use harper_core::TokenKind; use harper_core::expr::{All, Expr, LongestMatchOf, SequenceExpr}; use harper_core::patterns::{UPOSSet, WordSet}; use rand::seq::SliceRandom; @@ -48,6 +49,9 @@ pub enum MirrorAtom { Word(String), UPOS(SmallVec<[UPOS; 16]>), Whitespace, + /// Match if the current token is marked as a member of a noun phrase + /// via `WordMetadata::np_member == Some(true)`. + NPMember, } impl MirrorLayer { @@ -62,6 +66,14 @@ impl MirrorLayer { set.add_chars(&word.chars().collect::>()); seq = seq.then(set) } + MirrorAtom::NPMember => { + seq = seq.then( + |tok: &harper_core::Token, _source: &[char]| match &tok.kind { + TokenKind::Word(Some(md)) => md.np_member == Some(true), + _ => false, + }, + ); + } } } seq @@ -102,6 +114,7 @@ impl MirrorLayer { } } MirrorAtom::Whitespace => {} + MirrorAtom::NPMember => {} } } @@ -113,6 +126,8 @@ impl MirrorLayer { MirrorAtom::UPOS(all_upos) } else if random_bool(0.2) { MirrorAtom::Word(String::from("the")) + } else if random_bool(0.1) { + MirrorAtom::NPMember } else { MirrorAtom::Whitespace } From a5e4c88800d5437a929ef2f8bdb6588f8217c2ab Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Thu, 21 Aug 2025 13:16:03 -0600 Subject: [PATCH 22/28] feat: add seed flag and reword scoring --- clean.txt | 30 +++++++++++ rules/missing_article.txt | 30 +++++++++++ problems.txt => rules/to_too.txt | 0 src/main.rs | 93 +++++++++++++++++++++----------- 4 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 rules/missing_article.txt rename problems.txt => rules/to_too.txt (100%) diff --git a/clean.txt b/clean.txt index 43ec19df1..d9a452fc5 100644 --- a/clean.txt +++ b/clean.txt @@ -51,3 +51,33 @@ Its speed, flexibility, and seamless integration with FZF make it a compelling a It's not too easy, is it? Soundscapes are not merely environmental features; they are integral to human identity and cultural expression. Its speed, flexibility, and seamless integration with FZF make it a compelling alternative to traditional fuzzy finding solutions. +The cat jumped onto the couch and fell asleep. +I bought a new book yesterday. +The teacher asked the class to hand in the homework. +The sun was shining brightly over the city. +We went to the park after dinner. +She poured a glass of water for me. +The car stopped suddenly in the middle of the road. +The dog barked at a stranger outside. +I forgot the password again. +They traveled across the ocean in a small boat. +The bird flew out of the cage when the door opened. +The man standing at the corner looked suspicious. +The child dropped the toy on the floor. +The rain started falling just as the game began. +The house smelled like fresh paint. +The train arrived at the station late. +The friends gathered around the fire to keep warm. +The book sat untouched on the shelf for years. +The wind rattled the window all night long. +The doctor prescribed medicine for the cough. +The girl wore a red dress to the party. +The worker left the tools on the table. +The phone rang loudly during the meeting. +The snow covered the mountains by morning. +The river overflowed after the storm. +The artist displayed a painting in the gallery. +The student missed the bus to school. +The baby cried until the mother came. +The letter arrived without a stamp. +The bread burned in the oven. diff --git a/rules/missing_article.txt b/rules/missing_article.txt new file mode 100644 index 000000000..b791e47a9 --- /dev/null +++ b/rules/missing_article.txt @@ -0,0 +1,30 @@ +Cat jumped onto couch and fell asleep. +I bought new book yesterday. +Teacher asked class to hand in homework. +Sun was shining brightly over city. +We went to park after dinner. +She poured glass of water for me. +Car stopped suddenly in middle of road. +Dog barked at stranger outside. +I forgot password again. +They traveled across ocean in small boat. +Bird flew out of cage when door opened. +Man standing at corner looked suspicious. +Child dropped toy on floor. +Rain started falling just as game began. +House smelled like fresh paint. +Train arrived at station late. +Friends gathered around fire to keep warm. +Book sat untouched on shelf for years. +Wind rattled window all night long. +Doctor prescribed medicine for cough. +Girl wore red dress to party. +Worker left tools on table. +Phone rang loudly during meeting. +Snow covered mountains by morning. +River overflowed after storm. +Artist displayed painting in gallery. +Student missed bus to school. +Baby cried until mother came. +Letter arrived without stamp. +Bread burned in oven. diff --git a/problems.txt b/rules/to_too.txt similarity index 100% rename from problems.txt rename to rules/to_too.txt diff --git a/src/main.rs b/src/main.rs index bae40841f..1b6d23f7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use clap::Parser; use harper_core::Document; use harper_core::expr::ExprExt; use rand::seq::SliceRandom; -use rayon::iter::ParallelIterator; use rayon::slice::ParallelSliceMut; use std::fs; use std::time::Instant; @@ -42,6 +41,10 @@ struct Args { /// If not specified, Rayon will use the default number of threads. #[arg(short, long)] jobs: Option, + + /// Optional seed word to initialize the search with + #[arg(long)] + seed: Option, } fn main() { @@ -57,10 +60,17 @@ fn main() { let problems = load_documents(&args.problem_file); let clean = load_documents(&args.clean_file); - let mut mirs = vec![Mirror { - root: MirrorNode::Leaf(MirrorLayer { - seq: vec![MirrorAtom::Word("to".to_owned())], - }), + let mut mirs = vec![if let Some(seed) = args.seed.clone() { + Mirror { + root: MirrorNode::Leaf(MirrorLayer { + seq: vec![MirrorAtom::Word(seed)], + }), + } + } else { + // No seed provided: start with an empty leaf and let mutation explore + Mirror { + root: MirrorNode::Leaf(MirrorLayer { seq: vec![] }), + } }]; let mut last_best_score = 0; @@ -86,7 +96,7 @@ fn main() { mirs.shuffle(&mut rand::rng()); mirs.par_sort_by_cached_key(|s| { - let score = score(&s, &problems, &clean); + let score = score(s, &problems, &clean); usize::MAX - score }); @@ -125,7 +135,7 @@ fn load_documents(path: &str) -> Vec { .collect() } -// Treat correctness as the dominant term and use simplicity as a tiebreaker. +// Treat correctness as the dominant term and use simplicity as a small bonus. // "Simpler" = fewer non-whitespace atoms and smaller UPOS sets. fn mirror_complexity(m: &Mirror) -> usize { fn layer_cost(layer: &MirrorLayer) -> usize { @@ -139,7 +149,7 @@ fn mirror_complexity(m: &Mirror) -> usize { cost += 1; } MirrorAtom::UPOS(set) => { - cost += set.len().max(1); + cost += set.len(); } MirrorAtom::NPMember => { // Simple boolean check; treat similar to a basic atom @@ -162,43 +172,62 @@ fn mirror_complexity(m: &Mirror) -> usize { node_cost(&m.root) } -const TIE_SCALE: usize = 400; -const PROBLEM_REWARD: usize = 500; -const CLEAN_REWARD: usize = 1000; +// Upper bound for simplicity bonus points. This should be small relative +// to correctness so it cannot outweigh getting sentences right. +const SIMPLICITY_BONUS_MAX: usize = 150; fn score(candidate: &Mirror, problems: &[Document], clean: &[Document]) -> usize { let expr = candidate.to_expr(); - let mut correct = 0usize; - - // Early-exit counting: avoid scanning entire document when not necessary. - for problem in problems { - let mut it = expr.iter_matches_in_doc(problem); + // Clean correctness: percentage of clean sentences with zero matches. + let mut clean_correct = 0usize; + for c in clean { + if expr.iter_matches_in_doc(c).next().is_none() { + clean_correct += 1; + } + } + let clean_pct = if clean.is_empty() { + 0usize + } else { + (clean_correct * 100) / clean.len() + }; + + // Problem correctness: percentage of problem sentences that are flagged. + // Preserve the existing notion of a "correct" flag as exactly one match. + let mut problem_correct = 0usize; + for p in problems { + let mut it = expr.iter_matches_in_doc(p); let first = it.next().is_some(); let second = it.next().is_none(); if first && second { - // Exactly one match - correct += PROBLEM_REWARD; + problem_correct += 1; } } + let problem_pct = if problems.is_empty() { + 0usize + } else { + (problem_correct * 100) / problems.len() + }; - for clean in clean { - if expr.iter_matches_in_doc(clean).next().is_none() { - correct += CLEAN_REWARD; - } - } + // Combined correctness: clean is weighted 2x as requested. + let correctness_score = clean_pct * 2 + problem_pct; - let simplicity_bonus = TIE_SCALE.saturating_sub(mirror_complexity(candidate).min(TIE_SCALE)); + // Small simplicity bonus in 0..=SIMPLICITY_BONUS_MAX, decreasing with complexity. + let complexity = mirror_complexity(candidate); + let simplicity_bonus = SIMPLICITY_BONUS_MAX.saturating_sub(complexity); - correct.saturating_mul(TIE_SCALE) + simplicity_bonus + correctness_score * 100 + simplicity_bonus } pub fn max_possible_score(problems: &[Document], clean: &[Document]) -> usize { - let correctness = PROBLEM_REWARD - .saturating_mul(problems.len()) - .saturating_add(CLEAN_REWARD.saturating_mul(clean.len())); - - correctness - .saturating_mul(TIE_SCALE) - .saturating_add(TIE_SCALE) + // Max correctness = (2x clean%) + (1x problem%). + // Only count a component if its corpus is present. + let mut max = 0usize; + if !clean.is_empty() { + max += 200; // 2 * 100% + } + if !problems.is_empty() { + max += 100; // 1 * 100% + } + max * 100 + SIMPLICITY_BONUS_MAX } From fc3303202934b130949f7dfba2937fba6002d2fb Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Mon, 25 Aug 2025 10:42:59 -0600 Subject: [PATCH 23/28] feat: add output flag --- src/main.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main.rs b/src/main.rs index 1b6d23f7d..dd32f7f63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,10 @@ struct Args { /// Optional seed word to initialize the search with #[arg(long)] seed: Option, + + /// Output file to write the best candidate after all generations + #[arg(short = 'o', long = "output")] + output: Option, } fn main() { @@ -125,6 +129,17 @@ fn main() { last_best_score = best_score; } + + // After all generations, optionally save the best candidate to a file in a textual format + if let Some(path) = args.output.as_deref() { + if let Some(best_mir) = mirs.first() { + if let Err(e) = fs::write(path, format!("{:#?}", best_mir)) { + eprintln!("Failed to save best candidate to {}: {}", path, e); + } else { + println!("Saved best candidate to {}", path); + } + } + } } fn load_documents(path: &str) -> Vec { From a4671514c7d8edf4bf0c95a21884a25a2531c3d4 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Fri, 29 Aug 2025 10:53:32 -0600 Subject: [PATCH 24/28] feat: more data --- clean.txt | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ rules/how_to.txt | 25 ++++++++++++++++++++ rules/indp.txt | 35 +++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 rules/how_to.txt create mode 100644 rules/indp.txt diff --git a/clean.txt b/clean.txt index d9a452fc5..feceb803f 100644 --- a/clean.txt +++ b/clean.txt @@ -81,3 +81,64 @@ The student missed the bus to school. The baby cried until the mother came. The letter arrived without a stamp. The bread burned in the oven. +I can’t figure out how to fix this. +She asked how to get home before dusk. +Please show me how to configure the router. +Explain how to enable verbose logging in production. +Do you remember how to calculate compound interest? +We must decide how to allocate scarce bandwidth. +He demonstrated how to bake sourdough with a stiff levain. +Clarify how to deploy the service on Kubernetes. +Remind me how to change my billing address in the portal. +The brief outlines how to submit a compliant proposal. +The nurse explained how to taper the dosage safely. +Tell me how to pronounce “schadenfreude”. +Here’s how to replicate the experiment precisely. +Outline how to escalate a Sev1 incident. +The mentor taught her how to write idempotent handlers. +Let’s review how to troubleshoot kernel panics. +The SOP describes how to sanitize the fermenter. +Can you recall how to resolve a merge conflict in Git? +Please demonstrate how to calibrate the torque wrench. +The guide illustrates how to harden the container image. +We’re uncertain how to remediate the CVE quickly. +He forgot how to conjugate the verb under stress. +Map out how to integrate this OAuth flow. +Practice how to deliver the keynote without slides. +She’s unsure how to proceed given the constraints. +The meeting ran long, and the clients grew impatient. +I called the restaurant, but nobody answered the phone. +You can finish the slide deck, or you can push the deadline. +He wanted to go hiking, yet the forecast promised heavy rain. +We missed the exit, so we had to circle back. +She studied all night, for she feared the exam would be brutal. +The device keeps overheating, and the battery drains within minutes. +I washed the car, but the dust storm returned by noon. +They opened a second store, so the weekend shift needs more staff. +The software compiled successfully, yet the app crashed on launch. +He promised to call, or he will send a text instead. +We upgraded the servers, for the traffic spikes were overwhelming. +She finished the chapter, and she closed the book with relief. +The cat darted under the couch, so the dog lost interest. +I could join the early flight, or I could take the train tomorrow. +Our neighbors moved out, yet the street stays noisy every night. +He filed the report on time, but the figures were still wrong. +The lamp flickered, and the room went dark. +The door was unlocked, so anyone could have walked in. +They offered a refund, for the package arrived a week late. +The keynote started late, and the livestream crashed immediately. +I reviewed your pull request, but the failing tests still block the merge. +The sourdough rose overnight, yet the crust stayed disappointingly pale. +She booked the venue, so we finalized the invitations. +The forecast promised sun, yet hail hammered the valley by noon. +He saved the draft, or he risked losing an hour of work. +The server rebooted, and every session expired at once. +The rug looked antique, but the dye bled under a damp cloth. +I can lead the meeting, or you can take point this time. +We missed the turn, for the signage was hidden behind ivy. +The editor flagged a cliché, so I rewrote the paragraph. +The engine sputtered, and the dashboard lit up like a runway. +She set three alarms, yet she overslept again. +The gallery extended hours, so attendance increased by twenty percent. +He didn’t read the brief, nor did he consult the timeline. +The chef plated beautifully, but the sauce overwhelmed the fish. diff --git a/rules/how_to.txt b/rules/how_to.txt new file mode 100644 index 000000000..ec386fb8d --- /dev/null +++ b/rules/how_to.txt @@ -0,0 +1,25 @@ +I can’t figure out how fix this. +She asked how get home before dusk. +Please show me how configure the router. +Explain how enable verbose logging in production. +Do you remember how calculate compound interest? +We must decide how allocate scarce bandwidth. +He demonstrated how bake sourdough with a stiff levain. +Clarify how deploy the service on Kubernetes. +Remind me how change my billing address in the portal. +The brief outlines how submit a compliant proposal. +The nurse explained how taper the dosage safely. +Tell me how pronounce “schadenfreude”. +Here’s how replicate the experiment precisely. +Outline how escalate a Sev1 incident. +The mentor taught her how write idempotent handlers. +Let’s review how troubleshoot kernel panics. +The SOP describes how sanitize the fermenter. +Can you recall how resolve a merge conflict in Git? +Please demonstrate how calibrate the torque wrench. +The guide illustrates how harden the container image. +We’re uncertain how remediate the CVE quickly. +He forgot how conjugate the verb under stress. +Map out how integrate this OAuth flow. +Practice how deliver the keynote without slides. +She’s unsure how proceed given the constraints. diff --git a/rules/indp.txt b/rules/indp.txt new file mode 100644 index 000000000..0c0fca460 --- /dev/null +++ b/rules/indp.txt @@ -0,0 +1,35 @@ +I called the restaurant but nobody answered the phone. +You can finish the slide deck or you can push the deadline. +He wanted to go hiking yet the forecast promised heavy rain. +We missed the exit so we had to circle back. +She studied all night for she feared the exam would be brutal. +The device keeps overheating and the battery drains within minutes. +I washed the car but the dust storm returned by noon. +They opened a second store so the weekend shift needs more staff. +The software compiled successfully yet the app crashed on launch. +He promised to call or he will send a text instead. +We upgraded the servers for the traffic spikes were overwhelming. +She finished the chapter and she closed the book with relief. +The cat darted under the couch so the dog lost interest. +I could join the early flight or I could take the train tomorrow. +Our neighbors moved out yet the street stays noisy every night. +He filed the report on time but the figures were still wrong. +The lamp flickered and the room went dark. +The door was unlocked so anyone could have walked in. +They offered a refund for the package arrived a week late. +The keynote started late and the livestream crashed immediately. +I reviewed your pull request but the failing tests still block the merge. +The sourdough rose overnight yet the crust stayed disappointingly pale. +She booked the venue so we finalized the invitations. +The forecast promised sun yet hail hammered the valley by noon. +He saved the draft or he risked losing an hour of work. +The server rebooted and every session expired at once. +The rug looked antique but the dye bled under a damp cloth. +I can lead the meeting or you can take point this time. +We missed the turn for the signage was hidden behind ivy. +The editor flagged a cliché so I rewrote the paragraph. +The engine sputtered and the dashboard lit up like a runway. +She set three alarms yet she overslept again. +The gallery extended hours so attendance increased by twenty percent. +He didn’t read the brief nor did he consult the timeline. +The chef plated beautifully but the sauce overwhelmed the fish. From 08b47a86a55e12dcbd4a87e149a5936530f25e46 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Fri, 29 Aug 2025 16:55:36 +0000 Subject: [PATCH 25/28] feat: create queue --- queue.sh | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 queue.sh diff --git a/queue.sh b/queue.sh new file mode 100755 index 000000000..18f7297d9 --- /dev/null +++ b/queue.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/to_too.txt --clean-file clean.txt --max-mutations 60 --seed to -o to_too.sol +cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/missing_article.txt --clean-file clean.txt --max-mutations 60 -o missing_article.sol +cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/indp.txt --clean-file clean.txt --max-mutations 60 -o best.txt + From c505e31be339f58e973aa7c5dd607d5e69330415 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Wed, 3 Sep 2025 11:49:26 -0600 Subject: [PATCH 26/28] feat: wire `ripper` into the Cargo workspace --- Cargo.lock | 15 +++++++++++++++ Cargo.toml | 2 +- ripper/Cargo.toml | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6da794c40..901203990 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3859,6 +3859,21 @@ dependencies = [ "dirs 4.0.0", ] +[[package]] +name = "ripper" +version = "0.1.0" +dependencies = [ + "clap", + "harper-brill", + "harper-core", + "rand 0.9.2", + "rayon", + "serde", + "serde_json", + "smallvec", + "strum 0.27.2", +] + [[package]] name = "rmp" version = "0.8.14" diff --git a/Cargo.toml b/Cargo.toml index c5207e55e..eb4cc2e7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter", "harper-html", "harper-literate-haskell", "harper-typst" , "harper-stats", "harper-pos-utils", "harper-brill"] +members = [ "harper-cli", "harper-core", "harper-ls", "harper-comments", "harper-wasm", "harper-tree-sitter", "harper-html", "harper-literate-haskell", "harper-typst" , "harper-stats", "harper-pos-utils", "harper-brill", "ripper"] resolver = "2" # Comment out the below lines if you plan to use a debugger. diff --git a/ripper/Cargo.toml b/ripper/Cargo.toml index c12ea366d..8b40c751c 100644 --- a/ripper/Cargo.toml +++ b/ripper/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] clap = { version = "4.5.4", features = ["derive"] } -harper-brill = "0.57.0" -harper-core = { version = "0.57.0", features = ["concurrent"] } +harper-core = { path = "../harper-core", version = "0.61.0", features = ["concurrent"] } +harper-brill = { path = "../harper-brill", version = "0.61.0" } rand = { version = "0.9.2", features = ["small_rng"] } rayon = "1.10.0" serde = { version = "1.0.219", features = ["derive"] } From 2ef83779f09fcd461cb180613b47f846180df0b9 Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Wed, 3 Sep 2025 12:25:26 -0600 Subject: [PATCH 27/28] feat(ripper): reduce gens --- ripper/queue.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ripper/queue.sh b/ripper/queue.sh index 18f7297d9..f51a7eb40 100755 --- a/ripper/queue.sh +++ b/ripper/queue.sh @@ -1,6 +1,6 @@ #! /bin/bash -cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/to_too.txt --clean-file clean.txt --max-mutations 60 --seed to -o to_too.sol -cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/missing_article.txt --clean-file clean.txt --max-mutations 60 -o missing_article.sol -cargo run --release -- -m 1000000 -g 200 -c 10 --problem-file rules/indp.txt --clean-file clean.txt --max-mutations 60 -o best.txt +cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/to_too.txt --clean-file clean.txt --max-mutations 60 --seed to -o to_too.sol +cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/missing_article.txt --clean-file clean.txt --max-mutations 60 -o missing_article.sol +cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/indp.txt --clean-file clean.txt --max-mutations 60 -o best.txt From 6a96ebd75a67062fc34c5e176a0e0da902a7633b Mon Sep 17 00:00:00 2001 From: Elijah Potter Date: Wed, 10 Sep 2025 19:54:10 +0000 Subject: [PATCH 28/28] Added new potential rules to the queue --- ripper/clean.txt | 109 +++++++++++++++++++++++++++++++++ ripper/queue.sh | 5 +- ripper/rules/affect_effect.txt | 25 ++++++++ ripper/rules/effect_affect.txt | 31 ++++++++++ ripper/rules/missing_noun.txt | 71 +++++++++++++++++++++ ripper/rules/missing_to.txt | 30 +++++++++ 6 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 ripper/rules/affect_effect.txt create mode 100644 ripper/rules/effect_affect.txt create mode 100644 ripper/rules/missing_noun.txt create mode 100644 ripper/rules/missing_to.txt diff --git a/ripper/clean.txt b/ripper/clean.txt index feceb803f..1a9f30a43 100644 --- a/ripper/clean.txt +++ b/ripper/clean.txt @@ -142,3 +142,112 @@ She set three alarms, yet she overslept again. The gallery extended hours, so attendance increased by twenty percent. He didn’t read the brief, nor did he consult the timeline. The chef plated beautifully, but the sauce overwhelmed the fish. +The new tariff will affect import prices next quarter. +Prolonged droughts severely affect crop yields across the valley. +Caffeine can affect your sleep architecture. +The firmware bug doesn't affect older devices. +Her sarcasm seemed to affect the team's morale. +How will this outage affect our deployment timeline? +Cold temperatures drastically affect lithium-ion battery performance. +The policy change could affect your eligibility for benefits. +These confounding variables may affect the study's results. +The noisy HVAC fans constantly affect concentration in the lab. +Stress hormones can affect immune response during recovery. +The instructor's pacing tended to affect student engagement. +Humidity levels directly affect paint curing time. +The exchange rate will surely affect the final invoice. +Screen brightness settings can affect perceived contrast. +The medication didn't affect him the way the doctor expected. +Late payments will negatively affect your credit score. +Minor wording tweaks shouldn't affect the legal interpretation. +Traffic patterns often affect delivery windows downtown. +The rumor started to affect investor confidence by noon. +Seasonal allergies badly affect her productivity each April. +Your feedback won't immediately affect the roadmap. +Fluctuating bandwidth can affect video call quality. +The temperature gradient might affect the sensor's calibration. +Even tiny delays can affect user satisfaction metrics. +The surrounding architecture can affect GPS accuracy. +Lighting conditions strongly affect color perception. +The new coach's strategy will affect players' roles. +Overtraining can affect reaction time and coordination. +The warning label may affect how consumers use the product. +The new law had a positive effect on small businesses. +We measured the effect of caffeine on reaction time. +The side effects included nausea and fatigue. +Cause and effect are not the same thing. +The change will have an effect on our revenue. +The medicine took effect within minutes. +The policy will come into effect on October 1. +The rules are now in effect. +With immediate effect, the office is closed. +The director used stunning special effects. +The placebo effect can be powerful. +We felt the ripple effect across the entire market. +The snowball effect amplified the problem. +That decision had a knock-on effect throughout the team. +The greenhouse effect warms the planet. +Her apology had little effect. +The new settings go into effect after a restart. +They put the new plan into effect last week. +The contract comes into effect at midnight. +The warning had no effect on his behavior. +Inflation had the opposite effect than expected. +The regulation remains in effect until further notice. +The app changes take effect next week. +Sound effects were added in post. +I meant to call you last night. +She wants to finish early. +We need to talk about pricing. +They agreed to meet at dawn. +He forgot to send the file. +I’m trying to get better at chess. +She refused to answer the question. +We decided to leave at once. +I hope to see you again. +He managed to keep calm under pressure. +Don’t forget to lock the door. +She learned to drive on rural roads. +He prepared to leave immediately. +We’re ready to start the meeting. +I’m eager to see the results. +She longs to hear from you. +We aim to reduce costs this quarter. +He needs to find a reliable partner. +They attempted to salvage the prototype. +I intend to finish by noon. +I neglected to mention the caveat. +She endeavored to maintain composure. +We struggled to articulate our position. +He attempted to reconcile the data. +I'm inclined to believe you. +She expects to hear back today. +We arranged to meet at noon. +He aspires to lead the team. +I resolved to write daily. +She failed to capture the nuance. +I set the brittle porcelain figurine on the mantel and held my breath. +She folded the rumpled shirts into the suitcase before dawn. +He carried the cracked mirror up the stairwell, wincing at each step. +We rinsed the sticky beaker in the utility sink behind the lab. +The curator polished the tarnished silver candlestick until it finally glinted. +I trimmed the overgrown hedge behind the shed after the rain. +He vacuumed the shaggy carpet and emptied the canister twice. +She ironed the wrinkled dress and hung it by the foyer mirror. +They stored the fragile ceramics on a lower shelf near the wall. +I stitched the torn seam with invisible thread under a bright lamp. +We taped the splintered banister so nobody would slice a palm. +He sanded the rough edge until it felt almost like silk. +She repainted the flaking window trim before the open house began. +Please quarantine the putrescent specimen far from anything edible. +The technician centrifuged the viscous suspension until the opaque layer separated. +I wrapped the friable parchment leaf in acid-free tissue and labeled it. +She archived the lacunose codex in a climate-controlled drawer. +He patched the crazed glaze before firing the kiln again. +We decommissioned the inoperable compressor after the safety audit. +I decanted the turbid solution into a clean glass column. +He sieved the granular mixture until only the fine powder slipped through. +We autoclaved the contaminated instruments and logged the cycle. +I replaced the burnt fuse and reset the breaker without incident. +She chilled the lukewarm white wine because the guests complained. + diff --git a/ripper/queue.sh b/ripper/queue.sh index f51a7eb40..ddfc9854b 100755 --- a/ripper/queue.sh +++ b/ripper/queue.sh @@ -3,4 +3,7 @@ cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/to_too.txt --clean-file clean.txt --max-mutations 60 --seed to -o to_too.sol cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/missing_article.txt --clean-file clean.txt --max-mutations 60 -o missing_article.sol cargo run --release -- -m 1000000 -g 75 -c 10 --problem-file rules/indp.txt --clean-file clean.txt --max-mutations 60 -o best.txt - +cargo run --release -- -m 1600000 -g 75 -c 10 --problem-file rules/missing_noun.txt --clean-file clean.txt --max-mutations 60 -o missing_noun.txt +cargo run --release -- -m 1600000 -g 75 -c 10 --problem-file rules/effect_affect.txt --clean-file clean.txt --max-mutations 60 -o effect_affect.txt +cargo run --release -- -m 1600000 -g 75 -c 10 --problem-file rules/affect_effect.txt --clean-file clean.txt --max-mutations 60 -o affect_effect.txt +cargo run --release -- -m 1600000 -g 75 -c 10 --problem-file rules/missing_to.txt --clean-file clean.txt --max-mutations 60 -o missing_to.txt diff --git a/ripper/rules/affect_effect.txt b/ripper/rules/affect_effect.txt new file mode 100644 index 000000000..3eb5a112f --- /dev/null +++ b/ripper/rules/affect_effect.txt @@ -0,0 +1,25 @@ +The new law had a positive affect on small businesses. +We measured the affect of caffeine on reaction time. +The side affects included nausea and fatigue. +Cause and affect are not the same thing. +The change will have an affect on our revenue. +The medicine took affect within minutes. +The policy will come into affect on October 1. +The rules are now in affect. +With immediate affect, the office is closed. +The director used stunning special affects. +The placebo affect can be powerful. +We felt the ripple affect across the entire market. +The snowball affect amplified the problem. +That decision had a knock-on affect throughout the team. +The greenhouse affect warms the planet. +Her apology had little affect. +The new settings go into affect after a restart. +They put the new plan into affect last week. +The contract comes into affect at midnight. +The warning had no affect on his behavior. +Inflation had the opposite affect than expected. +The regulation remains in affect until further notice. +The app changes take affect next week. +Sound affects were added in post. + diff --git a/ripper/rules/effect_affect.txt b/ripper/rules/effect_affect.txt new file mode 100644 index 000000000..8304bc0b0 --- /dev/null +++ b/ripper/rules/effect_affect.txt @@ -0,0 +1,31 @@ +The new tariff will effect import prices next quarter. +Prolonged droughts severely effect crop yields across the valley. +Caffeine can effect your sleep architecture. +The firmware bug doesn't effect older devices. +Her sarcasm seemed to effect the team's morale. +How will this outage effect our deployment timeline? +Cold temperatures drastically effect lithium-ion battery performance. +The policy change could effect your eligibility for benefits. +These confounding variables may effect the study's results. +The noisy HVAC fans constantly effect concentration in the lab. +Stress hormones can effect immune response during recovery. +The instructor's pacing tended to effect student engagement. +Humidity levels directly effect paint curing time. +The exchange rate will surely effect the final invoice. +Screen brightness settings can effect perceived contrast. +The medication didn't effect him the way the doctor expected. +Late payments will negatively effect your credit score. +Minor wording tweaks shouldn't effect the legal interpretation. +Traffic patterns often effect delivery windows downtown. +The rumor started to effect investor confidence by noon. +Seasonal allergies badly effect her productivity each April. +Your feedback won't immediately effect the roadmap. +Fluctuating bandwidth can effect video call quality. +The temperature gradient might effect the sensor's calibration. +Even tiny delays can effect user satisfaction metrics. +The surrounding architecture can effect GPS accuracy. +Lighting conditions strongly effect color perception. +The new coach's strategy will effect players' roles. +Overtraining can effect reaction time and coordination. +The warning label may effect how consumers use the product. + diff --git a/ripper/rules/missing_noun.txt b/ripper/rules/missing_noun.txt new file mode 100644 index 000000000..5cff2d4fd --- /dev/null +++ b/ripper/rules/missing_noun.txt @@ -0,0 +1,71 @@ +I set the brittle on the mantel and held my breath. +She folded the rumpled into the suitcase before dawn. +He carried the cracked up the stairwell, wincing at each step. +We rinsed the sticky in the utility sink behind the lab. +The curator polished the tarnished until it finally glinted. +I trimmed the overgrown behind the shed after the rain. +He vacuumed the shaggy and emptied the canister twice. +She ironed the wrinkled and hung it by the foyer mirror. +They stored the fragile on a lower shelf near the wall. +I stitched the torn with invisible thread under a bright lamp. +We taped the splintered so nobody would slice a palm. +He sanded the rough until it felt almost like silk. +She repainted the flaking before the open house began. +Please quarantine the putrescent far from anything edible. +The technician centrifuged the viscous until the opaque separated. +I wrapped the friable in acid-free tissue and labeled it. +She archived the lacunose in a climate-controlled drawer. +He patched the crazed before firing the kiln again. +We decommissioned the inoperable after the safety audit. +I decanted the turbid into a clean glass column. +He sieved the granular until only the fine slipped through. +We autoclaved the contaminated and logged the cycle. +I replaced the burnt and reset the breaker without incident. +She chilled the lukewarm because the guests complained. +I boxed the dented and marked it for recycling. +She shelved the glossy beside the monographs. +He weighed the saturated and noted the delta. +We braced the warped with a temporary cleat. +The archivist humidified the desiccated before unfolding it. +I buffered the acidic until the meter steadied. +She sieved the clumpy and logged the yield. +He skimmed the congealed from the stockpot’s surface. +We decanted the limpid and discarded the cloudy. +The restorer inpainted the abraded near the signature. +I laminated the tattered under low heat. +We quarantined the infested on the loading dock. +He lubricated the squeaky and cycled the mechanism. +She sterilized the moldy and sealed the crate. +He replated the pitted after a deep polish. +We resurfaced the spalled along the balcony edge. +The tech recalibrated the erratic until drift ceased. +I compressed the springy with a bar clamp. +She neutralized the caustic before disposal. +He glazed the porous to reduce uptake. +We beveled the sharp to make it safe. +I indexed the unnumbered and added cross-references. +She rewound the tangled and replaced the leader. +He desoldered the scorched and bridged the trace. +We repotted the rootbound and watered deeply. +I culled the malformed from the tray. +She aired the musty on the veranda. +He trimmed the ragged and fitted new edging. +We archived the superseded for compliance. +I quarantined the compromised pending forensics. +He deburred the jagged along the seam. +We relabeled the ambiguous to avoid mix-ups. +I stitched the puckered and steamed it flat. +She sponged the sooty from the cornice. +We drained the brackish and refilled the cistern. +I buffered the noisy until the signal cleared. +She proofed the underbaked and slid the tray back in. +He baled the sodden and tarped the rest. +We softened the calcified with vinegar baths. +I sandbagged the eroding before the storm. +She lacquered the matte to match the trim. +He leveled the uneven with shims. +We tuned the discordant until overtones aligned. +I organized the miscellaneous into labeled bins. +She filtered the sulfurous and vented the hood. +He scrubbed the oily off the deck. + diff --git a/ripper/rules/missing_to.txt b/ripper/rules/missing_to.txt new file mode 100644 index 000000000..71b7883e6 --- /dev/null +++ b/ripper/rules/missing_to.txt @@ -0,0 +1,30 @@ +I meant call you last night. +She wants finish early. +We need talk about pricing. +They agreed meet at dawn. +He forgot send the file. +I’m trying get better at chess. +She refused answer the question. +We decided leave at once. +I hope see you again. +He managed keep calm under pressure. +Don’t forget lock the door. +She learned drive on rural roads. +He prepared leave immediately. +We’re ready start the meeting. +I’m eager see the results. +She longs hear from you. +We aim reduce costs this quarter. +He needs find a reliable partner. +They attempted salvage the prototype. +I intend finish by noon. +I neglected mention the caveat. +She endeavored maintain composure. +We struggled articulate our position. +He attempted reconcile the data. +I'm inclined believe you. +She expects hear back today. +We arranged meet at noon. +He aspires lead the team. +I resolved write daily. +She failed capture the nuance.