diff --git a/.env b/.env index f786bcd..909d742 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ BASE_URL="http://127.0.0.1:8001/v1" API_KEY="" -MODEL="unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M" +MODEL="unsloth/Qwen3.6-27B-GGUF:BF16" diff --git a/.gitignore b/.gitignore index a631419..9938a8f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .direnv/ .devenv/ .env +mutants.out/ +mutants.out.old/ diff --git a/Cargo.lock b/Cargo.lock index 1950d41..a0c1626 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # 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 = "aho-corasick" version = "1.1.4" @@ -11,24 +17,89 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "ansi_colours" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14eec43e0298190790f41679fe69ef7a829d2a2ddd78c8c00339e84710e435fe" +dependencies = [ + "rgb", +] + [[package]] name = "anstyle" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "as-any" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063" +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -63,6 +134,49 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.18", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +dependencies = [ + "arrayvec", +] + [[package]] name = "aws-lc-rs" version = "1.16.3" @@ -91,12 +205,33 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "bitstream-io" +version = "4.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +dependencies = [ + "no_std_io2", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -106,18 +241,36 @@ dependencies = [ "generic-array", ] +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.11.1" @@ -221,6 +374,22 @@ dependencies = [ "cc", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorgrad" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aee94de557db6ddae3ca7b37b5fbe77ed6f159219f1815a8c2c1a9854c73087e" +dependencies = [ + "csscolorparser", + "libm", +] + [[package]] name = "combine" version = "4.6.7" @@ -231,6 +400,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -257,6 +446,42 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[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 0.9.4", + "libc", +] + +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation 0.9.4", + "core-graphics", + "foreign-types", + "libc", +] + [[package]] name = "counter-example" version = "0.1.0" @@ -275,6 +500,15 @@ dependencies = [ "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 = "criterion" version = "0.5.1" @@ -287,7 +521,7 @@ dependencies = [ "clap", "criterion-plot", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -308,7 +542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -336,6 +570,29 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.11.1", + "crossterm_winapi", + "document-features", + "parking_lot", + "rustix", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -352,6 +609,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "csscolorparser" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199f851bd3cb5004c09474252c7f74e7c047441ed0979bf3688a7106a13da952" +dependencies = [ + "num-traits", + "phf", + "serde", +] + [[package]] name = "ctor" version = "0.1.26" @@ -368,6 +636,29 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -378,6 +669,27 @@ dependencies = [ "crypto-common", ] +[[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.61.2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -389,12 +701,42 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dwrote" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b35532432acc8b19ceed096e35dfa088d3ea037fe4f3c085f1f97f33b4d02" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "dyn-clone" version = "1.0.20" @@ -407,6 +749,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -416,6 +764,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -439,16 +807,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" dependencies = [ "futures-core", - "nom", + "nom 7.1.3", "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -465,12 +862,80 @@ dependencies = [ "tracing", ] +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +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 = "font-kit" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3" +dependencies = [ + "bitflags 2.11.1", + "byteorder", + "core-foundation 0.9.4", + "core-graphics", + "core-text", + "dirs", + "dwrote", + "float-ord", + "freetype-sys", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + +[[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 2.0.117", +] + +[[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.2" @@ -480,6 +945,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "freetype-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -617,6 +1093,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "glob" version = "0.3.3" @@ -868,6 +1354,59 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-traits", + "png 0.17.16", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png 0.18.1", + "qoi", + "ravif", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "2.14.0" @@ -878,6 +1417,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -914,6 +1464,15 @@ dependencies = [ "either", ] +[[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.18" @@ -974,6 +1533,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.95" @@ -992,12 +1557,28 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libloading" version = "0.8.9" @@ -1008,12 +1589,39 @@ dependencies = [ "windows-link", ] +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.14" @@ -1029,6 +1637,15 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -1044,6 +1661,15 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", +] + [[package]] name = "memchr" version = "2.8.0" @@ -1072,6 +1698,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "minstant" version = "0.1.7" @@ -1093,6 +1729,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "nanoid" version = "0.4.0" @@ -1102,6 +1748,21 @@ dependencies = [ "rand 0.8.6", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "no_std_io2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b51ed7824b6e07d354605f4abb3d9d300350701299da96642ee084f5ce631550" +dependencies = [ + "memchr", +] + [[package]] name = "nom" version = "7.1.3" @@ -1112,6 +1773,21 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1121,6 +1797,47 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[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-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" @@ -1128,6 +1845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1149,48 +1867,130 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "ordered-float" -version = "5.3.0" +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owo-colors" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +checksum = "4500030c302e4af1d423f36f3b958d1aecb6c04184356ed5a833bf6b60435777" dependencies = [ - "num-traits", + "rustc_version", ] [[package]] -name = "owo-colors" -version = "4.3.0" +name = "percent-encoding" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] -name = "parking_lot" -version = "0.12.5" +name = "phf" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "lock_api", - "parking_lot_core", + "phf_macros", + "phf_shared", + "serde", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "phf_generator" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", + "fastrand", + "phf_shared", ] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "phf_macros" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.117", + "uncased", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", + "uncased", +] [[package]] name = "pin-project" @@ -1218,15 +2018,26 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ + "font-kit", + "lazy_static", "num-traits", + "pathfinder_geometry", "plotters-backend", + "plotters-bitmap", "plotters-svg", + "ttf-parser", "wasm-bindgen", "web-sys", ] @@ -1237,6 +2048,16 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" +[[package]] +name = "plotters-bitmap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" +dependencies = [ + "image 0.24.9", + "plotters-backend", +] + [[package]] name = "plotters-svg" version = "0.3.7" @@ -1246,6 +2067,32 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -1283,6 +2130,61 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pxfm" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quantize-example" +version = "0.1.0" +dependencies = [ + "colorgrad", + "derive_more", + "plotters", + "rig-core", + "romu", + "symbiont", + "tokio", + "tracing", + "viuer", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quinn" version = "0.11.9" @@ -1424,6 +2326,55 @@ dependencies = [ "tracing", ] +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.4", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.18", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rgb", +] + [[package]] name = "rayon" version = "1.12.0" @@ -1450,7 +2401,18 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.11.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.17", + "libredox", + "thiserror 2.0.18", ] [[package]] @@ -1546,6 +2508,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + [[package]] name = "rig-core" version = "0.35.0" @@ -1608,6 +2579,28 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustls" version = "0.23.39" @@ -1744,7 +2737,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags", + "bitflags 2.11.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -1761,6 +2754,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1851,6 +2850,27 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "slab" version = "0.4.12" @@ -1972,7 +2992,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags", + "bitflags 2.11.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -1987,6 +3007,28 @@ dependencies = [ "libc", ] +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -2046,6 +3088,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -2169,7 +3225,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags", + "bitflags 2.11.1", "bytes", "futures-util", "http", @@ -2272,6 +3328,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + [[package]] name = "tungstenite" version = "0.23.0" @@ -2298,6 +3360,15 @@ version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + [[package]] name = "unicase" version = "2.9.0" @@ -2310,6 +3381,18 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -2340,6 +3423,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -2352,6 +3446,21 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "viuer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3a696d8afebb0cae4b263ff8cae3286b20ea88df0a82187b13ee6fe8398dce" +dependencies = [ + "ansi_colours", + "base64", + "console", + "crossterm", + "image 0.25.10", + "tempfile", + "termcolor", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -2501,6 +3610,28 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -2510,6 +3641,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-link" version = "0.2.1" @@ -2767,6 +3904,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "wit-bindgen" version = "0.57.1" @@ -2779,6 +3925,23 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "yoke" version = "0.8.2" @@ -2887,3 +4050,27 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 95db683..d291801 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ exclude = ["assets", "website"] members = [ "examples/counter", "examples/fizzbuzz", + "examples/quantize", "examples/rastrigin", "examples/sort", "examples/tictactoe", diff --git a/README.md b/README.md index f2b834b..56e7280 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ is appended to the prompt and the LLM retries automatically until it produces co ## Quick start -```rust +```rust,ignore symbiont::evolvable! { fn step(counter: &mut usize) { // default implementation body, entirely evolved by the LLM @@ -122,13 +122,14 @@ while `symbiont`'s constrained generation loop ensures the LLM output always com ## Use cases - Typed function body search (e.g., find an implementation that satisfies a test suite). - - See [fizzbuzz-example](examples/fizzbuzz/src/main.rs) - - See [rastrigin-example](examples/rastrigin/src/main.rs) + - See [fizzbuzz-example](examples/fizzbuzz/README.md) + - See [rastrigin-example](examples/rastrigin/README.md) - Performance Optimization under functional equivalence - - See [sort-example](examples/sort/src/main.rs) + - See [sort-example](examples/sort/README.md) - Game AI / strategic reasoning through evolved code - - See [tictactoe-example](examples/tictactoe/src/main.rs) + - See [tictactoe-example](examples/tictactoe/README.md) - Auto-research workflows with native-speed evaluation. + - See [quatize-example](examples/quantize/README.md) - Black-box optimization of inputs that produce desired outputs, e.g. Parameter Search. - Self-evolving feature processing pipelines. - Agentic code evolution generally. diff --git a/examples/quantize/Cargo.toml b/examples/quantize/Cargo.toml new file mode 100644 index 0000000..675a4f0 --- /dev/null +++ b/examples/quantize/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2024" +license = "MPL-2.0" +name = "quantize-example" +publish = false +version = "0.1.0" + +[dependencies] +symbiont = { path = "../../symbiont" } + +rig-core.workspace = true +romu.workspace = true +tokio.workspace = true +tracing.workspace = true + +colorgrad = { version = "0.8", features = ["preset"] } +derive_more = { version = "2", features = ["full"] } +plotters = { version = "0.3", default-features = false, features = [ + "bitmap_backend", + "bitmap_encoder", + "line_series", + "ttf", +] } +viuer = { version = "0.11", features = ["print-file"] } diff --git a/examples/quantize/README.md b/examples/quantize/README.md new file mode 100644 index 0000000..334df5f --- /dev/null +++ b/examples/quantize/README.md @@ -0,0 +1,184 @@ +# Quantize Example + +Optimal quantization via LLM-driven agentic search. +The LLM must implement a function that quantizes `f64` values into fewer +distinct levels, minimizing reconstruction error (MSE) while using as few +distinct output values as possible. + +## How it works + +1. An evolvable `fn quantize(input: &[f64], len: usize, output: &mut [f64])` + function starts as an identity copy — perfect fidelity, zero compression. +2. Each round the LLM receives the function signature, the current Pareto + frontier (with the source code that produced each point), and the last + attempt's result. +3. The runtime compiles the new implementation into a shared library in `--release` mode and + hot-swaps it in, then evaluates MSE and distinct-level count on fixed + test data, which is a laplacian distribution, samples 10_000 times, just to make it interesting. +4. Non-dominated (num_levels, MSE) pairs are tracked on a Pareto frontier + that grows across rounds. + +The prompt is structured into clear sections (Task, Constraints, Goal, +Current Frontier, Last Attempt, Direction) so the LLM can make informed +trade-offs rather than searching blindly. + +## Running + +```sh +cargo run -p quantize-example +``` + +Requires `API_KEY`, `BASE_URL`, and `MODEL` environment variables (or a +`.env` file) for the LLM backend. + +## Possible Improvements (Left as an excercise to the reader): +- Compare against some baseline algorithms (Uniform, Symmetric, Asymmetric, etc, who knows) +- Run on different input distributions to get specialized schemes. +- Prompting changes / context engineering might help the Agent reach better implementations. +- Try different SOTA models. `unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M` might be sub-optimal here. +- Run for more than 20 generations. +- Store the pareto frontier code somewhere for later retrieval (Not just printing it to stdout.) +- More rigorous evaluation procedure (Runtime is dominated by inference latency). +- Better progression plots, etc. + +## Pareto frontier progression + +The plot below shows how the frontier evolves over 20 rounds on a Laplacian +distribution with 10,000 samples. Each coloured line is the frontier snapshot +after that round. The x-axis (log2) is the number of distinct output levels; +the y-axis is MSE. +Model used is `unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M` running with `llama-cpp` on an `RTX Pro 6000 Blackwell (96GB)` + +![Pareto Frontier Progression](pareto_frontier.png) + +## Another Run (color, prompting and model change) + +Now with `unsloth/Qwen3.6-27B-GGUF:BF16` + +![Pareto Frontier Progression 2](run-2-new-colors.png) + +### Output: + +Evolution complete after 20 rounds. +Final aggregate Pareto frontier: +Laplacian frontier: +| Distinct levels | Bits/value | MSE | Round | +|-----------------|------------|------------|-------| +| 64 | 6.0 | 5.6879e-3 | 18 | +| 128 | 7.0 | 4.3793e-3 | 5 | +| 162 | 8.0 | 5.0992e-4 | 3 | +| 10000 | 14.0 | 0.0000e0 | 0 | + +Last implementation: +```rust +#[unsafe(no_mangle)] +pub fn quantize(input: &[f64], len: usize, output: &mut [f64]) { + if len == 0 { + return; + } + if len == 1 { + output[0] = input[0]; + return; + } + let mut data: Vec<(f64, usize)> = input + .iter() + .take(len) + .enumerate() + .map(|(i, &v)| (v, i)) + .collect(); + data.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal)); + let k = 64; + let k = if len < k { len } else { k }; + if k <= 1 { + let mean = data.iter().map(|&(v, _)| v).sum::() / len as f64; + for &(_, idx) in &data { + output[idx] = mean; + } + return; + } + let min_v = data[0].0; + let max_v = data[len - 1].0; + let range = max_v - min_v; + if range.abs() < f64::EPSILON { + for &(_, idx) in &data { + output[idx] = min_v; + } + return; + } + let mut centroids: Vec = Vec::with_capacity(k); + let chunk = len / k; + for i in 0..k { + let start = i * chunk; + let end = if i == k - 1 { len } else { (i + 1) * chunk }; + let mut sum = 0.0_f64; + for j in start..end { + sum += data[j].0; + } + centroids.push(sum / (end - start) as f64); + } + let eps = range.abs().max(1.0) * 1e-12; + centroids.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)); + for i in 1..k { + if centroids[i] <= centroids[i - 1] { + centroids[i] = centroids[i - 1] + eps; + } + } + let mut counts = vec![0usize; k]; + let mut sums = vec![0.0_f64; k]; + let mut empty_bins: Vec = Vec::with_capacity(k); + let tol = range.abs() * 1e-14; + for _ in 0..200 { + counts.fill(0); + sums.fill(0.0); + empty_bins.clear(); + let mut bin = 0; + for i in 0..len { + let v = data[i].0; + while bin < k - 1 && v >= (centroids[bin] + centroids[bin + 1]) * 0.5 { + bin += 1; + } + counts[bin] += 1; + sums[bin] += v; + } + let mut max_shift = 0.0; + for i in 0..k { + if counts[i] > 0 { + let new_c = sums[i] / counts[i] as f64; + let shift = (new_c - centroids[i]).abs(); + if shift > max_shift { + max_shift = shift; + } + centroids[i] = new_c; + } else { + empty_bins.push(i); + } + } + for &i in &empty_bins { + if i == 0 { + centroids[i] = centroids[1] - eps; + } else if i == k - 1 { + centroids[i] = centroids[k - 2] + eps; + } else { + centroids[i] = (centroids[i - 1] + centroids[i + 1]) * 0.5; + } + } + centroids.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)); + for i in 1..k { + if centroids[i] <= centroids[i - 1] { + centroids[i] = centroids[i - 1] + eps; + } + } + if max_shift <= tol { + break; + } + } + let mut bin = 0; + for i in 0..len { + let v = data[i].0; + while bin < k - 1 && v >= (centroids[bin] + centroids[bin + 1]) * 0.5 { + bin += 1; + } + output[data[i].1] = centroids[bin]; + } +} +``` diff --git a/examples/quantize/pareto_frontier.png b/examples/quantize/pareto_frontier.png new file mode 100644 index 0000000..b0a92e8 Binary files /dev/null and b/examples/quantize/pareto_frontier.png differ diff --git a/examples/quantize/run-2-new-colors.png b/examples/quantize/run-2-new-colors.png new file mode 100644 index 0000000..37ad304 Binary files /dev/null and b/examples/quantize/run-2-new-colors.png differ diff --git a/examples/quantize/src/main.rs b/examples/quantize/src/main.rs new file mode 100644 index 0000000..998a610 --- /dev/null +++ b/examples/quantize/src/main.rs @@ -0,0 +1,537 @@ +// SPDX-License-Identifier: MPL-2.0 +//! Optimal quantization: discover the best compression–fidelity trade-off. +//! +//! The LLM must implement a function that quantizes f64 values into fewer +//! distinct levels, minimizing reconstruction error (MSE) while using as +//! few distinct output values as possible. +//! +//! The default implementation copies the input unchanged — perfect fidelity +//! but zero compression. The LLM must discover quantization schemes that +//! reduce the number of distinct output values while keeping MSE low. +//! +//! Each round: +//! 1. Call the evolvable `quantize` function on data from a specific distribution. +//! 2. Measure MSE (reconstruction error) and count distinct output values. +//! 3. Update the Pareto frontier of (num_levels, MSE) trade-offs. +//! 4. Feed the frontier and per-distribution results back to the LLM. +//! +//! The Pareto frontier tracks non-dominated (num_levels, MSE) pairs across +//! all rounds, showing the LLM which trade-offs have been achieved and +//! challenging it to push the frontier further. + +use std::{ + collections::HashSet, + fmt::Display, +}; + +use colorgrad::Gradient; +use plotters::prelude::*; +use romu::Rng; +use symbiont::Runtime; +use tracing::{ + info, + warn, +}; + +/// Number of values per distribution. +const SAMPLE_LEN: usize = 10_000; + +// Default: identity copy — zero error, zero compression. +// The LLM must evolve this into an actual quantization scheme. +symbiont::evolvable! { + fn quantize(input: &[f64], len: usize, output: &mut [f64]) { + for i in 0..len { + output[i] = input[i]; + } + } +} + +// -- Data distributions ------------------------------------------------------ + +/// The specific input distribution to create a quantization for. +#[derive(Debug, Clone, Copy, derive_more::Display)] +#[expect( + dead_code, + reason = "Leave this in to manually play with input distributions." +)] +enum Distribution { + Uniform, + Gaussian, + Bimodal, + Laplacian, + LogNormal, +} + +impl Distribution { + fn generate(&self, len: usize, rng: &Rng) -> Vec { + use Distribution::*; + match self { + Uniform => Vec::from_iter((0..len).map(|_| rng.f64() * 2.0 - 1.0)), + Gaussian => Vec::from_iter((0..len).map(|_| { + let u1 = rng.f64().max(1e-15); + let u2 = rng.f64(); + (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos() + })), + Bimodal => Vec::from_iter((0..len).map(|_| { + let u1 = rng.f64().max(1e-15); + let u2 = rng.f64(); + let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos(); + if rng.f64() < 0.5 { + -2.0 + 0.5 * z + } else { + 2.0 + 0.5 * z + } + })), + Laplacian => Vec::from_iter((0..len).map(|_| { + let u = rng.f64() - 0.5; + -u.signum() * (1.0 - 2.0 * u.abs()).max(1e-15).ln() + })), + LogNormal => Vec::from_iter((0..len).map(|_| { + let u1 = rng.f64().max(1e-15); + let u2 = rng.f64(); + let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos(); + z.exp() + })), + } + } +} + +// -- Evaluation -------------------------------------------------------------- + +/// Result of evaluating the quantize function on one distribution. +struct EvalResult { + distr: Distribution, + mse: f64, + num_distinct: usize, + bits_per_value: f64, + panic: Option, +} + +fn count_distinct(data: &[f64]) -> usize { + let mut seen = HashSet::with_capacity(data.len()); + for &v in data { + seen.insert(v.to_bits()); + } + seen.len() +} + +fn evaluate(runtime: &Runtime, input: &[f64], distr: Distribution) -> EvalResult { + let mut output = vec![0.0f64; input.len()]; + quantize(input, input.len(), &mut output); + match runtime.take_panic() { + None => { + let mse = input + .iter() + .zip(output.iter()) + .map(|(a, b)| (a - b) * (a - b)) + .sum::() + / input.len() as f64; + let num_distinct = count_distinct(&output); + let bits_per_value = required_bits(num_distinct); + EvalResult { + distr, + mse, + num_distinct, + bits_per_value, + panic: None, + } + } + Some(msg) => EvalResult { + distr, + mse: f64::INFINITY, + num_distinct: 0, + bits_per_value: 0.0, + panic: Some(msg), + }, + } +} + +// -- Pareto frontier --------------------------------------------------------- + +/// A point on the Pareto frontier: (num_distinct, mse) from a given round, +/// together with the source code that produced it. +#[derive(Clone)] +struct ParetoPoint { + round: usize, + num_distinct: usize, + mse: f64, + code: String, +} + +#[inline] +fn required_bits(num_distinct: usize) -> f64 { + if num_distinct <= 1 { + 0.0 + } else { + (num_distinct as f64).log2().ceil() + } +} + +/// Maintains the Pareto frontier of (num_distinct, mse) trade-offs. +/// +/// A point is non-dominated if no other point has both fewer (or equal) +/// distinct values AND lower (or equal) MSE. +struct ParetoFrontier { + points: Vec, +} + +impl ParetoFrontier { + fn new() -> Self { + Self { points: Vec::new() } + } + + /// Add a candidate point. Returns true if it was added to the frontier + /// (i.e. it is non-dominated). + fn add(&mut self, point: ParetoPoint) -> bool { + // Check if dominated by any existing point. + let dominated = self.points.iter().any(|p| { + p.num_distinct <= point.num_distinct + && p.mse <= point.mse + && (p.num_distinct < point.num_distinct || p.mse < point.mse) + }); + if dominated { + return false; + } + + // Remove points dominated by the new one. + self.points.retain(|p| { + !(point.num_distinct <= p.num_distinct + && point.mse <= p.mse + && (point.num_distinct < p.num_distinct || point.mse < p.mse)) + }); + + self.points.push(point); + self.points.sort_by_key(|p| p.num_distinct); + true + } + + /// Snapshot the current frontier as (num_distinct, mse) pairs. + fn snapshot(&self) -> Vec<(f64, f64)> { + Vec::from_iter(self.points.iter().map(|p| (p.num_distinct as f64, p.mse))) + } + + fn format_table(&self) -> String { + if self.points.is_empty() { + return String::from("(no valid points yet)\n"); + } + let mut table = String::from( + "| Distinct levels | Bits/value | MSE | Round |\n\ + |-----------------|------------|------------|-------|\n", + ); + for p in &self.points { + let bits = if p.num_distinct <= 1 { + 0.0 + } else { + (p.num_distinct as f64).log2().ceil() + }; + table.push_str(&format!( + "| {:>15} | {:>10.1} | {:>10.4e} | {:>5} |\n", + p.num_distinct, bits, p.mse, p.round, + )); + } + table + } + + /// Format each frontier entry with its source code so the LLM can see + /// *how* each trade-off was achieved. + fn format_with_code(&self) -> String { + if self.points.is_empty() { + return String::from("(no valid points yet)\n"); + } + let mut s = String::new(); + for p in &self.points { + let bits = required_bits(p.num_distinct); + s.push_str(&format!( + "### {} distinct | {:.1} bits/value | MSE {:.4e} (round {})\n```rust\n{}\n```\n\n", + p.num_distinct, bits, p.mse, p.round, p.code, + )); + } + s + } +} + +// -- Reporting --------------------------------------------------------------- + +impl Display for EvalResult { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "| Distribution | Distinct | Bits/val | MSE |\n\ + |--------------|----------|----------|------------|\n", + )?; + + if self.panic.is_some() { + writeln!( + f, + "| {:<12} | PANIC | | |", + self.distr.to_string() + )?; + } else { + writeln!( + f, + "| {:<12} | {:>8} | {:>8.1} | {:>10.4e} |", + self.distr.to_string(), + self.num_distinct, + self.bits_per_value, + self.mse, + )?; + } + + Ok(()) + } +} + +// -- Plotting ---------------------------------------------------------------- + +/// Render the Pareto frontier progression to a PNG and display it with `viuer`. +fn plot_frontier_progression( + history: &[(usize, Vec<(f64, f64)>)], +) -> Result<(), Box> { + // Collect all points to determine axis ranges. + let all_points = + Vec::<(f64, f64)>::from_iter(history.iter().flat_map(|(_, pts)| pts.iter().copied())); + if all_points.is_empty() { + println!("No Pareto frontier data to plot."); + return Ok(()); + } + + let x_min = 16_f64; + let x_max = 10_000_f64; + let y_min = 0_f64; + let y_max = 0.035; + + // Add some padding to the ranges. + let x_lo = (x_min / 1.5).max(1.0); + let x_hi = x_max * 1.5; + let y_pad = (y_max - y_min).max(1e-10) * 0.08; + + let path = std::env::temp_dir().join("quantize_pareto.png"); + { + let root = BitMapBackend::new(&path, (2048, 2048)).into_drawing_area(); + root.fill(&WHITE)?; + + let mut chart = ChartBuilder::on(&root) + .caption( + "Pareto Frontier Progression", + ("sans-serif", 22).into_font().with_color(BLACK), + ) + .margin(10) + .x_label_area_size(40) + .y_label_area_size(60) + .build_cartesian_2d( + (x_lo..x_hi).log_scale().base(2.0), + (y_min - y_pad)..(y_max + y_pad), + )?; + + chart + .configure_mesh() + .x_desc("Distinct levels") + .y_desc("MSE") + .draw()?; + + let grad = colorgrad::preset::turbo(); + for (round, pts) in history { + let color = grad.at(*round as f32 / history.len() as f32).to_rgba8(); + let color = RGBColor(color[0], color[1], color[2]); + let label = format!("Round {round}"); + + // Draw the frontier line + points for this generation. + let mut sorted = pts.clone(); + sorted.sort_by(|a, b| a.0.partial_cmp(&b.0).expect("finite")); + + chart + .draw_series(LineSeries::new( + sorted.iter().copied(), + color.stroke_width(2), + ))? + .label(&label) + .legend(move |(x, y)| { + Rectangle::new([(x, y - 4), (x + 14, y + 4)], color.filled()) + }); + + chart.draw_series( + sorted + .iter() + .map(|&(x, y)| Circle::new((x, y), 4, color.filled())), + )?; + } + + chart + .configure_series_labels() + .background_style(WHITE.mix(0.8)) + .border_style(BLACK) + .position(SeriesLabelPosition::UpperRight) + .draw()?; + + root.present()?; + } + println!("Plot saved to: {}", path.display()); + + // Display in terminal via viuer. + let conf = viuer::Config { + width: Some(80), + absolute_offset: false, + ..Default::default() + }; + viuer::print_from_file(&path, &conf)?; + + Ok(()) +} + +// -- Main -------------------------------------------------------------------- + +#[tokio::main] +async fn main() -> symbiont::Result<()> { + symbiont::init_tracing(); + + let runtime = Runtime::init(SYMBIONT_DECLS, symbiont::Profile::Release).await?; + let fn_sigs = runtime.fn_sigs(); + info!("fn_sigs: {fn_sigs:?}"); + + let agent = symbiont::inference::init_agent()?; + + // Fixed test data — identical across rounds for fair comparison. + let rng = Rng::from_seed_with_64bit(42); + let distr = Distribution::Laplacian; + let dist_data = distr.generate(SAMPLE_LEN, &rng); + + let mut frontier = ParetoFrontier::new(); + + // Frontier snapshots per round for the final progression plot. + let mut frontier_history: Vec<(usize, Vec<(f64, f64)>)> = Vec::new(); + + // -- Round 0: evaluate the default (identity copy) ----------------------- + println!("\n=== Round 0: default implementation (identity copy) ==="); + let mut result: EvalResult = evaluate(runtime, &dist_data, distr); + println!("{result}"); + + // Seed frontiers with round 0 data. + if result.panic.is_none() { + frontier.add(ParetoPoint { + round: 0, + num_distinct: result.num_distinct, + mse: result.mse, + code: "for i in 0..len {\n output[i] = input[i];\n}".into(), + }); + frontier_history.push((0, frontier.snapshot())); + } + + // -- Evolution loop ------------------------------------------------------ + let max_rounds = 20; + let mut prev_code = String::new(); + + for round in 1..=max_rounds { + println!("\n=== Round {round}: evolving via LLM ==="); + + let sig = &fn_sigs[0]; + + let prompt = if let Some(ref panic_msg) = result.panic { + let last_attempt = if prev_code.is_empty() { + String::new() + } else { + format!("## Last Attempt\n```rust\n{prev_code}\n```\n\n") + }; + format!( + "## Task\n\ + Implement this function that quantizes `len` input values, writing \ + the reconstructed (quantized) values into `output`:\n\ + ```\n{sig}\n```\n\n\ + ## Constraints\n\ + - No external crates — only `std` and built-in operations.\n\ + - `input` and `output` are the same length; `len` gives the count.\n\ + - The function must not panic or crash for any input.\n\n\ + {last_attempt}\ + ## Runtime Panic\n\ + - {panic_msg}\n\n\ + Fix the panic. Rust code only.", + ) + } else { + let last_attempt = if prev_code.is_empty() { + String::new() + } else { + format!( + "## Last Attempt\n\ + ```rust\n{prev_code}\n```\n\ + Result: {result}\n\n", + ) + }; + format!( + "## Task\n\ + Implement this function that quantizes `len` input values, writing \ + the reconstructed (quantized) values into `output`:\n\ + ```\n{sig}\n```\n\n\ + ## Constraints\n\ + - No external crates — only `std` and built-in operations.\n\ + - `input` and `output` are the same length; `len` gives the count.\n\n\ + ## Goal\n\ + Minimize the number of distinct values in `output` (compression) while \ + minimizing reconstruction error (MSE).\n\ + - Fewer distinct output values = better compression (fewer bits per value)\n\ + - Lower MSE = better reconstruction quality\n\ + - The ideal solution adaptively chooses quantization bin boundaries \ + based on the input data distribution\n\n\ + ## Current Frontier ({distr}, {SAMPLE_LEN} samples)\n\ + {frontier}\n\ + {last_attempt}\ + ## Direction\n\ + Push the Pareto frontier: find solutions with fewer distinct levels at \ + the same or lower MSE, or lower MSE at the same number of levels. \ + Rust code only.", + frontier = frontier.format_with_code(), + ) + }; + + runtime + .evolve(&agent, &prompt) + .await + .expect("evolution should succeed"); + + prev_code = runtime + .read_clean_code() + .expect("failed to read generated code"); + + result = evaluate(runtime, &dist_data, distr); + println!("{result}"); + + // Update frontier. + if result.panic.is_none() { + frontier.add(ParetoPoint { + round, + num_distinct: result.num_distinct, + mse: result.mse, + code: prev_code.clone(), + }); + } + + // Always snapshot the frontier state after each round. + frontier_history.push((round, frontier.snapshot())); + } + + // -- Summary ------------------------------------------------------------- + println!("\nEvolution complete after {max_rounds} rounds."); + println!("Final aggregate Pareto frontier:"); + println!("{distr} frontier:"); + println!("{}", frontier.format_table()); + + if !prev_code.is_empty() { + println!("Last implementation:\n```rust\n{prev_code}```",); + } + + // Plot the Pareto frontier progression across generations. + if let Err(e) = plot_frontier_progression(&frontier_history) { + warn!("Failed to render Pareto frontier plot: {e}"); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_plot_frontier() { + let history = vec![(0, vec![(1.0, 2.0)])]; + plot_frontier_progression(&history).expect("Can plot") + } +} diff --git a/flake.nix b/flake.nix index 902369b..7fa5dc4 100644 --- a/flake.nix +++ b/flake.nix @@ -32,7 +32,10 @@ } ); - buildInputs = [ + buildInputs = with pkgs; [ + fontconfig + liberation_ttf + pkg-config rust ]; lsps = with pkgs; [ diff --git a/symbiont/src/compiler.rs b/symbiont/src/compiler.rs index 5b47180..c6b621a 100644 --- a/symbiont/src/compiler.rs +++ b/symbiont/src/compiler.rs @@ -2,12 +2,22 @@ use std::path::Path; use minstant::Instant; +use prettyplease::unparse; use tokio::process::Command; -use tracing::info; +use tracing::{ + debug, + info, +}; -use crate::error::{ - Error, - Result, +use crate::{ + error::{ + Error, + Result, + }, + unwind::{ + PANIC_PREAMBLE, + wrap_bodies_in_catch_unwind, + }, }; /// Compilation profile for the evolvable dylib. @@ -38,16 +48,32 @@ impl std::fmt::Display for Profile { /// Runs `cargo build --manifest-path /Cargo.toml`, /// adding `--release` when the profile is [`Profile::Release`]. /// Blocks (async) until compilation finishes. -pub(crate) async fn compile_dylib(crate_dir: &Path, profile: Profile) -> Result<()> { +pub(crate) async fn compile_dylib( + crate_dir: &Path, + profile: Profile, + clean_ast: &mut syn::File, +) -> Result<()> { let t0 = Instant::now(); - let manifest_path = crate_dir.join("Cargo.toml"); + let clean_code = unparse(clean_ast); + debug!("clean_code: {clean_code}"); + let clean_path = crate_dir.join("src").join("clean.rs"); + std::fs::write(&clean_path, &clean_code) + .map_err(|e| Error::WriteLib(format!("Failed to write clean.rs: {e}")))?; + + // Wrap function bodies in catch_unwind so panics stay inside the dylib. + wrap_bodies_in_catch_unwind(clean_ast); + // Write final lib.rs (preamble + wrapped code) for compilation. + let formatted = format!("{PANIC_PREAMBLE}\n{}", unparse(clean_ast)); + std::fs::write(crate_dir.join("src").join("lib.rs"), formatted)?; + info!("Created temp dylib crate at {}", crate_dir.display()); + + let manifest_path = crate_dir.join("Cargo.toml"); info!( "Compiling evolvable dylib ({profile}) at {}...", manifest_path.display() ); - let manifest_str = manifest_path.to_string_lossy(); let mut args = vec!["build", "--manifest-path", &manifest_str]; if profile == Profile::Release { @@ -58,7 +84,10 @@ pub(crate) async fn compile_dylib(crate_dir: &Path, profile: Profile) -> Result< .args(&args) .output() .await - .map_err(|e| Error::CompilationFailed(format!("Failed to spawn cargo: {e}")))?; + .map_err(|e| Error::CompilationFailed { + code: clean_code.clone(), + err: format!("Failed to spawn cargo: {e}"), + })?; if output.status.success() { info!( @@ -67,7 +96,10 @@ pub(crate) async fn compile_dylib(crate_dir: &Path, profile: Profile) -> Result< ); Ok(()) } else { - let stderr = String::from_utf8_lossy(&output.stderr).to_string(); - Err(Error::CompilationFailed(stderr)) + let err = String::from_utf8_lossy(&output.stderr).to_string(); + Err(Error::CompilationFailed { + code: clean_code.clone(), + err, + }) } } diff --git a/symbiont/src/error.rs b/symbiont/src/error.rs index 234191e..ad253e5 100644 --- a/symbiont/src/error.rs +++ b/symbiont/src/error.rs @@ -26,15 +26,11 @@ pub enum Error { #[error("Failed to write lib.rs: {0}")] WriteLib(String), - #[error("Validation failed: signature mismatch for '{name}'. Expected: {expected}. Got: {got}")] - SignatureMismatch { - name: String, - expected: String, - got: String, - }, - - #[error("Compilation failed:\n{0}")] - CompilationFailed(String), + #[error("Validation failed: signature mismatch. Expected: {expected}")] + SignatureMismatch { code: String, expected: String }, + + #[error("Compilation failed:\n{err}")] + CompilationFailed { code: String, err: String }, #[error("No evolvable functions found. Use the evolvable! macro to declare at least one.")] NoEvolvableFunctions, diff --git a/symbiont/src/runtime.rs b/symbiont/src/runtime.rs index f2c8b91..e0e6111 100644 --- a/symbiont/src/runtime.rs +++ b/symbiont/src/runtime.rs @@ -55,10 +55,6 @@ use crate::{ Result, }, parser::parse_rust_code, - unwind::{ - PANIC_PREAMBLE, - wrap_bodies_in_catch_unwind, - }, validation::validate_generated_ast, }; @@ -199,11 +195,10 @@ impl Runtime { // Write src/lib.rs from all default_source entries let lib_rs = generate_lib_rs(decls); - std::fs::write(crate_dir.join("src").join("lib.rs"), &lib_rs)?; - info!("Created temp dylib crate at {}", crate_dir.display()); + let mut ast = syn::parse_str(&lib_rs)?; // Compile - compile_dylib(&crate_dir, profile).await?; + compile_dylib(&crate_dir, profile, &mut ast).await?; // Find and load the .so let so_path = find_so(&crate_dir, profile)?; @@ -269,33 +264,15 @@ impl Runtime { let llm_time = t0.elapsed().as_millis(); info!("llm_response: {}", llm_response.blue()); - let t0 = Instant::now(); // Parse Rust from markdown fences let mut ast = parse_rust_code(&llm_response).map_err(|_| Error::CouldNotParseRust)?; // Validate signatures match declarations validate_generated_ast(&mut ast, &self.fn_sigs)?; - // Save the clean (unwrapped) LLM code for display / prompt feedback. - let clean_code = prettyplease::unparse(&ast); - let clean_path = self.crate_dir.join("src").join("clean.rs"); - std::fs::write(&clean_path, &clean_code) - .map_err(|e| Error::WriteLib(format!("Failed to write clean.rs: {e}")))?; - - // Wrap function bodies in catch_unwind so panics stay inside the dylib. - wrap_bodies_in_catch_unwind(&mut ast); - - // Write final lib.rs (preamble + wrapped code) for compilation. - let lib_rs_path = self.crate_dir.join("src").join("lib.rs"); - let formatted = format!("{PANIC_PREAMBLE}\n{}", prettyplease::unparse(&ast)); - std::fs::write(&lib_rs_path, &formatted) - .map_err(|e| Error::WriteLib(format!("Failed to write lib.rs: {e}")))?; - info!("Wrote evolved lib.rs to {}", lib_rs_path.display()); - let validation_time = t0.elapsed().as_millis(); - // Recompile let t0 = Instant::now(); - compile_dylib(&self.crate_dir, self.profile).await?; + compile_dylib(&self.crate_dir, self.profile, &mut ast).await?; let compile_time = t0.elapsed().as_millis(); // Copy .so to versioned path to defeat dlopen caching @@ -321,7 +298,7 @@ impl Runtime { *self.library.lock().expect("library Mutex poisoned") = Some(new_lib); info!( - "Hot-reloaded evolvable dylib (version {version}). Timings: LLM generation: {llm_time}ms, validation: {validation_time}ms, compilation: {compile_time}ms.", + "Hot-reloaded evolvable dylib (version {version}). Timings: LLM generation: {llm_time}ms, compilation: {compile_time}ms.", ); Ok(()) @@ -363,14 +340,13 @@ impl Runtime { ), WriteLib(_) => todo!(), SignatureMismatch { - name: _, + code, expected, - got, } => write!(prompt, - " Generated function signature miss-match. Expected ```{expected}```, Got ```{}```", got.red() + " Generated function signature miss-match. Expected ```{expected}```, Got Code ```{code}```", ).expect("Can write to prompt"), - CompilationFailed(ref stderr) => write!(prompt, - " The generated code failed to compile. Compiler output:\n```\n{}\n```\nPlease fix the compilation errors.", stderr.red() + CompilationFailed{code, err} => write!(prompt, + " Your generated code ```{}``` failed to compile. Compiler output:\n```\n{}\n```\nPlease fix the compilation errors.", code.blue(), err.red() ).expect("Can write to prompt"), e => { warn!("Unhandled error: {e}"); @@ -441,7 +417,7 @@ panic = "unwind" } fn generate_lib_rs(decls: &[EvolvableDecl]) -> String { - let mut src = PANIC_PREAMBLE.to_string(); + let mut src = String::with_capacity(1_000); for d in decls { src.push_str(d.default_source); src.push_str("\n\n"); diff --git a/symbiont/src/unwind.rs b/symbiont/src/unwind.rs index 08d7669..075d0dd 100644 --- a/symbiont/src/unwind.rs +++ b/symbiont/src/unwind.rs @@ -98,3 +98,41 @@ pub unsafe fn __symbiont_take_panic(buf: *mut u8, buf_len: usize) -> usize { } } "#; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_wrap_bodies_in_catch_unwind() { + let mut file: syn::File = syn::parse_str( + " + fn step(counter: &mut usize) { + panic!() + } + ", + ) + .expect("Can parse"); + wrap_bodies_in_catch_unwind(&mut file); + assert_eq!( + &prettyplease::unparse(&file), + r#"fn step(counter: &mut usize) { + match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { panic!() })) { + Ok(__symbiont_val) => __symbiont_val, + Err(__symbiont_err) => { + let __symbiont_msg = if let Some(s) = __symbiont_err.downcast_ref::<&str>() { + *s + } else if let Some(s) = __symbiont_err.downcast_ref::() { + s.as_str() + } else { + "unknown panic" + }; + __symbiont_store_panic(__symbiont_msg); + unsafe { ::core::mem::zeroed() } + } + } +} +"# + ); + } +} diff --git a/symbiont/src/validation.rs b/symbiont/src/validation.rs index 4a8e97a..8ba8915 100644 --- a/symbiont/src/validation.rs +++ b/symbiont/src/validation.rs @@ -1,3 +1,4 @@ +use prettyplease::unparse; // SPDX-License-Identifier: MPL-2.0 use quote::ToTokens; use syn::{ @@ -28,7 +29,7 @@ pub(crate) fn validate_generated_ast(file: &mut syn::File, expected_sigs: &[Stri return Ok(()); } - let mut found_sigs: Vec = Vec::new(); + let mut found_sigs: Vec = Vec::with_capacity(4); for item in &mut file.items { if let syn::Item::Fn(item_fn) = item { @@ -50,31 +51,14 @@ pub(crate) fn validate_generated_ast(file: &mut syn::File, expected_sigs: &[Stri let sig = format_signature(&item_fn.sig) .unwrap_or_else(|| format!("fn {}(...)", item_fn.sig.ident)); found_sigs.push(sig.clone()); - - if !expected_sigs.contains(&sig) { - let expected = expected_sigs.join(", "); - return Err(Error::SignatureMismatch { - name, - expected, - got: sig, - }); - } } } - // Ensure all expected signatures were found for expected in expected_sigs { if !found_sigs.contains(expected) { - // Try to extract function name for a better error message - let name = expected - .trim_start_matches("fn ") - .split('(') - .next() - .unwrap_or("unknown"); return Err(Error::SignatureMismatch { - name: name.to_string(), + code: unparse(file), expected: expected.clone(), - got: "not found".to_string(), }); } } @@ -213,11 +197,17 @@ pub fn add(a: i32, b: i32) -> i32 { let mut file = parse_rust_code(input).unwrap(); let expected = vec!["fn step(counter: &mut usize)".to_string()]; let err = validate_generated_ast(&mut file, &expected).unwrap_err(); - let msg = format!("{err}"); - assert!( - msg.contains("step") && msg.contains("add"), - "expected signature mismatch error, got: {msg}" - ); + dbg!(&err); + match err { + Error::SignatureMismatch { code, expected } => { + assert_eq!( + &code, + "#[unsafe(no_mangle)]\npub fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n" + ); + assert_eq!(expected, "fn step(counter: &mut usize)"); + } + _ => panic!("Invalid error"), + } } #[test]