diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..74b2ef13cda0025d642710c32bdd1f8b109aedc4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/target +__pycache__/ +*.so +*.egg-info/ +dist/ +dados/shard_*.jsonl +logs/ +*.log diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..f2810e22c7f76e5c148183c81ef2cfcb024572be --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1813 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arc-swap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380962b3d93b99642e50b9febf72c071e97e8b32d86eae9cf4ef582bb960ae6e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "built" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "candle-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecb245093b0f791b89d3420c3df9c6d49c60ab63ba54db896bf8a3baf486706" +dependencies = [ + "byteorder", + "float8", + "gemm", + "half", + "libc", + "libm", + "memmap2", + "num-traits", + "num_cpus", + "rand 0.9.5", + "rand_distr", + "rayon", + "safetensors", + "thiserror 2.0.21", + "tokenizers", + "yoke", + "zerocopy", + "zip", +] + +[[package]] +name = "candle-nn" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa10b6ccc365b33210ce404fbf45e60d3e0bdac1004463cf1052e6ee1c1739a" +dependencies = [ + "candle-core", + "half", + "libc", + "num-traits", + "rayon", + "safetensors", + "serde", + "thiserror 2.0.21", +] + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877bf67ac8e52449eb2f9e98a344ea163beb70dd1f9eebe3cc5357dcfeaee4df" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "crc32fast" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba106e844045ddc02c20768ac4b0b7cb45f2cc2ecbd833ac9f5dacb183c2055" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[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 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dary_heap" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe" +dependencies = [ + "serde", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.119", +] + +[[package]] +name = "dict_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "846a520b3b7937dcfe564d9674d2d26da9e3cd0f8f1bbef51ca42fd6b7bb4f4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dyn-stack" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8" +dependencies = [ + "bytemuck", + "dyn-stack-macros", +] + +[[package]] +name = "dyn-stack-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" + +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" + +[[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 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "esaxx-rs" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "float8" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc" +dependencies = [ + "half", + "num-traits", + "rand 0.9.5", + "rand_distr", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gemm" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb" +dependencies = [ + "dyn-stack", + "gemm-c32", + "gemm-c64", + "gemm-common", + "gemm-f16", + "gemm-f32", + "gemm-f64", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e" +dependencies = [ + "bytemuck", + "dyn-stack", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp", + "raw-cpuid", + "rayon", + "seq-macro", + "sysctl", +] + +[[package]] +name = "gemm-f16" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e" +dependencies = [ + "dyn-stack", + "gemm-common", + "gemm-f32", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", + "num-traits", + "rand 0.9.5", + "rand_distr", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", + "serde_core", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "indoc" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37b2691796cffeb8a8cd305ac66e65841559f147f4e63231d0eafa4db5384d1" +dependencies = [ + "rustversion", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "khtst-rust" +version = "0.1.11" +dependencies = [ + "anyhow", + "built", + "candle-core", + "candle-nn", + "crossbeam-channel", + "dict_derive", + "log", + "numpy", + "pyo3", + "pyo3-async-runtimes", + "pyo3-built", + "pyo3-log", + "pythonize", + "rand 0.8.8", + "rayon", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", +] + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "macro_rules_attribute" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ae8f6d608c795738406608304d30a2dfbdc8e58e44f7ba43236da5208ded3c" +dependencies = [ + "macro_rules_attribute-proc_macro", + "pastey", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc04a4c58212d57930a24bf47d3fa87485264a3a054e9c10e042eb373573ad3c" + +[[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "monostate" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" +dependencies = [ + "monostate-impl", + "serde", + "serde_core", +] + +[[package]] +name = "monostate-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[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.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "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 = "numpy" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94caae805f998a07d33af06e6a3891e38556051b8045c615470a71590e13e78" +dependencies = [ + "libc", + "ndarray", + "num-complex", + "num-integer", + "num-traits", + "pyo3", + "rustc-hash", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "onig" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2" +dependencies = [ + "bitflags", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e68317604e77e53b85896388e1a803c1d21b74c899ec9e5e1112db90735edd7" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulp" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" + +[[package]] +name = "pyo3" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-async-runtimes" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977dc837525cfd22919ba6a831413854beb7c99a256c03bf8624ad707e45810e" +dependencies = [ + "futures", + "once_cell", + "pin-project-lite", + "pyo3", + "tokio", +] + +[[package]] +name = "pyo3-build-config" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-built" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ee655adc94166665a1d714b439e27857dd199b947076891d6a17d32d396cde" + +[[package]] +name = "pyo3-ffi" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-log" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45192e5e4a4d2505587e27806c7b710c231c40c56f3bfc19535d0bb25df52264" +dependencies = [ + "arc-swap", + "log", + "pyo3", +] + +[[package]] +name = "pyo3-macros" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pythonize" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91a6ee7a084f913f98d70cdc3ebec07e852b735ae3059a1500db2661265da9ff" +dependencies = [ + "pyo3", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +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 = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[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.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[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.5", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-cond" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" +dependencies = [ + "either", + "itertools", + "rayon", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +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 = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "safetensors" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b079b829cb27a1c3c374341345ed2e8b2c0c839034522cee576c140bd7f846" +dependencies = [ + "hashbrown 0.16.1", + "libc", + "serde", + "serde_json", + "tempfile", +] + +[[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 = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" + +[[package]] +name = "spm_precompiled" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" +dependencies = [ + "base64", + "nom", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys", +] + +[[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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl 2.0.21", +] + +[[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 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223" +dependencies = [ + "ahash", + "aho-corasick", + "compact_str", + "dary_heap", + "derive_builder", + "esaxx-rs", + "getrandom 0.3.4", + "itertools", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.9.5", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 2.0.21", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + +[[package]] +name = "tokio" +version = "1.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c168a474b95bfecfe908a65d4bdffc523144b649a74c09c286afb35d53e0bc" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "typed-path" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54ec2755506471f54baf5e4bb5499d8e510cc1caf271270e778a736bd2d7336c" + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "unicode-normalization-alignments" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de" +dependencies = [ + "smallvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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 = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", + "synstructure", +] + +[[package]] +name = "zip" +version = "8.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", + "typed-path", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..86625de7f818d15d7ccb148962c23a61cf352ec7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "khtst-rust" +version = "0.1.11" +edition = "2021" +description = "KHTST_RUST — refatoração Rust/PyO3 do KHTST com NCM (Next-Concept Modeling), provas integradas, atenção ADBA e ponte duplex" +license = "Apache-2.0" + +[lib] +name = "khtst_rust" +crate-type = ["cdylib", "rlib"] + +[dependencies] +pyo3 = { version = "0.23", features = ["abi3-py310"] } +numpy = "0.23" +pythonize = "0.23" +pyo3-log = "0.12" +dict_derive = "0.5" +pyo3-built = "0.5" +pyo3-async-runtimes = { version = "0.23", optional = true, features = ["tokio-runtime"] } +tokio = { version = "1", features = ["rt-multi-thread"], optional = true } +candle-core = "0.11" +candle-nn = "0.11" +crossbeam-channel = "0.5" +rayon = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +anyhow = "1" +thiserror = "2" +log = "0.4" +rand = "0.8" + +[build-dependencies] +built = "0.8" + +[features] +default = ["ponte_async"] +ponte_async = ["pyo3-async-runtimes", "tokio"] + +[profile.release] +opt-level = 3 +debug = false diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..76e99ce1954c6e183808f463bb877d818a7ea50e --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +Apache License 2.0 — ver https://www.apache.org/licenses/LICENSE-2.0 diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..da324c082d47193c75ff723eadc99ddfdebe64be --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# KHTST_RUST — Next-Concept Modeling em Rust/PyO3 + +Refatoração completa do projeto **KHTST** (`PowerMachine/khtst-multimodal-ptbr`) para **Rust** via **PyO3**, integrando o paradigma **NCM (Next-Concept Modeling)** com todas as provas matemáticas da coleção `memoria-ncm-khtst`, e dois aprimoramentos novos: **ADBA** (atenção adaptativa no processamento paralelo) e **Ponte Duplex** (comunicação bidirecional simultânea entre modelos). + +## O que é + +- **Tokenizador de conceitos** (Estágio A): VQ-VAE residual multiscale com codebooks **Stiefel/RCO** e quantização **GSQ** (Gumbel-Softmax com gradiente exato) — contração geométrica (1−1/K) por nível (Teo A.1/D.4), nested dropout (prefixos anytime, Teo A.2). +- **Gerador next-concept** (Estágio B): fatoração `p(c) = Π_ℓ p(c_ℓ|c_{<ℓ})` com predição **paralela** intra-nível — **MLE exato sem ELBO** (Teo B.1), **NFE = L** (7 ≪ 256; Teo B.2), corrupção de condicionamento como DRO (Teo C.3), MTP ⊂ NCM (Teo D.6), PCGrad (Teo D.7). +- **Tronco híbrido 5:1**: 5 camadas **ADBA** + 1 slot **Mamba-3 SSD** (scan diagonal com adjunto exato) — máscara block-causal com 0 vazamentos (Teo D.1, V4). +- **Ponte Duplex**: A↔B com canais limitados, rodadas com timeout — sem deadlock estrutural (Teo P.1), direções simultâneas medidas (P.2). +- **Telemetria completa**: séries JSONL, escore de aprendizado, **ajuste automático auditado** de LR/clip/ε/λ/τ, diagnóstico de erros comuns de refatoração (Levenshtein/taxonomia). + +## Instalação + +```bash +pip install khtst_rust-*.whl # wheel abi3 (Python ≥ 3.10, manylinux) +# ou do fonte: maturin build --release && pip install target/wheels/*.whl +``` + +## Uso rápido + +```python +import khtst_rust as K + +cfg = K.Config("configs/base_rust.json") # valida + orçamento de cache +bpe = K.Bpe.treinar(textos, 16384) # BPE byte-level próprio + +# Fase A: tokenizador (nested dropout + GSQ/RCO Stiefel) +K.treinar_fase_a(cfg, sequencias, caminho_telemetria="tel_a.jsonl", + caminho_checkpoint="tokenizador.json", teto_seg=430) + +# Fase B: gerador (MLE exato + κ + MTP + JEPA + PCGrad) +K.treinar_fase_b(cfg, sequencias, "tokenizador.json", + caminho_telemetria="tel_b.jsonl", + caminho_checkpoint="gerador.json", teto_seg=330) + +# Geração paralela: NFE = L; parada anytime em qualquer prefixo +g = K.gerar_amostras(cfg, "tokenizador.json", "gerador.json", n_amostras=2) +assert g["nfe"] == 7 # = L + +# Ponte duplex entre modelos +p = K.PonteDupla(capacidade=64, timeout_ms=2000) +est = p.demo_professor_aluno(rodadas=200, dim=24) +``` + +## Estrutura + +``` +src/ 19 módulos Rust (ver docs/memorias/r-02-arquitetura.md) +configs/ base_rust.json (espelho do base.json v23 + seção ncm) +scripts/ 39_coletar_dados.py · 40_treinar.py · 41_teste.py · 42_publicar.py +docs/memorias/ r-01..r-07 (diagnóstico, arquitetura, rastreabilidade provas→código, + prova ADBA, prova ponte duplex, telemetria, resultados) +resultados/ checkpoints, telemetria JSONL, suíte V, resumo de treino +``` + +## Verificações + +- **15/15 testes cargo** (adjuntos validados contra diferenças finitas e implementação nativa) +- **Suíte V**: 7/7 bloqueadoras verdes (V0,V1,V4,V9,V10,V13,V14) + evidenciais +- **Treino real** (Wikipédia PT-BR, streaming controlado): fase A perda 9,89→8,11, δ_ort ≤ 9,9e-7 durante o treino, codebook 52/64 sem colapso; fase B CE 4,19→3,98; geração NFE=7, anytime k=3 + +## Provas e teoria + +Toda a fundamentação matemática (20 teoremas + 10 corolários da integração NCM×KHTST; Teos R.1–R.3 da ADBA; Teos P.1–P.3 da ponte duplex) está em `docs/memorias/` com rastreabilidade teorema→código→verificação (r-03). + +## Convenções herdadas do projeto + +Teoremas numerados com ∎ · nascimento neutro (opt-in) · leitura honesta (wall-clock como medido, ganhos não declaráveis por ΔCE curto) · tetos de arquivo/RAM · RNG dedicado para pareamento A/B · token HF apenas em variável de ambiente, apagado após uso. + +## Licença + +Apache-2.0 diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..152dabad0af45d9e1ce5f6b6bc40f1632a58b23b --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +fn main() { + // built 0.8: write_built_file() gera OUT_DIR/built.rs + if let Err(e) = built::write_built_file() { + println!("cargo:warning=falha ao gerar metadados built: {e}"); + } +} diff --git a/configs/base_rust.json b/configs/base_rust.json new file mode 100644 index 0000000000000000000000000000000000000000..cf85ae12e68d2554b4690ec16289b9764a360a12 --- /dev/null +++ b/configs/base_rust.json @@ -0,0 +1,106 @@ +{ + "modelo": { + "vocab": 16384, + "d_modelo": 192, + "n_camadas": 6, + "n_cabecas": 4, + "d_ff": 512, + "comprimento_ctx": 256, + "janela_sliding": 192, + "kv_cache_max": 2048, + "usar_atencao_arvore": true, + "mtp": { + "ativo": true, + "k_cabecas": 2, + "beta_entropia": 0.05, + "k_adaptativo": true + } + }, + "ncm": { + "ativo": true, + "niveis": [ + 4, + 8, + 16, + 32, + 64, + 128, + 256 + ], + "d_lat": 64, + "k_por_nivel": 64, + "ema_codebook": 0.99, + "beta_commit": 0.25, + "nested_dropout": { + "tipo": "uniforme" + }, + "corrupcao_cond": 0.15, + "dropout_cfg": 0.1, + "cfg_scale": 1.0, + "gsq": { + "tau0": 1.0, + "tau_min": 0.5, + "t_alvo": 400 + }, + "pesos_nivel": "uniforme", + "lambdas": { + "conceito": 0.0, + "rec": 1.0, + "rho_ancora": 0.05 + }, + "temperaturas": { + "auto": true, + "entropia_alvo": null, + "limites": [ + 0.5, + 1.5 + ] + }, + "mbr": { + "n_cand": 1 + }, + "escala_r": "ema_projecao", + "modo_quantizacao": "gsq_rco", + "niveis_token": false + }, + "adba": { + "ativo": true, + "gamma_ancora": 1.0, + "reponderacao_nivel": true, + "temperatura_nivel": true + }, + "ponte": { + "ativo": true, + "capacidade": 64, + "timeout_ms": 2000, + "rodadas_demo": 24 + }, + "treino": { + "lr": 0.003, + "aquecimento": 40, + "passos_fase_a": 400, + "passos_fase_b": 400, + "lote": 4, + "clip": 1.0, + "peso_decaimento": 0.01, + "telemetria_a_cada": 25 + }, + "telemetria": { + "jsonl": true, + "deteccao_aprendizado": true, + "ajuste_automatico": true, + "paciencia_plateau": 120, + "fator_lr_plateau": 0.6 + }, + "dados": { + "shard_treino": "dados/shard_treino.jsonl", + "shard_validacao": "dados/shard_validacao.jsonl", + "max_artigos": 1200, + "max_bytes": 6000000 + }, + "memoria": { + "som_lado": 16, + "lambda_jepa": 0.1, + "rm_dois_tempos": true + } +} \ No newline at end of file diff --git a/dados/bpe.json b/dados/bpe.json new file mode 100644 index 0000000000000000000000000000000000000000..7f7ca85d0c5f2dfbda87b7205e8bfc9d8753fc21 --- /dev/null +++ b/dados/bpe.json @@ -0,0 +1 @@ +{"merges":[[104,105],[104,115],[118,101],[105,119],[114,120],[103,115],[104,101],[115,119],[101,119],[118,109],[113,101],[103,101],[120,105],[118,105],[199,167],[120,101],[109,119],[115,118],[103,109],[113,105],[199,173],[105,118],[199,171],[101,112],[105,114],[117,121],[109,114],[118,115],[105,113],[120,109],[114,101],[109,101],[265,113],[120,115],[199,177],[119,105],[116,101],[114,115],[105,264],[199,165],[112,101],[167,115],[116,115],[274,115],[112,109],[112,115],[101,114],[109,115],[119,109],[285,105],[104,109],[120,121],[171,199],[101,118],[114,109],[116,105],[264,105],[263,120],[121,113],[115,114],[261,119],[115,121],[109,103],[119,120],[112,105],[121,112],[101,113],[199,183],[105,109],[121,270],[265,114],[109,120],[119,115],[113,115],[107,109],[101,261],[106,109],[115,48],[119,121],[122,105],[116,277],[101,48],[113,109],[260,119],[264,115],[122,101],[114,103],[103,105],[108,101],[115,112],[118,263],[122,109],[107,121],[101,199],[119,48],[266,260],[199,174],[106,115],[269,101],[292,115],[105,112],[120,199],[109,113],[270,109],[103,121],[101,120],[116,287],[121,114],[109,112],[109,271],[266,119],[262,114],[105,124],[119,101],[109,118],[107,105],[107,101],[262,119],[101,104],[296,262],[199,185],[105,103],[121,119],[116,109],[120,118],[108,115],[109,199],[121,109],[126,101],[122,115],[104,121],[114,261],[109,104],[112,121],[264,101],[112,108],[116,269],[114,105],[109,122],[115,50],[108,105],[185,263],[109,126],[279,264],[357,109],[264,109],[282,274],[109,265],[114,119],[106,105],[119,50],[276,120],[263,119],[262,113],[199,190],[102,109],[292,116],[113,102],[114,104],[53,61],[106,277],[116,267],[264,263],[330,119],[107,115],[273,107],[105,48],[101,50],[120,262],[199,166],[101,109],[363,119],[260,118],[272,113],[272,118],[114,108],[121,101],[119,281],[115,113],[109,266],[118,267],[265,264],[105,120],[115,102],[263,116],[278,101],[317,101],[101,107],[105,262],[174,114],[101,266],[199,164],[118,199],[122,281],[295,121],[49,119],[103,268],[121,262],[112,48],[115,107],[121,120],[269,103],[296,118],[265,119],[114,199],[103,112],[101,115],[116,121],[262,112],[101,103],[268,119],[294,119],[260,114],[109,261],[105,121],[102,105],[261,118],[338,101],[278,266],[116,281],[102,101],[45,48],[119,303],[265,118],[109,116],[115,269],[121,199],[53,60],[113,121],[269,115],[377,109],[490,112],[109,262],[109,275],[298,118],[171,101],[270,114],[101,116],[109,106],[118,120],[121,118],[101,264],[118,121],[101,102],[104,199],[116,118],[262,199],[113,268],[112,113],[121,105],[263,103],[121,300],[276,272],[273,101],[363,115],[109,260],[199,184],[315,305],[102,115],[275,264],[119,199],[103,199],[263,48],[315,300],[317,105],[114,107],[173,113],[271,112],[73,119],[113,280],[54,52],[103,108],[112,267],[285,101],[102,199],[271,118],[275,113],[278,115],[478,260],[69,112],[302,260],[109,316],[268,48],[267,48],[114,267],[112,199],[262,120],[425,109],[101,262],[114,303],[272,114],[110,101],[105,324],[107,262],[109,107],[121,107],[494,105],[113,116],[113,199],[106,101],[120,267],[317,121],[273,112],[86,105],[514,118],[116,112],[119,113],[396,113],[269,120],[302,116],[114,268],[269,119],[271,116],[569,121],[536,102],[574,199],[575,173],[576,113],[109,105],[265,112],[287,116],[122,199],[230,132],[101,122],[73,113],[71,319],[103,120],[271,48],[420,270],[45,50],[107,114],[115,101],[262,261],[285,109],[101,260],[101,49],[104,276],[114,278],[70,491],[118,114],[280,103],[396,114],[102,273],[166,114],[348,102],[601,103],[101,121],[102,121],[115,262],[183,269],[277,272],[300,118],[112,294],[118,113],[296,294],[604,109],[614,119],[321,120],[567,105],[618,109],[273,103],[71,115],[105,122],[165,269],[278,105],[81,101],[120,269],[330,108],[573,300],[82,115],[103,263],[110,105],[261,48],[270,120],[286,106],[310,122],[627,105],[636,103],[116,300],[119,512],[120,263],[270,118],[304,271],[332,102],[279,114],[416,115],[109,270],[112,50],[281,119],[109,267],[119,119],[271,113],[284,261],[112,122],[120,277],[83,119],[113,263],[165,120],[547,199],[299,273],[615,275],[273,109],[288,116],[299,112],[338,102],[340,120],[84,277],[264,199],[280,120],[317,199],[371,260],[572,109],[113,267],[280,112],[286,101],[423,120],[105,50],[110,121],[116,350],[177,119],[106,367],[112,268],[263,101],[411,199],[286,104],[605,109],[637,109],[685,116],[103,281],[262,122],[295,107],[687,101],[199,141],[690,121],[121,314],[275,112],[330,103],[343,103],[462,272],[82,101],[102,304],[102,307],[115,109],[124,109],[280,113],[310,106],[483,118],[671,120],[121,263],[273,106],[283,109],[289,122],[299,269],[306,267],[89,314],[284,119],[421,119],[101,279],[101,297],[262,48],[273,120],[683,183],[721,269],[113,286],[114,260],[294,116],[302,112],[366,104],[433,116],[541,118],[707,101],[727,121],[107,670],[423,109],[658,167],[734,115],[171,115],[263,50],[290,120],[77,77],[84,101],[119,652],[271,114],[292,121],[462,289],[69,119],[185,105],[263,105],[273,114],[275,261],[336,112],[643,273],[115,261],[183,118],[115,106],[269,105],[277,263],[286,107],[375,262],[119,600],[174,119],[262,103],[268,120],[343,105],[446,261],[103,294],[110,115],[115,103],[260,109],[280,269],[283,107],[292,105],[365,280],[314,103],[437,122],[665,121],[730,112],[759,121],[777,112],[103,348],[104,291],[112,291],[118,103],[277,107],[298,105],[305,271],[561,261],[108,722],[112,120],[120,268],[171,274],[286,103],[659,101],[660,264],[793,263],[101,282],[102,118],[112,276],[118,48],[184,114],[260,113],[268,105],[281,262],[779,270],[71,101],[109,102],[122,276],[177,113],[260,116],[268,50],[285,199],[327,119],[103,325],[105,107],[177,114],[267,115],[271,261],[278,114],[299,119],[310,273],[315,112],[351,266],[775,107],[113,367],[285,283],[286,119],[294,289],[305,107],[366,103],[562,101],[822,121],[71,438],[105,273],[121,289],[165,118],[262,104],[271,266],[278,199],[281,114],[329,114],[101,311],[177,122],[183,107],[262,109],[269,114],[282,199],[297,279],[454,119],[582,152],[102,491],[113,48],[311,262],[343,120],[488,314],[849,105],[854,109],[855,118],[72,105],[101,267],[105,275],[109,121],[120,371],[121,49],[267,50],[271,199],[273,116],[293,261],[339,126],[412,115],[444,199],[619,118],[628,282],[666,120],[69,529],[102,262],[108,839],[109,278],[126,109],[177,106],[279,120],[444,105],[528,275],[791,112],[853,103],[883,294],[884,116],[885,109],[114,122],[116,470],[173,103],[279,112],[319,260],[656,113],[882,121],[103,673],[105,269],[115,116],[124,115],[126,105],[265,48],[306,109],[326,102],[342,112],[405,107],[705,105],[763,114],[837,174],[873,269],[904,273],[906,114],[909,103],[910,109],[52,52],[122,712],[276,119],[279,118],[286,109],[372,116],[696,105],[733,260],[785,112],[919,118],[38,50],[101,126],[262,118],[286,108],[289,271],[471,109],[571,120],[651,116],[823,261],[833,112],[871,274],[931,109],[932,115],[279,104],[283,105],[371,103],[639,270],[654,114],[783,101],[861,119],[869,173],[940,114],[942,103],[944,109],[945,105],[49,101],[124,101],[286,115],[332,278],[366,122],[371,120],[624,264],[709,105],[828,263],[868,101],[921,101],[933,126],[955,119],[53,59],[106,326],[106,927],[260,103],[260,122],[366,116],[633,105],[738,121],[880,103],[907,103],[38,48],[105,110],[260,48],[286,266],[357,262],[894,121],[935,109],[975,112],[260,106],[276,113],[317,118],[372,276],[414,102],[684,109],[778,115],[958,101],[959,115],[54,48],[105,266],[116,956],[118,118],[183,112],[283,101],[315,269],[726,294],[969,101],[87,105],[118,107],[119,325],[165,122],[338,268],[340,275],[362,340],[434,269],[561,104],[1003,120],[73,121],[107,118],[288,102],[304,122],[434,113],[485,107],[510,118],[905,122],[994,289],[1013,115],[1015,112],[1016,122],[101,276],[111,113],[267,120],[286,122],[291,48],[372,288],[441,109],[465,268],[728,115],[770,121],[812,311],[872,121],[1023,116],[1025,119],[1028,262],[1030,112],[108,199],[109,264],[279,113],[284,268],[297,122],[691,112],[974,113],[1004,101],[53,57],[102,112],[266,261],[271,262],[758,112],[830,263],[840,283],[856,115],[87,303],[106,199],[108,109],[114,610],[260,120],[266,113],[269,107],[294,112],[428,102],[1006,580],[1058,101],[1060,112],[107,291],[112,263],[115,122],[177,104],[262,106],[263,109],[273,265],[350,116],[424,122],[443,110],[645,118],[669,165],[1024,114],[1061,108],[1070,281],[1076,114],[101,269],[101,973],[103,358],[108,267],[109,279],[119,45],[119,289],[272,262],[277,270],[289,113],[295,110],[488,331],[530,53],[635,281],[743,114],[1072,120],[1093,101],[1094,113],[1095,105],[1096,264],[115,49],[267,101],[273,113],[273,122],[279,109],[444,101],[617,118],[675,109],[680,266],[1088,101],[1091,119],[1104,267],[1105,120],[107,284],[113,274],[115,38],[118,104],[126,115],[173,120],[260,112],[287,114],[336,278],[416,121],[744,118],[820,267],[957,104],[1005,199],[1029,107],[1110,121],[1124,183],[1127,118],[1128,109],[118,119],[121,264],[269,265],[271,120],[273,104],[275,114],[289,116],[292,102],[296,109],[308,113],[316,118],[317,109],[350,119],[430,124],[529,104],[619,262],[639,113],[716,121],[881,261],[1017,109],[1097,115],[1144,109],[101,903],[103,400],[106,328],[115,45],[118,50],[269,102],[308,107],[313,120],[333,260],[356,114],[356,119],[634,112],[645,119],[693,114],[865,118],[892,115],[900,270],[920,109],[953,199],[1031,109],[1120,120],[1170,177],[1173,106],[1174,109],[1175,103],[101,45],[106,121],[110,299],[264,262],[272,115],[276,275],[282,101],[298,262],[304,113],[390,371],[411,115],[416,118],[559,126],[870,115],[886,115],[902,108],[978,109],[1172,101],[1186,120],[1193,114],[1195,105],[54,53],[82,610],[103,118],[105,330],[106,273],[269,267],[271,121],[278,268],[305,114],[345,269],[349,121],[365,262],[497,304],[688,271],[1033,115],[1092,109],[54,54],[116,263],[118,299],[119,288],[261,109],[269,113],[270,107],[272,103],[276,105],[286,199],[289,120],[298,101],[302,122],[362,116],[372,315],[421,120],[505,327],[596,116],[706,105],[787,101],[916,278],[1010,115],[1158,114],[1171,106],[1218,119],[1237,109],[69,324],[102,281],[102,801],[109,287],[116,120],[119,274],[177,278],[199,133],[262,107],[265,50],[271,50],[275,118],[283,280],[284,265],[296,114],[350,105],[351,122],[494,115],[533,114],[533,264],[540,118],[579,115],[617,262],[803,266],[967,262],[1002,275],[1054,105],[1125,101],[1163,121],[1169,126],[1210,271],[1239,103],[1258,261],[1267,112],[1269,101],[1271,101],[69,118],[69,120],[71,109],[87,101],[105,104],[107,313],[109,124],[173,119],[270,199],[302,264],[333,122],[360,280],[472,120],[479,199],[497,284],[686,261],[697,115],[697,118],[908,264],[911,101],[929,115],[1047,101],[1236,109],[1253,264],[1290,268],[1298,106],[1301,109],[1302,271],[49,112],[73,323],[75,121],[104,411],[113,49],[114,414],[115,271],[298,115],[306,299],[419,55],[620,105],[757,121],[888,101],[983,122],[1045,103],[1071,105],[1196,109],[1206,107],[1252,113],[1265,264],[1286,109],[1287,120],[1289,177],[1318,120],[1327,105],[1328,118],[53,48],[78,115],[84,287],[87,325],[115,104],[121,260],[287,270],[298,199],[302,105],[330,106],[347,112],[366,106],[412,105],[416,101],[451,119],[470,109],[913,267],[961,294],[966,113],[1146,268],[1209,122],[1312,112],[1347,112],[1351,276],[108,299],[121,373],[260,121],[272,264],[284,107],[284,108],[306,105],[308,271],[343,104],[423,121],[441,105],[441,118],[513,112],[540,113],[691,109],[867,263],[1324,279],[1325,269],[1326,115],[1348,199],[1362,105],[1368,119],[1370,264],[1372,261],[1373,165],[1378,120],[1379,109],[53,58],[55,48],[112,429],[114,48],[119,103],[120,287],[166,113],[267,119],[281,107],[283,120],[308,261],[326,116],[338,116],[527,105],[552,120],[563,334],[866,119],[962,271],[1012,109],[1129,115],[1166,263],[1376,115],[1394,114],[52,48],[53,56],[70,101],[71,108],[71,313],[102,287],[105,101],[112,524],[112,1315],[116,199],[121,282],[267,109],[281,120],[300,114],[315,262],[328,262],[368,108],[372,272],[405,103],[562,109],[675,118],[693,109],[743,113],[810,177],[893,109],[968,109],[1068,114],[1192,199],[1262,119],[1299,262],[1352,291],[1396,303],[1399,120],[1401,105],[1423,107],[1424,121],[1427,113],[1431,185],[1437,114],[1438,109],[1440,109],[1441,263],[1442,120],[89,113],[107,425],[107,502],[113,414],[115,120],[121,332],[122,349],[269,199],[299,289],[313,272],[330,110],[364,110],[372,120],[441,101],[443,437],[497,350],[510,101],[530,54],[634,277],[638,114],[694,266],[808,115],[954,118],[1220,114],[1228,269],[1234,101],[1403,104],[1446,101],[1461,122],[1462,105],[1473,199],[1476,114],[1477,165],[1478,120],[1479,269],[102,288],[113,387],[122,283],[266,48],[273,126],[275,109],[278,260],[280,116],[284,117],[299,107],[306,261],[385,279],[416,112],[529,120],[530,52],[596,103],[701,305],[762,118],[925,101],[939,101],[950,101],[977,268],[1074,105],[1102,115],[1119,101],[1185,109],[1266,118],[1336,114],[1353,105],[1363,113],[1465,270],[1467,260],[1488,114],[1498,107],[1504,114],[1514,120],[1515,291],[1516,120],[53,55],[84,313],[87,436],[105,49],[105,115],[112,289],[115,264],[121,126],[261,113],[261,121],[269,266],[272,199],[285,284],[371,199],[412,101],[429,405],[472,115],[547,119],[606,293],[638,264],[750,108],[819,109],[890,108],[946,119],[1075,115],[1137,121],[1184,112],[1207,101],[1215,117],[1226,115],[1292,102],[1350,199],[1480,101],[1490,121],[1508,113],[1537,120],[1541,120],[1548,121],[1551,173],[1553,101],[1554,109],[1557,109],[1558,119],[1560,114],[1561,119],[1564,101],[53,54],[88,802],[102,269],[103,928],[104,118],[114,291],[115,1506],[121,281],[124,120],[177,116],[265,121],[270,266],[275,48],[283,279],[286,105],[286,283],[293,266],[294,114],[295,112],[347,101],[390,268],[419,59],[423,105],[425,121],[503,269],[510,262],[513,199],[539,298],[550,261],[570,103],[585,119],[669,167],[731,126],[771,199],[918,109],[964,105],[981,120],[982,304],[1160,118],[1360,109],[1468,109],[1494,105],[1536,113],[1539,101],[1559,264],[1563,101],[1591,122],[1592,171],[1593,105],[1597,115],[1599,171],[1600,120],[1605,287],[1606,119],[1608,109],[1610,115],[1613,199],[1614,110],[1620,114],[1623,115],[38,45],[53,52],[60,48],[69,270],[74,702],[106,937],[115,524],[261,50],[267,199],[268,103],[269,268],[273,110],[277,260],[284,199],[289,265],[308,120],[325,108],[348,122],[420,199],[443,262],[622,349],[731,282],[774,109],[829,199],[1077,115],[1149,113],[1164,120],[1168,109],[1277,112],[1294,263],[1366,109],[1483,293],[1495,115],[1545,119],[1617,115],[1644,171],[1646,121],[1649,171],[1651,105],[1654,429],[1658,261],[1659,120],[1663,199],[1664,114],[1665,405],[1667,199],[1669,120],[1670,103],[49,273],[69,121],[84,115],[105,126],[105,270],[105,390],[107,199],[107,267],[109,268],[114,318],[114,381],[116,1603],[121,103],[121,115],[173,118],[198,190],[261,49],[261,105],[295,264],[296,273],[302,276],[309,48],[315,285],[332,112],[350,121],[375,115],[384,356],[385,110],[428,120],[467,102],[541,107],[664,49],[686,104],[800,115],[943,276],[1036,102],[1201,115],[1213,103],[1240,270],[1317,199],[1345,113],[1429,101],[1481,115],[1489,115],[1517,101],[1653,119],[1672,115],[1679,271],[1684,263],[1692,109],[1696,284],[1700,119],[1701,105],[1706,101],[1708,113],[1710,113],[1711,101],[1712,114],[1713,177],[1722,119],[1729,109],[1731,108],[1732,104],[1735,101],[1736,121],[55,52],[69,116],[71,50],[77,1140],[86,115],[101,422],[102,306],[103,1257],[109,272],[113,277],[115,62],[120,294],[278,116],[278,118],[304,272],[324,122],[419,54],[420,113],[461,101],[462,120],[479,113],[487,61],[598,48],[612,114],[628,118],[901,109],[1011,109],[1039,113],[1046,113],[1089,268],[1152,101],[1165,261],[1176,115],[1181,269],[1337,167],[1421,114],[1439,199],[1457,121],[1466,105],[1511,115],[1512,199],[1572,112],[1585,297],[1604,114],[1624,101],[1647,274],[1698,112],[1702,101],[1717,271],[1765,114],[1766,105],[1767,105],[1773,115],[1776,264],[1779,171],[1784,115],[1785,120],[1789,264],[1790,114],[1793,199],[1796,105],[1797,120],[1800,105],[44,261],[56,48],[69,114],[81,105],[81,115],[81,313],[87,115],[106,112],[109,293],[116,414],[126,199],[183,120],[184,113],[264,118],[281,115],[284,105],[284,278],[285,263],[286,276],[295,260],[314,271],[350,103],[356,113],[414,112],[419,61],[428,104],[483,116],[538,119],[563,116],[598,50],[616,48],[939,115],[981,272],[989,119],[1011,105],[1059,105],[1321,115],[1475,101],[1656,126],[1673,115],[1703,304],[1715,112],[1762,107],[1774,119],[1828,115],[1844,121],[84,548],[87,121],[109,282],[116,108],[116,273],[120,600],[183,116],[266,50],[266,120],[290,278],[293,48],[293,275],[304,107],[314,265],[330,104],[364,118],[421,109],[463,120],[564,263],[582,151],[662,273],[680,282],[729,114],[731,120],[739,77],[817,105],[879,118],[913,268],[943,109],[965,269],[977,101],[980,121],[1147,109],[1225,114],[1230,116],[1264,112],[1309,279],[1338,275],[1430,108],[1499,115],[1704,262],[1705,273],[1734,101],[1764,298],[1830,414],[1857,115],[1876,126],[1879,120],[1884,118],[1886,105],[1889,107],[1892,102],[1895,121],[1897,103],[1898,109],[1899,304],[1900,262],[1902,199],[1903,271],[70,1419],[81,121],[85,121],[106,1581],[107,268],[109,48],[115,1232],[118,280],[119,267],[121,50],[122,268],[184,279],[260,50],[260,126],[270,264],[271,102],[284,122],[289,103],[304,102],[343,109],[352,114],[362,102],[419,53],[443,377],[446,102],[474,287],[479,119],[497,327],[500,480],[514,269],[596,119],[678,105],[706,263],[714,122],[852,101],[911,268],[951,199],[996,352],[1014,271],[1027,114],[1123,115],[1187,269],[1194,261],[1436,115],[1450,308],[1730,199],[1788,101],[1795,101],[1825,289],[1836,113],[1840,101],[1859,112],[1881,120],[1882,269],[1893,114],[1934,119],[1936,101],[1939,116],[1946,119],[1949,118],[1952,171],[1959,115],[1961,101],[1964,115],[1967,199],[1970,114],[57,48],[69,667],[73,417],[90,109],[101,106],[102,283],[104,280],[114,121],[273,121],[276,48],[277,115],[279,275],[296,116],[317,262],[324,107],[441,262],[446,120],[625,358],[686,113],[715,101],[723,105],[750,267],[825,120],[870,267],[917,350],[964,109],[1059,101],[1154,293],[1204,119],[1248,101],[1340,121],[1358,105],[1412,101],[1464,53],[1491,121],[1609,119],[1622,167],[1641,121],[1792,115],[1853,114],[1877,105],[1894,101],[1905,167],[1931,105],[1938,114],[1940,281],[1991,105],[1997,119],[2004,114],[2005,107],[2009,115],[2010,101],[2012,109],[2015,115],[2016,112],[2018,119],[2019,264],[2021,108],[2027,105],[2029,115],[2031,103],[56,52],[58,48],[61,48],[69,418],[73,124],[73,324],[77,557],[86,307],[103,1823],[105,593],[118,294],[121,48],[291,50],[305,262],[310,107],[310,268],[343,119],[413,115],[414,314],[419,56],[419,58],[429,114],[434,103],[434,262],[479,272],[535,102],[539,102],[548,118],[579,105],[585,260],[605,199],[616,263],[621,362],[659,268],[732,119],[803,261],[824,117],[886,267],[1027,113],[1069,105],[1159,263],[1212,48],[1319,293],[1542,277],[1631,199],[1709,118],[1718,112],[1752,103],[1759,109],[1926,107],[1932,116],[1943,177],[1951,271],[1968,48],[1998,104],[2003,300],[2058,114],[2064,177],[2066,102],[2070,121],[2083,114],[2084,105],[2085,114],[2088,115],[2089,118],[2090,103],[2091,116],[2092,262],[2093,281],[2096,278],[2100,109],[70,1143],[81,280],[89,270],[101,483],[101,711],[105,45],[113,50],[113,322],[119,327],[121,265],[199,145],[261,103],[264,121],[266,114],[267,106],[270,103],[272,269],[281,266],[286,261],[290,118],[295,272],[300,261],[300,279],[338,118],[366,107],[397,107],[419,52],[485,105],[487,57],[535,122],[728,105],[819,120],[829,120],[875,115],[888,115],[908,114],[941,106],[986,119],[1069,115],[1123,101],[1136,115],[1259,109],[1285,115],[1443,267],[1533,171],[1589,263],[1661,101],[1671,177],[1783,104],[1969,112],[1971,167],[1972,260],[2040,280],[2056,105],[2081,121],[2099,105],[2108,261],[2132,264],[2134,199],[2150,109],[2152,122],[2155,115],[2157,269],[2158,109],[2164,101],[2165,105],[2167,115],[70,105],[74,937],[74,2149],[77,92],[78,1634],[80,276],[101,460],[104,262],[105,276],[108,125],[112,112],[119,38],[119,62],[120,48],[121,261],[262,126],[272,122],[275,269],[277,114],[277,199],[284,103],[284,281],[294,102],[294,122],[298,109],[299,122],[300,289],[305,278],[311,101],[313,104],[338,103],[339,305],[350,109],[365,269],[432,109],[453,119],[505,299],[533,120],[573,112],[635,109],[641,199],[678,109],[701,112],[714,261],[740,571],[771,118],[786,119],[820,268],[852,105],[875,101],[892,101],[917,305],[936,113],[1089,267],[1151,101],[1188,109],[1231,267],[1242,101],[1261,114],[1275,199],[1293,109],[1307,109],[1314,102],[1323,105],[1329,199],[1380,103],[1448,115],[1449,421],[1470,199],[1471,113],[1598,109],[1691,114],[1723,261],[1728,267],[1772,101],[1975,115],[1993,262],[2028,109],[2078,174],[2135,262],[2176,173],[2177,102],[2203,278],[2209,118],[2210,267],[2214,199],[2223,262],[2231,171],[2236,177],[2237,101],[2240,173],[2241,105],[2243,199],[2247,262],[2250,119],[2253,115],[2254,266],[2255,115],[2257,183],[2259,199],[2260,119],[2262,120],[2263,264],[2264,171],[2267,101],[2268,260],[2270,107],[2272,120],[2275,101],[2278,109],[2279,109],[2282,103],[69,903],[71,1546],[75,105],[77,107],[81,367],[87,474],[88,901],[90,281],[101,366],[101,1693],[103,273],[105,105],[112,107],[116,992],[118,49],[122,262],[122,288],[126,121],[177,261],[270,112],[272,112],[272,124],[275,199],[283,272],[285,268],[306,107],[310,126],[324,109],[344,119],[378,113],[419,57],[447,118],[447,287],[456,101],[470,115],[487,54],[519,115],[533,276],[563,286],[579,199],[668,109],[713,48],[757,112],[778,267],[829,103],[830,199],[966,269],[1008,115],[1021,263],[1126,109],[1279,344],[1331,303],[1395,118],[1444,271],[1507,275],[1550,105],[1602,199],[1668,167],[1685,265],[1758,263],[1775,171],[1833,121],[1847,101],[1864,199],[1896,115],[1944,114],[1955,113],[1979,271],[2061,101],[2128,334],[2162,101],[2163,167],[2193,107],[2206,122],[2208,289],[2217,103],[2224,274],[2228,109],[2234,105],[2273,109],[2290,280],[2292,124],[2297,122],[2305,120],[2308,105],[2313,286],[2328,109],[2329,174],[2330,101],[2331,262],[2332,120],[2339,118],[2340,174],[2341,115],[2344,199],[2347,171],[2351,266],[2355,115],[2357,101],[2359,109],[2364,113],[2365,109],[2366,262],[2369,276],[2370,115],[2371,119],[2374,109],[2375,120],[2376,114],[2379,199],[2383,101],[2385,270],[2387,120],[2388,114],[2392,103],[2396,262],[2398,109],[2400,101],[53,50],[69,115],[83,1781],[84,606],[89,88],[92,90],[105,413],[106,2169],[114,263],[114,329],[118,270],[119,769],[120,303],[120,1824],[121,279],[177,120],[266,118],[271,122],[271,260],[276,112],[278,122],[281,103],[287,264],[291,114],[293,114],[299,106],[310,283],[330,117],[347,324],[353,190],[360,263],[371,107],[400,102],[478,104],[515,109],[524,119],[535,107],[616,50],[617,287],[621,333],[677,266],[714,303],[967,273],[1012,105],[1014,265],[1101,115],[1106,113],[1148,119],[1194,199],[1223,177],[1259,115],[1274,266],[1279,394],[1288,109],[1293,105],[1484,277],[1487,119],[1502,112],[1519,105],[1582,119],[1596,289],[1616,115],[1733,109],[1798,167],[1860,101],[1920,105],[1994,115],[2007,101],[2198,113],[2213,260],[2227,113],[2249,266],[2283,101],[2287,1637],[2356,109],[2378,167],[2393,167],[2397,101],[2445,122],[2448,105],[2450,171],[2462,120],[2465,115],[2468,106],[2471,114],[2473,260],[2477,115],[2478,115],[2481,264],[2482,199],[2483,121],[2485,109],[2491,167],[2493,101],[2494,115],[49,116],[49,295],[70,313],[72,109],[72,411],[73,1815],[74,105],[77,114],[80,121],[83,121],[101,105],[103,304],[106,118],[108,392],[115,63],[122,267],[165,48],[165,119],[184,314],[198,182],[262,105],[263,121],[271,269],[276,50],[276,109],[278,120],[280,48],[286,265],[289,261],[294,278],[302,121],[304,120],[313,309],[319,119],[323,118],[366,272],[393,126],[409,260],[419,60],[420,272],[446,122],[465,299],[472,119],[487,55],[487,59],[501,118],[535,118],[568,199],[644,267],[644,277],[684,121],[710,279],[733,119],[738,115],[784,114],[794,48],[963,115],[983,271],[985,261],[1107,48],[1126,199],[1141,113],[1268,284],[1273,48],[1307,269],[1323,263],[1371,103],[1371,265],[1428,114],[1453,275],[1469,199],[1497,109],[1509,103],[1612,115],[1750,120],[1754,101],[1782,101],[1837,109],[1842,271],[1845,199],[1925,281],[1950,118],[1953,112],[1954,261],[2022,105],[2137,109],[2139,121],[2146,104],[2230,109],[2271,167],[2322,115],[2336,199],[2405,305],[2429,121],[2431,260],[2436,101],[2444,126],[2451,278],[2455,106],[2456,122],[2463,121],[2472,105],[2475,101],[2476,101],[2534,118],[2537,101],[2538,119],[2542,115],[2548,264],[2549,120],[2557,177],[2559,278],[2565,261],[2567,174],[2568,116],[2571,121],[2574,101],[2576,167],[2581,113],[2582,122],[2584,101],[2586,115],[2590,109],[2593,101],[2594,115],[2595,109],[2596,105],[2598,264],[2601,101],[2603,119],[2604,116],[2610,114],[2611,112],[2612,112],[2614,115],[2617,260],[2619,119],[2624,115],[2626,109],[2628,103],[2629,109],[2633,120],[2636,109],[2637,114],[44,321],[54,50],[69,102],[78,1618],[82,105],[83,1009],[105,102],[105,260],[106,674],[108,268],[108,1948],[109,2622],[110,1642],[113,299],[116,1992],[118,122],[119,272],[120,1500],[121,102],[122,291],[183,114],[260,49],[262,50],[269,126],[270,48],[272,121],[273,48],[281,122],[283,275],[287,103],[287,107],[294,113],[295,103],[295,269],[295,279],[304,275],[306,104],[311,118],[313,285],[322,108],[393,107],[442,287],[444,115],[456,115],[503,371],[506,171],[528,296],[535,120],[550,108],[572,101],[585,103],[593,112],[622,298],[694,122],[762,105],[766,122],[804,275],[856,101],[929,267],[950,105],[980,105],[1048,279],[1075,101],[1103,199],[1140,109],[1165,266],[1176,101],[1188,105],[1221,114],[1365,115],[1463,112],[1472,112],[1493,113],[1595,105],[1638,119],[1707,103],[1738,115],[1865,101],[1870,101],[1901,109],[1923,115],[1935,290],[2013,266],[2063,109],[2095,121],[2103,101],[2116,121],[2121,101],[2129,262],[2174,101],[2202,263],[2318,103],[2447,112],[2480,105],[2486,120],[2501,269],[2502,105],[2627,115],[2630,115],[2653,115],[2674,101],[2679,109],[2681,313],[2685,107],[2689,101],[2694,281],[2697,269],[2700,266],[2702,264],[2704,171],[2705,115],[2708,105],[2709,115],[2716,118],[2721,112],[2723,260],[2724,124],[2727,113],[2729,113],[2731,119],[2732,109],[2735,105],[2738,112],[2746,119],[2747,114],[2748,260],[2749,105],[2750,115],[2751,118],[2752,114],[2753,112],[2757,101],[2758,105],[2759,101],[2761,101],[2763,115],[2773,114],[2776,107],[2777,120],[2778,109],[2780,101],[53,53],[54,57],[70,121],[71,503],[72,121],[77,70],[80,105],[88,400],[92,2175],[101,309],[101,2430],[107,288],[107,306],[116,546],[118,116],[119,319],[119,1868],[120,580],[121,116],[165,106],[177,102],[190,114],[275,102],[277,113],[279,269],[283,199],[284,282],[290,122],[290,282],[292,199],[296,104],[321,287],[330,122],[336,107],[336,118],[338,315],[365,286],[366,110],[432,101],[475,101],[487,58],[496,109],[539,107],[553,122],[585,295],[620,121],[634,105],[646,107],[658,185],[680,278],[713,50],[715,109],[716,109],[716,199],[771,120],[787,265],[824,109],[835,109],[852,109],[893,105],[930,50],[954,269],[963,112],[1019,198],[1021,105],[1044,119],[1106,261],[1108,267],[1108,268],[1112,105],[1149,104],[1152,115],[1154,120],[1202,117],[1270,199],[1288,118],[1306,802],[1319,289],[1320,104],[1331,108],[1380,265],[1393,281],[1406,108],[1425,264],[1469,105],[1556,267],[1629,126],[1652,115],[1740,811],[1756,268],[1780,113],[1827,109],[1862,109],[2059,115],[2094,101],[2106,124],[2205,102],[2248,112],[2251,120],[2326,199],[2349,261],[2361,120],[2390,107],[2464,104],[2550,113],[2558,101],[2608,101],[2639,101],[2652,103],[2715,120],[2719,103],[2736,120],[2755,122],[2792,262],[2811,173],[2815,121],[2819,105],[2826,112],[2830,263],[2831,115],[2835,177],[2841,113],[2845,182],[2846,264],[2855,121],[2856,171],[2859,122],[2872,105],[2877,109],[2878,121],[2880,121],[2881,174],[2883,109],[2884,101],[2885,101],[2886,109],[2891,105],[2892,109],[2893,115],[2897,262],[2899,108],[2901,114],[2902,122],[2907,199],[2909,264],[2910,265],[2912,118],[2913,119],[2914,122],[2916,260],[2917,101],[2919,115],[2924,105],[2926,105],[2928,101],[2930,115],[2933,114],[2938,101],[44,115],[49,82],[54,58],[54,59],[56,45],[69,417],[70,87],[70,281],[71,326],[71,349],[72,50],[72,115],[77,119],[84,118],[88,101],[101,270],[101,2769],[101,2932],[102,818],[103,327],[105,116],[109,352],[113,610],[114,282],[115,1418],[115,2080],[116,284],[116,308],[119,2591],[122,263],[166,264],[173,269],[177,107],[177,112],[260,104],[262,102],[271,109],[280,119],[283,265],[283,271],[293,112],[293,269],[295,116],[309,113],[310,279],[311,102],[323,262],[327,118],[328,287],[339,107],[340,117],[364,296],[367,108],[382,335],[434,118],[487,60],[512,113],[539,293],[552,109],[552,279],[675,101],[720,115],[744,278],[806,274],[819,199],[951,101],[961,267],[962,265],[980,109],[1002,120],[1032,119],[1080,261],[1103,114],[1136,267],[1139,116],[1141,112],[1153,106],[1164,109],[1189,284],[1229,105],[1264,109],[1305,299],[1329,109],[1459,262],[1459,273],[1493,114],[1569,199],[1590,112],[1662,282],[1721,199],[1869,274],[1873,270],[1891,105],[1937,115],[1995,109],[2014,199],[2072,268],[2143,114],[2159,109],[2173,109],[2291,260],[2395,266],[2413,105],[2474,119],[2490,101],[2503,432],[2539,109],[2638,101],[2687,114],[2711,101],[2772,49],[2833,114],[2836,101],[2844,101],[2906,105],[2922,115],[2923,101],[2958,109],[2990,121],[2992,115],[2999,264],[3002,116],[3003,115],[3004,171],[3009,199],[3012,108],[3015,115],[3019,118],[3020,119],[3022,126],[3026,167],[3028,274],[3029,171],[3030,115],[3035,171],[3038,120],[3039,119],[3045,101],[3046,104],[3048,108],[3050,101],[3063,199],[3064,166],[3067,109],[3071,115],[3072,199],[3076,103],[3078,101],[3080,49],[3081,167],[3082,114],[3083,115],[3085,167],[3087,104],[3089,115],[3090,103],[3091,118],[3092,115],[3093,105],[3095,109],[3099,101],[44,71],[44,481],[49,113],[49,115],[50,50],[54,60],[69,344],[70,2002],[73,114],[74,281],[78,121],[78,2518],[81,694],[82,2406],[87,71],[92,92],[101,38],[101,405],[101,2816],[102,313],[103,262],[103,269],[105,106],[105,261],[107,305],[110,1618],[112,280],[116,119],[121,104],[174,113],[199,172],[273,260],[276,103],[276,116],[279,262],[283,48],[284,101],[284,109],[294,103],[304,115],[307,114],[310,278],[313,107],[332,279],[332,300],[335,120],[338,119],[349,294],[366,102],[372,103],[372,281],[382,332],[406,115],[427,71],[437,263],[440,119],[446,118],[453,266],[475,415],[496,105],[510,115],[510,121],[533,104],[588,199],[588,261],[598,105],[612,260],[644,119],[663,291],[684,199],[706,109],[729,116],[740,296],[764,119],[768,124],[808,105],[838,101],[875,267],[928,199],[930,48],[941,113],[953,109],[976,266],[976,278],[1032,112],[1077,101],[1134,109],[1201,199],[1251,260],[1256,267],[1278,355],[1339,109],[1343,118],[1390,109],[1458,101],[1502,276],[1540,115],[1549,101],[1607,124],[1639,184],[1648,199],[1652,101],[1675,323],[1699,107],[1874,267],[1966,105],[2001,101],[2037,118],[2052,265],[2073,109],[2079,115],[2112,118],[2141,115],[2178,277],[2188,105],[2194,112],[2207,274],[2215,119],[2274,101],[2352,49],[2391,101],[2492,109],[2508,270],[2675,112],[2693,115],[2710,112],[2744,105],[2771,115],[2814,105],[2890,101],[2895,199],[2896,118],[2989,105],[3000,264],[3016,105],[3037,119],[3041,113],[3053,118],[3054,264],[3125,102],[3144,264],[3145,118],[3154,50],[3158,260],[3166,109],[3167,118],[3172,118],[3176,114],[3181,109],[3184,114],[3200,279],[3201,171],[3206,119],[3210,120],[3213,118],[3217,115],[3224,108],[3228,107],[3231,171],[3232,103],[3233,275],[3237,105],[3241,105],[3245,118],[3247,105],[3248,104],[3250,101],[3251,114],[3255,113],[3257,101],[3258,109],[3259,199],[3260,109],[3262,264],[3265,120],[3273,115],[3274,105],[53,45],[55,50],[55,57],[57,45],[57,50],[59,48],[69,104],[69,107],[69,113],[69,2420],[75,349],[75,448],[76,115],[80,101],[80,109],[80,328],[81,2682],[84,105],[84,1280],[87,1359],[101,3153],[103,50],[103,324],[105,199],[106,3268],[107,1161],[110,3059],[114,266],[114,1983],[115,290],[119,263],[119,275],[119,291],[119,307],[121,124],[125,48],[125,114],[126,286],[177,101],[177,103],[261,114],[265,102],[266,104],[269,106],[270,269],[275,124],[275,266],[276,199],[280,118],[281,199],[283,106],[284,267],[286,260],[293,270],[295,276],[300,120],[306,121],[311,283],[313,270],[321,122],[327,107],[327,269],[336,113],[336,271],[366,113],[372,347],[378,122],[393,120],[395,105],[413,101],[423,103],[444,109],[479,103],[479,270],[496,121],[528,119],[528,272],[535,114],[559,293],[606,403],[621,264],[635,121],[637,105],[656,105],[661,114],[663,103],[664,323],[688,120],[762,101],[770,115],[804,290],[806,121],[817,265],[821,48],[825,116],[872,115],[915,271],[963,109],[968,199],[978,105],[1009,273],[1049,48],[1074,121],[1145,119],[1153,107],[1161,278],[1168,112],[1230,124],[1268,199],[1278,1161],[1309,103],[1320,199],[1341,276],[1398,48],[1408,112],[1443,199],[1458,115],[1513,119],[1528,109],[1556,115],[1595,109],[1607,120],[1611,104],[1742,114],[1777,275],[1809,756],[1871,267],[1887,114],[1933,115],[1974,184],[1985,105],[1986,114],[1989,199],[2017,120],[2030,101],[2082,120],[2101,48],[2104,115],[2109,109],[2153,115],[2168,118],[2170,112],[2187,199],[2233,114],[2334,119],[2345,49],[2363,265],[2367,115],[2422,109],[2434,262],[2547,119],[2577,266],[2646,105],[2692,199],[2712,113],[2765,101],[2824,313],[2829,105],[2840,114],[2857,115],[2874,199],[2875,114],[2925,167],[2934,112],[2979,114],[3058,105],[3060,115],[3061,101],[3069,101],[3086,115],[3146,101],[3149,112],[3171,104],[3208,280],[3236,199],[3238,101],[3239,105],[3240,283],[3275,101],[3287,113],[3294,116],[3303,281],[3306,263],[3330,116],[3348,109],[3351,114],[3359,112],[3361,119],[3363,121],[3369,101],[3372,109],[3374,261],[3376,177],[3385,109],[3386,174],[3387,278],[3388,324],[3389,171],[3390,119],[3396,114],[3406,114],[3407,114],[3408,112],[3409,107],[3410,177],[3412,269],[3413,109],[3416,266],[3423,119],[3427,109],[3428,120],[3429,260],[3430,109],[3432,105],[3438,171],[3440,115],[3449,105],[3450,101],[3452,165],[3457,109],[3458,115],[3460,120],[3461,105],[3464,107],[3466,112],[3470,106],[3472,114],[3475,199],[3478,101],[3479,109],[3481,105],[3482,119],[3483,101],[3485,260],[3486,105],[3487,103],[3490,262],[3491,264],[3492,199],[3496,122],[3497,101],[3498,112],[3499,105],[3500,114],[3503,109],[3504,278],[3507,115],[3508,109],[3509,120],[3515,105],[3517,105],[3519,109],[3521,104],[3522,103],[3525,118],[3526,109],[3529,275],[3533,103],[3534,114],[3535,101],[3536,101],[44,69],[44,84],[49,81],[49,103],[49,106],[52,50],[57,52],[59,50],[60,45],[69,109],[71,2197],[75,670],[76,722],[76,949],[77,355],[78,101],[82,267],[82,303],[84,3345],[91,368],[101,63],[101,278],[101,302],[102,331],[102,1143],[103,293],[103,1546],[105,2000],[106,263],[106,2424],[109,355],[113,325],[114,1359],[114,2195],[115,124],[115,2991],[119,674],[121,323],[126,263],[183,106],[183,119],[263,45],[263,106],[265,115],[267,103],[268,109],[272,101],[276,101],[278,112],[279,103],[280,114],[281,113],[282,268],[283,108],[283,270],[289,107],[290,114],[291,113],[294,101],[294,104],[294,265],[300,102],[300,107],[310,282],[321,311],[324,279],[332,305],[339,103],[343,101],[362,296],[365,113],[366,120],[372,109],[442,103],[442,267],[456,267],[470,101],[483,120],[487,56],[497,273],[503,281],[539,280],[546,101],[583,283],[629,345],[645,114],[699,282],[914,115],[976,101],[1009,118],[1009,287],[1038,101],[1041,118],[1047,105],[1090,53],[1108,109],[1111,280],[1160,112],[1274,261],[1278,298],[1291,119],[1333,48],[1341,263],[1355,266],[1365,109],[1392,300],[1395,287],[1449,302],[1519,101],[1540,267],[1550,118],[1555,262],[1616,101],[1639,177],[1675,352],[1724,115],[1738,267],[1753,262],[1856,101],[1922,115],[1960,101],[1976,300],[2033,105],[2033,109],[2042,105],[2050,105],[2060,429],[2136,101],[2140,103],[2211,104],[2212,171],[2256,101],[2293,103],[2358,271],[2394,112],[2399,120],[2419,101],[2435,199],[2510,287],[2529,115],[2553,118],[2563,101],[2640,101],[2686,101],[2688,101],[2733,120],[2779,115],[2784,284],[2817,269],[2945,118],[2982,101],[3034,120],[3065,115],[3096,113],[3112,119],[3122,116],[3151,103],[3164,171],[3168,101],[3179,183],[3193,120],[3194,120],[3222,282],[3225,119],[3234,105],[3269,101],[3271,101],[3272,167],[3297,115],[3350,105],[3377,114],[3399,101],[3411,105],[3426,112],[3454,113],[3463,105],[3488,269],[3501,101],[3502,115],[3523,101],[3548,350],[3549,101],[3557,303],[3568,105],[3570,289],[3571,121],[3572,105],[3575,276],[3603,102],[3609,267],[3620,113],[3624,105],[3625,199],[3632,119],[3636,115],[3641,119],[3643,102],[3649,109],[3652,114],[3665,114],[3667,109],[3669,115],[3674,109],[3675,112],[3676,167],[3678,112],[3686,267],[3687,115],[3690,121],[3691,112],[3692,105],[3694,120],[3696,199],[3699,109],[3700,121],[3706,115],[3713,105],[3715,101],[3720,261],[3722,109],[3727,287],[3728,106],[3730,264],[3731,185],[3734,115],[3735,121],[3737,119],[3738,291],[3741,122],[3743,115],[3746,118],[3749,264],[3750,115],[3753,260],[3755,114],[3758,262],[3762,263],[3763,118],[3765,121],[3770,105],[3773,120],[3777,112],[3779,105],[3780,101],[44,38],[44,288],[49,53],[49,107],[49,260],[53,912],[54,45],[54,61],[61,61],[69,106],[69,122],[69,391],[69,550],[70,307],[70,360],[70,673],[71,1020],[74,1420],[75,387],[80,115],[83,997],[87,108],[87,447],[88,288],[90,105],[102,125],[102,992],[103,284],[104,48],[104,123],[105,351],[105,409],[106,1388],[108,48],[108,281],[109,50],[111,286],[112,104],[112,286],[113,411],[113,1162],[114,276],[114,307],[118,260],[118,3008],[120,299],[126,280],[165,49],[190,102],[262,116],[265,109],[265,116],[272,120],[275,122],[277,120],[278,267],[278,275],[283,122],[284,104],[284,106],[287,113],[287,265],[289,106],[295,120],[295,285],[304,103],[306,114],[310,275],[324,103],[325,119],[333,310],[374,113],[385,122],[396,122],[409,273],[414,119],[441,199],[450,116],[487,53],[488,308],[505,280],[506,167],[506,177],[541,114],[552,122],[611,107],[620,109],[628,278],[629,389],[633,199],[672,120],[682,118],[688,122],[701,285],[714,124],[714,266],[723,276],[744,103],[776,109],[785,109],[787,103],[804,269],[806,101],[840,101],[846,101],[857,382],[954,109],[968,120],[1014,103],[1026,50],[1035,118],[1038,115],[1046,48],[1071,442],[1080,199],[1117,105],[1129,267],[1133,199],[1137,109],[1138,48],[1147,105],[1217,109],[1260,109],[1303,120],[1305,273],[1343,114],[1343,262],[1407,674],[1412,199],[1507,120],[1569,109],[1601,118],[1602,109],[1612,109],[1643,291],[1660,119],[1666,119],[1724,101],[1742,109],[1743,496],[1753,118],[1827,121],[1841,48],[1869,199],[2017,199],[2025,103],[2038,512],[2042,109],[2050,101],[2105,115],[2115,114],[2148,115],[2190,101],[2232,120],[2276,48],[2281,271],[2307,262],[2315,294],[2323,184],[2338,261],[2360,115],[2372,112],[2409,119],[2457,263],[2524,118],[2527,265],[2543,105],[2544,166],[2561,120],[2569,105],[2570,119],[2585,126],[2588,184],[2606,105],[2643,506],[2673,273],[2714,121],[2770,260],[2794,108],[2809,105],[2821,289],[2823,106],[2827,118],[2837,119],[2838,266],[2848,118],[2854,267],[2865,263],[2939,112],[2947,112],[2967,265],[2984,114],[3014,112],[3017,199],[3024,113],[3033,48],[3057,271],[3077,112],[3079,101],[3088,82],[3119,270],[3147,272],[3160,109],[3163,262],[3188,184],[3199,115],[3203,118],[3212,267],[3254,115],[3266,105],[3296,287],[3320,101],[3368,104],[3418,115],[3439,115],[3471,113],[3477,101],[3505,167],[3528,112],[3588,199],[3600,115],[3638,115],[3653,119],[3656,120],[3668,109],[3689,262],[3697,107],[3707,262],[3751,167],[3794,118],[3798,107],[3848,284],[3853,106],[3860,120],[3870,115],[3872,173],[3875,105],[3876,199],[3880,121],[3881,119],[3882,119],[3891,268],[3896,267],[3897,171],[3901,114],[3903,113],[3905,101],[3906,109],[3908,108],[3911,177],[3912,263],[3913,101],[3921,115],[3923,199],[3926,185],[3927,171],[3928,268],[3930,113],[3940,265],[3941,114],[3950,114],[3954,101],[3955,314],[3957,167],[3964,263],[3965,119],[3967,260],[3972,109],[3974,119],[3975,263],[3976,171],[3982,115],[3987,113],[3989,299],[4000,115],[4002,166],[4003,262],[4004,112],[4006,121],[4009,105],[4011,115],[4012,118],[4013,109],[4015,109],[4017,114],[4018,269],[4019,110],[4020,177],[4021,112],[4026,199],[4027,101],[4030,122],[4032,119],[4034,114],[4035,118],[4036,165],[4037,263],[4038,101],[4040,105],[4041,112],[4042,109],[4043,109],[4046,115],[4047,120],[4050,113],[4053,199],[4054,122],[4055,109],[4056,112],[4058,114],[4060,115],[4061,118],[4064,101],[4065,271],[4066,271],[4067,101],[4069,101],[4070,113],[4071,101],[4072,167],[4075,120],[4076,109],[4078,269],[4081,114],[4082,101],[4083,101],[4089,101],[4090,103],[4091,291],[4092,109],[4093,107],[4094,101],[4098,112],[4100,109],[4101,118],[4102,115],[4103,109],[4104,119],[4106,120],[4113,109],[4120,113],[4121,115],[4122,101],[4123,115],[44,340],[44,960],[54,56],[55,53],[55,59],[56,50],[69,3698],[70,115],[70,3216],[71,1257],[75,115],[77,408],[81,109],[81,268],[81,319],[82,1388],[87,512],[88,115],[88,3621],[101,293],[101,550],[102,4084],[105,38],[105,364],[106,356],[106,461],[107,273],[108,121],[110,3935],[111,105],[112,45],[112,49],[112,281],[114,283],[116,280],[116,3869],[118,102],[119,365],[119,2324],[120,108],[121,275],[123,101],[125,50],[171,268],[173,107],[183,109],[190,119],[190,261],[198,180],[261,112],[265,49],[265,107],[266,105],[266,112],[268,116],[271,264],[276,106],[277,266],[278,113],[279,271],[286,280],[287,48],[288,109],[291,118],[295,124],[296,120],[297,102],[297,275],[299,278],[300,122],[304,266],[306,103],[306,283],[307,269],[308,264],[313,289],[318,109],[318,115],[324,125],[324,276],[325,120],[333,262],[333,324],[344,118],[357,293],[362,315],[368,348],[373,344],[383,264],[383,344],[418,291],[420,114],[446,113],[446,199],[447,267],[453,114],[469,273],[470,105],[470,121],[493,112],[537,114],[541,262],[662,118],[664,119],[678,119],[696,115],[699,537],[729,263],[748,199],[831,276],[857,302],[928,115],[941,116],[952,105],[985,282],[1090,57],[1101,105],[1101,109],[1118,115],[1151,115],[1200,826],[1207,105],[1213,104],[1232,264],[1247,106],[1261,103],[1276,593],[1294,105],[1297,48],[1316,261],[1342,114],[1356,119],[1357,101],[1420,268],[1471,199],[1529,120],[1538,269],[1555,118],[1565,119],[1588,107],[1648,121],[1668,185],[1777,120],[1834,113],[1843,113],[1846,119],[1871,115],[1921,105],[2001,268],[2020,199],[2082,272],[2104,267],[2140,199],[2204,260],[2229,266],[2280,119],[2288,310],[2333,199],[2350,267],[2353,121],[2382,104],[2438,101],[2467,113],[2605,115],[2616,101],[2635,271],[2649,114],[2695,118],[2696,288],[2760,115],[2785,115],[2786,952],[2795,109],[2799,268],[2810,274],[2812,118],[2834,102],[2852,115],[2863,106],[2868,199],[2898,120],[2937,119],[2949,199],[2959,310],[2961,283],[2964,103],[2974,109],[2978,199],[2998,293],[3006,101],[3052,119],[3159,370],[3182,119],[3204,118],[3220,101],[3252,267],[3342,115],[3393,167],[3400,115],[3401,101],[3403,120],[3421,107],[3431,184],[3434,122],[3435,114],[3442,199],[3444,119],[3459,115],[3462,105],[3468,262],[3473,268],[3506,107],[3532,115],[3551,101],[3585,120],[3619,120],[3666,113],[3671,105],[3677,107],[3679,118],[3701,274],[3771,107],[3795,268],[3800,115],[3801,270],[3803,900],[3805,306],[3833,119],[3856,101],[3862,271],[3863,49],[3867,101],[3878,119],[3884,102],[3893,115],[3929,113],[3947,116],[3951,115],[3962,107],[3984,264],[3995,199],[4016,101],[4068,101],[4112,271],[4133,120],[4135,291],[4138,289],[4142,101],[4143,270],[4181,105],[4186,114],[4202,107],[4209,103],[4223,104],[4226,109],[4229,263],[4232,118],[4233,114],[4236,119],[4239,115],[4241,274],[4249,101],[4251,461],[4261,174],[4266,121],[4268,263],[4271,105],[4279,171],[4280,114],[4283,283],[4284,171],[4289,102],[4298,105],[4299,103],[4301,115],[4303,109],[4306,184],[4309,184],[4310,107],[4312,109],[4314,183],[4319,120],[4320,299],[4321,126],[4324,115],[4327,101],[4328,121],[4329,279],[4331,119],[4332,171],[4338,105],[4343,105],[4347,115],[4354,101],[4360,105],[4363,115],[4365,101],[4367,165],[4371,105],[4373,120],[4376,103],[4377,109],[4379,121],[4380,109],[4381,101],[4384,101],[4386,118],[4387,115],[4388,260],[4389,101],[4390,114],[4393,114],[4397,199],[4398,118],[4400,101],[4402,112],[4403,114],[4406,115],[4407,112],[4408,101],[4409,106],[4410,121],[4414,120],[4418,264],[4425,112],[4426,121],[4427,120],[4429,300],[4430,120],[4431,114],[4432,112],[4433,120],[4437,103],[4438,120],[4440,115],[4442,109],[4443,109],[4444,114],[4445,109],[4447,109],[4448,112],[4449,118],[4450,105],[4451,263],[4452,120],[4454,118],[4459,109],[4460,105],[4464,101],[4465,103],[4476,101],[44,48],[44,63],[44,1048],[44,3114],[55,41],[55,45],[58,50],[59,45],[69,1229],[70,109],[71,710],[72,101],[73,262],[76,299],[77,48],[77,120],[80,322],[83,755],[84,71],[84,109],[87,802],[101,2666],[101,4031],[103,280],[104,299],[104,3347],[105,125],[106,268],[106,281],[106,365],[106,469],[107,818],[108,2122],[111,109],[112,125],[112,277],[113,291],[113,319],[114,126],[114,367],[114,2918],[115,126],[115,706],[115,1781],[116,50],[118,262],[118,303],[119,63],[119,116],[120,280],[122,277],[122,284],[122,306],[124,105],[172,273],[198,174],[210,181],[266,199],[267,45],[268,113],[273,102],[273,264],[276,274],[277,269],[279,260],[279,272],[281,263],[283,117],[283,263],[285,276],[286,268],[289,264],[293,116],[293,121],[294,106],[297,113],[297,261],[300,121],[300,264],[302,263],[302,272],[311,261],[313,113],[315,282],[319,48],[324,120],[326,109],[327,116],[333,264],[333,297],[338,336],[343,116],[351,300],[356,314],[360,268],[372,105],[373,102],[384,299],[385,300],[393,290],[409,126],[434,199],[441,115],[447,269],[456,120],[465,294],[488,266],[500,102],[503,277],[524,114],[531,362],[533,118],[563,283],[588,266],[615,304],[625,271],[635,276],[635,286],[641,103],[660,120],[661,120],[669,177],[677,394],[717,269],[718,50],[726,109],[729,109],[739,48],[740,325],[750,279],[758,199],[810,166],[831,121],[844,103],[865,199],[962,103],[989,112],[1001,264],[1005,115],[1010,267],[1017,105],[1019,987],[1026,48],[1038,268],[1103,103],[1107,113],[1117,101],[1118,126],[1134,121],[1166,115],[1204,266],[1215,115],[1226,267],[1227,350],[1270,266],[1276,311],[1317,109],[1355,320],[1358,112],[1364,199],[1444,265],[1521,289],[1521,300],[1531,177],[1531,183],[1542,115],[1589,112],[1611,118],[1635,101],[1635,105],[1635,109],[1721,261],[1748,120],[1786,261],[1798,185],[1819,120],[1837,121],[1839,261],[1870,115],[1873,113],[1874,115],[1901,105],[1908,331],[1909,1492],[1941,103],[1989,121],[2024,266],[2043,116],[2053,57],[2060,281],[2062,199],[2079,267],[2136,115],[2153,101],[2160,264],[2168,262],[2170,109],[2192,105],[2211,260],[2220,119],[2232,199],[2256,115],[2310,281],[2350,115],[2354,112],[2372,109],[2421,199],[2500,661],[2530,115],[2532,199],[2551,104],[2592,119],[2607,104],[2651,101],[2690,126],[2754,199],[2775,261],[2791,112],[2818,107],[2825,109],[2860,101],[2873,103],[2894,109],[2905,115],[2915,199],[2946,72],[3001,118],[3044,112],[3051,101],[3075,115],[3113,103],[3150,112],[3161,112],[3187,120],[3229,118],[3244,109],[3249,120],[3264,115],[3270,264],[3289,112],[3349,118],[3353,263],[3357,115],[3364,199],[3380,101],[3392,267],[3436,101],[3467,112],[3476,109],[3516,185],[3560,270],[3635,120],[3647,112],[3688,327],[3725,112],[3739,101],[3747,109],[3761,263],[3767,101],[3792,2530],[3793,2988],[3809,114],[3841,199],[3866,119],[3873,262],[3889,120],[3900,183],[3949,109],[3958,120],[3963,106],[3973,112],[3985,262],[3990,103],[4088,167],[4196,115],[4211,107],[4216,118],[4218,105],[4220,171],[4221,120],[4237,276],[4244,119],[4252,101],[4257,103],[4276,167],[4287,115],[4294,115],[4305,199],[4313,103],[4348,262],[4382,101],[4395,120],[4405,115],[4416,101],[4422,262],[4453,267],[4455,101],[4467,49],[4468,267],[4471,115],[4488,106],[4493,3169],[4495,264],[4517,271],[4520,199],[4557,109],[4558,114],[4563,262],[4568,278],[4573,364],[4576,114],[4581,103],[4583,114],[4585,306],[4587,260],[4588,296],[4596,101],[4601,103],[4604,115],[4608,171],[4609,264],[4610,314],[4612,190],[4613,268],[4615,115],[4616,118],[4627,104],[4631,119],[4634,104],[4636,115],[4637,190],[4640,279],[4641,119],[4644,101],[4652,263],[4657,199],[4674,119],[4678,171],[4683,119],[4684,166],[4685,120],[4690,101],[4691,261],[4693,165],[4699,109],[4702,171],[4704,114],[4708,294],[4709,121],[4713,118],[4718,109],[4721,166],[4726,115],[4727,263],[4729,109],[4731,119],[4737,115],[4739,282],[4744,112],[4745,262],[4747,109],[4750,199],[4751,115],[4755,103],[4756,199],[4757,115],[4761,109],[4762,115],[4764,109],[4765,177],[4767,106],[4769,105],[4782,174],[4783,101],[4784,103],[4786,105],[4789,121],[4790,109],[4793,114],[4795,101],[4796,118],[4797,199],[4798,109],[4800,102],[4803,109],[4804,121],[4806,121],[4807,102],[4808,261],[4809,264],[4813,165],[4815,199],[4817,113],[4820,118],[4821,120],[4822,115],[4823,199],[4825,116],[4828,120],[4829,114],[4830,114],[4833,307],[4836,109],[4839,183],[4844,101],[4846,260],[4847,278],[4848,109],[4852,109],[4853,264],[4854,112],[4856,126],[4857,114],[4860,103],[4861,112],[4862,101],[4865,101],[4867,115],[4868,120],[4870,109],[4872,109],[4873,114],[4875,109],[4877,278],[4878,101],[4881,116],[4885,101],[4886,101],[4887,105],[4888,120],[4889,280],[4890,115],[4892,109],[4893,112],[4896,109],[4898,103],[4899,101],[4900,115],[4903,109],[4907,121],[4910,271],[4917,262],[38,69],[44,77],[44,101],[44,309],[49,87],[50,38],[56,41],[57,41],[60,50],[60,60],[61,45],[61,60],[69,103],[69,282],[69,405],[69,525],[69,650],[70,4625],[71,112],[71,121],[71,1052],[72,747],[75,73],[75,1914],[76,101],[76,367],[76,1948],[80,1524],[80,4203],[81,430],[81,500],[81,2680],[82,268],[84,580],[84,1219],[84,4611],[86,1334],[87,1389],[88,118],[88,4219],[101,409],[102,469],[102,3366],[103,114],[103,429],[103,1185],[103,3717],[103,4235],[103,4245],[103,4571],[104,50],[104,273],[104,683],[104,1223],[105,265],[106,992],[106,2521],[109,269],[111,115],[112,119],[113,3615],[116,3141],[116,4743],[118,108],[121,305],[122,331],[126,48],[166,314],[177,269],[183,113],[190,48],[210,195],[260,115],[261,120],[263,117],[265,104],[267,49],[268,45],[268,199],[269,117],[269,261],[272,48],[272,109],[274,267],[275,270],[277,104],[277,275],[278,103],[280,278],[282,115],[283,115],[288,115],[291,290],[292,101],[293,113],[293,262],[294,269],[295,273],[299,48],[304,260],[304,278],[304,293],[305,113],[305,290],[309,273],[310,199],[313,263],[313,266],[315,120],[317,115],[319,104],[328,275],[332,106],[333,112],[338,260],[339,269],[342,107],[342,304],[351,339],[352,101],[367,266],[368,121],[376,289],[378,285],[378,342],[384,267],[385,113],[397,376],[400,273],[416,105],[423,115],[433,268],[443,272],[443,289],[469,328],[503,119],[524,118],[527,103],[527,109],[538,48],[541,112],[547,115],[553,104],[563,122],[579,101],[593,264],[625,291],[651,109],[660,266],[664,310],[677,344],[696,112],[697,105],[699,126],[699,311],[701,113],[709,115],[715,115],[729,103],[735,50],[740,371],[742,101],[758,261],[762,115],[763,113],[769,103],[774,105],[786,121],[794,50],[804,287],[812,293],[823,310],[828,105],[893,199],[905,108],[923,325],[965,277],[985,114],[996,382],[1038,288],[1041,114],[1053,48],[1086,112],[1106,104],[1133,101],[1139,102],[1146,199],[1147,199],[1159,286],[1159,294],[1189,281],[1202,264],[1228,310],[1229,121],[1231,105],[1234,115],[1263,119],[1268,105],[1292,114],[1303,261],[1313,55],[1321,101],[1337,177],[1339,115],[1342,119],[1354,102],[1355,370],[1365,199],[1390,115],[1390,121],[1402,119],[1425,266],[1460,120],[1464,54],[1497,121],[1501,118],[1521,299],[1528,199],[1538,114],[1544,119],[1547,199],[1590,107],[1611,199],[1629,116],[1638,114],[1661,268],[1697,121],[1707,114],[1723,113],[1728,115],[1733,199],[1745,260],[1756,121],[1757,114],[1763,263],[1775,177],[1787,48],[1817,262],[1839,199],[1843,109],[1888,261],[1913,121],[1921,109],[1922,105],[1923,109],[1935,297],[1957,261],[1957,266],[1974,165],[1985,101],[1986,120],[2020,101],[2024,261],[2025,265],[2030,105],[2057,119],[2112,287],[2115,418],[2120,108],[2147,119],[2148,101],[2229,261],[2233,264],[2258,199],[2281,265],[2284,115],[2307,118],[2315,121],[2319,54],[2362,121],[2380,119],[2466,266],[2506,384],[2536,113],[2580,119],[2605,101],[2625,112],[2644,48],[2645,123],[2655,279],[2670,108],[2683,118],[2690,103],[2701,112],[2725,119],[2742,272],[2754,101],[2756,119],[2764,101],[2766,119],[2787,75],[2790,48],[2861,114],[2862,119],[2864,291],[2908,115],[2911,109],[2921,119],[2931,119],[2956,263],[3025,101],[3074,199],[3107,109],[3110,273],[3142,115],[3143,121],[3170,190],[3175,101],[3226,105],[3230,104],[3284,723],[3333,286],[3344,115],[3358,121],[3375,119],[3494,270],[3606,293],[3612,50],[3628,267],[3634,266],[3684,101],[3712,109],[3714,103],[3752,112],[3756,112],[3799,101],[3813,104],[3814,311],[3815,105],[3846,277],[3854,274],[3890,118],[3933,310],[3961,115],[3986,261],[4022,113],[4048,267],[4086,101],[4116,271],[4119,271],[4178,114],[4234,119],[4248,266],[4290,119],[4326,103],[4330,105],[4335,114],[4342,115],[4356,112],[4361,104],[4385,274],[4428,119],[4439,167],[4463,101],[4473,101],[4477,119],[4499,119],[4500,101],[4566,101],[4639,261],[4643,262],[4646,112],[4653,199],[4668,171],[4672,105],[4688,109],[4711,101],[4810,113],[4818,115],[4835,101],[4838,271],[4850,114],[4883,119],[4884,105],[4902,112],[4912,271],[4933,277],[4941,114],[4943,278],[4950,116],[4959,105],[4967,171],[4972,166],[4976,115],[4981,105],[4994,121],[4995,109],[5004,114],[5007,112],[5017,113],[5019,118],[5034,119],[5037,275],[5043,109],[5048,104],[5061,114],[5069,122],[5071,121],[5072,114],[5076,118],[5091,283],[5093,177],[5097,261],[5099,102],[5103,101],[5104,112],[5106,165],[5107,177],[5112,282],[5115,121],[5117,264],[5123,118],[5125,109],[5127,165],[5129,262],[5132,115],[5138,115],[5140,171],[5142,171],[5146,282],[5147,119],[5148,105],[5150,165],[5151,109],[5152,112],[5158,171],[5168,118],[5174,109],[5177,291],[5183,171],[5192,267],[5193,105],[5199,264],[5202,109],[5203,101],[5210,73],[5220,107],[5221,185],[5222,114],[5223,109],[5224,114],[5226,119],[5230,276],[5233,261],[5236,269],[5239,260],[5241,126],[5242,105],[5243,108],[5246,199],[5247,101],[5251,115],[5255,115],[5262,260],[5264,109],[5266,103],[5269,121],[5270,115],[5271,113],[5272,115],[5283,199],[5287,115],[5291,103],[5297,122],[5298,101],[5299,108],[5300,114],[5302,114],[5304,109],[5306,106],[5307,108],[5311,120],[5312,118],[5314,109],[5315,101],[5318,104],[5323,287],[5326,120],[5331,113],[5333,118],[5336,113],[5337,199],[5338,199],[5340,120],[5341,114],[5342,118],[5343,118],[5344,101],[5346,120],[5347,118],[5349,199],[5351,264],[5352,115],[5353,266],[5356,105],[5357,263],[5358,105],[5359,262],[5360,101],[5361,120],[5362,120],[5364,101],[5366,101],[5369,174],[5374,115],[5375,109],[5382,109],[5383,115],[5385,125],[5386,120],[5387,103],[5389,109],[5391,105],[5393,120],[5397,109],[5399,109],[5400,291],[5403,118],[5404,120],[5405,109],[5406,101],[5408,109],[5410,167],[5411,105],[5413,260],[5419,269],[5420,262],[5422,199],[5423,114],[5426,101],[5427,112],[5430,109],[5431,103],[5435,115],[5442,115],[5447,171],[5448,278],[5450,122],[5452,101],[5457,109],[44,55],[44,80],[44,83],[44,87],[49,84],[49,487],[51,321],[54,55],[55,56],[58,45],[58,57],[59,52],[69,3115],[70,50],[70,306],[70,377],[70,438],[71,267],[71,2695],[72,307],[72,474],[73,300],[73,334],[73,3812],[76,105],[76,284],[76,331],[77,724],[78,299],[80,1810],[80,2818],[81,447],[81,3152],[81,5108],[82,2918],[83,118],[83,2080],[83,2966],[84,281],[84,306],[84,382],[84,2002],[84,3177],[84,3782],[87,349],[88,105],[88,1153],[89,82],[91,50],[101,265],[101,1364],[101,2442],[101,5418],[102,267],[102,291],[102,1420],[103,113],[103,298],[103,2544],[104,303],[105,3969],[105,5466],[107,48],[107,113],[107,335],[107,349],[107,358],[108,111],[108,114],[108,484],[108,949],[110,382],[111,281],[111,385],[112,279],[112,1500],[113,45],[113,303],[113,1642],[114,524],[116,268],[116,305],[118,38],[118,117],[118,278],[118,3152],[119,283],[119,1223],[119,2672],[120,276],[120,524],[122,307],[122,1187],[122,2123],[126,50],[165,103],[166,279],[167,263],[174,121],[211,133],[262,49],[265,126],[266,107],[269,118],[269,122],[270,261],[271,270],[272,102],[272,270],[273,105],[273,261],[275,50],[277,273],[278,264],[279,124],[280,50],[280,276],[281,48],[284,124],[284,126],[286,121],[287,50],[289,115],[290,48],[290,289],[296,269],[297,114],[297,120],[299,102],[299,121],[302,102],[304,261],[305,269],[305,273],[309,109],[310,293],[313,112],[313,262],[315,104],[315,109],[318,102],[318,286],[321,118],[333,120],[333,261],[336,265],[338,261],[340,199],[342,275],[351,316],[357,264],[361,190],[364,124],[365,118],[368,267],[372,101],[382,271],[385,377],[393,102],[425,105],[443,269],[453,260],[475,348],[505,294],[528,103],[538,50],[549,49],[554,273],[567,199],[580,115],[583,516],[594,117],[621,345],[625,269],[625,371],[674,113],[688,199],[688,275],[720,101],[735,48],[745,308],[750,113],[750,327],[776,48],[780,264],[787,268],[806,109],[811,295],[825,105],[825,275],[827,115],[852,118],[893,119],[901,268],[912,52],[918,260],[920,48],[937,115],[950,115],[960,57],[965,267],[985,266],[1019,54],[1049,119],[1053,49],[1056,121],[1068,113],[1080,266],[1085,120],[1100,115],[1103,112],[1117,109],[1150,119],[1151,265],[1199,48],[1221,109],[1227,324],[1247,119],[1256,115],[1261,262],[1274,199],[1275,261],[1275,266],[1285,101],[1285,109],[1297,119],[1305,263],[1314,116],[1332,104],[1341,121],[1356,49],[1364,124],[1407,313],[1407,928],[1408,275],[1433,261],[1439,109],[1460,107],[1470,109],[1534,119],[1538,113],[1567,48],[1568,112],[1588,118],[1622,185],[1662,289],[1676,260],[1683,280],[1740,682],[1743,270],[1758,294],[1782,115],[1786,113],[1808,611],[1808,624],[1847,268],[1852,261],[1868,107],[1872,48],[1891,101],[1908,454],[1937,105],[1945,48],[1976,284],[1977,1757],[1984,260],[1987,276],[1987,283],[1995,118],[1999,48],[2013,120],[2059,199],[2073,103],[2098,48],[2125,113],[2138,48],[2143,119],[2144,119],[2160,114],[2196,104],[2216,48],[2242,266],[2261,48],[2274,115],[2285,48],[2288,261],[2358,103],[2363,103],[2367,267],[2435,101],[2505,471],[2561,102],[2585,101],[2589,48],[2625,120],[2635,265],[2660,107],[2691,199],[2696,715],[2698,48],[2730,48],[2741,113],[2774,119],[2828,282],[2839,103],[2860,115],[2869,119],[2873,199],[2887,104],[2905,101],[3025,119],[3070,267],[3074,274],[3120,287],[3156,115],[3186,261],[3218,48],[3219,112],[3261,112],[3288,334],[3292,342],[3302,115],[3323,101],[3328,277],[3336,126],[3337,105],[3362,115],[3405,115],[3420,167],[3474,115],[3513,101],[3530,105],[3531,115],[3561,109],[3573,554],[3622,109],[3633,45],[3644,279],[3724,113],[3733,119],[3744,115],[3760,105],[3822,121],[3843,199],[3857,103],[3883,101],[3898,119],[3916,104],[3934,119],[3992,114],[4007,266],[4014,282],[4051,199],[4074,101],[4145,261],[4151,279],[4155,112],[4162,119],[4164,276],[4165,270],[4192,287],[4193,273],[4224,264],[4225,264],[4228,199],[4231,199],[4263,266],[4293,103],[4307,115],[4323,122],[4341,118],[4352,126],[4366,199],[4378,115],[4383,118],[4417,113],[4423,261],[4441,113],[4543,115],[4577,118],[4589,120],[4593,121],[4633,118],[4662,101],[4665,101],[4667,120],[4687,177],[4697,120],[4714,109],[4724,104],[4734,282],[4748,115],[4759,120],[4766,101],[4768,119],[4778,199],[4788,260],[4799,266],[4802,48],[4832,271],[4841,105],[4869,167],[4874,167],[4901,268],[4908,119],[4932,4711],[4934,112],[4936,288],[4945,107],[4948,199],[4954,105],[4956,1056],[4962,264],[4965,299],[4973,166],[4982,115],[5035,106],[5036,262],[5047,289],[5049,120],[5052,122],[5057,121],[5063,349],[5064,102],[5067,114],[5084,116],[5089,264],[5096,103],[5100,120],[5102,113],[5109,119],[5111,105],[5118,108],[5137,177],[5143,199],[5164,101],[5178,267],[5187,296],[5205,120],[5206,103],[5225,279],[5234,199],[5261,105],[5290,199],[5327,101],[5330,263],[5363,48],[5368,101],[5390,115],[5402,167],[5414,113],[5424,114],[5425,115],[5429,115],[5446,199],[5451,101],[5456,268],[5459,113],[5472,739],[5477,113],[5478,112],[5480,354],[5487,116],[5489,262],[5492,112],[5500,108],[5502,113],[5506,111],[5510,103],[5518,173],[5529,327],[5538,281],[5548,102],[5603,277],[5605,121],[5606,105],[5610,263],[5612,109],[5613,299],[5620,107],[5622,122],[5623,114],[5631,121],[5636,166],[5640,113],[5641,263],[5642,119],[5651,121],[5666,105],[5670,108],[5675,261],[5676,279],[5680,171],[5689,114],[5691,120],[5697,105],[5698,120],[5703,122],[5704,263],[5705,122],[5707,269],[5708,118],[5710,103],[5716,113],[5723,101],[5724,114],[5726,112],[5728,121],[5730,199],[5731,190],[5732,120],[5734,102],[5736,120],[5738,261],[5739,101],[5746,268],[5747,101],[5749,114],[5751,121],[5754,109],[5756,288],[5757,183],[5767,171],[5768,101],[5772,115],[5780,275],[5783,269],[5787,113],[5788,115],[5791,114],[5793,115],[5795,101],[5797,264],[5800,107],[5801,262],[5802,262],[5807,199],[5812,185],[5818,106],[5823,115],[5824,171],[5826,260],[5827,105],[5831,101],[5832,165],[5836,118],[5838,118],[5840,115],[5844,279],[5846,114],[5847,101],[5851,107],[5852,101],[5855,183],[5856,119],[5857,260],[5861,115],[5862,115],[5865,101],[5866,108],[5867,102],[5868,358],[5869,172],[5870,109],[5871,121],[5872,105],[5873,289],[5874,113],[5876,109],[5878,122],[5880,105],[5881,112],[5882,121],[5883,115],[5884,108],[5885,105],[5886,105],[5887,109],[5889,105],[5890,289],[5892,105],[5893,114],[5894,165],[5899,109],[5900,264],[5903,171],[5909,115],[5911,101],[5912,112],[5914,171],[5917,105],[5919,115],[5922,105],[5923,112],[5924,286],[5925,111],[5926,102],[5927,385],[5929,118],[5932,115],[5935,119],[5938,119],[5940,307],[5941,278],[5943,113],[5946,115],[5948,114],[5949,101],[5950,119],[5951,264],[5952,199],[5954,115],[5955,113],[5956,121],[5957,101],[5962,121],[5966,101],[5968,165],[5969,114],[5970,109],[5971,118],[5972,101],[5974,260],[5977,109],[5979,122],[5981,118],[5982,199],[5986,101],[5987,109],[5989,120],[5992,105],[5993,109],[5996,167],[5997,263],[6000,199],[6002,109],[6003,282],[6004,122],[6006,115],[6008,264],[6009,268],[6011,109],[6013,118],[6018,49],[6019,101],[6020,112],[6022,273],[6024,263],[6027,109],[6031,101],[6032,282],[6035,114],[6037,115],[6038,264],[6040,103],[6041,109],[6043,101],[6045,199],[6047,112],[6048,115],[6049,199],[6050,114],[6051,119],[6052,114],[6054,109],[6055,286],[6056,121],[6057,122],[6058,109],[6059,112],[6060,120],[6062,269],[6063,116],[6064,109],[6065,106],[6066,104],[6069,101],[6070,167],[6073,260],[6075,112],[6077,118],[6078,103],[6079,122],[6080,115],[6083,101],[6084,101],[6085,104],[6086,167],[6088,101],[6089,105],[6091,101],[6092,115],[6096,274],[6097,105],[6099,115],[6101,101],[6102,114],[6103,119],[6104,119],[6110,274],[6111,108],[6112,114],[6113,105],[6114,109],[6115,115],[6117,167],[6119,107],[6121,120],[6123,104],[6130,105],[6131,119],[6132,105],[6135,101],[6137,115],[6140,109],[6141,121],[6146,291],[6147,115],[6152,115],[6156,109],[6157,105],[6159,115],[6165,115],[6166,109],[6167,115],[6168,199],[6175,112],[6179,101],[6183,101],[6185,174],[6186,115],[6189,114],[6191,103],[6192,109],[6193,101],[41,50],[44,45],[44,846],[49,70],[49,80],[56,55],[56,56],[56,57],[56,58],[57,912],[58,912],[61,50],[70,125],[70,381],[71,78],[71,83],[71,327],[71,502],[71,1392],[71,4555],[72,78],[72,263],[72,6209],[73,408],[73,3115],[74,112],[74,5614],[75,287],[75,5774],[76,3312],[77,102],[77,275],[78,414],[78,591],[80,125],[81,1280],[81,3334],[83,87],[83,102],[83,124],[84,5281],[86,101],[86,3858],[87,368],[87,1135],[88,1524],[89,116],[90,77],[90,349],[90,360],[101,273],[101,316],[101,641],[101,3595],[101,5381],[102,268],[102,511],[102,1817],[102,5616],[103,299],[103,489],[104,286],[104,307],[105,62],[105,282],[105,300],[106,262],[106,283],[106,1143],[106,2669],[110,267],[110,328],[111,101],[111,107],[112,38],[112,275],[114,50],[114,281],[114,288],[115,265],[115,304],[115,5804],[116,325],[116,936],[118,285],[118,446],[118,457],[118,5029],[119,306],[120,113],[120,125],[120,126],[121,294],[122,298],[122,1208],[122,5157],[132,151],[132,161],[190,304],[199,186],[210,190],[211,134],[261,124],[263,62],[266,264],[267,105],[267,265],[268,115],[270,104],[270,260],[271,45],[271,104],[273,49],[274,48],[277,48],[277,261],[280,107],[283,103],[283,112],[284,260],[284,266],[284,280],[287,275],[289,101],[289,126],[290,113],[291,45],[295,104],[295,270],[295,271],[296,276],[297,112],[298,263],[299,103],[299,118],[300,103],[302,114],[302,300],[303,50],[308,122],[310,113],[310,116],[310,269],[311,287],[313,121],[313,299],[314,267],[315,103],[318,121],[319,268],[325,266],[326,263],[326,277],[332,304],[333,289],[336,305],[338,110],[339,273],[342,118],[345,109],[347,102],[349,108],[349,327],[350,115],[351,275],[352,281],[357,316],[361,166],[364,119],[365,267],[366,105],[368,199],[372,289],[372,326],[374,287],[376,371],[383,124],[383,272],[383,275],[389,115],[404,48],[413,105],[415,327],[418,115],[425,262],[437,199],[440,120],[446,104],[469,318],[469,412],[471,263],[479,106],[479,120],[480,271],[480,289],[496,266],[502,293],[503,115],[503,430],[515,101],[528,116],[528,311],[535,199],[539,106],[540,114],[556,120],[559,278],[562,105],[568,109],[583,263],[585,266],[585,294],[606,323],[625,293],[626,102],[638,271],[641,120],[663,109],[693,262],[715,267],[723,108],[726,115],[728,267],[740,471],[742,104],[742,115],[742,199],[764,48],[770,101],[780,107],[783,199],[800,101],[806,275],[818,119],[821,50],[831,116],[843,115],[915,267],[917,304],[918,102],[918,112],[918,264],[923,121],[943,105],[951,115],[957,113],[960,58],[960,60],[965,199],[976,118],[997,298],[998,48],[1020,105],[1021,268],[1029,271],[1031,105],[1032,109],[1033,267],[1038,267],[1041,261],[1049,50],[1073,120],[1077,267],[1080,120],[1090,52],[1092,119],[1126,105],[1133,109],[1153,376],[1178,311],[1192,303],[1227,267],[1231,115],[1233,48],[1247,118],[1248,113],[1270,261],[1306,291],[1306,313],[1306,434],[1313,52],[1313,59],[1314,264],[1316,107],[1332,103],[1332,122],[1338,120],[1339,105],[1339,121],[1350,105],[1364,118],[1392,112],[1392,304],[1409,279],[1411,48],[1416,109],[1417,282],[1426,105],[1444,103],[1450,112],[1474,114],[1474,261],[1496,56],[1496,57],[1496,60],[1501,114],[1501,262],[1503,50],[1509,101],[1518,48],[1567,50],[1579,109],[1583,104],[1587,60],[1588,112],[1588,117],[1596,281],[1625,48],[1625,50],[1631,105],[1671,167],[1699,279],[1709,262],[1718,109],[1748,273],[1754,321],[1755,56],[1771,50],[1771,62],[1772,268],[1791,48],[1806,316],[1824,307],[1849,268],[1849,280],[1863,119],[1863,332],[1865,121],[1880,118],[1885,48],[1887,106],[1896,267],[1904,119],[1909,283],[1913,118],[1925,105],[1954,114],[1980,915],[2006,48],[2022,284],[2049,50],[2052,271],[2054,52],[2062,120],[2074,101],[2095,109],[2103,268],[2105,267],[2109,101],[2113,304],[2118,199],[2130,118],[2141,105],[2204,119],[2242,118],[2242,261],[2258,261],[2284,101],[2284,121],[2286,361],[2304,105],[2316,116],[2324,265],[2342,50],[2391,115],[2407,77],[2420,109],[2422,276],[2442,199],[2466,261],[2467,119],[2479,261],[2479,266],[2495,48],[2506,428],[2510,118],[2522,115],[2533,50],[2535,52],[2563,268],[2573,119],[2575,266],[2632,119],[2640,268],[2654,285],[2683,119],[2691,105],[2703,118],[2720,104],[2742,116],[2774,199],[2804,105],[2807,165],[2834,122],[2839,115],[2852,101],[2853,119],[2866,49],[2868,115],[2894,105],[2911,199],[2948,109],[2953,1824],[2994,263],[3018,261],[3031,120],[3051,115],[3075,267],[3107,114],[3109,2452],[3115,83],[3128,992],[3156,105],[3162,112],[3170,177],[3189,48],[3286,524],[3302,267],[3322,114],[3355,105],[3362,101],[3382,321],[3384,48],[3398,261],[3405,199],[3417,119],[3420,185],[3448,104],[3453,104],[3453,199],[3469,119],[3474,267],[3513,115],[3530,199],[3531,101],[3562,119],[3563,101],[3582,118],[3601,115],[3616,101],[3618,114],[3645,285],[3650,104],[3663,114],[3664,119],[3682,119],[3695,105],[3695,199],[3708,264],[3709,104],[3709,119],[3710,113],[3716,282],[3748,101],[3768,119],[3827,120],[3840,101],[3887,261],[3922,101],[3924,126],[3936,101],[3944,109],[3977,115],[3981,48],[4044,199],[4045,265],[4059,120],[4062,113],[4073,199],[4108,119],[4110,115],[4148,265],[4201,199],[4212,262],[4215,121],[4247,265],[4250,105],[4262,118],[4264,115],[4291,113],[4339,119],[4346,105],[4351,118],[4355,261],[4391,105],[4404,113],[4413,109],[4456,115],[4458,105],[4462,266],[4475,109],[4503,120],[4507,277],[4580,119],[4595,266],[4600,113],[4642,269],[4658,116],[4660,267],[4663,120],[4666,45],[4670,118],[4696,109],[4706,279],[4740,174],[4746,199],[4753,262],[4775,260],[4780,101],[4794,266],[4826,308],[4859,167],[4871,105],[4876,121],[4882,112],[4891,115],[4897,265],[4905,112],[4914,112],[4940,580],[4946,103],[4951,105],[4960,275],[4968,112],[4969,103],[5021,262],[5060,105],[5074,262],[5080,199],[5094,115],[5113,262],[5184,119],[5201,120],[5208,112],[5229,115],[5232,107],[5253,121],[5254,119],[5296,263],[5301,101],[5303,112],[5305,105],[5308,115],[5313,269],[5316,109],[5328,274],[5345,199],[5370,261],[5371,119],[5376,126],[5378,115],[5395,105],[5398,105],[5409,115],[5421,112],[5433,101],[5437,101],[5438,115],[5441,104],[5475,199],[5482,293],[5483,2201],[5486,112],[5490,101],[5507,73],[5547,184],[5561,109],[5566,266],[5574,109],[5579,109],[5584,122],[5594,270],[5627,110],[5628,165],[5634,108],[5644,105],[5646,275],[5660,120],[5664,101],[5669,264],[5679,199],[5681,119],[5688,121],[5712,105],[5717,101],[5752,112],[5763,274],[5784,105],[5811,101],[5815,268],[5820,114],[5825,167],[5830,115],[5837,105],[5930,120],[5937,199],[5939,101],[5942,101],[5944,48],[5963,109],[5978,109],[5998,101],[6010,103],[6014,101],[6033,262],[6044,115],[6095,118],[6098,112],[6120,167],[6126,265],[6134,115],[6142,101],[6145,119],[6153,112],[6161,101],[6163,104],[6216,260],[6224,324],[6237,119],[6241,3128],[6248,199],[6252,106],[6255,121],[6278,115],[6304,109],[6323,114],[6336,305],[6337,107],[6349,122],[6350,107],[6351,328],[6358,112],[6365,113],[6367,264],[6370,120],[6380,165],[6383,121],[6388,112],[6392,304],[6393,124],[6396,261],[6397,165],[6399,104],[6401,112],[6405,261],[6406,113],[6412,261],[6418,263],[6419,109],[6420,114],[6425,166],[6435,108],[6436,262],[6437,305],[6438,112],[6449,112],[6451,119],[6458,109],[6461,113],[6462,122],[6464,287],[6474,118],[6477,105],[6478,105],[6481,268],[6484,119],[6488,112],[6492,264],[6493,268],[6494,289],[6500,261],[6501,113],[6506,262],[6509,108],[6510,121],[6511,122],[6514,119],[6515,115],[6516,120],[6517,114],[6518,119],[6529,278],[6532,113],[6535,199],[6540,262],[6541,120],[6542,267],[6544,119],[6549,114],[6555,171],[6556,267],[6557,118],[6558,120],[6563,109],[6564,190],[6566,105],[6573,177],[6575,119],[6580,267],[6589,109],[6590,101],[6591,109],[6593,101],[6594,280],[6595,171],[6598,105],[6602,119],[6603,114],[6605,177],[6607,307],[6608,120],[6618,120],[6621,118],[6631,105],[6634,171],[6638,174],[6642,260],[6646,199],[6647,101],[6652,177],[6653,101],[6654,105],[6655,115],[6656,105],[6657,274],[6669,171],[6673,171],[6677,173],[6679,262],[6682,109],[6684,105],[6687,199],[6690,102],[6694,260],[6695,119],[6699,260],[6700,105],[6702,115],[6704,115],[6708,264],[6710,165],[6712,49],[6713,112],[6715,122],[6716,115],[6717,119],[6718,101],[6724,115],[6725,101],[6729,268],[6730,112],[6731,103],[6733,165],[6749,104],[6750,115],[6751,185],[6756,114],[6760,269],[6763,101],[6764,177],[6767,281],[6769,3115],[6770,114],[6774,113],[6778,118],[6779,199],[6782,101],[6783,113],[6784,101],[6785,171],[6788,114],[6791,115],[6792,114],[6796,115],[6798,114],[6799,263],[6800,190],[6804,114],[6805,199],[6807,109],[6812,199],[6813,115],[6822,125],[6823,291],[6824,992],[6825,165],[6829,118],[6834,284],[6837,286],[6841,300],[6844,115],[6847,115],[6850,102],[6853,266],[6854,109],[6855,114],[6856,115],[6858,290],[6860,105],[6862,122],[6866,263],[6870,119],[6872,105],[6874,116],[6880,101],[6883,269],[6886,101],[6888,177],[6890,105],[6893,101],[6894,101],[6898,104],[6899,304],[6900,103],[6901,119],[6902,105],[6904,114],[6908,112],[6909,199],[6910,112],[6911,105],[6912,268],[6915,118],[6917,104],[6918,119],[6919,199],[6920,114],[6921,114],[6922,177],[6924,278],[6925,107],[6927,118],[6928,264],[6929,115],[6930,199],[6931,199],[6932,120],[6934,114],[6935,264],[6936,167],[6937,291],[6941,114],[6942,112],[6944,115],[6945,269],[6952,120],[6953,113],[6956,120],[6958,109],[6960,263],[6961,120],[6964,112],[6966,83],[6967,109],[6968,268],[6969,109],[6970,167],[6972,105],[6974,199],[6975,120],[6977,101],[6979,120],[6980,105],[6983,171],[6984,115],[6985,183],[6990,119],[6991,101],[6993,105],[6997,269],[6998,120],[6999,126],[7000,109],[7006,101],[7008,112],[7010,101],[7012,119],[7016,101],[7017,115],[7018,121],[7019,113],[7022,101],[7023,167],[7024,113],[7027,105],[7028,199],[7030,167],[7031,103],[7032,101],[7033,113],[7035,105],[7037,105],[7039,167],[7041,109],[7043,105],[7044,263],[7046,120],[7047,109],[7049,115],[7050,263],[7051,105],[7052,121],[7053,261],[7055,105],[7056,109],[7058,113],[7061,115],[7062,269],[7063,167],[7064,115],[7066,105],[7068,199],[7069,114],[7070,107],[7073,264],[7074,107],[7076,101],[7081,109],[7082,260],[7084,199],[7085,115],[7086,107],[7087,115],[7088,105],[7090,167],[7091,115],[7092,109],[7094,109],[7095,113],[7097,115],[7098,103],[7101,105],[7102,275],[7105,264],[7106,101],[7109,101],[7112,103],[7113,115],[7117,101],[7118,109],[7120,101],[7121,199],[7124,165],[7128,264],[7131,101],[7132,271],[7135,115],[7137,114],[7138,105],[7141,101],[7146,171],[7147,269],[7148,105],[7152,101],[7153,48],[7154,114],[7155,199],[7161,167],[7162,115],[38,71],[38,101],[38,2789],[44,73],[44,89],[44,2541],[45,63],[48,56],[49,69],[49,90],[49,102],[49,419],[50,51],[53,49],[53,481],[55,55],[55,58],[55,61],[56,912],[58,54],[59,56],[59,60],[60,58],[60,59],[61,54],[69,50],[69,126],[69,602],[69,613],[69,6445],[70,71],[70,287],[70,503],[70,3177],[70,5638],[70,5657],[71,348],[71,474],[71,936],[71,2987],[72,313],[72,446],[72,2813],[72,4204],[73,555],[74,50],[74,923],[75,319],[75,710],[75,805],[75,3169],[75,4524],[76,484],[76,485],[77,112],[80,398],[81,360],[81,469],[81,1131],[81,6301],[82,329],[82,443],[82,446],[82,524],[82,4647],[83,524],[83,4752],[84,300],[84,349],[84,469],[84,2787],[86,443],[87,83],[87,306],[87,348],[87,469],[87,652],[88,1686],[88,2975],[88,5046],[90,1817],[101,1229],[101,4238],[102,276],[102,325],[102,360],[102,368],[102,715],[102,6310],[103,48],[103,300],[103,1184],[103,5122],[105,278],[105,2323],[105,4059],[106,276],[106,393],[106,503],[106,801],[106,825],[106,5647],[106,6470],[106,6490],[107,3590],[108,50],[108,120],[108,274],[108,319],[108,326],[109,109],[109,117],[109,320],[110,325],[110,387],[113,276],[113,2701],[114,2805],[115,272],[115,279],[115,305],[115,1229],[116,454],[116,682],[116,1463],[116,2187],[116,3782],[118,45],[118,125],[118,261],[118,271],[118,311],[118,382],[119,318],[119,772],[119,1581],[120,119],[120,123],[120,725],[121,122],[122,325],[122,341],[122,936],[122,4675],[124,306],[125,105],[125,119],[125,272],[173,121],[177,118],[177,260],[183,104],[183,122],[183,124],[183,304],[199,175],[210,189],[211,136],[260,101],[262,117],[263,38],[264,108],[265,105],[265,120],[265,262],[266,122],[267,38],[267,62],[268,101],[269,45],[270,113],[273,117],[273,270],[275,103],[275,120],[277,102],[277,122],[277,267],[278,106],[279,101],[280,104],[281,102],[281,271],[282,121],[283,260],[284,115],[284,277],[285,281],[286,110],[286,278],[287,105],[287,260],[288,268],[289,112],[290,121],[290,266],[290,285],[291,261],[294,107],[294,261],[294,262],[294,282],[296,126],[296,272],[297,48],[297,270],[298,121],[299,262],[300,48],[300,270],[302,271],[302,288],[305,48],[306,282],[313,310],[318,116],[323,269],[324,48],[324,101],[327,122],[327,278],[330,115],[330,260],[333,279],[333,290],[335,118],[339,294],[343,112],[345,264],[347,262],[351,118],[351,126],[351,261],[352,313],[356,264],[357,120],[360,113],[365,120],[367,276],[371,104],[372,49],[378,325],[379,104],[382,295],[393,103],[394,114],[396,119],[397,115],[400,371],[403,105],[405,114],[409,339],[415,102],[416,199],[416,262],[421,105],[438,280],[442,385],[446,114],[447,262],[456,109],[459,262],[460,119],[462,112],[463,113],[467,287],[469,300],[469,311],[474,271],[479,265],[480,275],[480,291],[480,445],[482,62],[485,121],[497,263],[500,294],[500,429],[503,306],[503,332],[503,367],[515,115],[518,101],[524,110],[528,295],[530,487],[539,116],[539,305],[539,352],[541,109],[544,119],[563,107],[567,101],[567,109],[572,120],[582,160],[588,118],[612,285],[620,108],[621,279],[621,305],[625,276],[629,122],[638,297],[653,313],[666,199],[666,275],[674,270],[677,571],[701,107],[705,121],[705,294],[716,101],[716,105],[717,101],[720,199],[729,122],[730,109],[732,126],[740,290],[748,266],[758,109],[761,109],[771,264],[802,261],[804,383],[812,289],[817,199],[857,106],[857,351],[857,460],[861,103],[865,101],[867,48],[871,199],[875,109],[875,268],[881,120],[901,267],[907,265],[914,101],[915,119],[917,267],[917,325],[961,109],[965,101],[976,271],[985,113],[993,115],[998,49],[1008,269],[1020,115],[1033,101],[1036,199],[1038,105],[1068,118],[1069,109],[1090,54],[1090,55],[1090,58],[1090,59],[1102,267],[1111,105],[1115,290],[1125,121],[1133,105],[1141,122],[1154,275],[1161,106],[1188,115],[1196,105],[1227,300],[1227,304],[1240,124],[1247,653],[1255,118],[1256,281],[1256,291],[1260,105],[1277,280],[1299,118],[1305,268],[1314,109],[1320,118],[1320,120],[1330,57],[1341,105],[1353,263],[1377,119],[1386,271],[1392,305],[1393,277],[1402,50],[1406,374],[1426,48],[1429,106],[1433,49],[1433,118],[1436,101],[1448,101],[1457,105],[1458,267],[1474,199],[1481,267],[1497,199],[1511,109],[1540,101],[1547,113],[1547,266],[1552,113],[1552,199],[1552,261],[1555,101],[1565,261],[1584,105],[1587,52],[1619,48],[1632,48],[1641,275],[1685,271],[1689,48],[1714,48],[1719,48],[1727,119],[1743,125],[1746,119],[1759,276],[1760,54],[1760,56],[1769,119],[1777,110],[1783,199],[1805,310],[1807,285],[1826,52],[1835,50],[1841,50],[1842,265],[1845,101],[1848,107],[1862,101],[1862,121],[1864,120],[1907,119],[1909,328],[1929,55],[1941,117],[1955,270],[1957,199],[1960,115],[1960,267],[1981,114],[1984,112],[1988,119],[1994,199],[2007,268],[2025,271],[2037,273],[2043,122],[2051,119],[2086,48],[2106,104],[2130,327],[2138,50],[2154,48],[2156,114],[2173,105],[2191,165],[2212,177],[2221,48],[2221,50],[2258,118],[2261,50],[2266,50],[2285,50],[2286,459],[2309,121],[2314,56],[2316,106],[2317,112],[2319,56],[2342,48],[2353,262],[2354,199],[2386,119],[2406,74],[2434,273],[2442,109],[2446,119],[2453,119],[2484,48],[2499,287],[2529,199],[2551,260],[2554,261],[2564,119],[2575,199],[2575,261],[2578,105],[2579,113],[2606,109],[2651,103],[2654,124],[2658,113],[2660,110],[2707,119],[2720,113],[2720,261],[2733,121],[2734,118],[2734,121],[2760,109],[2764,115],[2768,119],[2795,115],[2799,109],[2812,287],[2823,116],[2827,116],[2838,106],[2843,261],[2843,266],[2854,268],[2861,306],[2864,1022],[2865,105],[2876,118],[2876,199],[2879,48],[2888,261],[2939,109],[2952,332],[2962,48],[2968,48],[2976,124],[2987,107],[3006,115],[3018,260],[3023,103],[3023,199],[3044,109],[3047,119],[3049,118],[3056,113],[3097,48],[3116,50],[3132,119],[3165,119],[3175,115],[3198,261],[3214,263],[3227,114],[3229,114],[3249,119],[3261,109],[3264,101],[3270,114],[3285,1020],[3292,1085],[3319,105],[3323,115],[3334,114],[3335,279],[3338,109],[3343,260],[3352,120],[3360,118],[3365,267],[3367,269],[3378,48],[3398,266],[3445,199],[3448,118],[3494,113],[3558,263],[3581,105],[3611,107],[3618,103],[3648,50],[3661,121],[3672,48],[3673,109],[3724,270],[3744,199],[3760,199],[3764,109],[3778,48],[3796,305],[3802,527],[3849,109],[3868,121],[3904,265],[3907,112],[3914,109],[3915,101],[3922,115],[3931,119],[3936,115],[3938,48],[3939,199],[3945,48],[3945,50],[3970,48],[3997,48],[3998,115],[3999,114],[4029,113],[4045,271],[4052,113],[4097,199],[4107,119],[4109,48],[4110,101],[4117,279],[4137,453],[4175,71],[4182,115],[4189,120],[4198,263],[4214,119],[4230,289],[4253,279],[4269,268],[4277,113],[4302,199],[4302,274],[4311,279],[4336,199],[4394,101],[4394,268],[4466,103],[4486,199],[4487,300],[4494,105],[4501,121],[4506,118],[4561,268],[4564,107],[4569,115],[4575,106],[4582,105],[4584,114],[4586,266],[4592,275],[4594,274],[4599,113],[4618,121],[4622,109],[4624,119],[4626,126],[4638,119],[4648,119],[4700,261],[4701,118],[4716,105],[4741,101],[4763,119],[4805,109],[4827,101],[4842,167],[4864,283],[4880,265],[4913,115],[4916,115],[4935,360],[4947,726],[4953,269],[4957,109],[4970,1741],[4985,327],[5025,166],[5028,118],[5030,118],[5033,280],[5038,121],[5055,277],[5062,121],[5073,276],[5085,101],[5092,104],[5105,115],[5114,118],[5128,49],[5141,101],[5144,101],[5155,261],[5159,126],[5167,119],[5170,199],[5181,119],[5182,115],[5186,114],[5188,48],[5198,2426],[5227,114],[5231,115],[5249,263],[5252,103],[5260,109],[5278,114],[5310,101],[5319,270],[5339,274],[5367,121],[5401,185],[5434,271],[5453,48],[5455,274],[5458,199],[5531,275],[5578,115],[5587,199],[5590,273],[5599,124],[5607,173],[5652,109],[5662,50],[5671,113],[5684,106],[5692,112],[5695,119],[5700,199],[5743,119],[5775,118],[5779,48],[5796,50],[5803,166],[5821,126],[5845,115],[5849,115],[5850,274],[5879,109],[5901,185],[5920,115],[5928,105],[5947,109],[5960,265],[5967,279],[5985,122],[5999,119],[6028,103],[6108,265],[6109,118],[6128,267],[6154,119],[6170,113],[6207,1118],[6208,309],[6214,260],[6218,286],[6225,5085],[6227,383],[6228,285],[6231,105],[6247,105],[6289,279],[6306,199],[6322,109],[6339,101],[6360,262],[6389,126],[6394,112],[6398,273],[6402,122],[6415,101],[6433,271],[6439,271],[6463,266],[6467,114],[6473,266],[6483,114],[6491,101],[6495,120],[6507,109],[6538,117],[6550,101],[6554,261],[6561,118],[6577,119],[6606,112],[6617,107],[6619,107],[6623,108],[6625,261],[6629,184],[6648,120],[6664,109],[6671,199],[6696,121],[6697,263],[6726,112],[6728,115],[6732,112],[6740,335],[6754,109],[6773,271],[6777,101],[6795,115],[6802,104],[6816,113],[6830,101],[6839,109],[6846,120],[6848,109],[6864,105],[6871,101],[6875,49],[6877,119],[6879,199],[6881,101],[6884,101],[6896,109],[6946,112],[6948,101],[6951,112],[6962,105],[6982,101],[6992,280],[7014,120],[7020,109],[7034,115],[7042,101],[7048,119],[7075,115],[7079,268],[7103,49],[7110,115],[7116,167],[7126,115],[7129,115],[7151,119],[7191,121],[7192,286],[7193,109],[7196,368],[7197,118],[7198,114],[7201,275],[7203,261],[7207,264],[7215,49],[7216,302],[7217,126],[7222,108],[7223,121],[7225,360],[7228,121],[7233,294],[7235,281],[7241,111],[7242,101],[7244,126],[7256,113],[7258,183],[7265,276],[7266,105],[7267,112],[7278,126],[7281,268],[7298,112],[7302,109],[7335,121],[7343,261],[7350,113],[7360,105],[7371,102],[7375,268],[7387,264],[7388,118],[7390,103],[7392,101],[7394,311],[7395,286],[7405,120],[7415,273],[7422,261],[7427,101],[7430,270],[7432,269],[7438,114],[7439,101],[7442,261],[7443,112],[7447,101],[7450,108],[7451,269],[7452,114],[7457,120],[7461,109],[7469,173],[7471,118],[7475,278],[7478,199],[7481,119],[7482,101],[7483,113],[7485,119],[7486,115],[7489,275],[7490,122],[7491,173],[7493,261],[7494,119],[7498,185],[7507,119],[7508,112],[7510,113],[7513,101],[7516,118],[7517,183],[7518,112],[7520,262],[7529,107],[7532,268],[7533,122],[7535,264],[7537,306],[7538,313],[7539,122],[7546,120],[7548,109],[7555,272],[7559,109],[7560,119],[7564,103],[7566,171],[7568,177],[7574,171],[7577,118],[7590,119],[7594,101],[7595,171],[7601,121],[7603,121],[7604,261],[7606,109],[7610,121],[7612,171],[7615,109],[7617,120],[7618,183],[7622,283],[7625,109],[7626,278],[7629,120],[7632,120],[7639,262],[7642,112],[7646,113],[7647,171],[7650,121],[7655,265],[7656,183],[7660,171],[7662,119],[7663,105],[7665,101],[7666,109],[7668,101],[7670,105],[7675,122],[7679,271],[7681,121],[7682,105],[7683,109],[7691,171],[7694,119],[7701,109],[7704,119],[7707,105],[7712,121],[7717,119],[7718,119],[7720,199],[7722,120],[7723,118],[7724,114],[7725,278],[7729,105],[7732,120],[7735,171],[7737,268],[7739,262],[7741,109],[7745,126],[7747,183],[7748,173],[7749,199],[7751,107],[7752,109],[7753,102],[7754,262],[7755,114],[7756,101],[7757,101],[7763,171],[7769,120],[7772,105],[7773,171],[7777,264],[7778,114],[7782,120],[7784,120],[7785,260],[7788,185],[7789,115],[7790,264],[7791,171],[7794,268],[7795,183],[7796,103],[7797,121],[7804,112],[7805,199],[7808,115],[7809,121],[7811,101],[7813,109],[7821,115],[7823,115],[7828,263],[7830,199],[7831,116],[7833,269],[7834,279],[7835,199],[7837,103],[7840,101],[7841,275],[7845,119],[7850,101],[7852,173],[7855,101],[7858,104],[7861,105],[7862,120],[7863,108],[7866,115],[7868,263],[7871,115],[7872,171],[7874,106],[7878,113],[7879,122],[7881,109],[7882,199],[7883,263],[7885,183],[7894,115],[7896,105],[7899,199],[7901,264],[7902,101],[7904,101],[7909,115],[7911,273],[7913,115],[7914,101],[7915,272],[7916,109],[7917,112],[7918,112],[7934,104],[7936,105],[7938,121],[7940,119],[7944,121],[7945,284],[7948,113],[7949,105],[7951,183],[7952,118],[7955,107],[7959,114],[7963,105],[7966,105],[7968,109],[7969,199],[7970,119],[7972,174],[7976,105],[7979,266],[7981,120],[7982,115],[7983,119],[7989,107],[7991,115],[7997,114],[7998,199],[8000,108],[8006,115],[8007,105],[8011,106],[8012,120],[8013,281],[8014,112],[8016,105],[8017,107],[8019,114],[8020,109],[8023,109],[8026,119],[8028,112],[8029,105],[8031,115],[8033,121],[8034,107],[8036,108],[8038,109],[8040,279],[8042,199],[8044,118],[8045,114],[8046,121],[8050,119],[8051,109],[8052,261],[8053,113],[8056,171],[8059,199],[8061,114],[8066,103],[8067,263],[8069,291],[8070,105],[8071,279],[8073,269],[8076,115],[8077,105],[8078,101],[8079,101],[8080,104],[8081,263],[8082,101],[8084,122],[8086,103],[8087,105],[8088,120],[8089,199],[8090,116],[8091,199],[8095,199],[8097,101],[8099,122],[8100,105],[8101,199],[8104,106],[8105,105],[8108,105],[8109,109],[8111,277],[8113,199],[8114,119],[8116,112],[8117,199],[8119,264],[8120,113],[8123,264],[8126,112],[8128,271],[8129,199],[8131,118],[8133,264],[8135,199],[8137,171],[8138,121],[8139,120],[8142,114],[8143,113],[8144,274],[8148,101],[8149,107],[8150,118],[8151,171],[8152,291],[8153,126],[8154,283],[8156,104],[8159,199],[8160,105],[8161,114],[8162,199],[8163,105],[8164,115],[8165,262],[8166,121],[8167,119],[8168,263],[8170,105],[8171,199],[8173,112],[8176,108],[8177,171],[8179,112],[8182,114],[8185,165],[8187,101],[8188,120],[8189,183],[8190,121],[8195,107],[8197,115],[8199,109],[8204,199],[8205,273],[8208,120],[8209,177],[8211,122],[8213,119],[8214,171],[8219,112],[8222,118],[8226,109],[8228,281],[8232,109],[8234,118],[8235,107],[8236,109],[8237,101],[8238,114],[8239,118],[8240,118],[8241,177],[8242,105],[8243,114],[8244,101],[8245,260],[8246,109],[8249,105],[8251,101],[8252,184],[8253,101],[8256,109],[8259,108],[8260,120],[8261,109],[8262,120],[8263,126],[8269,112],[8270,105],[8272,118],[8273,264],[8274,183],[8279,122],[8282,101],[8283,165],[8284,101],[8288,264],[8289,269],[8290,101],[8291,269],[8295,273],[8299,101],[8301,121],[8302,167],[8303,121],[8306,109],[8310,109],[8313,113],[8314,263],[8317,115],[8319,105],[8320,105],[8321,115],[8322,101],[8326,115],[8329,118],[8331,199],[8333,115],[8334,199],[8335,109],[8336,109],[8337,199],[8339,101],[8341,121],[8342,185],[8344,120],[8348,112],[8353,167],[8354,109],[8355,101],[8356,101],[8357,115],[8361,118],[8362,112],[8363,112],[8364,109],[8366,122],[8369,101],[8370,103],[8371,105],[8373,199],[8379,109],[8383,120],[8385,115],[8386,114],[8388,103],[8389,118],[8392,262],[8394,114],[8396,265],[8398,118],[8399,103],[8401,101],[8402,115],[8404,115],[8405,101],[8406,120],[8411,115],[8412,103],[8416,113],[8417,262],[8418,115],[8419,112],[8423,120],[8424,107],[8426,264],[8431,171],[8433,171],[8438,120],[8439,105],[8440,105],[8442,115],[8443,103],[8444,114],[8447,115],[8448,105],[8449,268],[8453,109],[8455,167],[8456,115],[8457,105],[8459,101],[8460,109],[8462,112],[8463,291],[8465,115],[8467,264],[8470,118],[8471,109],[8473,101],[8474,105],[8478,101],[8480,105],[8481,199],[8482,199],[8483,115],[8484,119],[8487,101],[8490,115],[8493,115],[8497,101],[8501,263],[8503,103],[8504,114],[8505,114],[8508,167],[8509,167],[8510,118],[8519,120],[8520,115],[8521,115],[8523,105],[38,63],[38,88],[38,115],[44,70],[44,82],[44,103],[44,260],[44,297],[44,431],[45,62],[49,71],[49,105],[49,263],[49,267],[49,305],[50,45],[50,48],[50,55],[50,198],[53,530],[54,83],[56,49],[56,60],[57,49],[57,54],[57,56],[57,57],[58,61],[60,52],[60,56],[60,57],[61,55],[61,56],[61,58],[64,51],[69,125],[69,304],[69,422],[69,453],[69,607],[69,898],[69,2806],[69,4176],[69,4554],[69,7726],[70,86],[70,288],[70,1410],[70,3148],[71,461],[71,1066],[71,4238],[71,7346],[72,48],[72,4622],[73,71],[74,109],[74,115],[74,262],[74,469],[74,5006],[74,5040],[74,5593],[75,752],[75,2807],[75,8340],[77,314],[77,395],[77,5564],[78,105],[78,325],[78,469],[79,284],[80,263],[80,267],[80,321],[80,442],[80,805],[80,7836],[81,263],[81,306],[81,322],[81,891],[81,4548],[83,460],[84,956],[84,1388],[84,1417],[84,3148],[84,3682],[84,6447],[84,7504],[86,121],[86,328],[86,331],[87,72],[87,109],[87,327],[87,367],[87,531],[87,2996],[87,3819],[88,109],[88,1500],[88,2190],[88,5635],[88,7631],[89,87],[90,48],[90,321],[91,365],[91,1420],[101,62],[101,111],[101,125],[101,339],[101,424],[101,1816],[101,3658],[101,5683],[102,305],[102,3216],[102,3584],[103,5618],[103,7379],[104,107],[104,274],[105,289],[105,1119],[105,1753],[106,120],[106,280],[106,349],[106,489],[106,2119],[106,3336],[108,313],[108,335],[108,360],[108,5785],[109,110],[109,3627],[109,7505],[110,2518],[110,7440],[111,48],[111,119],[112,270],[112,925],[112,1225],[112,1580],[112,6315],[112,7402],[112,7727],[113,471],[113,3598],[114,45],[114,49],[114,114],[114,271],[114,1342],[114,1534],[114,6162],[115,111],[115,115],[115,199],[115,775],[115,2489],[115,7424],[116,429],[116,516],[116,2978],[116,3001],[116,3187],[116,8230],[118,63],[118,106],[119,111],[119,364],[119,1359],[119,6371],[119,7640],[120,50],[120,274],[120,275],[120,400],[121,269],[122,286],[122,319],[122,710],[122,1311],[122,4599],[123,109],[123,119],[123,286],[124,294],[124,360],[125,51],[125,120],[126,108],[126,328],[132,152],[132,157],[151,53],[161,50],[173,48],[173,112],[177,199],[184,297],[190,104],[190,113],[190,279],[199,151],[210,191],[210,192],[210,193],[212,180],[219,155],[260,102],[261,45],[261,107],[261,126],[262,38],[262,45],[265,103],[266,117],[269,104],[270,49],[271,103],[273,50],[273,199],[275,106],[275,273],[276,121],[277,50],[280,109],[280,272],[281,50],[281,275],[283,49],[283,50],[283,102],[283,261],[284,271],[287,112],[287,120],[287,121],[288,274],[288,276],[289,270],[289,282],[290,275],[291,266],[291,276],[295,109],[295,265],[296,287],[296,289],[302,120],[302,280],[303,48],[304,265],[305,279],[308,112],[308,260],[310,261],[310,299],[313,103],[313,271],[315,310],[318,268],[322,282],[324,124],[326,115],[326,270],[326,321],[327,297],[328,124],[328,272],[329,107],[331,272],[336,280],[339,112],[339,261],[340,272],[342,293],[343,106],[345,340],[347,261],[348,273],[351,112],[351,269],[351,280],[352,291],[357,107],[359,62],[361,184],[362,121],[362,277],[364,109],[365,287],[371,101],[372,280],[372,296],[373,276],[375,305],[376,270],[379,106],[381,112],[382,306],[382,313],[389,275],[403,101],[419,50],[420,104],[420,120],[420,275],[429,297],[432,118],[433,199],[443,119],[443,434],[445,112],[447,305],[448,48],[462,199],[465,277],[469,108],[475,300],[479,114],[479,116],[480,374],[487,52],[488,282],[501,262],[503,262],[513,107],[528,315],[531,121],[531,318],[531,326],[531,484],[539,122],[539,288],[540,49],[550,104],[553,121],[563,322],[565,329],[571,265],[572,199],[583,306],[585,122],[585,285],[585,308],[588,112],[588,113],[588,114],[588,120],[596,265],[606,124],[606,361],[608,109],[615,311],[617,277],[620,199],[621,316],[621,405],[622,306],[625,290],[625,438],[633,269],[634,109],[641,118],[641,265],[643,269],[654,103],[660,261],[661,122],[661,262],[662,199],[663,265],[664,110],[665,115],[669,173],[671,122],[673,109],[684,276],[691,261],[694,106],[696,121],[701,272],[705,109],[709,112],[711,105],[718,48],[720,262],[723,121],[729,260],[740,506],[744,266],[751,116],[751,120],[751,122],[754,281],[757,118],[774,101],[794,45],[795,277],[804,506],[805,397],[805,769],[812,113],[817,126],[818,49],[819,103],[825,121],[831,113],[844,101],[865,121],[869,177],[879,115],[888,267],[894,105],[915,107],[918,116],[923,328],[925,115],[929,101],[934,50],[936,107],[938,50],[941,109],[941,112],[949,122],[951,280],[985,118],[989,109],[992,107],[996,102],[1008,101],[1021,281],[1027,280],[1041,113],[1064,267],[1079,48],[1080,114],[1080,118],[1085,116],[1106,199],[1138,124],[1139,121],[1142,115],[1142,121],[1148,50],[1150,48],[1169,266],[1178,272],[1178,376],[1181,118],[1189,288],[1191,48],[1216,116],[1220,109],[1223,190],[1231,121],[1247,121],[1247,513],[1251,104],[1260,115],[1266,114],[1270,118],[1273,50],[1276,272],[1306,286],[1313,54],[1313,56],[1316,262],[1332,106],[1338,270],[1339,112],[1345,114],[1360,124],[1363,112],[1364,113],[1364,114],[1381,57],[1393,273],[1395,269],[1398,50],[1405,61],[1408,102],[1421,118],[1425,121],[1425,261],[1430,119],[1433,104],[1436,121],[1456,48],[1459,286],[1460,103],[1463,122],[1472,261],[1474,118],[1475,199],[1482,49],[1499,199],[1501,49],[1509,115],[1552,104],[1555,115],[1566,59],[1569,101],[1580,112],[1587,53],[1607,113],[1638,113],[1685,103],[1693,103],[1693,260],[1724,267],[1745,265],[1748,106],[1755,52],[1760,57],[1769,48],[1794,48],[1804,110],[1808,351],[1808,445],[1826,57],[1834,264],[1835,48],[1839,266],[1842,278],[1843,48],[1860,105],[1863,293],[1872,45],[1883,48],[1888,118],[1888,199],[1890,119],[1891,263],[1911,115],[1921,199],[1922,101],[1929,52],[1929,61],[1933,116],[1950,119],[1984,102],[1990,48],[1990,114],[1999,50],[2020,115],[2026,50],[2043,112],[2049,48],[2053,61],[2054,54],[2065,48],[2069,119],[2074,199],[2076,50],[2077,263],[2116,105],[2118,261],[2125,264],[2126,48],[2127,114],[2129,118],[2131,55],[2131,60],[2133,52],[2133,55],[2159,112],[2172,442],[2172,1643],[2174,115],[2191,171],[2192,281],[2202,105],[2207,267],[2266,48],[2276,50],[2293,112],[2309,101],[2309,105],[2314,55],[2317,119],[2323,173],[2337,48],[2338,266],[2349,266],[2354,104],[2360,263],[2361,199],[2394,264],[2407,739],[2407,1872],[2438,115],[2438,268],[2466,282],[2469,48],[2490,115],[2496,48],[2519,119],[2528,272],[2533,48],[2535,60],[2541,53],[2543,267],[2546,263],[2553,113],[2569,109],[2572,264],[2577,275],[2588,183],[2602,113],[2607,261],[2613,50],[2623,118],[2623,121],[2673,121],[2686,199],[2703,113],[2703,261],[2717,48],[2718,119],[2730,50],[2743,263],[2745,113],[2764,109],[2765,105],[2770,119],[2785,468],[2788,303],[2804,121],[2809,109],[2810,199],[2817,262],[2822,59],[2828,269],[2888,266],[2904,48],[2908,101],[2908,267],[2936,48],[2951,276],[2951,1580],[2954,290],[2995,52],[3005,122],[3008,120],[3017,120],[3018,266],[3024,270],[3032,48],[3032,50],[3047,118],[3057,265],[3088,90],[3133,109],[3159,266],[3183,119],[3186,279],[3192,118],[3198,282],[3204,262],[3207,266],[3226,101],[3243,48],[3252,115],[3286,296],[3288,106],[3289,109],[3295,305],[3331,114],[3353,268],[3355,199],[3357,101],[3364,262],[3365,115],[3365,268],[3382,306],[3424,119],[3436,115],[3446,113],[3467,109],[3484,261],[3489,38],[3516,167],[3540,306],[3558,119],[3561,291],[3581,115],[3584,113],[3592,115],[3606,120],[3607,116],[3610,115],[3610,199],[3610,263],[3611,102],[3614,48],[3615,112],[3616,105],[3626,48],[3628,263],[3634,106],[3650,261],[3662,104],[3662,261],[3663,121],[3683,126],[3693,48],[3704,199],[3708,102],[3714,264],[3723,103],[3732,48],[3736,121],[3742,115],[3742,267],[3752,113],[3756,109],[3757,48],[3764,199],[3797,112],[3817,102],[3832,109],[3840,115],[3842,101],[3842,273],[3847,199],[3850,104],[3850,261],[3859,173],[3859,174],[3868,101],[3883,268],[3885,114],[3886,282],[3887,266],[3888,50],[3904,199],[3907,270],[3909,199],[3960,118],[3968,105],[3977,267],[4005,272],[4005,293],[4014,278],[4062,114],[4099,48],[4128,56],[4147,199],[4148,103],[4199,276],[4207,262],[4215,101],[4242,48],[4243,112],[4250,263],[4258,105],[4259,120],[4262,115],[4264,267],[4274,118],[4274,122],[4281,119],[4292,48],[4304,119],[4336,261],[4345,118],[4351,262],[4355,266],[4358,261],[4391,109],[4404,114],[4412,119],[4413,105],[4420,119],[4446,119],[4456,267],[4458,101],[4462,120],[4466,271],[4470,48],[4475,112],[4486,115],[4494,284],[4508,293],[4550,115],[4561,101],[4567,272],[4574,281],[4592,266],[4606,276],[4647,114],[4654,50],[4655,118],[4695,105],[4698,119],[4710,101],[4710,108],[4712,107],[4712,120],[4716,263],[4752,121],[4754,263],[4760,261],[4779,48],[4785,119],[4787,275],[4787,282],[4811,118],[4824,101],[4824,115],[4827,115],[4842,185],[4849,119],[4851,119],[4855,103],[4855,271],[4863,126],[4863,199],[4864,101],[4880,103],[4911,48],[4913,101],[4916,103],[4919,48],[4937,105],[4937,286],[4938,818],[4939,568],[4955,105],[4958,818],[4961,120],[4991,211],[4999,121],[5013,114],[5032,273],[5041,119],[5041,323],[5044,262],[5044,289],[5050,112],[5053,266],[5054,275],[5065,101],[5065,115],[5095,49],[5120,48],[5131,48],[5160,119],[5162,261],[5163,199],[5171,118],[5216,118],[5250,267],[5259,48],[5280,113],[5282,167],[5282,185],[5332,120],[5354,119],[5380,167],[5380,185],[5388,287],[5394,109],[5394,112],[5439,101],[5439,115],[5445,101],[5445,268],[5479,107],[5485,269],[5515,199],[5569,114],[5573,121],[5588,269],[5598,262],[5624,273],[5637,113],[5648,269],[5649,112],[5677,291],[5687,120],[5690,119],[5693,109],[5702,108],[5714,266],[5764,101],[5769,261],[5773,265],[5794,356],[5809,104],[5816,276],[5817,101],[5829,105],[5841,48],[5888,109],[5898,121],[5904,113],[5931,263],[5965,101],[6023,118],[6029,101],[6034,115],[6039,271],[6074,261],[6076,199],[6081,119],[6094,167],[6105,105],[6129,115],[6136,261],[6139,101],[6160,115],[6182,50],[6211,310],[6212,126],[6213,267],[6221,115],[6229,4562],[6233,774],[6234,420],[6263,268],[6280,121],[6281,112],[6282,119],[6311,109],[6317,199],[6328,121],[6342,121],[6353,294],[6359,112],[6377,305],[6379,119],[6382,121],[6384,115],[6387,115],[6407,262],[6411,199],[6413,114],[6424,114],[6431,119],[6434,109],[6448,199],[6459,48],[6466,120],[6469,289],[6472,290],[6486,291],[6487,120],[6499,48],[6519,121],[6547,48],[6553,279],[6610,199],[6613,109],[6639,119],[6680,119],[6685,48],[6701,103],[6709,113],[6711,113],[6745,115],[6748,261],[6753,103],[6761,104],[6790,48],[6806,126],[6811,115],[6819,112],[6820,101],[6832,109],[6833,115],[6836,122],[6838,101],[6842,108],[6859,101],[6868,109],[6887,101],[6916,121],[6981,49],[7003,114],[7009,120],[7040,167],[7067,119],[7100,48],[7108,119],[7139,112],[7143,112],[7144,265],[7156,101],[7195,279],[7202,114],[7219,287],[7231,271],[7232,125],[7243,268],[7245,199],[7249,107],[7262,461],[7286,104],[7297,280],[7307,261],[7339,109],[7348,109],[7352,105],[7382,269],[7408,262],[7412,199],[7416,304],[7417,185],[7428,115],[7431,283],[7433,118],[7434,112],[7441,114],[7444,266],[7445,112],[7453,262],[7454,101],[7458,121],[7474,114],[7495,105],[7506,109],[7509,107],[7522,48],[7536,271],[7542,119],[7544,115],[7557,287],[7578,282],[7596,278],[7597,263],[7609,48],[7658,118],[7687,114],[7698,101],[7715,120],[7721,115],[7728,114],[7799,115],[7806,107],[7844,112],[7846,106],[7854,119],[7875,165],[7876,126],[7890,264],[7891,101],[7895,199],[7921,279],[7924,101],[7926,104],[7932,199],[7941,105],[8002,122],[8004,84],[8005,271],[8015,121],[8025,105],[8032,285],[8035,260],[8037,267],[8048,319],[8054,117],[8055,112],[8064,120],[8083,101],[8103,105],[8107,267],[8110,106],[8124,101],[8141,101],[8147,101],[8186,105],[8215,115],[8223,113],[8227,119],[8231,268],[8254,264],[8264,120],[8281,48],[8287,118],[8298,101],[8304,167],[8305,167],[8311,264],[8318,167],[8324,167],[8332,267],[8345,167],[8380,115],[8381,101],[8403,113],[8421,265],[8430,101],[8436,185],[8445,119],[8446,119],[8452,104],[8454,276],[8479,267],[8492,115],[8500,119],[8517,268],[8522,263],[8562,281],[8567,339],[8568,103],[8570,118],[8571,264],[8575,122],[8576,109],[8577,120],[8581,108],[8587,112],[8589,114],[8591,177],[8593,278],[8594,268],[8595,115],[8596,306],[8598,285],[8602,276],[8603,377],[8605,263],[8606,115],[8608,118],[8609,107],[8611,377],[8613,121],[8617,118],[8618,118],[8623,2200],[8628,114],[8632,121],[8636,107],[8637,119],[8638,360],[8643,262],[8645,121],[8647,265],[8648,109],[8649,103],[8650,105],[8655,105],[8659,103],[8661,115],[8662,103],[8670,199],[8671,104],[8677,101],[8679,119],[8681,289],[8682,291],[8693,114],[8707,109],[8718,107],[8752,121],[8757,190],[8759,106],[8763,118],[8768,101],[8778,112],[8786,120],[8798,274],[8808,276],[8809,108],[8818,101],[8826,266],[8829,118],[8830,114],[8835,263],[8836,261],[8842,263],[8843,112],[8845,115],[8850,279],[8857,105],[8860,121],[8862,199],[8866,102],[8867,321],[8870,274],[8871,119],[8872,199],[8874,108],[8875,107],[8878,282],[8880,276],[8881,260],[8884,261],[8887,294],[8888,184],[8894,114],[8897,280],[8899,114],[8900,115],[8902,114],[8905,109],[8907,177],[8908,115],[8911,120],[8912,101],[8917,118],[8918,103],[8920,105],[8921,262],[8923,120],[8925,116],[8926,177],[8929,121],[8930,109],[8932,263],[8936,177],[8939,286],[8943,112],[8947,118],[8948,261],[8950,102],[8955,114],[8961,101],[8964,119],[8969,113],[8976,171],[8983,260],[8984,102],[8989,109],[8991,279],[8992,275],[8995,109],[8996,119],[8997,120],[9001,280],[9004,113],[9007,109],[9008,101],[9011,116],[9015,103],[9019,114],[9021,118],[9022,120],[9023,101],[9024,262],[9027,120],[9028,101],[9031,165],[9033,184],[9034,119],[9036,101],[9042,105],[9044,268],[9048,119],[9049,115],[9054,267],[9055,280],[9056,112],[9063,109],[9068,171],[9071,112],[9084,199],[9090,167],[9097,107],[9098,263],[9103,101],[9104,385],[9106,109],[9107,101],[9113,108],[9115,112],[9118,107],[9122,101],[9124,171],[9134,113],[9135,262],[9141,116],[9142,119],[9143,101],[9152,167],[9154,118],[9161,114],[9162,199],[9167,185],[9168,261],[9170,115],[9177,112],[9180,105],[9182,115],[9189,105],[9193,264],[9194,113],[9195,274],[9196,106],[9201,287],[9202,115],[9203,119],[9207,177],[9209,120],[9212,261],[9216,119],[9219,115],[9221,319],[9223,118],[9226,277],[9227,101],[9230,120],[9231,109],[9237,109],[9239,101],[9244,171],[9251,49],[9252,105],[9253,119],[9255,177],[9260,120],[9261,264],[9262,174],[9263,121],[9265,113],[9269,261],[9274,104],[9275,171],[9277,119],[9281,101],[9282,119],[9285,171],[9287,101],[9293,119],[9294,109],[9295,118],[9298,105],[9303,199],[9304,105],[9308,291],[9319,112],[9324,199],[9326,260],[9338,262],[9344,274],[9347,121],[9349,105],[9352,268],[9355,171],[9356,276],[9357,101],[9360,101],[9363,115],[9364,119],[9365,109],[9366,120],[9367,49],[9368,280],[9370,105],[9372,121],[9376,261],[9377,109],[9378,119],[9387,171],[9393,115],[9394,105],[9395,267],[9397,115],[9398,263],[9400,119],[9406,115],[9408,185],[9410,118],[9411,103],[9413,122],[9414,105],[9416,101],[9418,115],[9419,105],[9421,101],[9422,260],[9423,112],[9427,115],[9432,112],[9433,262],[9437,115],[9442,171],[9444,115],[9445,109],[9447,119],[9451,107],[9454,106],[9456,101],[9457,104],[9463,171],[9466,101],[9468,107],[9473,112],[9474,177],[9475,199],[9476,199],[9479,167],[9482,265],[9485,121],[9489,264],[9490,183],[9495,101],[9496,109],[9497,101],[9498,107],[9503,105],[9511,101],[9513,118],[9515,262],[9516,116],[9517,119],[9519,115],[9527,112],[9528,104],[9531,272],[9533,183],[9535,101],[9536,199],[9537,269],[9538,118],[9539,275],[9540,101],[9543,120],[9544,171],[9545,115],[9546,105],[9549,118],[9550,108],[9551,307],[9552,264],[9556,262],[9557,104],[9559,199],[9560,101],[9566,274],[9570,105],[9573,105],[9575,120],[9577,105],[9578,276],[9579,101],[9581,122],[9582,101],[9583,109],[9585,171],[9586,264],[9589,177],[9590,119],[9591,101],[9592,101],[9593,113],[9594,105],[9596,109],[9599,119],[9600,121],[9602,109],[9606,109],[9615,105],[9616,263],[9618,263],[9620,115],[9621,115],[9623,115],[9624,115],[9626,115],[9632,263],[9643,261],[9644,101],[9645,108],[9646,105],[9647,291],[9648,199],[9650,115],[9651,105],[9652,199],[9653,278],[9654,101],[9658,263],[9663,267],[9664,115],[9667,109],[9668,118],[9670,281],[9671,119],[9672,101],[9673,319],[9674,113],[9679,101],[9681,264],[9683,118],[9684,199],[9685,177],[9686,109],[9687,118],[9688,115],[9691,109],[9692,109],[9693,109],[9695,114],[9700,109],[9701,115],[9705,261],[9706,278],[9708,109],[9711,105],[9712,120],[9713,262],[9715,112],[9717,115],[9720,105],[9721,174],[9723,105],[9726,118],[9728,112],[9729,297],[9732,109],[9733,113],[9734,108],[9735,114],[9736,269],[9737,112],[9738,109],[9739,262],[9740,119],[9741,114],[9743,113],[9745,105],[9747,261],[9748,122],[9749,119],[9750,102],[9752,101],[9753,109],[9754,112],[9755,273],[9756,108],[9760,199],[9762,115],[9763,266],[9768,115],[9771,120],[9773,115],[9776,105],[9777,118],[9779,119],[9780,115],[9781,199],[9782,122],[9783,114],[9784,105],[9786,264],[9791,120],[9793,262],[9794,199],[9795,109],[9796,177],[9797,115],[9799,119],[9801,122],[9802,119],[9804,115],[9806,109],[9808,199],[9810,105],[9812,120],[9814,115],[9816,119],[9817,167],[9818,263],[9820,118],[9822,112],[9823,118],[9824,112],[9825,101],[9826,101],[9827,115],[9828,109],[9831,50],[9832,122],[9833,115],[9838,199],[9840,118],[9843,271],[9845,199],[9846,113],[9847,264],[9850,109],[9851,101],[9852,114],[9853,262],[9856,121],[9857,199],[9861,199],[9864,122],[9867,165],[9868,114],[9870,109],[9871,177],[9874,115],[9876,119],[9877,48],[9878,199],[9883,109],[9884,102],[9885,115],[9886,267],[9887,269],[9888,126],[9891,104],[9893,101],[9895,119],[9901,263],[9902,199],[9904,105],[9907,118],[9909,264],[9918,101],[9920,115],[9921,109],[9922,120],[9924,274],[9925,260],[9927,109],[9928,269],[9929,171],[9930,183],[9931,115],[9933,260],[9934,105],[9935,107],[9938,119],[9939,109],[9940,118],[9941,121],[9942,267],[9944,273],[9945,105],[9948,199],[9950,112],[9957,109],[9958,101],[9959,272],[9967,171],[9969,115],[9970,119],[9972,105],[9975,112],[9976,105],[9978,103],[9979,199],[9981,122],[9984,118],[9985,116],[9986,112],[9987,101],[9988,121],[9991,101],[10002,114],[10003,125],[10006,190],[10008,126],[10009,171],[10010,101],[10011,112],[10015,115],[10016,115],[10022,113],[10025,174],[10026,120],[10029,112],[10030,266],[10032,115],[10033,105],[10034,271],[10037,120],[10041,199],[10042,270],[10045,114],[10046,113],[10048,109],[10053,104],[10056,103],[10058,115],[10059,115],[10061,114],[10065,101],[10066,118],[10067,120],[10070,101],[10071,167],[10072,112],[10074,118],[10075,115],[10076,118],[10077,119],[10078,121],[10081,171],[10082,105],[10083,115],[10085,101],[10086,109],[10087,113],[10088,167],[10089,114],[10090,102],[10093,284],[10096,115],[10097,185],[10099,101],[10101,105],[10102,115],[10105,279],[10107,108],[10111,101],[10113,115],[10115,171],[10116,105],[10118,167],[10119,101],[10120,115],[10121,126],[10123,278],[10125,262],[10127,167],[10128,101],[10129,106],[10130,119],[10131,103],[10132,119],[10136,167],[10138,101],[10139,114],[10140,49],[10143,101],[10147,167],[10148,121],[10153,101],[10154,199],[10155,115],[10158,115],[10159,101],[10160,119],[10164,262],[10166,101],[10170,120],[10172,165],[10173,109],[10174,122],[10177,199],[10181,101],[10184,167],[10185,105],[10186,199],[10187,121],[10188,101],[10190,119],[10193,114],[10194,113],[10195,101],[10196,101],[10198,113],[10199,118],[10201,105],[10202,121],[10204,101],[10205,260],[10210,171],[10211,114],[10212,103],[10214,115],[10215,109],[10216,101],[10218,112],[10219,104],[10220,119],[10222,115],[10224,115],[10228,199],[10230,199],[10231,199],[10233,113],[10235,271],[10236,105],[10237,115],[10238,101],[10239,269],[10242,263],[10244,48],[10246,264],[10247,101],[10250,115],[10251,103],[10252,115],[10253,118],[10254,119],[10255,101],[10258,115],[10260,109],[10262,101],[10267,81],[10269,115],[10272,183],[10276,289],[10277,106],[10279,115],[10280,269],[10281,103],[10284,264],[10285,115],[10287,165],[10288,119],[10291,103],[10292,101],[10295,105],[10296,113],[10297,264],[10298,120],[10299,118],[10301,199],[10303,109],[10305,271],[10307,115],[10312,166],[10317,114],[10320,115],[10323,105],[10328,109],[10334,115],[10336,269],[10338,115],[10340,115],[10341,101],[10346,108],[10348,264],[10349,105],[10350,105],[10351,109],[10356,107],[10357,114],[10358,120],[10361,114],[10362,264],[10363,115],[10367,121],[10368,105],[10369,264],[10372,109],[10373,105],[10374,105],[10375,108],[10376,263],[10378,119],[10380,105],[10384,115],[10387,48],[10388,119],[38,52],[38,53],[38,81],[38,83],[38,655],[38,1885],[41,481],[42,88],[43,48],[43,119],[44,212],[44,267],[44,359],[44,745],[44,1050],[44,1272],[44,1381],[44,1435],[44,2006],[44,5355],[49,73],[49,76],[49,114],[49,117],[49,118],[50,64],[51,77],[51,108],[51,111],[53,987],[53,1382],[54,41],[55,54],[55,912],[56,59],[57,481],[58,52],[58,55],[58,59],[59,53],[59,57],[59,58],[61,41],[61,53],[61,57],[69,48],[69,82],[69,88],[69,323],[69,339],[69,460],[69,499],[69,1748],[69,1816],[69,5702],[69,6643],[70,273],[70,319],[70,321],[70,568],[70,838],[70,4998],[70,7194],[71,77],[71,105],[71,125],[71,325],[71,358],[71,400],[71,450],[71,485],[71,513],[71,571],[71,1887],[71,1983],[71,3604],[71,3622],[71,3717],[71,5618],[71,6414],[71,8769],[71,9224],[72,268],[72,303],[72,360],[72,578],[72,3161],[72,5011],[72,8891],[72,9190],[73,45],[73,88],[73,390],[73,481],[73,525],[73,533],[73,557],[73,7385],[74,77],[74,121],[74,367],[74,1157],[74,2169],[74,3132],[75,50],[75,71],[75,101],[75,118],[75,1524],[76,125],[76,313],[76,438],[76,839],[76,3134],[76,9462],[77,113],[77,346],[77,525],[78,436],[78,594],[78,6346],[78,7378],[79,105],[80,280],[80,286],[80,5055],[81,381],[81,414],[81,548],[81,594],[81,6312],[81,6314],[81,7401],[82,54],[82,89],[82,109],[82,1342],[82,4648],[82,6162],[83,481],[83,844],[83,2991],[83,5585],[83,10525],[84,72],[84,378],[84,925],[84,2682],[84,3333],[84,3593],[84,6597],[84,7582],[85,387],[86,109],[87,103],[87,280],[87,281],[87,500],[87,2591],[87,6661],[88,281],[88,283],[88,371],[88,372],[88,429],[88,438],[88,500],[88,502],[88,1310],[88,4537],[88,5572],[89,118],[89,997],[90,101],[90,322],[90,374],[90,936],[90,3143],[91,109],[91,2123],[94,360],[101,117],[101,271],[101,275],[101,290],[101,351],[101,1422],[101,6363],[101,9073],[102,119],[102,1056],[102,3134],[102,3586],[102,6391],[103,111],[103,274],[103,275],[103,502],[103,571],[103,2551],[103,6381],[104,43],[104,45],[104,113],[104,120],[104,125],[104,269],[104,294],[104,925],[104,2671],[105,63],[105,305],[105,496],[105,8951],[106,106],[106,319],[106,381],[106,546],[106,568],[106,802],[106,7815],[106,9798],[106,9903],[106,10035],[107,112],[107,263],[107,276],[107,283],[107,546],[107,4555],[107,5122],[107,6597],[107,6650],[108,1642],[109,45],[109,111],[109,289],[109,300],[109,5877],[110,199],[110,459],[110,2201],[111,108],[111,121],[112,63],[112,1008],[112,1643],[113,113],[113,1491],[113,7383],[114,38],[114,110],[114,274],[114,1686],[115,105],[115,273],[115,285],[115,293],[115,6885],[116,116],[116,286],[116,2002],[116,6851],[116,7971],[119,49],[119,104],[119,108],[119,294],[119,710],[119,5077],[120,103],[120,120],[120,1118],[120,2437],[121,266],[121,271],[121,272],[121,283],[121,338],[121,748],[122,294],[122,313],[122,326],[122,1141],[122,6851],[122,8954],[122,9464],[123,105],[123,554],[124,199],[125,101],[126,126],[126,6344],[134,48],[137,525],[143,230],[165,104],[165,112],[173,50],[183,276],[186,113],[190,103],[198,175],[198,191],[199,168],[199,10685],[210,179],[210,184],[213,133],[213,147],[229,192],[260,107],[261,38],[265,38],[265,101],[265,117],[266,45],[266,116],[267,116],[270,262],[271,101],[272,104],[273,118],[273,263],[273,266],[273,268],[273,271],[275,272],[276,115],[277,121],[278,270],[279,65],[279,107],[279,121],[281,112],[281,261],[281,272],[281,273],[283,113],[283,121],[284,112],[284,114],[285,102],[286,48],[286,263],[286,267],[286,271],[286,281],[287,106],[290,279],[291,121],[292,109],[293,265],[294,126],[296,103],[296,121],[297,262],[297,282],[299,104],[299,293],[300,104],[300,272],[300,297],[302,104],[304,116],[304,126],[305,121],[306,48],[306,108],[306,199],[306,266],[307,290],[307,300],[307,305],[309,112],[309,264],[310,105],[310,112],[311,113],[311,116],[311,269],[313,48],[313,119],[313,265],[313,280],[314,113],[314,120],[315,115],[315,261],[315,273],[318,263],[319,50],[319,107],[319,126],[319,266],[321,293],[322,294],[323,199],[323,303],[325,112],[325,267],[326,121],[326,268],[326,294],[327,289],[330,105],[331,268],[332,113],[332,272],[332,296],[332,297],[333,105],[333,266],[334,107],[334,121],[336,105],[336,124],[336,126],[339,120],[343,107],[347,306],[351,102],[351,104],[351,262],[352,105],[357,271],[358,103],[359,48],[364,102],[364,114],[364,302],[366,109],[368,318],[369,107],[370,50],[372,121],[372,302],[372,340],[373,103],[373,109],[373,126],[374,299],[376,126],[376,293],[379,199],[381,273],[382,289],[383,262],[389,271],[390,116],[390,262],[392,356],[393,101],[394,112],[396,199],[397,281],[412,109],[413,109],[414,289],[414,342],[414,358],[416,109],[423,101],[425,101],[428,122],[428,126],[428,199],[432,105],[432,119],[434,105],[434,114],[437,120],[446,112],[446,119],[447,298],[447,325],[453,102],[453,274],[457,103],[461,121],[462,285],[465,280],[467,300],[469,120],[472,109],[475,365],[483,104],[483,115],[496,104],[501,199],[502,310],[503,313],[505,446],[507,48],[518,280],[527,115],[527,261],[528,289],[528,293],[528,373],[528,421],[530,419],[531,109],[531,286],[535,116],[539,348],[539,412],[546,115],[547,113],[550,260],[551,302],[559,122],[559,289],[561,199],[563,409],[565,268],[565,299],[585,107],[585,110],[588,48],[596,275],[606,104],[606,310],[621,260],[621,296],[621,314],[621,351],[621,394],[621,422],[625,294],[625,433],[625,572],[625,620],[626,112],[626,264],[628,269],[629,109],[633,115],[634,101],[641,50],[641,263],[655,308],[656,115],[660,122],[662,121],[663,102],[664,104],[664,120],[664,263],[664,279],[669,190],[671,114],[674,48],[677,260],[677,294],[680,261],[692,579],[693,286],[694,120],[695,105],[696,118],[699,289],[701,104],[702,293],[704,109],[707,199],[709,66],[709,121],[709,262],[710,101],[712,115],[718,116],[720,109],[720,118],[723,109],[723,268],[728,263],[729,104],[733,107],[739,589],[742,105],[744,261],[748,101],[748,104],[751,114],[758,104],[761,101],[763,110],[770,268],[771,113],[780,48],[791,281],[797,267],[797,275],[802,104],[806,199],[808,101],[820,105],[821,119],[828,121],[835,121],[848,48],[857,126],[880,262],[900,105],[900,122],[901,269],[917,112],[918,104],[924,101],[936,103],[936,264],[938,120],[941,103],[941,199],[946,50],[951,105],[951,284],[960,59],[960,61],[963,101],[963,118],[964,101],[965,121],[969,268],[976,105],[987,55],[995,48],[996,116],[1004,109],[1007,299],[1010,109],[1019,51],[1021,284],[1031,263],[1032,50],[1035,121],[1042,55],[1042,60],[1042,912],[1048,109],[1052,281],[1053,63],[1054,101],[1056,115],[1081,116],[1087,115],[1097,101],[1109,50],[1111,115],[1115,115],[1115,349],[1126,103],[1135,107],[1138,50],[1139,109],[1139,296],[1142,101],[1150,50],[1151,271],[1159,276],[1163,101],[1171,103],[1178,851],[1184,104],[1184,118],[1187,118],[1199,50],[1204,112],[1209,199],[1224,121],[1227,325],[1231,199],[1240,111],[1241,199],[1247,352],[1266,103],[1275,118],[1276,297],[1288,105],[1295,48],[1303,114],[1303,269],[1311,113],[1313,53],[1316,114],[1316,118],[1329,105],[1332,110],[1333,45],[1333,50],[1340,300],[1340,317],[1352,109],[1355,122],[1375,62],[1377,48],[1381,50],[1381,52],[1381,58],[1382,59],[1402,38],[1405,50],[1405,60],[1405,198],[1407,369],[1417,266],[1421,269],[1428,118],[1430,117],[1433,113],[1433,122],[1434,50],[1448,50],[1453,293],[1453,318],[1456,50],[1466,267],[1470,105],[1471,105],[1472,120],[1472,262],[1474,113],[1475,115],[1483,275],[1489,109],[1495,269],[1496,53],[1499,267],[1509,267],[1510,48],[1512,118],[1517,105],[1520,50],[1520,52],[1520,60],[1529,118],[1547,114],[1547,261],[1549,38],[1552,114],[1556,101],[1566,55],[1566,58],[1572,276],[1584,115],[1585,273],[1596,275],[1604,101],[1624,115],[1627,61],[1637,105],[1643,284],[1645,50],[1650,48],[1662,109],[1662,278],[1673,101],[1676,467],[1699,113],[1704,118],[1719,50],[1726,48],[1737,45],[1737,48],[1745,108],[1746,49],[1755,53],[1755,54],[1755,55],[1755,57],[1755,61],[1756,115],[1760,58],[1760,60],[1763,50],[1771,119],[1778,50],[1782,109],[1792,101],[1795,115],[1804,114],[1806,297],[1826,55],[1826,56],[1826,60],[1839,118],[1846,262],[1849,294],[1849,852],[1852,105],[1852,199],[1863,122],[1865,105],[1868,105],[1874,199],[1878,48],[1883,109],[1888,112],[1908,108],[1908,308],[1910,279],[1911,263],[1929,59],[1933,105],[1933,276],[1944,262],[1947,119],[1958,109],[1958,113],[1960,268],[1969,276],[1971,185],[1972,104],[1974,183],[1977,762],[1979,278],[1980,122],[1981,120],[1984,106],[1984,114],[1987,109],[1992,199],[1993,109],[2006,50],[2008,50],[2014,261],[2014,266],[2023,50],[2024,49],[2024,282],[2032,48],[2032,119],[2035,56],[2037,262],[2048,109],[2054,53],[2062,103],[2071,50],[2076,48],[2094,105],[2098,263],[2105,341],[2115,112],[2120,118],[2120,121],[2124,262],[2130,377],[2131,53],[2131,58],[2133,57],[2133,58],[2133,59],[2137,267],[2148,109],[2154,50],[2154,109],[2154,113],[2156,418],[2159,114],[2166,48],[2171,48],[2172,300],[2172,305],[2172,551],[2204,104],[2235,48],[2238,269],[2251,261],[2271,185],[2286,783],[2288,104],[2291,279],[2293,264],[2303,48],[2311,311],[2316,114],[2316,120],[2317,113],[2321,117],[2324,271],[2326,263],[2333,114],[2335,48],[2342,119],[2353,279],[2389,50],[2394,109],[2395,199],[2399,118],[2402,1689],[2407,48],[2430,102],[2440,48],[2440,50],[2459,48],[2459,50],[2464,120],[2467,114],[2470,48],[2470,62],[2479,113],[2484,50],[2488,48],[2492,278],[2499,102],[2499,262],[2504,588],[2505,104],[2509,460],[2519,102],[2524,114],[2532,107],[2539,101],[2540,57],[2540,60],[2541,52],[2543,115],[2545,48],[2554,118],[2555,119],[2569,263],[2572,113],[2573,48],[2588,185],[2599,48],[2613,48],[2616,109],[2620,50],[2638,115],[2645,351],[2649,276],[2651,115],[2655,261],[2668,268],[2669,113],[2675,264],[2676,118],[2678,106],[2678,294],[2683,114],[2684,48],[2691,112],[2692,115],[2693,121],[2701,109],[2707,50],[2710,122],[2713,48],[2737,120],[2742,122],[2762,48],[2771,199],[2775,266],[2779,101],[2783,52],[2784,121],[2788,319],[2791,278],[2797,266],[2813,50],[2821,293],[2824,318],[2825,101],[2825,105],[2829,109],[2839,101],[2840,112],[2843,114],[2850,48],[2857,105],[2858,119],[2861,408],[2863,122],[2864,326],[2866,114],[2876,104],[2887,120],[2898,275],[2925,185],[2927,48],[2927,50],[2929,48],[2934,109],[2936,119],[2947,111],[2948,199],[2948,315],[2952,293],[2953,704],[2954,475],[2956,113],[2959,314],[2965,48],[2969,199],[2987,102],[2994,105],[2995,54],[3007,48],[3007,49],[3014,304],[3023,120],[3040,48],[3042,48],[3062,50],[3065,199],[3068,48],[3079,115],[3105,50],[3110,118],[3116,48],[3118,102],[3120,102],[3147,116],[3160,110],[3162,262],[3178,48],[3178,50],[3182,106],[3185,50],[3188,183],[3192,101],[3196,48],[3196,50],[3202,104],[3205,50],[3219,109],[3219,113],[3221,119],[3230,118],[3230,199],[3242,48],[3242,50],[3243,50],[3246,105],[3254,101],[3285,287],[3285,461],[3290,115],[3319,118],[3328,101],[3331,118],[3331,266],[3337,109],[3342,121],[3343,282],[3352,101],[3358,262],[3382,313],[3393,185],[3400,101],[3402,48],[3402,49],[3402,50],[3421,199],[3422,48],[3433,48],[3433,50],[3434,310],[3435,113],[3442,103],[3445,113],[3445,118],[3446,104],[3447,50],[3455,50],[3456,114],[3459,267],[3462,199],[3468,118],[3473,101],[3476,274],[3484,121],[3484,262],[3495,119],[3506,112],[3510,48],[3514,48],[3532,101],[3539,297],[3554,352],[3569,48],[3569,50],[3574,282],[3589,105],[3590,109],[3593,48],[3602,274],[3607,103],[3607,106],[3608,103],[3612,45],[3627,264],[3635,269],[3645,270],[3647,109],[3651,114],[3651,262],[3657,113],[3657,199],[3661,262],[3662,113],[3680,50],[3681,118],[3684,267],[3685,119],[3688,267],[3704,114],[3711,119],[3725,276],[3736,113],[3736,118],[3739,199],[3742,105],[3761,105],[3767,115],[3769,263],[3797,107],[3797,334],[3808,272],[3814,289],[3827,199],[3837,115],[3839,266],[3854,303],[3859,177],[3861,57],[3865,126],[3885,113],[3888,38],[3890,101],[3909,104],[3909,261],[3914,105],[3924,199],[3933,2049],[3939,261],[3943,50],[3966,50],[3971,50],[3983,118],[3986,104],[3988,119],[3998,267],[3998,268],[3999,104],[4007,261],[4008,104],[4022,120],[4051,109],[4073,113],[4086,115],[4087,48],[4105,115],[4105,267],[4105,268],[4124,48],[4139,2676],[4141,107],[4144,266],[4145,49],[4147,260],[4151,49],[4155,276],[4162,116],[4164,294],[4165,113],[4189,107],[4191,121],[4192,269],[4194,199],[4195,261],[4199,106],[4201,115],[4208,112],[4208,122],[4225,113],[4230,276],[4247,103],[4254,113],[4269,299],[4273,50],[4316,119],[4323,282],[4325,119],[4341,262],[4344,113],[4345,280],[4346,199],[4352,103],[4358,266],[4359,48],[4368,261],[4370,48],[4378,267],[4383,104],[4396,48],[4417,114],[4424,48],[4436,48],[4457,48],[4489,351],[4501,273],[4506,279],[4507,267],[4508,325],[4510,104],[4529,266],[4538,101],[4545,121],[4553,263],[4560,115],[4565,109],[4565,289],[4575,119],[4579,171],[4579,183],[4584,118],[4586,199],[4594,199],[4618,118],[4624,48],[4642,112],[4650,115],[4651,119],[4656,50],[4658,48],[4660,268],[4663,199],[4675,106],[4676,113],[4682,48],[4692,263],[4694,119],[4695,263],[4696,105],[4700,266],[4730,48],[4738,48],[4741,109],[4742,118],[4749,119],[4753,118],[4771,261],[4771,266],[4772,118],[4772,261],[4774,113],[4779,50],[4780,105],[4791,268],[4791,294],[4811,113],[4812,50],[4851,50],[4859,185],[4876,109],[4879,48],[4882,109],[4891,101],[4897,271],[4905,109],[4906,113],[4909,48],[4914,109],[4921,87],[4947,290],[4949,268],[4949,277],[4952,108],[4955,109],[4957,105],[4961,348],[4964,297],[4975,113],[4978,4187],[4991,210],[5011,282],[5032,120],[5053,261],[5068,119],[5073,313],[5075,115],[5075,280],[5081,112],[5082,118],[5082,119],[5092,260],[5105,199],[5114,114],[5134,118],[5134,119],[5135,49],[5136,48],[5141,115],[5155,104],[5163,112],[5176,102],[5180,119],[5182,101],[5195,261],[5204,48],[5219,48],[5219,50],[5228,48],[5245,48],[5252,265],[5257,49],[5260,115],[5263,48],[5285,113],[5285,261],[5310,115],[5317,109],[5317,199],[5319,113],[5321,266],[5325,109],[5325,199],[5332,293],[5339,199],[5388,118],[5401,167],[5407,199],[5417,48],[5428,50],[5434,265],[5455,199],[5474,260],[5479,103],[5491,266],[5493,108],[5494,48],[5498,121],[5501,48],[5512,261],[5515,303],[5525,315],[5550,113],[5559,210],[5564,101],[5570,118],[5589,103],[5597,114],[5598,273],[5602,114],[5615,121],[5619,113],[5633,105],[5633,114],[5648,120],[5655,121],[5658,103],[5661,119],[5677,1022],[5687,199],[5690,112],[5696,118],[5696,121],[5709,48],[5711,119],[5714,120],[5719,109],[5719,112],[5741,119],[5745,38],[5755,119],[5792,119],[5794,280],[5809,120],[5813,113],[5822,101],[5822,105],[5834,105],[5834,199],[5839,263],[5848,261],[5853,104],[5888,105],[5895,261],[5895,266],[5897,279],[5898,115],[5913,50],[5953,266],[5959,101],[5964,48],[5988,48],[5991,118],[6023,262],[6026,103],[6039,265],[6067,261],[6076,120],[6094,185],[6100,48],[6105,125],[6125,48],[6129,267],[6133,271],[6139,268],[6148,48],[6155,48],[6160,101],[6172,104],[6174,115],[6174,267],[6222,284],[6226,116],[6230,307],[6238,122],[6239,266],[6240,358],[6243,275],[6244,108],[6246,103],[6250,263],[6276,105],[6276,109],[6277,113],[6290,199],[6329,122],[6332,118],[6363,293],[6368,263],[6368,286],[6386,105],[6386,277],[6390,120],[6395,300],[6400,101],[6400,105],[6421,183],[6423,269],[6426,109],[6426,114],[6430,121],[6443,183],[6443,185],[6456,109],[6456,121],[6479,112],[6480,199],[6482,103],[6530,267],[6548,101],[6548,109],[6560,119],[6562,48],[6565,122],[6571,101],[6571,118],[6581,116],[6583,48],[6596,112],[6596,118],[6599,101],[6628,119],[6632,101],[6632,115],[6633,101],[6633,115],[6645,104],[6645,260],[6660,101],[6660,115],[6666,266],[6678,120],[6678,261],[6686,118],[6707,118],[6734,119],[6737,109],[6738,50],[6765,48],[6771,114],[6772,119],[6775,101],[6801,199],[6809,199],[6810,119],[6826,199],[6828,264],[6831,113],[6831,270],[6835,275],[6843,278],[6843,282],[6845,121],[6857,199],[6867,113],[6876,49],[6878,115],[6891,101],[6891,115],[6897,105],[6903,106],[6903,120],[6906,293],[6913,261],[6913,266],[6940,119],[6957,48],[6976,50],[6989,48],[7001,119],[7004,115],[7021,101],[7021,268],[7026,48],[7060,101],[7065,113],[7077,271],[7119,105],[7119,263],[7122,103],[7122,265],[7123,48],[7125,48],[7140,48],[7145,48],[7158,50],[7160,115],[7204,123],[7205,103],[7212,126],[7213,102],[7220,102],[7246,120],[7248,300],[7254,287],[7268,199],[7277,50],[7285,101],[7289,105],[7296,119],[7328,199],[7342,262],[7354,261],[7367,264],[7391,115],[7406,109],[7410,109],[7411,305],[7435,290],[7449,48],[7455,307],[7456,120],[7472,104],[7473,262],[7480,105],[7487,199],[7496,118],[7499,266],[7501,199],[7521,48],[7526,262],[7528,263],[7541,113],[7550,120],[7561,101],[7569,261],[7572,119],[7588,283],[7607,45],[7621,101],[7630,119],[7641,45],[7651,103],[7664,101],[7672,199],[7680,114],[7699,274],[7702,120],[7703,177],[7716,103],[7736,101],[7758,113],[7781,109],[7801,115],[7802,118],[7803,109],[7807,199],[7825,119],[7829,261],[7839,122],[7843,109],[7864,104],[7873,113],[7877,105],[7900,119],[7922,309],[7927,115],[7930,261],[7933,50],[7937,103],[7943,324],[7946,268],[7954,105],[7958,261],[7962,115],[7967,275],[7975,121],[7977,279],[7980,114],[7999,104],[8024,265],[8027,263],[8043,266],[8047,113],[8062,114],[8063,115],[8072,263],[8074,268],[8075,199],[8093,274],[8106,101],[8121,113],[8125,112],[8127,262],[8140,115],[8146,119],[8180,112],[8184,48],[8191,112],[8194,261],[8200,115],[8217,118],[8266,105],[8271,267],[8276,115],[8280,119],[8285,108],[8307,109],[8309,185],[8315,167],[8325,115],[8327,167],[8328,101],[8343,119],[8349,109],[8350,48],[8358,101],[8367,167],[8376,104],[8378,103],[8397,101],[8400,101],[8420,48],[8422,101],[8428,199],[8435,103],[8450,103],[8451,101],[8464,50],[8466,115],[8472,119],[8477,115],[8488,101],[8494,119],[8495,50],[8506,112],[8532,6414],[8565,118],[8569,106],[8574,293],[8586,325],[8590,106],[8621,103],[8627,268],[8631,115],[8634,40],[8651,269],[8669,115],[8675,109],[8680,271],[8698,119],[8700,271],[8706,277],[8708,105],[8716,266],[8743,212],[8745,101],[8747,113],[8748,105],[8785,199],[8794,105],[8804,115],[8821,337],[8853,115],[8861,103],[8863,105],[8865,122],[8869,263],[8890,283],[8892,173],[8893,114],[8895,107],[8896,121],[8898,103],[8903,109],[8909,105],[8916,109],[8924,120],[8928,267],[8931,275],[8935,266],[8938,103],[8940,101],[8944,319],[8946,102],[8952,199],[8953,272],[8957,115],[8959,199],[8962,113],[8965,115],[8966,762],[8975,199],[8978,112],[8979,114],[8993,323],[9009,101],[9013,56],[9014,113],[9018,115],[9026,282],[9032,263],[9037,121],[9039,112],[9045,105],[9046,119],[9058,263],[9061,266],[9072,173],[9076,105],[9078,115],[9095,118],[9102,48],[9105,307],[9125,105],[9126,48],[9127,48],[9151,114],[9160,120],[9165,112],[9178,111],[9208,118],[9228,265],[9229,185],[9233,101],[9242,263],[9245,105],[9246,105],[9250,48],[9266,113],[9270,274],[9271,113],[9273,183],[9313,48],[9327,275],[9328,104],[9334,109],[9335,199],[9336,105],[9345,113],[9353,48],[9354,109],[9371,261],[9373,303],[9392,105],[9407,117],[9409,271],[9415,266],[9420,114],[9426,114],[9429,113],[9459,262],[9465,112],[9470,101],[9491,115],[9499,119],[9500,115],[9501,115],[9509,105],[9534,268],[9547,112],[9553,115],[9554,113],[9567,114],[9587,261],[9597,119],[9610,50],[9622,105],[9640,48],[9657,49],[9662,116],[9666,109],[9677,119],[9694,105],[9696,101],[9707,119],[9714,114],[9716,166],[9719,115],[9730,105],[9746,102],[9751,101],[9764,262],[9766,101],[9767,101],[9774,109],[9775,101],[9785,119],[9789,112],[9800,118],[9803,113],[9805,276],[9811,115],[9815,105],[9841,101],[9848,48],[9849,262],[9862,118],[9866,49],[9882,48],[9905,264],[9916,274],[9937,271],[9947,109],[9949,103],[9952,184],[9953,267],[9961,105],[9962,101],[9964,105],[9966,109],[9977,48],[9990,271],[10005,48],[10007,48],[10023,105],[10024,263],[10027,265],[10038,199],[10039,103],[10047,101],[10050,120],[10054,265],[10064,115],[10068,199],[10092,115],[10109,261],[10117,266],[10126,167],[10142,101],[10157,101],[10203,101],[10206,119],[10209,115],[10232,112],[10234,118],[10249,118],[10256,101],[10257,48],[10264,115],[10282,115],[10283,167],[10289,48],[10294,48],[10300,119],[10308,105],[10313,177],[10314,185],[10315,115],[10332,271],[10333,105],[10337,265],[10342,105],[10353,167],[10371,103],[10379,48],[10381,101],[10391,38],[10438,10398],[10439,287],[10441,327],[10446,268],[10452,177],[10455,6340],[10457,311],[10461,264],[10462,120],[10466,264],[10472,109],[10474,49],[10477,102],[10480,116],[10483,313],[10485,284],[10486,261],[10488,113],[10492,121],[10494,118],[10502,286],[10505,262],[10507,112],[10509,126],[10512,113],[10518,308],[10520,109],[10521,108],[10523,108],[10526,4579],[10528,261],[10531,115],[10533,114],[10537,283],[10541,278],[10542,103],[10545,385],[10548,334],[10550,261],[10553,119],[10555,279],[10557,285],[10560,199],[10563,360],[10570,123],[10571,199],[10577,115],[10579,113],[10581,101],[10583,122],[10589,105],[10591,101],[10599,105],[10606,199],[10610,113],[10620,103],[10621,112],[10624,101],[10632,286],[10636,262],[10639,109],[10640,105],[10644,324],[10652,119],[10658,264],[10663,265],[10669,299],[10671,260],[10677,115],[10696,323],[10706,121],[10711,120],[10733,109],[10740,65],[10750,113],[10754,291],[10771,119],[10784,105],[10799,118],[10801,262],[10802,266],[10803,112],[10804,101],[10806,112],[10809,277],[10812,262],[10817,108],[10821,121],[10822,102],[10823,286],[10828,275],[10835,177],[10836,120],[10842,264],[10845,185],[10846,112],[10848,106],[10849,112],[10852,112],[10853,107],[10857,171],[10866,108],[10868,115],[10871,263],[10874,269],[10875,119],[10876,267],[10881,279],[10882,271],[10885,113],[10886,118],[10889,265],[10891,105],[10895,109],[10897,101],[10899,105],[10901,114],[10902,277],[10903,101],[10904,165],[10905,273],[10907,119],[10909,121],[10911,264],[10917,112],[10920,262],[10921,199],[10922,199],[10923,108],[10925,101],[10926,266],[10927,272],[10929,264],[10934,101],[10936,121],[10938,287],[10939,116],[10941,104],[10942,103],[10944,121],[10945,126],[10947,105],[10948,261],[10949,299],[10951,105],[10952,115],[10953,109],[10956,167],[10958,107],[10967,120],[10968,109],[10969,115],[10976,101],[10986,177],[10987,118],[10994,114],[10996,281],[10998,294],[10999,109],[11001,105],[11002,105],[11005,177],[11008,109],[11012,105],[11016,122],[11017,41],[11020,115],[11021,106],[11022,114],[11023,108],[11024,282],[11027,109],[11032,199],[11034,112],[11035,118],[11042,327],[11043,109],[11044,105],[11046,300],[11047,289],[11052,270],[11053,109],[11055,101],[11062,119],[11063,185],[11065,171],[11067,120],[11069,112],[11070,119],[11072,261],[11073,101],[11076,261],[11078,119],[11079,105],[11082,48],[11084,268],[11085,326],[11096,107],[11098,115],[11100,121],[11102,101],[11105,121],[11106,263],[11109,120],[11111,109],[11112,113],[11114,121],[11116,265],[11127,101],[11128,261],[11129,119],[11131,261],[11135,50],[11137,114],[11138,264],[11140,121],[11142,109],[11143,261],[11147,115],[11149,300],[11163,121],[11169,119],[11171,121],[11176,48],[11179,282],[11180,105],[11183,268],[11184,109],[11185,114],[11186,183],[11188,119],[11192,264],[11195,107],[11197,114],[11200,105],[11203,263],[11205,114],[11208,288],[11209,126],[11210,199],[11211,115],[11212,289],[11213,177],[11220,295],[11224,41],[11226,275],[11228,109],[11231,118],[11234,1643],[11237,120],[11241,48],[11245,266],[11247,266],[11248,105],[11249,115],[11258,101],[11260,263],[11262,291],[11263,112],[11264,105],[11266,262],[11268,199],[11269,105],[11270,121],[11272,101],[11273,261],[11276,264],[11278,119],[11279,171],[11283,262],[11288,101],[11289,101],[11295,115],[11299,123],[11315,263],[11318,266],[11320,121],[11323,107],[11324,118],[11326,105],[11329,101],[11330,119],[11331,107],[11333,121],[11335,101],[11338,105],[11340,101],[11343,183],[11347,748],[11349,113],[11358,101],[11359,261],[11364,276],[11365,268],[11367,115],[11368,109],[11370,263],[11374,119],[11376,105],[11377,185],[11378,115],[11380,109],[11381,300],[11382,105],[11385,177],[11386,109],[11387,114],[11390,117],[11396,183],[11398,112],[11400,115],[11402,109],[11404,284],[11406,48],[11409,109],[11411,113],[11415,101],[11417,119],[11421,171],[11425,119],[11428,121],[11429,111],[11430,105],[11435,112],[11437,112],[11440,263],[11445,171],[11451,105],[11454,101],[11457,261],[11459,174],[11460,115],[11462,115],[11464,113],[11470,261],[11471,101],[11474,274],[11478,115],[11479,105],[11480,109],[11481,293],[11483,105],[11485,107],[11486,119],[11487,261],[11488,113],[11490,171],[11491,113],[11492,105],[11498,261],[11501,105],[11503,165],[11504,109],[11506,119],[11511,122],[11512,171],[11516,114],[11518,105],[11520,48],[11521,261],[11522,101],[11524,119],[11525,171],[11532,101],[11538,101],[11540,115],[11548,118],[11549,199],[11550,122],[11551,119],[11553,305],[11555,109],[11556,269],[11557,115],[11558,262],[11561,171],[11563,101],[11564,113],[11566,101],[11569,268],[11570,105],[11571,269],[11574,274],[11576,109],[11578,114],[11579,174],[11586,101],[11588,119],[11592,104],[11593,102],[11594,264],[11596,266],[11597,101],[11600,109],[11602,114],[11603,265],[11606,115],[11609,177],[11613,115],[11619,165],[11620,283],[11631,101],[11633,199],[11642,119],[11643,105],[11646,105],[11647,119],[11649,119],[11652,119],[11653,105],[11655,119],[11656,83],[11657,118],[11661,116],[11663,273],[11664,114],[11668,199],[11669,123],[11672,280],[11673,112],[11674,104],[11679,183],[11680,119],[11681,119],[11682,119],[11683,119],[11686,101],[11688,109],[11698,119],[11699,113],[11701,105],[11703,121],[11705,177],[11709,167],[11711,185],[11712,267],[11713,115],[11714,171],[11718,185],[11719,109],[11720,263],[11721,112],[11722,115],[11729,121],[11734,110],[11735,107],[11740,108],[11741,267],[11743,121],[11746,171],[11747,108],[11752,125],[11753,119],[11759,114],[11760,105],[11761,105],[11765,174],[11772,264],[11781,268],[11784,109],[11785,105],[11795,101],[11798,112],[11799,109],[11800,300],[11802,118],[11810,115],[11811,171],[11812,277],[11816,101],[11817,109],[11818,270],[11819,115],[11821,114],[11822,114],[11823,114],[11824,119],[11825,119],[11826,104],[11828,119],[11829,105],[11830,103],[11831,101],[11832,101],[11833,177],[11837,122],[11840,109],[11842,101],[11843,112],[11846,114],[11853,109],[11857,260],[11859,118],[11866,108],[11869,171],[11870,171],[11872,177],[11873,115],[11874,268],[11877,115],[11878,274],[11880,171],[11881,105],[11882,119],[11884,119],[11885,119],[11886,114],[11887,105],[11888,199],[11902,105],[11906,101],[11914,286],[11916,101],[11917,119],[11918,125],[11922,166],[11925,118],[11927,171],[11929,118],[11930,105],[11931,103],[11932,107],[11933,115],[11934,107],[11937,114],[11938,268],[11939,109],[11940,106],[11941,114],[11942,165],[11944,260],[11945,177],[11947,112],[11948,101],[11951,113],[11957,101],[11959,101],[11961,171],[11962,109],[11963,267],[11964,115],[11966,109],[11967,113],[11971,120],[11972,265],[11973,171],[11978,101],[11994,264],[11995,120],[12001,109],[12005,171],[12006,115],[12008,115],[12011,113],[12017,119],[12024,119],[12025,263],[12026,115],[12028,115],[12034,115],[12035,101],[12036,101],[12041,171],[12042,101],[12044,119],[12049,119],[12054,199],[12057,266],[12058,118],[12059,108],[12061,121],[12063,118],[12068,261],[12073,120],[12076,174],[12077,102],[12081,109],[12082,264],[12085,279],[12086,113],[12087,120],[12088,105],[12089,119],[12090,121],[12091,266],[12092,289],[12093,271],[12094,267],[12100,119],[12101,112],[12102,171],[12105,171],[12107,101],[12109,174],[12110,275],[12111,199],[12112,269],[12114,48],[12115,115],[12117,274],[12118,120],[12124,260],[12125,113],[12126,103],[12127,112],[12128,109],[12130,269],[12134,104],[12135,199],[12137,108],[12139,112],[12140,263],[12147,115],[12148,105],[12149,120],[12152,199],[12153,261],[12154,174],[12156,105],[12161,114],[12162,121],[12163,118],[12165,105],[12166,307],[12167,105],[12169,291],[12170,112],[12173,116],[12177,115],[12178,107],[12179,105],[12180,101],[12187,115],[12190,112],[12193,104],[12194,113],[12196,114],[12197,101],[12199,119],[12202,266],[12207,105],[12209,119],[12210,119],[12211,114],[12213,113],[12215,119],[12217,105],[12218,115],[12221,108],[12222,114],[12233,103],[12235,165],[12236,109],[12240,121],[12241,183],[12245,115],[12247,114],[12248,119],[12253,267],[12257,119],[12258,115],[12262,114],[12263,104],[12264,105],[12270,115],[12277,297],[12279,112],[12282,108],[12283,109],[12284,105],[12285,118],[12286,80],[12287,118],[12288,112],[12290,108],[12291,118],[12293,118],[12294,109],[12295,109],[12297,121],[12298,328],[12300,271],[12301,118],[12302,281],[12304,183],[12306,265],[12309,115],[12310,109],[12313,118],[12315,107],[12316,109],[12317,166],[12319,119],[12320,166],[12324,199],[12327,109],[12328,183],[12329,105],[12330,121],[12331,109],[12339,263],[12341,269],[12342,115],[12344,118],[12345,105],[12346,109],[12347,120],[12349,267],[12351,113],[12353,262],[12356,109],[12363,109],[12364,276],[12366,119],[12368,109],[12369,263],[12370,101],[12371,109],[12373,101],[12375,101],[12376,101],[12379,126],[12380,104],[12382,264],[12384,109],[12386,112],[12387,114],[12389,114],[12394,118],[12396,289],[12399,108],[12400,38],[12401,165],[12402,165],[12403,101],[12405,260],[12410,116],[12411,199],[12412,109],[12413,108],[12414,119],[12418,269],[12419,120],[12420,114],[12421,122],[12423,109],[12424,101],[12428,122],[12429,120],[12431,119],[12432,278],[12433,104],[12435,110],[12436,119],[12437,105],[12439,101],[12441,119],[12442,109],[12446,120],[12447,165],[12448,108],[12450,107],[12451,115],[12456,119],[12459,105],[12460,115],[12461,101],[12462,104],[12472,115],[12473,118],[12474,109],[12479,122],[12483,104],[12488,119],[12493,114],[12496,120],[12499,101],[12502,262],[12504,116],[12505,120],[12506,105],[12507,121],[12508,199],[12509,264],[12511,109],[12514,177],[12516,113],[12517,119],[12521,115],[12524,109],[12526,260],[12527,260],[12528,264],[12530,114],[12532,276],[12533,108],[12536,183],[12537,264],[12538,105],[12541,115],[12543,199],[12546,119],[12547,114],[12548,554],[12550,260],[12554,264],[12556,289],[12557,109],[12558,294],[12559,112],[12560,118],[12561,114],[12562,107],[12564,105],[12570,122],[12573,112],[12574,263],[12575,290],[12576,115],[12578,114],[12579,103],[12582,121],[12583,109],[12586,199],[12589,103],[12590,109],[12593,199],[12595,112],[12596,105],[12598,107],[12601,274],[12605,114],[12606,121],[12609,118],[12610,269],[12611,115],[12613,112],[12614,115],[12617,114],[12621,199],[12623,114],[12625,114],[12627,118],[12629,101],[12630,199],[12631,121],[12632,119],[12634,118],[12637,199],[12640,114],[12642,183],[12643,109],[12644,105],[12646,120],[12647,265],[12650,274],[12651,102],[12652,101],[12655,114],[12657,115],[12658,119],[12659,109],[12660,114],[12664,118],[12665,101],[12666,260],[12668,113],[12669,291],[12670,119],[12672,107],[12673,107],[12674,118],[12675,115],[12676,113],[12677,165],[12678,289],[12679,264],[12680,119],[12681,113],[12684,114],[12689,112],[12691,185],[12692,101],[12694,280],[12695,109],[12696,304],[12700,105],[12702,115],[12703,105],[12704,105],[12705,114],[12709,263],[12712,199],[12713,263],[12714,118],[12715,105],[12716,105],[12718,114],[12719,115],[12720,267],[12723,112],[12724,199],[12725,105],[12728,109],[12730,264],[12731,114],[12732,115],[12734,122],[12735,119],[12737,199],[12739,297],[12740,104],[12741,290],[12742,199],[12743,263],[12748,120],[12749,109],[12750,109],[12751,113],[12754,109],[12758,270],[12759,114],[12761,119],[12763,268],[12768,101],[12769,199],[12770,199],[12771,278],[12772,112],[12774,114],[12775,115],[12776,199],[12777,114],[12778,105],[12781,120],[12782,262],[12783,165],[12784,264],[12789,105],[12790,114],[12792,199],[12795,101],[12796,113],[12797,114],[12798,276],[12799,283],[12801,199],[12802,109],[12803,199],[12804,118],[12806,119],[12807,109],[12812,199],[12813,126],[12816,115],[12818,115],[12820,274],[12822,105],[12823,105],[12825,199],[12828,109],[12830,113],[12837,199],[12841,183],[12842,260],[12843,105],[12844,109],[12845,49],[12848,105],[12849,114],[12850,276],[12851,120],[12852,263],[12853,264],[12856,112],[12858,112],[12860,122],[12861,261],[12864,109],[12865,199],[12866,199],[12867,114],[12868,121],[12869,114],[12870,166],[12871,101],[12874,115],[12875,101],[12878,120],[12879,109],[12880,115],[12881,119],[12882,199],[12883,165],[12885,115],[12888,264],[12889,109],[12890,174],[12892,114],[12893,264],[12894,120],[12896,114],[12899,264],[12902,109],[12903,107],[12904,109],[12905,114],[12907,120],[12909,109],[12910,109],[12911,120],[12914,260],[12915,264],[12918,120],[12920,105],[12923,114],[12924,109],[12925,199],[12926,119],[12929,107],[12931,115],[12932,50],[12936,120],[12937,101],[12938,119],[12940,270],[12941,109],[12942,109],[12943,122],[12945,115],[12946,101],[12947,109],[12948,109],[12951,107],[12952,103],[12955,287],[12957,101],[12959,109],[12962,266],[12964,101],[12965,101],[12966,114],[12968,114],[12969,184],[12970,118],[12971,107],[12972,114],[12973,119],[12974,103],[12975,105],[12976,267],[12978,199],[12980,114],[12983,115],[12984,261],[12985,104],[12988,115],[12989,103],[12991,114],[12992,103],[12997,101],[13000,113],[13001,260],[13002,104],[13003,109],[13004,265],[13005,274],[13007,120],[13008,48],[13009,112],[13011,109],[13012,173],[13013,115],[13014,115],[13016,115],[13018,283],[13019,281],[13021,260],[13022,105],[13023,101],[13024,199],[13025,120],[13026,101],[13027,101],[13028,120],[13029,264],[13031,115],[13032,265],[13034,118],[13035,105],[13036,109],[13037,114],[13038,113],[13045,119],[13046,101],[13049,276],[13050,101],[13053,115],[13054,101],[13057,171],[13058,105],[13059,115],[13060,119],[13061,109],[13062,275],[13063,114],[13064,122],[13067,105],[13068,115],[13071,124],[13072,115],[13073,118],[13075,167],[13077,101],[13080,105],[13081,265],[13082,106],[13083,261],[13084,113],[13085,119],[13086,120],[13087,109],[13088,264],[13089,101],[13090,105],[13092,120],[13094,120],[13095,121],[13096,199],[13097,119],[13098,183],[13100,103],[13101,167],[13102,120],[13104,101],[13105,115],[13106,103],[13108,108],[13109,102],[13111,105],[13114,167],[13115,120],[13116,120],[13117,267],[13120,115],[13123,167],[13124,101],[13125,112],[13126,101],[13128,101],[13130,115],[13131,105],[13132,119],[13133,120],[13136,115],[13137,103],[13138,115],[13139,199],[13141,276],[13146,109],[13147,116],[13149,106],[13153,115],[13154,120],[13156,263],[13157,273],[13158,103],[13159,271],[13160,265],[13162,112],[13165,120],[13167,185],[13169,101],[13171,114],[13172,108],[13174,115],[13175,120],[13176,167],[13178,115],[13179,105],[13180,103],[13184,166],[13187,118],[13188,167],[13190,115],[13191,113],[13193,267],[13194,120],[13195,199],[13196,278],[13198,113],[13201,167],[13202,267],[13203,115],[13204,276],[13207,120],[13209,105],[13211,120],[13212,115],[13214,109],[13215,167],[13217,101],[13218,105],[13219,113],[13221,171],[13222,101],[13223,171],[13224,109],[13225,120],[13226,126],[13228,101],[13229,114],[13231,115],[13234,167],[13236,115],[13237,167],[13238,276],[13240,104],[13241,105],[13242,119],[13245,116],[13248,105],[13249,108],[13253,271],[13254,167],[13255,167],[13257,120],[13258,105],[13259,114],[13262,118],[13263,109],[13264,119],[13265,114],[13266,113],[13267,165],[13268,269],[13269,119],[13270,105],[13272,114],[13273,103],[13274,105],[13275,115],[13276,101],[13277,105],[13278,101],[13279,109],[13280,101],[13281,120],[13282,199],[13283,103],[13284,103],[13287,115],[13288,105],[13290,109],[13291,113],[13292,174],[13293,120],[13294,109],[13297,105],[13301,115],[13302,101],[13303,105],[13305,106],[13306,113],[13307,114],[13308,115],[13313,105],[13316,109],[13317,104],[13319,115],[13320,262],[13321,120],[13323,115],[13326,186],[13327,107],[13330,101],[13332,115],[13334,101],[13335,104],[13336,115],[13338,118],[13339,115],[13342,109],[13345,271],[13346,103],[13351,119],[13352,119],[13354,113],[13355,165],[13356,115],[13358,114],[13359,115],[13363,117],[13364,119],[13365,265],[13366,101],[13367,115],[13368,120],[13370,275],[13372,112],[13374,101],[13377,109],[13378,266],[13381,101],[13384,109],[13387,115],[13388,112],[13391,115],[13393,105],[13395,115],[13397,115],[13399,125],[13401,105],[13402,112],[13403,177],[13405,120],[13407,115],[13408,121],[13411,109],[13412,125],[13413,105],[13414,118],[13415,115],[13416,115],[13417,115],[13420,115],[13421,276],[13422,291],[13423,48],[13424,199],[13426,120],[13428,105],[13430,109],[13432,171],[13434,101],[13435,101],[13436,109],[13438,105],[13441,121],[13445,115],[13446,263],[13448,101],[13451,121],[13452,115],[13455,109],[13456,114],[13458,115],[13460,105],[13462,115],[13463,171],[13464,101],[13466,115],[13468,107],[13470,105],[13472,109],[13475,115],[13477,109],[13479,199],[13481,199],[13482,115],[13483,109],[13484,101],[13486,101],[13488,115],[13490,115],[13492,115],[13494,105],[13498,114],[13499,115],[13500,115],[13501,109],[13502,101],[13503,103],[13505,122],[13506,113],[13507,101],[13509,269],[13513,103],[13514,109],[13517,199],[13520,101],[13522,105],[13523,166],[13524,121],[13525,101],[13528,117],[13529,115],[13530,114],[13531,109],[13532,103],[13533,119],[13535,114],[13537,199],[13538,105],[13542,101],[13543,291],[13545,106],[13546,101],[13548,113],[13549,101],[13550,260],[13551,119],[13552,199],[13553,105],[13555,115],[13559,109],[13560,109],[13562,105],[13563,269],[13566,118],[13567,121],[13569,119],[13570,112],[13572,101],[13574,105],[13576,271],[13577,260],[13579,265],[13582,118],[13583,114],[13584,48],[13588,101],[13589,113],[13590,109],[13592,262],[13593,101],[13594,114],[13596,101],[13601,48],[13604,171],[13607,101],[13608,199],[13610,120],[13613,112],[13617,262],[13619,101],[13620,104],[13622,114],[13624,199],[13627,109],[13629,103],[13631,118],[13632,167],[13634,119],[13635,271],[13645,103],[13646,113],[13647,109],[13649,115],[13650,112],[13652,109],[13653,101],[13654,171],[13657,113],[13658,112],[13660,121],[13662,103],[13663,103],[13664,115],[13667,185],[13668,114],[13671,115],[13677,171],[13680,105],[13681,266],[13682,114],[13683,115],[13684,105],[13685,109],[13692,119],[13693,113],[13694,120],[13696,119],[13697,109],[13698,103],[13701,103],[13702,199],[13704,199],[13707,109],[13708,268],[13709,112],[13711,109],[13712,120],[13713,167],[13714,101],[13715,101],[13717,115],[13721,105],[13722,101],[13725,101],[13727,199],[13728,109],[13729,101],[13730,105],[13731,109],[13732,101],[13734,263],[13735,120],[13736,119],[13737,199],[13738,119],[13739,260],[13740,120],[13742,119],[13745,105],[13746,105],[13748,103],[13749,115],[13750,108],[13751,171],[13752,167],[13753,101],[13756,101],[13757,115],[13758,115],[13762,264],[13767,118],[13769,101],[13772,115],[13774,167],[13777,115],[13781,101],[13782,119],[13783,121],[13784,199],[13785,115],[13790,105],[13794,115],[13798,119],[13799,167],[38,38],[38,66],[38,80],[38,87],[38,260],[38,261],[38,266],[38,288],[38,318],[38,375],[38,771],[38,1049],[38,1966],[38,2057],[38,2495],[38,9218],[38,11805],[38,11920],[43,102],[43,109],[44,81],[44,86],[44,88],[44,105],[44,124],[44,286],[44,290],[44,329],[44,453],[44,466],[44,549],[44,577],[44,655],[44,772],[44,984],[44,1151],[44,1191],[44,1300],[44,1322],[44,1726],[44,1739],[44,2337],[44,2573],[44,2609],[44,2634],[44,2789],[44,2847],[44,3660],[44,4340],[44,5169],[44,5740],[44,6498],[44,6705],[44,7591],[44,7889],[44,8312],[44,8724],[44,9017],[44,9050],[44,9100],[44,11399],[45,54],[48,54],[48,55],[49,54],[49,57],[49,58],[49,59],[49,60],[49,72],[49,74],[49,75],[49,83],[49,88],[49,91],[49,109],[49,120],[49,122],[49,199],[49,261],[49,262],[49,270],[49,960],[50,52],[51,54],[51,102],[51,116],[52,41],[52,49],[52,53],[52,60],[52,481],[53,1404],[53,1587],[53,2319],[53,11134],[55,60],[55,63],[55,1973],[55,2034],[56,61],[56,11088],[58,1214],[59,55],[59,59],[59,481],[59,912],[60,61],[61,7185],[62,38],[64,118],[69,74],[69,84],[69,87],[69,267],[69,279],[69,290],[69,297],[69,432],[69,500],[69,557],[69,782],[69,874],[69,973],[69,2212],[69,2550],[69,2769],[69,2969],[69,6416],[69,7920],[69,8723],[70,48],[70,72],[70,118],[70,262],[70,365],[70,497],[70,502],[70,971],[70,2187],[70,3138],[70,3307],[70,5005],[70,6312],[71,45],[71,82],[71,84],[71,118],[71,287],[71,303],[71,365],[71,439],[71,443],[71,457],[71,469],[71,497],[71,500],[71,606],[71,673],[71,718],[71,2659],[71,3698],[71,3874],[71,4187],[71,4199],[71,5077],[71,7332],[71,7340],[71,7781],[71,8844],[71,9259],[71,10482],[71,10997],[71,11733],[71,12513],[72,82],[72,328],[72,398],[72,3141],[72,6709],[72,9989],[72,10995],[73,48],[73,107],[73,112],[73,116],[73,122],[73,325],[73,472],[73,653],[73,681],[73,1183],[73,1574],[73,1580],[73,1911],[73,2426],[74,45],[74,101],[74,369],[74,568],[74,661],[74,927],[74,1086],[74,2805],[74,2961],[74,3177],[74,5569],[74,5592],[74,7815],[74,8913],[74,12434],[75,45],[75,325],[75,438],[75,860],[75,1590],[75,2955],[75,3590],[75,4546],[75,5157],[75,8828],[76,54],[76,392],[76,2659],[76,5785],[76,8547],[76,10709],[76,10792],[76,11057],[77,73],[77,121],[77,297],[77,316],[77,345],[77,481],[77,5039],[77,7323],[77,8990],[78,50],[78,497],[78,3059],[78,6344],[78,10837],[79,121],[79,297],[79,313],[79,365],[79,387],[79,5596],[79,13976],[80,50],[80,75],[80,84],[80,88],[80,389],[80,414],[80,459],[80,554],[80,646],[80,813],[80,1182],[80,1527],[80,1677],[80,5005],[80,8807],[81,48],[81,84],[81,87],[81,274],[81,368],[81,606],[81,668],[81,674],[81,1580],[81,2205],[81,2961],[81,3837],[81,7407],[81,8801],[81,9114],[82,327],[82,503],[82,578],[82,589],[82,813],[82,2680],[82,10720],[83,263],[83,1056],[83,1222],[83,1506],[83,3837],[83,6885],[83,9205],[83,10672],[83,10811],[84,80],[84,108],[84,307],[84,321],[84,407],[84,481],[84,1225],[84,1534],[84,1603],[84,1817],[84,1992],[84,2205],[84,2423],[84,2659],[84,2946],[84,2980],[84,3137],[84,3621],[84,4849],[84,7971],[84,8980],[84,10741],[84,10863],[85,436],[86,87],[86,369],[86,747],[86,805],[86,1037],[86,1634],[86,3129],[86,7407],[86,8889],[87,50],[87,113],[87,116],[87,272],[87,311],[87,315],[87,443],[87,484],[87,501],[87,509],[87,600],[87,754],[87,1645],[87,6371],[87,7310],[87,10718],[87,12367],[88,50],[88,69],[88,121],[88,349],[88,896],[88,900],[88,971],[88,1914],[88,1983],[88,2425],[88,4544],[88,4546],[88,5764],[88,8825],[88,10991],[88,11476],[88,11736],[89,114],[89,502],[90,291],[90,294],[90,674],[90,923],[90,2807],[90,8760],[90,10751],[90,12208],[91,277],[91,328],[92,48],[92,77],[92,4605],[93,453],[94,105],[101,289],[101,320],[101,325],[101,347],[101,379],[101,382],[101,517],[101,738],[101,1045],[101,1272],[101,3005],[101,3347],[101,4547],[101,5803],[101,7419],[101,7643],[101,7920],[101,8977],[101,10858],[101,11007],[101,11061],[101,11979],[101,12612],[101,12745],[102,407],[102,438],[102,1419],[102,1492],[102,2201],[102,5657],[102,10869],[103,276],[103,282],[103,287],[103,452],[103,494],[103,755],[103,784],[103,6403],[103,8945],[104,119],[104,377],[104,413],[104,5200],[104,5635],[104,9989],[104,10973],[105,111],[105,117],[105,267],[105,268],[105,272],[105,383],[105,432],[105,533],[105,1232],[105,8919],[105,9264],[105,10861],[105,11037],[106,48],[106,66],[106,288],[106,294],[106,299],[106,307],[106,327],[106,377],[106,2047],[106,2668],[106,4548],[106,4560],[106,6317],[106,7530],[106,10100],[107,108],[107,269],[107,281],[107,294],[107,1383],[107,1887],[107,2196],[107,2807],[107,3327],[107,11475],[107,12104],[108,263],[108,283],[108,291],[108,318],[108,414],[108,2194],[108,2201],[108,2547],[108,8775],[108,13142],[109,63],[109,273],[109,274],[109,281],[109,283],[109,299],[109,304],[109,405],[109,3168],[109,5668],[109,5727],[110,111],[110,274],[110,306],[111,111],[111,125],[111,262],[111,263],[111,267],[111,850],[111,2960],[112,43],[112,102],[112,106],[112,260],[112,266],[112,298],[112,299],[112,327],[112,1359],[112,4740],[112,5601],[113,38],[113,54],[113,114],[113,415],[113,914],[113,5602],[114,43],[114,294],[114,390],[114,436],[114,460],[114,1086],[115,260],[115,300],[115,389],[115,476],[115,3495],[115,12362],[116,48],[116,276],[116,282],[116,289],[116,293],[116,299],[116,303],[116,324],[116,327],[116,369],[116,440],[116,811],[116,926],[116,1100],[116,2425],[116,2977],[116,3161],[116,3366],[116,3593],[116,3874],[116,4048],[116,4243],[116,4522],[116,5083],[116,5281],[116,6428],[117,484],[118,265],[118,273],[118,327],[118,2602],[118,4219],[119,106],[119,265],[119,278],[119,284],[119,791],[119,826],[119,992],[119,2304],[119,4204],[119,6661],[120,45],[120,230],[120,272],[120,286],[120,411],[120,1486],[120,5786],[120,7947],[120,13143],[121,110],[121,287],[121,290],[121,3595],[122,48],[122,119],[122,121],[122,290],[122,322],[122,411],[122,663],[122,973],[122,1500],[122,5083],[122,13556],[123,112],[123,114],[123,306],[124,276],[124,286],[124,1008],[126,51],[126,298],[132,143],[133,4534],[135,211],[136,210],[136,220],[136,4991],[142,220],[151,78],[151,219],[152,219],[165,50],[166,48],[169,121],[171,221],[171,267],[174,49],[174,314],[177,220],[179,210],[181,221],[183,278],[183,279],[183,285],[183,305],[188,169],[189,210],[189,211],[190,118],[190,211],[190,271],[191,50],[193,1858],[195,138],[199,132],[199,158],[199,192],[200,151],[201,145],[210,176],[210,187],[211,135],[211,144],[212,184],[212,188],[213,132],[213,143],[219,151],[219,153],[219,157],[219,173],[219,14414],[220,181],[220,14418],[221,142],[229,188],[229,195],[260,117],[261,101],[263,49],[263,122],[264,49],[266,49],[266,109],[267,63],[268,38],[269,110],[269,111],[269,112],[269,116],[269,121],[269,264],[270,50],[270,116],[270,124],[270,265],[271,63],[273,62],[273,115],[273,125],[274,49],[274,50],[274,119],[274,263],[275,107],[276,262],[276,265],[277,106],[277,117],[277,118],[278,261],[278,263],[279,115],[280,102],[280,117],[280,273],[281,118],[281,121],[281,270],[281,279],[283,116],[283,282],[284,121],[286,111],[286,269],[286,277],[287,102],[287,104],[287,126],[287,266],[288,48],[289,266],[289,287],[290,261],[290,276],[291,264],[291,282],[293,103],[293,271],[294,115],[294,266],[294,272],[296,107],[296,275],[297,105],[297,293],[299,49],[299,114],[300,125],[300,276],[300,278],[300,282],[302,109],[304,104],[304,105],[304,111],[304,270],[304,282],[305,103],[305,104],[305,120],[306,276],[306,278],[307,122],[307,270],[308,48],[308,50],[309,115],[309,266],[309,269],[310,103],[310,271],[310,303],[311,112],[311,119],[311,120],[311,122],[311,297],[313,102],[313,267],[313,279],[314,126],[314,282],[314,293],[315,266],[316,50],[319,283],[320,48],[320,50],[320,109],[321,48],[321,102],[322,105],[322,121],[322,299],[323,286],[323,299],[324,126],[324,278],[325,199],[327,304],[327,315],[328,110],[331,108],[331,199],[331,303],[332,49],[332,116],[332,270],[333,102],[333,305],[333,320],[335,50],[335,116],[336,102],[336,293],[336,300],[338,105],[338,106],[338,107],[338,114],[338,294],[338,300],[338,314],[338,322],[339,293],[340,62],[340,103],[340,265],[342,300],[342,324],[343,113],[345,126],[345,278],[346,273],[346,281],[347,269],[347,289],[350,101],[351,105],[351,107],[351,260],[352,305],[356,49],[357,278],[357,279],[357,297],[358,50],[358,114],[360,108],[360,112],[360,294],[360,305],[360,324],[364,262],[364,289],[364,305],[364,361],[365,277],[365,317],[366,114],[366,279],[367,282],[368,112],[371,110],[371,111],[372,115],[373,121],[373,124],[373,264],[373,294],[375,269],[375,300],[375,349],[376,325],[378,110],[378,291],[378,299],[379,112],[381,111],[382,268],[382,286],[382,321],[382,326],[383,277],[384,199],[384,294],[384,327],[385,269],[385,328],[385,333],[387,320],[389,126],[389,264],[389,267],[389,273],[389,293],[389,321],[390,285],[390,300],[390,309],[390,323],[390,377],[391,114],[392,307],[393,275],[393,332],[397,121],[397,293],[397,300],[397,324],[409,102],[411,113],[415,293],[415,302],[417,121],[417,283],[423,199],[424,300],[425,50],[425,118],[425,199],[429,113],[431,50],[433,109],[437,262],[441,121],[442,314],[443,105],[447,356],[451,309],[453,120],[453,272],[461,268],[462,103],[462,278],[465,281],[467,124],[467,314],[467,413],[468,120],[469,118],[469,289],[469,348],[469,350],[472,104],[474,103],[474,106],[475,102],[475,309],[475,324],[476,105],[476,113],[476,115],[477,122],[479,104],[479,260],[479,266],[480,262],[480,278],[480,294],[482,48],[484,199],[487,45],[487,198],[496,261],[497,280],[501,108],[503,268],[503,273],[503,286],[503,323],[503,360],[505,356],[507,120],[513,102],[516,314],[518,271],[518,297],[518,361],[523,107],[527,108],[529,114],[530,912],[531,306],[533,273],[538,45],[539,268],[539,279],[539,300],[546,105],[549,48],[551,286],[552,48],[552,103],[552,107],[553,106],[556,107],[559,121],[559,269],[559,270],[559,347],[559,358],[559,389],[561,106],[563,105],[563,276],[563,330],[563,347],[563,467],[567,115],[568,113],[572,105],[578,122],[579,108],[582,143],[583,284],[583,291],[583,298],[584,294],[585,106],[585,108],[588,109],[588,262],[594,116],[596,113],[598,63],[598,109],[600,114],[602,122],[604,50],[606,279],[607,596],[612,278],[621,417],[621,479],[624,114],[625,275],[625,297],[625,307],[625,376],[633,101],[633,121],[633,268],[634,199],[634,262],[638,272],[638,275],[641,48],[641,106],[641,107],[643,105],[644,278],[656,101],[662,112],[663,276],[664,106],[664,116],[664,265],[664,271],[664,272],[664,295],[664,299],[674,120],[674,260],[677,104],[677,122],[677,413],[678,101],[678,115],[680,310],[682,114],[693,105],[694,103],[694,303],[696,109],[697,101],[701,279],[703,331],[710,103],[710,114],[711,263],[725,278],[726,121],[726,276],[729,112],[729,113],[729,119],[732,113],[739,50],[739,481],[740,269],[740,394],[740,511],[742,109],[744,121],[745,332],[745,338],[748,103],[748,115],[748,119],[748,121],[748,260],[750,270],[754,294],[757,105],[759,50],[763,118],[768,118],[770,280],[780,118],[786,48],[795,199],[797,101],[801,109],[803,113],[803,122],[804,272],[808,118],[808,199],[812,286],[813,725],[821,38],[825,276],[827,291],[831,280],[831,296],[831,331],[840,306],[846,48],[846,50],[846,114],[853,278],[857,115],[857,310],[859,114],[859,116],[864,171],[865,105],[873,112],[879,199],[880,119],[890,38],[890,50],[891,48],[894,120],[902,199],[908,113],[914,105],[916,266],[926,114],[934,48],[935,121],[937,101],[938,48],[950,199],[951,276],[953,115],[958,115],[959,101],[960,48],[965,109],[965,115],[966,118],[976,114],[976,199],[987,54],[987,57],[993,107],[994,270],[996,260],[998,50],[998,265],[1001,102],[1008,121],[1019,50],[1021,115],[1024,119],[1024,261],[1026,262],[1027,270],[1032,48],[1041,104],[1042,52],[1042,54],[1043,674],[1045,109],[1045,122],[1052,479],[1054,109],[1068,103],[1074,107],[1074,108],[1100,105],[1101,263],[1102,101],[1108,115],[1108,274],[1109,48],[1117,116],[1120,112],[1137,101],[1150,38],[1157,267],[1158,101],[1167,50],[1181,112],[1187,112],[1190,48],[1190,49],[1192,313],[1198,48],[1199,49],[1203,48],[1209,109],[1210,103],[1211,266],[1212,62],[1213,119],[1213,120],[1216,104],[1221,108],[1221,120],[1227,269],[1230,119],[1232,120],[1236,267],[1240,121],[1242,109],[1248,121],[1254,115],[1254,276],[1256,109],[1256,268],[1256,284],[1256,288],[1256,337],[1260,50],[1261,107],[1268,109],[1275,113],[1276,309],[1276,347],[1276,529],[1277,626],[1281,262],[1285,121],[1295,50],[1296,114],[1297,50],[1313,58],[1315,280],[1316,122],[1321,105],[1325,118],[1330,56],[1332,102],[1332,107],[1332,109],[1332,113],[1333,49],[1336,264],[1340,275],[1345,106],[1345,119],[1349,48],[1354,230],[1367,115],[1369,48],[1369,50],[1375,48],[1381,55],[1381,59],[1381,61],[1383,113],[1383,418],[1386,107],[1386,113],[1389,109],[1393,118],[1393,269],[1393,280],[1393,324],[1400,48],[1403,266],[1405,48],[1405,1042],[1405,6201],[1406,527],[1406,1354],[1407,306],[1408,114],[1408,122],[1409,101],[1411,63],[1418,114],[1418,261],[1425,118],[1426,50],[1445,48],[1448,267],[1450,311],[1456,106],[1458,268],[1463,114],[1463,119],[1463,262],[1472,266],[1472,276],[1474,120],[1480,115],[1492,118],[1496,54],[1496,58],[1496,59],[1496,61],[1497,273],[1501,269],[1507,272],[1509,109],[1518,50],[1519,263],[1532,268],[1543,50],[1544,48],[1544,121],[1545,118],[1547,118],[1547,264],[1552,49],[1576,122],[1583,103],[1584,122],[1587,54],[1587,55],[1587,56],[1587,57],[1587,59],[1587,61],[1590,114],[1590,118],[1598,105],[1601,113],[1612,101],[1627,41],[1627,53],[1627,56],[1628,57],[1632,50],[1643,281],[1645,48],[1647,199],[1648,266],[1650,50],[1655,50],[1656,266],[1662,294],[1671,185],[1675,293],[1676,105],[1676,344],[1676,417],[1676,1067],[1697,284],[1705,104],[1707,107],[1715,109],[1720,48],[1721,103],[1721,118],[1724,268],[1726,50],[1730,118],[1733,101],[1734,103],[1737,50],[1740,1037],[1742,103],[1742,113],[1744,48],[1746,50],[1748,275],[1752,118],[1752,121],[1755,58],[1760,52],[1760,53],[1769,50],[1770,48],[1778,119],[1786,118],[1787,45],[1788,115],[1799,48],[1804,320],[1804,343],[1804,375],[1804,424],[1804,432],[1804,663],[1805,271],[1805,305],[1805,307],[1805,768],[1805,780],[1805,1117],[1806,276],[1806,394],[1806,661],[1807,119],[1807,265],[1807,295],[1809,387],[1817,107],[1821,114],[1825,347],[1826,53],[1826,54],[1826,59],[1826,61],[1829,48],[1836,114],[1840,115],[1846,50],[1848,109],[1848,261],[1849,844],[1849,993],[1852,115],[1852,266],[1863,275],[1866,50],[1867,55],[1871,277],[1873,107],[1877,101],[1888,104],[1888,114],[1894,115],[1904,104],[1904,112],[1905,185],[1906,50],[1910,109],[1913,113],[1917,267],[1921,115],[1929,57],[1929,60],[1937,109],[1943,165],[1945,50],[1953,109],[1953,262],[1957,118],[1963,48],[1975,101],[1976,1419],[1977,916],[1980,279],[1985,280],[1987,101],[1987,294],[1988,118],[1989,101],[1992,109],[1995,199],[2011,119],[2014,118],[2020,109],[2028,115],[2030,115],[2032,38],[2035,55],[2038,116],[2038,280],[2038,662],[2043,113],[2043,114],[2048,263],[2051,122],[2052,103],[2053,52],[2053,55],[2053,58],[2053,60],[2054,55],[2054,57],[2054,61],[2055,352],[2061,109],[2062,107],[2063,119],[2067,48],[2073,120],[2074,48],[2078,183],[2098,50],[2101,50],[2109,115],[2118,115],[2120,101],[2128,107],[2130,262],[2130,287],[2131,61],[2133,53],[2146,120],[2154,276],[2156,48],[2163,185],[2175,48],[2178,327],[2181,101],[2190,105],[2190,109],[2192,112],[2212,173],[2213,104],[2215,48],[2216,50],[2218,50],[2222,119],[2227,104],[2230,115],[2238,48],[2238,62],[2245,50],[2248,109],[2248,199],[2249,120],[2252,48],[2265,48],[2277,48],[2277,119],[2281,103],[2283,115],[2294,261],[2303,107],[2303,108],[2303,109],[2304,101],[2304,263],[2310,288],[2311,120],[2314,53],[2314,58],[2314,59],[2317,49],[2319,55],[2319,60],[2322,101],[2327,48],[2333,121],[2334,50],[2336,267],[2337,50],[2362,118],[2362,262],[2381,50],[2382,113],[2389,48],[2390,261],[2395,261],[2399,199],[2413,115],[2413,263],[2418,123],[2419,109],[2426,119],[2446,48],[2449,49],[2452,119],[2454,114],[2459,276],[2460,50],[2480,109],[2486,103],[2489,48],[2492,120],[2499,103],[2499,273],[2499,293],[2500,542],[2500,712],[2504,338],[2504,390],[2504,1339],[2505,124],[2506,287],[2508,298],[2519,115],[2528,126],[2528,267],[2532,115],[2532,120],[2535,55],[2535,58],[2540,52],[2540,61],[2541,54],[2547,112],[2554,122],[2554,199],[2562,50],[2564,50],[2572,261],[2572,262],[2578,48],[2579,45],[2589,50],[2606,199],[2607,101],[2607,262],[2608,115],[2616,267],[2616,268],[2618,50],[2623,49],[2623,113],[2625,199],[2639,268],[2643,413],[2643,2051],[2644,50],[2645,311],[2645,1043],[2646,284],[2655,122],[2673,268],[2677,287],[2687,266],[2698,50],[2713,50],[2714,118],[2718,48],[2725,45],[2725,48],[2726,48],[2728,113],[2734,114],[2734,262],[2743,50],[2744,199],[2760,199],[2766,50],[2767,48],[2767,50],[2770,104],[2775,199],[2779,199],[2786,309],[2786,347],[2787,81],[2806,104],[2813,38],[2816,279],[2821,311],[2822,52],[2822,53],[2822,54],[2822,61],[2828,112],[2828,275],[2847,48],[2851,48],[2862,48],[2866,113],[2875,117],[2888,113],[2889,48],[2896,104],[2898,103],[2904,50],[2911,120],[2915,49],[2921,114],[2945,267],[2948,302],[2949,280],[2949,324],[2952,112],[2952,1383],[2953,414],[2954,344],[2954,453],[2955,126],[2955,261],[2956,50],[2959,116],[2960,276],[2960,294],[2964,199],[2964,261],[2965,50],[2966,260],[2967,285],[2974,121],[2975,199],[2980,105],[2980,281],[2982,121],[2995,60],[2998,275],[2998,282],[3005,50],[3007,119],[3010,63],[3031,48],[3031,50],[3034,264],[3056,50],[3056,112],[3060,101],[3061,115],[3066,119],[3069,115],[3070,119],[3077,120],[3077,199],[3086,101],[3094,48],[3098,119],[3100,48],[3101,73],[3101,125],[3108,50],[3109,373],[3109,1389],[3109,1988],[3110,104],[3111,306],[3111,323],[3111,344],[3112,199],[3113,106],[3113,278],[3114,87],[3116,77],[3118,106],[3118,112],[3118,120],[3119,113],[3120,262],[3123,322],[3148,113],[3150,263],[3151,278],[3157,105],[3162,118],[3163,118],[3165,48],[3173,50],[3174,48],[3185,48],[3190,48],[3191,119],[3192,107],[3192,115],[3193,199],[3197,120],[3198,266],[3198,279],[3199,109],[3203,262],[3205,48],[3212,277],[3222,264],[3223,48],[3223,120],[3234,263],[3244,48],[3253,48],[3261,120],[3266,199],[3267,48],[3269,115],[3271,268],[3272,185],[3276,48],[3276,50],[3279,57],[3284,342],[3286,119],[3290,631],[3290,1417],[3291,641],[3295,661],[3295,1532],[3296,262],[3318,115],[3322,261],[3334,283],[3336,266],[3339,101],[3339,266],[3341,118],[3343,112],[3343,293],[3344,281],[3344,298],[3349,114],[3352,113],[3368,274],[3375,104],[3375,106],[3378,113],[3380,115],[3398,113],[3401,105],[3415,48],[3418,267],[3419,48],[3422,45],[3431,183],[3441,48],[3447,48],[3456,118],[3456,199],[3469,118],[3471,270],[3505,185],[3511,119],[3528,109],[3537,48],[3537,119],[3545,41],[3554,3319],[3558,304],[3563,115],[3563,267],[3573,439],[3574,266],[3581,199],[3582,116],[3595,115],[3601,267],[3611,300],[3616,109],[3617,52],[3617,59],[3617,61],[3619,275],[3627,266],[3630,279],[3633,48],[3637,119],[3645,261],[3651,113],[3655,48],[3658,103],[3670,119],[3671,109],[3672,50],[3673,50],[3679,101],[3680,48],[3683,107],[3701,199],[3703,48],[3704,118],[3705,48],[3708,116],[3710,118],[3716,261],[3716,266],[3719,48],[3721,48],[3721,49],[3723,104],[3723,116],[3723,122],[3747,199],[3748,48],[3764,105],[3766,50],[3768,48],[3772,48],[3772,50],[3772,119],[3774,119],[3783,83],[3789,76],[3791,41],[3791,62],[3796,112],[3796,285],[3799,105],[3804,117],[3804,360],[3808,640],[3809,109],[3813,275],[3815,109],[3817,261],[3822,109],[3827,114],[3834,109],[3837,109],[3839,261],[3843,116],[3847,281],[3850,48],[3861,56],[3866,199],[3879,120],[3885,122],[3886,118],[3889,199],[3898,48],[3900,167],[3907,109],[3910,48],[3910,50],[3915,118],[3915,119],[3916,119],[3916,126],[3917,113],[3938,45],[3938,50],[3948,119],[3949,107],[3953,38],[3958,199],[3961,101],[3963,120],[3966,48],[3971,113],[3983,114],[3985,269],[3990,265],[3997,50],[4005,275],[4008,118],[4008,120],[4008,261],[4010,48],[4023,48],[4024,50],[4031,109],[4044,261],[4074,267],[4074,268],[4077,48],[4085,50],[4088,185],[4096,48],[4097,118],[4097,266],[4105,101],[4109,50],[4111,48],[4114,50],[4116,265],[4117,263],[4119,265],[4126,48],[4128,59],[4131,56],[4132,57],[4134,361],[4136,49],[4136,50],[4139,371],[4141,105],[4141,106],[4144,370],[4147,104],[4177,115],[4182,101],[4191,101],[4191,275],[4191,293],[4194,102],[4194,266],[4212,269],[4214,45],[4222,101],[4224,107],[4228,107],[4230,275],[4231,121],[4234,120],[4235,173],[4242,50],[4243,118],[4246,48],[4253,116],[4253,122],[4259,118],[4260,48],[4263,126],[4265,50],[4278,48],[4282,48],[4293,282],[4295,48],[4296,50],[4317,48],[4322,48],[4326,120],[4330,263],[4335,264],[4345,199],[4357,113],[4358,282],[4359,50],[4361,119],[4366,101],[4368,104],[4368,120],[4368,199],[4369,49],[4385,199],[4396,50],[4401,38],[4411,48],[4412,109],[4423,282],[4428,126],[4434,48],[4439,185],[4441,114],[4446,48],[4457,50],[4463,103],[4472,48],[4472,50],[4473,268],[4489,320],[4497,344],[4497,4235],[4505,263],[4510,118],[4534,48],[4534,210],[4534,211],[4538,105],[4542,113],[4550,199],[4564,126],[4567,106],[4569,118],[4572,48],[4574,105],[4574,277],[4577,282],[4579,165],[4580,118],[4582,101],[4589,275],[4593,199],[4595,101],[4597,48],[4597,119],[4603,106],[4603,278],[4614,38],[4614,48],[4614,50],[4628,50],[4632,48],[4632,119],[4633,269],[4649,118],[4650,263],[4650,267],[4655,119],[4662,115],[4665,105],[4666,48],[4667,107],[4677,50],[4687,171],[4695,101],[4697,104],[4701,48],[4714,105],[4715,48],[4717,113],[4722,113],[4722,118],[4722,199],[4733,112],[4733,199],[4733,261],[4738,50],[4742,113],[4746,115],[4748,199],[4759,199],[4760,118],[4766,115],[4774,49],[4775,116],[4788,104],[4791,267],[4792,418],[4799,271],[4805,199],[4814,48],[4832,265],[4841,109],[4869,185],[4874,185],[4894,113],[4901,101],[4918,48],[4931,3791],[4938,299],[4938,1345],[4939,755],[4940,324],[4946,101],[4949,269],[4958,1162],[4960,269],[4964,279],[4964,346],[4968,279],[4969,271],[4975,264],[4980,119],[4985,287],[4993,101],[4993,105],[5010,114],[5014,115],[5024,114],[5025,183],[5028,269],[5046,199],[5050,118],[5054,293],[5058,102],[5060,109],[5062,101],[5066,48],[5070,119],[5074,273],[5075,268],[5078,101],[5078,115],[5078,263],[5081,49],[5113,112],[5133,48],[5134,272],[5144,115],[5154,50],[5159,119],[5162,114],[5171,113],[5173,49],[5173,119],[5176,103],[5185,50],[5191,119],[5195,118],[5195,199],[5200,115],[5200,267],[5200,268],[5201,199],[5208,276],[5214,50],[5216,199],[5227,118],[5229,101],[5237,50],[5244,48],[5257,199],[5258,48],[5267,50],[5273,48],[5277,113],[5277,118],[5280,118],[5285,104],[5289,50],[5295,48],[5301,268],[5308,267],[5313,273],[5316,276],[5317,119],[5320,48],[5320,50],[5321,101],[5321,262],[5325,115],[5328,199],[5345,274],[5348,50],[5370,118],[5376,199],[5378,267],[5381,48],[5384,50],[5392,263],[5395,109],[5398,109],[5407,266],[5409,267],[5412,48],[5412,50],[5421,109],[5433,199],[5438,101],[5441,103],[5458,261],[5460,60],[5462,81],[5462,88],[5473,74],[5474,108],[5474,265],[5484,286],[5484,583],[5485,114],[5493,119],[5495,800],[5496,48],[5496,50],[5498,106],[5499,48],[5504,48],[5505,365],[5505,766],[5511,118],[5512,276],[5525,106],[5525,334],[5531,289],[5535,107],[5545,48],[5546,116],[5580,114],[5585,266],[5586,115],[5587,294],[5590,118],[5595,121],[5597,109],[5599,293],[5607,171],[5615,107],[5615,275],[5617,48],[5617,50],[5619,264],[5624,262],[5626,115],[5626,273],[5630,48],[5649,102],[5652,274],[5655,118],[5658,116],[5659,57],[5673,48],[5684,101],[5693,125],[5694,126],[5700,115],[5706,49],[5737,48],[5743,121],[5748,48],[5750,101],[5769,104],[5770,48],[5778,45],[5778,50],[5790,50],[5806,48],[5813,48],[5829,109],[5835,48],[5843,49],[5843,113],[5848,104],[5848,118],[5849,101],[5850,199],[5859,48],[5897,266],[5901,167],[5902,119],[5907,104],[5907,113],[5910,50],[5915,48],[5920,101],[5928,109],[5933,263],[5945,50],[5947,199],[5953,104],[5953,261],[5959,115],[5959,268],[5960,103],[5964,50],[5965,267],[5967,282],[5991,261],[6005,105],[6026,265],[6026,271],[6028,265],[6029,268],[6034,101],[6036,50],[6053,48],[6067,104],[6067,262],[6071,119],[6074,104],[6106,48],[6108,271],[6128,115],[6133,103],[6133,265],[6136,199],[6149,119],[6158,48],[6158,50],[6170,120],[6172,261],[6194,48],[6210,54],[6211,314],[6212,388],[6213,286],[6220,756],[6220,3339],[6221,199],[6222,121],[6223,48],[6226,265],[6229,319],[6230,674],[6234,48],[6236,2303],[6243,293],[6244,267],[6246,116],[6253,114],[6254,293],[6257,103],[6263,101],[6268,50],[6281,109],[6290,261],[6295,210],[6313,101],[6332,269],[6335,286],[6348,104],[6348,120],[6354,112],[6355,115],[6356,115],[6356,267],[6381,115],[6382,101],[6384,199],[6387,121],[6390,113],[6407,118],[6409,115],[6416,114],[6417,50],[6421,184],[6423,266],[6424,115],[6430,324],[6434,105],[6441,60],[6448,115],[6454,119],[6466,119],[6471,119],[6472,114],[6475,48],[6479,199],[6487,106],[6496,119],[6497,45],[6497,48],[6497,50],[6503,48],[6508,48],[6521,45],[6521,48],[6526,48],[6526,113],[6530,277],[6533,109],[6536,48],[6539,199],[6546,48],[6552,48],[6552,50],[6565,265],[6567,119],[6574,119],[6581,112],[6584,48],[6599,103],[6610,115],[6640,48],[6644,118],[6644,261],[6666,126],[6670,119],[6672,48],[6675,48],[6676,119],[6683,121],[6688,119],[6691,118],[6691,261],[6692,48],[6701,265],[6711,106],[6714,113],[6719,113],[6720,119],[6723,48],[6727,261],[6735,119],[6737,105],[6742,50],[6743,48],[6745,199],[6746,113],[6746,118],[6762,119],[6768,48],[6768,50],[6771,261],[6781,261],[6787,120],[6787,126],[6789,261],[6789,266],[6797,48],[6801,120],[6806,199],[6809,261],[6811,267],[6814,48],[6820,115],[6826,109],[6832,199],[6833,101],[6835,293],[6836,121],[6838,115],[6842,101],[6857,261],[6859,268],[6868,113],[6878,105],[6882,50],[6887,105],[6889,109],[6889,112],[6889,118],[6892,48],[6897,109],[6906,120],[6916,115],[6923,119],[6926,121],[6933,119],[6940,50],[6947,48],[6955,48],[6963,48],[6973,113],[6978,48],[6989,50],[6994,266],[6994,282],[7004,101],[7009,199],[7011,48],[7013,119],[7040,185],[7057,48],[7057,50],[7060,268],[7065,118],[7071,50],[7077,265],[7078,113],[7078,118],[7083,38],[7089,50],[7093,104],[7093,199],[7104,48],[7139,109],[7143,109],[7149,48],[7156,267],[7160,101],[7163,50],[7168,73],[7190,281],[7199,50],[7204,102],[7206,48],[7208,284],[7208,356],[7210,284],[7210,291],[7211,126],[7211,282],[7212,112],[7213,468],[7218,348],[7238,111],[7239,413],[7246,103],[7250,294],[7255,109],[7259,104],[7261,124],[7261,277],[7268,109],[7276,115],[7277,291],[7280,119],[7285,115],[7287,114],[7287,261],[7288,261],[7289,115],[7296,373],[7304,103],[7304,107],[7326,118],[7334,199],[7349,122],[7353,104],[7355,112],[7367,118],[7385,120],[7386,119],[7389,114],[7391,109],[7397,266],[7397,310],[7399,267],[7404,106],[7406,101],[7410,199],[7423,103],[7423,122],[7435,114],[7456,122],[7463,199],[7464,113],[7466,288],[7466,341],[7470,112],[7470,264],[7479,173],[7479,183],[7480,101],[7492,284],[7492,286],[7496,262],[7501,121],[7512,104],[7514,115],[7514,199],[7519,104],[7524,50],[7526,120],[7528,199],[7530,105],[7547,101],[7550,278],[7554,48],[7576,114],[7576,262],[7579,48],[7588,606],[7591,48],[7592,48],[7598,48],[7605,120],[7605,126],[7608,270]],"vocab":["","","","","\u0000","\u0001","\u0002","\u0003","\u0004","\u0005","\u0006","\u0007","\b","\t","\n","\u000b","\f","\r","\u000e","\u000f","\u0010","\u0011","\u0012","\u0013","\u0014","\u0015","\u0016","\u0017","\u0018","\u0019","\u001a","\u001b","\u001c","\u001d","\u001e","\u001f"," ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","�","de","do","ra","es","nt","co","da","os","as","ri","ma","ca","te","re","��","ta","is","or","ci","me","��","er","��","al","en","qu","in","ro","em","ti","na","ia","com","to","��","se","pa","no","ent","��","la","�o","po","��o","li","lo","an","io","si","que","di","tu","��","ar","ni","pe","nte","est","um","on","dos","ou","ic","st","le","ul","am","��","ei","uma","con","it","so","mo","gi","ado","fi","o,","su","ve","por","a,","mi","des","nto","va","nc","ce","ha","ol","res","vi","gu","a�","s,","dade","��","fo","ria","como","el","t�","im","mai","cu","at","pro","un","il","ica","das","ran","ex","sa","ir","ge","ga","ras","ad","para","��","ec","us","pi","tr","ho","i�","ui","za","vo","du","ndo","id","lu","nta","lh","pri","ne","iv","o.","he","�es","iz","ment","foi","nti","����","ico","ns","fe","s.","ist","ess","ram","��","bi","comp","mb","nd","19","for","pos","ntes","cons","go","reg","e,","a.","tra","��","ai","mais","der","tem","ter","nh","ua","ser","om","ida","ros","cont","et","ob","esp","cia","esta","ag","era","�n","ada","��","r�","ver","seu","-s","cas","ura","l,","og","ut","ric","par","cos","n�","cl","ao","pu","ral","ac","ass","��s","den","ido","eu","be","dor","sua","cida","per","ba","),","s��o","cor","ip","ori","u�","18","mu","rio","rasi","rasil","ira","ita","entr","�a","man","ap","if","rt","ur","ant","ru","ab","d�","pr","ra�","mas","lm","ue","esc","ula","iste","rea","maio","ide","��","pelo","bo","tant","s�","c�","es,","pela","este","ng","�m","cal","Es","m��","20","ch","los","qua","b�","car","tam","cio","cidade","Al","pode","inte","as,","os,","nos","l�","rat","regi","ara","n��o","ten","ja","ele","gra","ig","ug","entre","mp","m�","fa","tos","estu","rel","Re","maior","pl","sm","prim","rit","pop","nas","ris","cap","popu","tamb","tamb�","tamb��","tamb��m","ie","col","rop","v�","��","av","Em","Con","ct","ca,","forma",").","gn","oa","rado","qui","ade","a-","dis","nci","Brasil","rn","��c","prin","bre","�n","hab","princ","au","bu","ora","�ri","orte","lar","l��","rm","pa��","habi","pa��s","out","prime","primei","rec","Co","ev","�ri","cie","Ma","tri","conh","popula","No","ces","je","do,","mat","inf","div","conhe","conhec","pla","siste","tes","mar","lica","sob","men","compo","ima","l.","ers","ios","ss","cam","endo","lv","tor","Os","mes","�t","regi�","��re","habita","rei","emp","��l","sub","port","Por","nt�","��t","est�","rande","capi","mos","��l","ina","const","e.","ju","pres","�s","fun","las","esa","ist�","ind","princi","conheci","princip","cer","rav","seg","principa","��","segu","uni","tal","conc","desc","parte","Na","bli","bio","oi","xi","��m","dif","corr","capit","ues","ref","ali","tiv","��ri","anos","Uni","ens","poss","ame","ano","ra,","ret","ist��","ist��ri","min","nde","��p","pol","prod","temp","inter","capita","produ","grande","consi","regi��","regi��o","�o","es.","nat","II","Pa","sendo","can","comu","parti","As","�e","ese","ren","tado","fil","sobre","odo","�r","of","rie","ores","ing","gera","s��c","�s","rac","ast","dese","estado","c��","jo","oc","dei","��ri","alg","come","at��","nic","serv","portu","capital","s��cu","s��cul","cha","dia","lia","rc","org","ente","loca","estudo","hist��ri","lt","tas","���","inc","��rea","habitant","habitantes","a��","br","lis","r,","�n","dem","ase","erra","chama","Ca","ib","vis","�m","dep","as.","qu�","��s","cul","eg","�n","oso","cado","cin","��s","dire","pel","vida","portug","mun","qual","ins","��ti","log","proc","rela","portugu","Com","ere","uti","�r","rad","cada","ci�","ern","uman","atu","�v","�g","rai","rin","���","nome","seus","���","brasil","m,","tura","dest","muni","brasile","brasilei","brasileir","De","aos","eta","iu","tran","u-","os.","ca�","rep","todo","vez","esso","esp�","primeir","popula��","Port","Am��","bra","human","ici","zi","�f","met","espe","Esta","incl","munic","munic��","munic��p","munic��pi","nv","pass","�c","mel","onde","mesm","inclu","c��l","eri","op","xo","ze","co,","ani","amb","mil","ntig","dife","desen","ci��","Am��ri","difere","ci��n","ci��nc","ci��nci","00","v��ri","iss","mer","ini","exp","conce","conside","local","consider","\".","az","rar","inh","tica","��si","rist","camp","mundo","util","popula����","utili","popula����o","med","ale","ranc","sistema","torn","orga","trans","esp��","organ","esp��c","esp��ci","esp��cie","-a","xa","ino","soci","prov","rant","cient","refe","proces","essoa","considera","utiliz","process","17","fam","f��si","dec","dev","prop","mate","natu","espec","Am��ric","\",","ej","de,","inda","fora","c��lu","medi","c��lul","def","ism","estr","exis","��b","indi","s��culo","utiliza","processo","2,","eda","pessoa","rr","�l","ala","peri","pol��","Am��rica","Se","rg","sul","�v","suas","porta","impor","terri","estud","territ","Eu","gr","emb","liv","term","orig","escr","desenv","pol��ti","desenvo","desenvol","desenvolv","ais","km","ost","inv","ia,","exem","conti","clas","tempo","algu","cultu","Portu","exemp","class","cultura","exempl","h�","int","mem","enas","nov","principal","foram","estuda","15","bl","dado","cara","geral","portugues","atual","brasileiro","S��o","f�","hi","norte","det","dam","rig","��l","trab","Europ","traba","trabal","gia","les","ov","�d","raf","esi","reco","resp","gov","obj","compor","est��","contin","trabalh","gover","govern","ari","ainda","cria","hos","ime","s)","sti","tera","orma","tim","sej","muit","201","diver","comun","comport","comporta","comportam","comportame","comportament","o-","osa","rem","rev","mei","espa","outr","consti","funda","seja","divers","outros","constit","gen","m��","o\"","rd","zo","�t","del","ron","fici","compu","partir","pelos","considerad","territ�","Portug","constitu","territ��","territ��r","territ��ri","rs","unt","rico","cat","red","tan","tip","comb","pai","sim","nter","esti","ress","aix","m��d","primeira","sistem","possu","Estado","desenvolvi","comportamento","m��di","antig","che","fei","o)","r.","rib","sig","art","mode","��n","��s","infl","compos","segun","repr","mesmo","anima","locali","cient�","classi","comput","cient��","cient��f","cient��fi","cient��fic","a)","fu","j��","ntra","teo","ista","��a","entra","lim","duran","isto","compr","faz","primeiro","munic��pio","milh","defi","computa","durant","defin","durante","21","Norte","cr","econ","fre","rios","cau","cias","lon","vari","olu","atra","apli","cerca","exemplo","comuni","22","pes","r��","sem","doi","rim","mag","tec","ise","in�","tit","enta","pov","imp","expe","post","pr��","disp","corre","hist��ria","inici","termo","sign","classif","dois","classifi","Ale","ber","base","iro","pt","s��","�ci","��","rag","co.","ca.","tar","al��","enco","pan","rese","viv","entro","quan","quant","poder","colo","outra","chamada","natura","importa","dete","Portuga","influ","localiz","aplica","classific","quando","Portugal","localiza","classifica","Ar","At","Ci","Sa","ed","gar","ix","�s","ma�","pont","mov","el��","dent","per�","apen","conhecido","desco","descr","diferent","ci��ncia","campo","portuguesa","signi","encont","apenas","signif","signifi","significa","-l","Est","Gu","dist","m-","n��","oca","ento","an��","193","rece","ingu","passa","indiv","carac","obje","defini","long","al��m","important","movi","el��t","per��","caract","caracte","caracter","1,","Jo","Pro","Sul","od","ude","roma","ent�","poe","conf","cel","prof","esse","compa","��s","assi","v��rios","fam��","matem","sistemas","atrav","an��l","fam��l","an��lis","h��","usa","deu","tent","eng","enh","ane","sica","desd","consu","conte","contr","real","podem","principai","vezes","movime","el��tri","per��o","matem�","desde","principais","moviment","per��odo","matem��","matem��t","matem��ti","16","3,","l��","n,","sc","tro","�m","oss","erg","alt","sido","amp","sup","cale","elet","Regi","todos","f��sica","escri","territ��rio","repres","movimento","calen","0,","14","Ba","Ch","Car","bro","ea","leste","lingu","p�","u��","osi","ert","lan","pera","eira","ilh","exte","ntic","reli","constr","segui","comum","qu��","inclui","especi","recon","milh�","outras","encontra","fam��lia","Regi��o","escrit","represe","relig","constru","qu��m","milh��","represen","religi","qu��mi","milh��es","represent","Um","greg","gru","m��","ot","uso","vol","ri�","��ti","arte","conj","cuj","ext","conta","obser","apres","esca","202","infor","plan","unida","depo","refer","magn","experi","inicia","calend","representa","observ","aprese","calend�","apresen","calend��","apresent","calend��ri","bem","mui","val","da,","rez","tai","cide","��p","enq","��g","ando","home","compl","m��t","200","disc","biolo","astr","inha","torna","socia","c��lulas","contine","meio","ficia","limi","deter","roman","an��lise","consum","informa","unidade","ciden","biolog","continen","cident","biologia","continent","13","Par","Sua","e-","eo","lti","ont","uz","dom","dou","rida","te�","quen","ran�","essa","��nti","deno","regis","auto","plant","filh","direi","melh","esp��cies","trabalho","combu","entral","varia","pesq","povo","descob","atrav�","apresenta","enqu","determ","regist","direit","pesqu","atrav��","enqua","determi","pesqui","atrav��s","determin","pesquis","pesquisa","12","Terra","bri","crist","dr","nia","oficia","uer","xt","�p","cou","mada","ta,","alme","ine","inal","toda","��n","sel","cea","duas","197","conse","regu","abri","escra","rea�","Alent","tendo","nasc","Cons","est��","produz","come�","concei","deve","exist","��bli","moder","anei","depoi","comple","denom","planta","enquant","determina","escrav","rea��","Alente","est��o","come��","conceit","aneiro","depois","denomi","enquanto","rea���","Alentej","denomin","Alentejo","\")","10","8,","Ama","Foi","franc","oeste","do.","os�","asc","rias","rej","orde","en�","tico","sit","ulh","hav","for�","obra","evol","produ��","servi","rela�","governo","desenvolvim","compost","animai","Atl","diferentes","reali","muito","m��to","combus","conceito","for��","evolu","rela��","desenvolvime","Atl��","m��todo","combust","rela���","desenvolvimen","Atl��nti","combust�","desenvolviment","Atl��ntic","-re","Au","Po","ez","ema","edu","g�","gos","ias","num","nec","p��bli","uc","uo","�r","��","do-","doe","sent","pare","pois","que,","pequ","sol","resu","geo","tr��","hoj","trat","pub","integ","sub-","conhecid","demo","organis","memb","econo","comunic","Alema","indiv�","assim","especia","calend��rio","��po","cidenta","animais","desenvolvimento","educa","neces","senti","pequen","tr��s","hoje","conhecida","organism","econom","comunica","Aleman","indiv��","necess","economi","Alemanh","indiv��d","Alemanha","indiv��du","30","Ap","C.","Inter","Ro","antes","ban","centro","ite","mor","o:","t��","cip","cir","lite","lev","192","form","rica","part","perm","189","Brasil,","l��n","popular","ambi","origi","principalm","geralm","muitas","antiga","segundo","cient��fico","teori","ent��","exten","constru�","conju","plane","consumo","informa�","oficial","ceano","modern","denomina","produ����","resul","trata","��poca","origin","principalme","geralme","ent��o","conjunt","informa��","produ����o","result","principalment","geralmen","informa���","principalmente","geralment","geralmente","(do","4,","An","Me","Mo","Mar","So","fl","ito","p��","z�","�t","�m","ntr","ero","ene","enci","ques","inis","sede","nica","resc","��m","��l","199","trad","corp","cidades","Rep","Brasil.","pa��s,","torno","existe","pessoas","orige","Europe","longo","observa","realiz","Atl��ntico","publi","especial","l��ng","extens","corpo","l��ngu","Para","Su","i��","ph","pre","t��c","�p","da.","dat","naci","to,","tota","lig","nico","cond","cur","posi","cost","maiores","���","empre","fun��","intern","produt","III","cine","metr","v��rias","organi","propri","c��lula","estru","possui","entan","pr��p","natural","n��me","poeta","reconh","astro","integra","sub-re","economia","ambient","Rep��","nacio","organiz","estrut","n��mer","reconhe","sub-reg","Rep��b","estrutu","reconhec","sub-regi","Rep��bli","estrutura","sub-regi�","Rep��blica","Beira","Mu","Qu","final","gas","i,","ocorre","r��","sos","u.","vas","�me","de.","dez","mant","cab","env","tic","lib","desi","gun","imb","191","obras","estab","euro","pers","ap��","urba","maiori","diss","prese","corres","Univ","desta","ci��ncias","prov�","Segu","pol��tica","algun","considerado","istori","computado","escrito","m��si","comunica�","origina","resulta","��lti","origem","realiza","total","entant","pr��pri","nacion","ap��s","maioria","corresp","alguns","computador","comunica��","entanto","naciona","correspo","comunica���","correspon","5,","Ant�","Emb","Vi","af","bal","d��","nu","reu","is,","oro","meta","pap","estra","leg","contra","estat","Maria","conhecim","ensa","mine","filos","inst","primeiros","expres","devi","Europa","feito","caus","raga","celu","enge","lingua","2021","��gu","plantas","rea����","situ","conjunto","t��cn","proprie","organiza","sub-regi��","estabe","presen","Univer","conhecime","express","engen","linguag","rea����o","situa","t��cni","sub-regi��o","estabel","Univers","conheciment","engenh","estabele","conhecimento","estabelec","40","6,","9,","And","Ex","Ele","Imp","Rio","cresc","equi","r��","u,","ia.","lora","dig","dias","dess","ramo","��ni","194","196","��n","terc","terra","perte","carb","Alb","arar","cole","Conde","princ�","pa��ses","Coim","��reas","grandes","chamado","qualq","munic��pios","algum","respe","artes","exemplo,","objeto","melhor","franc�","membr","cidental","circ","permi","desig","europ","prov��","m��sica","entanto,","devid","celula","perten","princ��","Coimb","qualqu","design","europe","prov��n","devido","celular","pertenc","princ��p","Coimbra","qualquer","prov��nci","princ��pi","Baix","M��","Uma","acor","ativ","e)","m.","mic","s��","uco","��","doc","ntu","dan","osf","mac","teri","erda","indo","nar","sete","lado","lame","sur","prog","neg","190","orie","185","carv","tempe","diret","relat","humano","passo","diferen","transf","processos","respo","considerada","tipo","quanti","ponto","religios","ran��","regues","for��a","combust��","denominad","nacional","comunica����","corresponde","Imp��","terce","circu","pertence","acordo","orient","carv�","reguesi","combust��v","comunica����o","Imp��ri","tercei","reguesia","combust��ve","Imp��rio","Be","Franc","Fran��","IX","Jos�","Lis","aut","dra","eis","hy","ll","s\"","s:","t,","udo","raz","tev","tari","orn","or�","enc","ener","��b","��v","enti","��v","lati","loci","tua","ard","suc","velo","resi","atri","deri","vers","pr��","quat","popul","divi","mar�","presi","biol","Unido","Paris","comer","estudos","pelas","deste","humana","mesma","explo","alem","muitos","m��dia","compri","dispos","basea","colon","classifica�","descri","disti","receb","importante","caracter�","matem��tic","grego","grupos","magn�","experim","produzi","doen","sentido","organismos","teoria","Embo","minera","Universi","franc��","tempera","Jos��","Lisb","veloci","quatr","populos","biol�","explora","classifica��","caracter��","matem��tica","magn��","experime","doen�","Embora","franc��s","Lisbo","velocida","quatro","biol��","classifica���","caracter��s","magn��t","experiment","doen��","Lisboa","velocidade","biol��g","caracter��st","doen��a","biol��gi","caracter��sti","caracter��stic","Antig","Central","Ge","Ig","Mun","Seu","Tamb","Ver","apro","apare","cre","ee","lg","pala","r-","vra","vem","zu","�do","mal","tel","tex","ta�","alte","quas","ang","diz","lei","ntos","adm","195","agr","agro","casa","asso","182","tanto","quais","Rein","col�","��ti","anos,","ingl","s��culos","relac","portugu�","materi","embo","inves","constitui","Santo","Jo��o","eletr","qu��mica","limita","descobe","exist�","rela����","p��blico","partes","constru��","tornou","l��ngua","posi�","n��mero","Segun","��ltim","d��ca","arara","surgi","orienta","carv��","energ","deriv","pr��ti","comerc","alem��","disposi","recebe","magn��ti","Tamb��","aprox","palav","text","quase","admin","relaci","portugu��","materia","embora","invest","descober","exist��","rela����o","constru���","posi��","d��cada","carv��o","deriva","comerci","Tamb��m","aproxi","palavra","adminis","relacio","portugu��s","investi","descobert","exist��n","posi���","comercia","aproxima","administ","relacion","exist��nc","administra","exist��nci","exist��ncia","1.","Ao","Oceano","Pau","UT","XV","eram","freguesia","nes","numa","rma","s��ri","t��o","t��m","ume","�t","dar","cav","cade","isl","civ","erc","ront","ian","ton","��f","dial","conq","cele","a��","eles","rang","heb","cidad","idei","estes","carg","pa��s.","outro","Como","juda","Uni��o","nature","escre","pol��tico","revo","fundam","Estados","computa�","in��","quanto","localizada","Santa","denti","descre","valor","tais","social","continente","todas","Consti","come��o","necessi","informa����","liga","deze","filoso","��gua","latim","preside","comprim","Universida","caracter��stica","Igrej","energi","constru����","posi����","relaciona","escrev","fundame","computa��","Constit","informa����o","filosof","presiden","Universidade","constru����o","posi����o","fundament","computa���","Constitu","filosofi","computa����","filosofia","computa����o","-p","-se","Bar","Di","Dist","Entr","Fe","In","Lu","Ou","ae","cli","fr","hid","o;","vos","�,","�s","�ni","��","rae","esu","cari","is.","isi","cit","��,","inco","tido","��ci","pou","lit","arque","ons","str","prote","luz","fede","198","forte","estav","cl��","dens","183","187","antr","carr","rit�","menos","menor","indu","alime","consis","nato","enten","habitantes,","deco","indica","utilizado","seja,","constitu�","estim","influen","Portugal,","distri","importantes","el��tric","el��trico","incluin","volta","refer�","disci","romanc","escravo","t��t","leva","moderna","Europei","publica","extens�","liber","escritor","original","resultado","linguage","relati","passou","quantid","coloni","classifica����","Reino","eletr�","Paulo","conqu","a��de","ideia","naturez","in��ci","dentif","descrev","come��ou","comprime","Igreja","energia","feder","estava","cl��s","antro","aliment","consist","constitu��","influenci","incluindo","refer��","discip","t��tu","Europeia","extens��","linguagem","relativ","quantida","classifica����o","conqui","natureza","in��cio","dentifi","descreve","compriment","federa","cl��ss","antrop","refer��n","discipl","t��tul","extens��o","quantidade","conquis","comprimento","cl��ssi","refer��nc","discipli","conquist","refer��nci","disciplin","(ou","2.","Ab","Janeiro","Ne","Oliv","eb","ede","fina","has","histori","identifi","julh","m��","pensa","rv","ste","tinha","ub","via","�n","de-","ra.","riz","ma,","teu","re,","erv","alta","roc","rog","��m","sec","seri","seme","lita","and","tur","arqu","ich","lug","etro","espo","caso","abran","ra��","Espa","cart","tenh","capa","Conc","quil","event","univ","aste","jov","Cata","brasileira","campos","socie","estre","atualme","trabalha","espa�","nteri","segunda","cient��fica","compre","tecn","contro","escal","inicial","homem","nasce","ordes","democ","indiv��duo","costa","interna","reconheci","envo","urbana","proprieda","Condei","europeu","prov��ncia","docu","teria","progra","Fran��a","suces","assoc","revol","escreve","president","Distri","Entre","antropo","t��tulo","julho","seria","arqui","lugar","abrang","tenha","univer","Catari","socieda","atualment","espa��","nterio","compree","tecno","democr","envol","propriedade","Condeix","docum","program","sucess","associ","presidente","antropol","univers","Catarin","sociedade","atualmente","espa��o","nterior","compreen","tecnol","Condeixa","docume","programa","associa","antropolo","documen","antropolog","document","antropologi","antropologia","11","25","Bu","Cab","Du","IB","Le","The","XIX","aque","acele","gem","gan","prat","rp","son","sempre","trop","up","�f","�b","�n","tab","orm","meri","al�","en��","nav","na��","com�","pad","ouro","conv","fig","fir","supe","atin","proj","dera","bea","186","mani","Alg","grav","Conse","recu","infe","imag","regi��","funci","anos.","ensi","possi","poss�","comet","hist��rico","quali","radi","desti","inclue","mundo.","referi","decl","km�","inve","dados","fundado","diversos","diversas","m��e","desenvolvid","antigo","feit","freq","aplica�","dentr","Guerra","objeti","definid","Joh","matem��tico","super","Bah","seguint","refere","direitos","Amaz","composto","Ap��s","formas","oficialm","tradi","condi","carbo","designa","M��x","atrib","mineral","temperat","ingl�","Segundo","disposit","investig","necessid","natom","estima","influencia","refer��ncia","identific","ordest","internac","Distrit","envolv","acelera","com��","figu","proje","Consel","regi��es","funcio","poss��","incluem","km��","invent","frequ","aplica��","objetiv","oficialme","M��xi","atribu","temperatu","ingl��","dispositi","investiga","necessida","natomi","ordeste","internaci","Distrito","figura","Conselh","funcion","poss��v","aplica���","oficialment","M��xico","temperatur","ingl��s","dispositiv","necessidade","natomia","internacio","poss��ve","oficialmente","temperatura","dispositivo","internacion","internaciona","(o","-N","26","27","4)","Amb","BS","Ber","Cam","Col","D.","Do","Is","Pr","Ta","ama","anterior","anatomia","b��s","c��","ep","igu","morte","n��","opera","ocidental","pen","psi","sa��de","ves","�nt","�ri","�g","�l","ded","rab","cai","��s","alco","alca","tol","tori","sep","quem","dime","tub","stra","��r","eiro","veg","porq","cupa","unh","usado","terr","188","istem","Alto","elei","eleme","consta","reto","partici","vis��","dire�","prova","famos","f��sico","estri","import","culturas","criado","espan","tipos","simp","estil","chef","composi","fazen","poste","naturai","Est��","caracteri","extra","extre","homen","crist�","abril","evolu��","educa�","fun����","cinema","ambiente","disso","insti","organiza�","algumas","respon","circui","Franci","Verde","aproximada","s��rie","caracter��sticas","fundamenta","Feder","densi","conquista","Espan","escala","Condeixa-","ensin","cometa","decla","freque","Conselho","funciona","b��si","porqu","unho","element","particip","vis��o","dire��","import�","espanh","estilo","poster","naturais","caracteriz","crist��","evolu����","educa��","fun����o","organiza��","circuit","Francis","Federa","densid","Espanh","Condeixa-a","dire���","import��","posteri","evolu����o","educa���","Francisc","densida","Condeixa-a-","dire����","import��n","posterio","educa����","densidad","dire����o","import��nc","posterior","educa����o","densidade","import��nci","import��ncia","(C","(),","-m","-o","..","28","Anto","Braga","En","Fer","Ju","Jesu","Muni","NUT","SC","XX","a\"","anti","afir","bar","cra","cri","ef","edo","glo","janeiro","l��","ps","ud","�m","��","rede","isc","isp","mera","al,","ena","eni","��c","lio","ion","dici","arg","some","sola","adot","sus","ol��","prob","exc","exer","usso","����o","a.C","seres","ross","estar","verda","bebi","mane","esco","escu","quad","forma�","formado","Brasile","l��de","mens","��lia","ind�","corri","interp","Papa","estados","deix","depe","erna","humanos","rist�","mundo,","transm","cienti","medida","medici","cultural","governa","redi","econ�","tarde","vivos","Cidade","confi","compar","alti","cuja","sociais","filho","povoa","complex","en��","servi�","composta","Aust","geog","metros","computadore","causa","Andr","��nico","respei","membro","micr","transfo","autor","teve","��bl","vers��","Unidos","experimenta","arara-","descoberta","Constitui","clima","semel","evento","control","abrange","tecnolo","conve","identifica","acelera�","com��r","vege","constant","chefe","respons","aproximadam","declar","frequent","glob","soment","solar","a.C.","verdade","Brasilei","l��der","interpr","depen","transmi","medicin","en��me","servi��","computadores","respeit","transfor","vers��o","semelh","tecnolog","acelera��","com��rc","vegeta","aproximadame","somente","Brasileir","interpre","depend","medicina","en��men","transform","semelha","tecnologi","acelera���","com��rci","aproximadament","interpret","com��rcio","aproximadamente","1)","3.","35","5)","5.","7,","Ad","Ag","Am","Acade","Gol","Gera","Ho","La","Li","Lei","Metro","Pe","Ped","Senh","a����o","c.","cle","e�","fen��men","g��n","junho","nda","noro","ona","ses","sta","sia","sio","ux","y,","yn","zin","�a","�c","don","cob","dad","rif","mari","tax","tada","is�","��r","er�","alf","enos","inde","toma","seis","lat","anu","tual","arma","ouv","��g","��ri","fim","fica","prom","exce","adv","lut","lhe","rama","consc","espi","perc","perma","manu","Ess","Este","carn","fato","aument","Cont","divu","conhece","mese","rein","��lc","subst","cert","asta","algo","Cana","visu","cinco","vida,","insp","Porto","merca","deci","espec�","defe","livre","brasileiro,","continu","primeiras","cheg","��nci","animal","pr��x","influ�","Ci��n","n��c","defini�","profis","f��sica,","Carl","religi�","cujo","unidades","domi","direito","nasci","complet","determinad","Intern","planeta","flores","produtos","astron","perso","Ant��","pape","estran","estat�","present","engenha","permit","Coimbra,","princ��pio","ativi","denominado","terceir","combust��vel","raz�","distin","Santos","tornou-","magn��tico","texto","civi","hebra","indus","liberda","Olive","quil�","inicialm","Catarina","Algar","image","destin","dentro","condi�","carbon","aplica����","poss��vel","alcan","porque","elemento","participa","caracteriza","Francisco","adota","probl","corrid","Andr��","respons�","declara","frequente","global","interpreta","Academ","Metrop","g��ner","noroes","indep","consci","perman","divul","meses","��lcu","visua","inspi","mercado","espec��","pr��xi","influ��","Ci��nci","n��cle","defini��","profiss","domin","person","Ant��n","papel","estrang","estat��","engenhari","permiti","ativida","tornou-s","hebrai","indust","liberdade","Olivei","inicialme","condi��","aplica����o","proble","corrida","respons��","Academi","Metropo","noroest","indepe","divulg","��lcul","espec��f","influ��n","defini���","persona","Ant��ni","estrange","estat��s","engenharia","atividade","tornou-se","hebraic","Oliveira","inicialment","condi���","respons��v","Academia","Metropol","noroeste","indepen","espec��fi","influ��nci","Ant��nio","estrangei","estat��st","inicialmente","respons��ve","Metropoli","independ","espec��fic","estrangeir","estat��sti","Metropolita","estat��stic","Metropolitan","estat��stica","Metropolitana","(A","(P","-M","-c","-f","0.","50","7.","8)","Ai","C��v","Grande","Hist��ri","Hino","Idade","Ja","Nos","N��o","Plut","Wil","a;","aci","apo","bit","baix","cto","central","efeito","fes","front","idade","mul","nenh","n��v","ox","ocupa","sina","ust","zes","�f","�s","es)","esf","coo","osc","asi","tea","isa","cil","mec","��n","erm","��as","alh","alma","tig","nan","iam","��a","��d","��co","lab","lag","di��","outu","leme","solo","vec","desa","impa","atm","prot","exi","etc","etos","casos","assa","cort","184","apre","aber","Al��","rata","aval","Nova","compon","Na��","isso","media","livr","livro","nova","estudar","portuguese","2011","diversi","gen��","model","localizado","Cient","conhecidos","Sul,","profes","usada","contri","ampla","eletro","grupo","continenta","filhos","descobr","registra","come��a","en��","Augu","pequeno","indiv��duos","litera","data","cabo","pr��pria","Vila","estabelece","estabeleci","cresce","desse","Alb��","direta","diferenc","divid","mar��","populosa","aparec","pr��tica","comercial","administrat","cava","cidad�","hidro","arqueo","decor","el��trica","disciplina","ra��a","carta","revolt","documento","Buen","superi","Ambr","sepa","instit","espanho","posteriorm","Jesus","crip","exerc","forma��","mensa","rist��","compart","altit","Constitui��","eventos","constante","transforma","tecnologia","acelera����","Senho","perce","defen","completa","presente","civil","frequentem","permane","industri","divulga","��lculo","influ��ncia","Aires","C��va","Plut��o","fronte","multi","nenhu","n��ve","sinais","outub","atmos","Al��m","compone","Na���","portugueses","modelo","profess","contrib","descobri","en��n","Alb��n","diferenci","mar��o","administrati","caval","cidad��","arqueol","Buenos","superio","institu","espanhol","posteriorme","cript","forma���","comparti","altitu","acelera����o","frequenteme","industria","C��vado","frontei","outubro","atmosf","component","Na����","professo","contribu","en��ns","Alb��nia","administrativ","cidad��o","superior","posteriorment","cripto","altitude","frequentemen","fronteira","Na����es","professor","en��nsu","posteriormente","frequentement","en��nsul","frequentemente","en��nsula","(\"","(em","-1","-g","-de","100","2)","29","99","Af","Av","Ando","Aten","Bio","Bel","B��l","Cost","Filh","Gui","Lo","Org","Sh","Sag","Tem","Ve","by","bala","cen","d,","dw","evi","efe","foss","h,","her","i.","kin","ld","lin","mist","m��s","nis","nio","rde","restri","t��","z��","�-","�b","rap","coi","cop","tet","tav","ort","cios","cita","alv","end","enf","rom","roco","tif","set","sequ","lic","ann","dita","lec","uls","modi","irm","hov","priv","fere","��s","cont�","adap","181","musi","pr��","ra��","ra��","inten","elev","larg","reci","populaci","Novo","mat�","most","esar","cerv","bioqu","Unix","Unida","minis","partic","capitali","locai","hist��ric","Cari","visa","atua","nomea","Deus","refei","espect","pol��tic","tempo.","intr","novo","geral,","objet","cria�","dele","territ��rios","cat�","combi","pai,","possue","semi","poderi","significat","Estre","compan","compara","China","lingu�","limit","cristi","dever","existi","escravi","havia","conceitos","m��todos","pequena","Interi","Roman","liter","tradu","Atl��ntico,","fun���","presen�","t��cnic","Existe","cresci","dessa","Baixo","��n","religioso","orna","descrit","Lisboa,","biol��gica","altera","agr��","col��","limitado","alem��o","material","freguesias","valores","incor","pouco","carre","rit��","distrit","romance","escravos","coloniz","eletr��","consiste","Abra�","secre","nasceu","compreende","ganh","nave","beati","manif","recur","hist��ricos","qualida","fundador","feitos","seguintes","internacional","Berl","psico","dimen","simpl","composi�","extrem","disso,","b��sica","Federal","Espanha","Condeixa-a-N","afirma","suste","manei","quadra","econ��","complexo","Austr","micros","respeito","depende","Pedro","dada","Canad","terceiro","carbono","pr��xim","domina","defini����","respons��vel","mec�","labo","Ciento","Augus","literat","dividi","separa","mensag","Senhora","forma����","Andor","B��lg","licen","modif","adapt","populacio","mat��","cerve","bioqu�","particu","capitalis","locais","pol��ticas","objetos","cria��","combin","possuem","poderia","significati","companh","lingu��","limites","cristia","Interio","liter�","fun����","presen��","t��cnicas","crescim","agr��co","col��n","rit��n","coloniza","eletr��ni","Abra��","manifes","recurs","qualidade","Berli","dimens","simples","composi��","Condeixa-a-No","econ��m","Austr��","defini����o","mec��","labora","Cientol","literatu","mensage","forma����o","Andorr","B��lgi","modifi","populacion","mat��ri","cervej","bioqu��","particul","cria���","combina","significativ","lingu��s","cristian","Interior","liter��","fun����es","presen��a","crescime","agr��col","col��ni","rit��ni","Abra��o","manifest","Berlim","composi���","Condeixa-a-Nov","econ��mi","Austr��l","mec��n","Cientolo","literatur","Andorra","B��lgica","modifica","populaciona","cerveja","bioqu��m","particula","cria����","lingu��st","cristiani","liter��ri","crescimen","agr��cola","col��nia","Condeixa-a-Nova","econ��mic","Austr��lia","mec��ni","Cientolog","literatura","populacional","bioqu��mi","particular","cria����o","lingu��sti","cristianis","cresciment","Cientologi","cristianism","crescimento","Cientologia","cristianismo","(por","(17","24","31","37","4.","Arist��","Bo","B��bl","Centro","Go","Ins","Mi","Mas","Mon","Noss","Siste","To","Trata","ato","aten","brit��ni","e\"","ecu","f��","fric","gre","hu","jorna","ke","l)","l-","ler","nal","p��","preci","rb","sat","s��ti","th","uta","wa","y.","�as","�g","�i","�s","�do","��","dol","co-","cog","dae","dal","asp","cant","isf","orda","cim","meca","in��","ro,","emi","iar","sex","pat","nob","nota","��ci","lav","lida","anc","anal","iori","sint","arti","umi","umo","ley","leis","ult","mora","mole","ntor","foto","impe","ilha","santo","pint","pinto","ndia","forn","estam","esta�","agos","vern","acre","asse","assu","ital","cion","intera","empr","subs","press","conco","Nacio","interes","ren�","Comis","Depo","risto","transp","rante","utiliza��","2015","reve","revi","rono","m��dio","cr��ti","varie","comunid","corrent","��f","coloc","Arqui","diferente","portuguesa,","passado","essen","deus","tenta","ilhas","experi�","dout","autori","registr","pesquisas","conseg","serviu","rela����","planet","existem","especialm","corpos","produto","mante","causas","express�","permite","princ��pios","diferen�","reside","baseada","doen��as","Mundi","constitui�","��ltimos","surgiu","derivad","carga","dezem","alimento","relativa","cl��ssica","finan","aster","jovem","sucesso","Cabo","Durant","prati","tropas","na����","padr","possib","desenvolvido","superf","Amaz�","projet","dispositivos","Col�","c��di","igual","operac","dedi","alco�","eleito","famosa","cometas","bebidas","cientis","geogr","arara-a","servi��os","promo","religi��","determinado","Interna","florest","disting","quil��","Algarv","imagen","alcan�","elementos","g��nero","conscie","inspira","Ci��ncias","personag","estrangeiro","Hist��ria","teat","abert","diretam","aparece","hidrog","decorr","Constitui����","criptog","Atenas","Filho","Guima","Organi","Sagan","cois","priva","musica","pr��-","eleva","Unidas","Carib","intro","Existem","incorp","distrito","naveg","sustent","Canad�","adapta","mat��ria","mec��nica","Arist��t","B��blia","Insti","Nossa","Sistema","aspe","mecan","artig","molec","acred","itali","empres","concor","Nacion","Comiss","transpo","utiliza����","comunida","��fric","experi��","consegu","rela����es","especialme","diferen��","residen","Mundial","constitui��","dezemb","Durante","pratic","na����o","possibi","Amaz��","Col��","c��dig","operaci","alco��","cientist","geogr��","arara-az","religi��o","floresta","distingu","quil��me","imagens","alcan��","personage","diretame","Constitui����o","coisa","Caribe","incorpo","navega","Canad��","Arist��te","Instit","aspec","mecani","molecu","acredi","italia","Naciona","transpor","utiliza����o","comunidade","��frica","experi��n","especialmen","constitui���","dezembr","pratica","possibil","Amaz��n","operacio","alco��l","cientista","geogr��f","arara-azu","quil��met","diretament","Arist��tel","Institu","aspect","molecula","acredit","italian","Nacional","transport","experi��nc","especialment","dezembro","possibili","Amaz��ni","operacion","alco��li","geogr��fi","arara-azul","quil��metr","diretamente","Arist��teles","Institut","molecular","experi��nci","especialmente","operaciona","alco��lic","alco��lica","(,","(;","(atual","(NUT","3%","3)","6.","7)","Apost","Bi","Cali","Da","Era","H��","I,","It","Lic","Orie","PC","Pi","Serra","ateu","acompanh","c��","d��","drama","ey","fas","fer","fat","fac","g��s","herda","ki","ly","lor","mia","mon","nz","nun","nordeste","oz","ocorr","oceano","p.","rra","r��o","s;","sp","t��","vor","ven","van","xe","�re","��","��","da�","os)","asm","reb","rent","is��","orri","mede","mete","eres","alq","ales","quis","inas","tint","top","tou","��f","nom","nodo","lau","lant","poes","pote","tudo","arm","pe��","on,","let","ami","��p","mont","mono","sufi","desp","vila","��ni","elas","exe","sab","tr��","hola","luna","fez","ter�","conto","agri","cast","cl��","muda","urb","abor","esten","chim","quar","Real","formada","habili","Maca","divis","divin","marc","habitat","reit","est��","junta","ameri","ano.","poli","interi","II,","Paul","filme","gera�","qu��","Comu","rinc","rep�","f��sic","pessoal","portant","territo","termos","desenvolve","km2,","tempo,","novas","espac","sejam","dela","ronz","redu","repro","cauda","peso","povos","impres","aplicada","Artu","indivi","usados","engl","conte�","qu��mico","Parti","Parla","te��","te��","melho","regul","determinar","asca","asce","asci","educado","mort","tratado","informa����","quest","Europeu","observado","interno","cinem","metro","reconhece","Muit","Quando","destac","estatu","situada","equip","1945","Alber","cole�","membros","direto","denominada","pertencent","terceira","combust��vei","ence","divide","destes","descri�","populoso","dizer","��ltimo","oriental","materiai","isl�","Direi","onso","prote�","entend","ideias","constitu��d","historia","capaz","democr�","associado","aquel","ating","gravi","definida","tradic","envolvi","invento","investiga�","BSD","retor","fundamental","ensina","circuito","Munic","excl","escol","redit","conver","verdadei","transmit","Brasileiro","semelhant","Geral","espir","Esses","aumento","subst�","continua","Carlos","destina","visual","profissi","condi����","acima","gen��t","continental","Ambr��","n��vel","diferencia","institui","componentes","administrativa","Afons","Aveiro","balan","end�","intens","mostra","refeit","cat��","carrei","secret","beatif","psicol","maneira","microsc","composi����","lavo","fotog","pintor","forne","esta��","agost","Depois","revis","coloca","essenc","express��","derivado","astero","superf�","dedic","criptogra","empresa","resident","c��digo","alcan��a","incorpora","aspectos","acredita","arara-azul-","quil��metros","Instituto","Calif","It��lia","Orient","nunca","ocorr�","poesi","poten","letra","sufici","execu","holan","agric","cl��n","urban","estende","chimpa","marca","americ","interio","gera��","qu��nt","Comuni","rep��","f��sicas","portanto","territor","reprod","impress","individ","englo","conte��","Parlame","te��s","regula","informa����es","cinem�","combust��veis","descri��","materiais","isl��","Direit","constitu��da","historiado","democr��","tradici","investiga��","retorn","Munic��","exclu","verdadeir","espiri","subst��","profissio","condi����es","gen��ti","Ambr��s","Afonso","balan��","cat��l","carreira","beatifi","microsc�","composi����o","fornec","esta���","agosto","essenci","express��o","asteroi","superf��","criptograf","residente","ocorr��","poesia","potenc","suficie","agricu","cl��ni","chimpan","america","interior","gera���","qu��nti","rep��b","territori","reprodu","individu","englob","conte��do","Parlament","cinem��","descri���","isl��m","historiador","democr��t","tradicio","investiga���","Munic��p","espirit","subst��n","profission","Ambr��sio","cat��li","microsc��","essencia","asteroide","superf��ci","criptografi","potenci","suficient","agricul","chimpanz","american","qu��ntic","rep��bl","territoria","engloba","Parlamento","cinem��t","isl��mi","democr��ti","tradicion","Munic��pi","subst��nci","profissiona","microsc��p","criptografia","potencia","suficiente","agricult","chimpanz��","americano","rep��bli","territorial","cinem��ti","democr��tic","tradiciona","Munic��pio","microsc��pi","agricultu","rep��blica","agricultura","\"A","(I","(a","(que","-S",".\"","4%","5%","8.","88","9)","98","Ac","A��","Anti","Ang","Ass","Bronz","Cl","Cu","Chi","Dese","GE","Gr��","Ha","Hun","Histori","Leo","Lumi","Mai","Mur","Mich","Nas","Prop","Prim","Princ","Rod","Serg","Tr","Testam","afe","bac","basta","cn","c��","clim","c��lculo","cren�","crono","c��ni","d.","dre","dist�","din�","eco","fala","fisi","iri","ko","ls","massa","pion","prefeit","rh","ulo","vit","z,","�ni","�ri","�m","�,","��","deo","dot","esq","cod","os-","as)","as�","riq","rido","te,","tei","��os","tama","ord","orta","cic","��ci","��o","alo","emo","iana","coma","tom","tora","��ri","sere","��,","lide","lici","lito","lom","lona","quere","di�","ares","arda","pet","esto","ond","eita","sof","mol","sude","veri","mig","mili","vive","gua","unda","ilu","gati","adqu","admi","tros","hom","nega","here","compe","conso","temas","obte","obti","acei","abs","ester","calc","cali","cidade,","intel","regio","grad","Rev","cola","quint","Maia","cami","habitada","subdi","junto","concl","desce","Naz","Natu","biom","refo","enso","interc","regi��o.","Paran","cana","gerado","asto","desem","��ric","serve","estudou","habitantes.","Caro","culto","mundi","proce","inclu�","desenh","azul","propor","utilizan","Seus","novem","estudan","norte,","ormal","fundad","cata","simb","sistem�","possu�","artin","art��","fazer","frent","expedi","postu","dispe","inicio","chamadas","influe","descon","significado","1933","longa","ent��","confo","esses","h��b","usadas","contr�","alto","altu","movimentos","seguida","contat","2022","discu","tornar","Par��","dom�","auton","trabalhos","varia�","abrig","determina�","Amap","orden","for��as","solu","demon","sentim","organismo","necess�","bande","formu","rican","populares","constru��","��poca,","enera","observa�","especiali","integrado","ocorreu","manti","cabe","envi","urbano","realizado","realizada","Ant��","papa","estrat","expressa","situado","t��cnico","engenhe","terras","micro","��nd","mach","pontos","religiosa","baseado","distint","explora�","biol��gico","Antigo","alter","agru","1822","recebeu","d��cadas","ligada","Outr","fortem","resultados","alimenta","federal","Janeiro,","New","pensame","roch","espor","capac","estrel","europeus","arquite","democra","propriedades","universa","sociedades","IBG","XIX,","John","matem��ticos","Bahia","objetivo","atribui","figuras","necessidades","anteriores","homena","organiza���","Antoi","Ferre","dicio","argu","ind��","deixa","controle","identificad","Admin","latin","advo","Contu","decis","problema","vecto","etc.","livros","diversida","revolta","civili","permanec","compartil","industrial","Costa","evid","efetu","fosse","setor","irm��","espectr","��ndi","ganho","quadrado","capitalism","recursos","manifesta","bioqu��mica","lingu��stica","cogn","interess","varieda","alimentos","Internac","Algarve","conscien","aberto","musical","introd","Comiss��","mecanis","constitui����","Amaz��nia","experi��ncia","alco��licas","ateus","acompanha","monta","Partido","melhora","ascal","quest�","cole��","pertencente","entendi","redita","te��sm","Direito","balan��a","beatifica","ocorr��n","asteroides","superf��cie","profissional","cinem��tica","A��or","Desen","Gr��ci","Murp","Testame","cren��","dist��","fisio","pione","esqu","codi","taman","cicl","serem","lider","sudes","milita","adqui","hered","region","subdiv","conclu","descen","refor","mundial","inclu��","utilizando","novemb","fundada","catal","sistem��","possu��","expedi��","iniciou","influent","confor","h��bi","contr��","altura","contato","autono","varia��","determina��","solu��","demons","sentime","necess��","bandei","formul","observa��","Ant��r","engenhei","��ndia","explora��","Outros","forteme","pensament","capaci","estrela","IBGE","homenag","organiza����","Antoin","Ferrei","dicion","ind��s","Adminis","Contudo","vectori","diversidade","civiliz","permanece","compartilh","evid�","efetua","espectro","capitalismo","variedade","Internaci","conscienc","introdu","Comiss��o","mecanism","constitui����o","cole���","te��smo","ocorr��nc","Desenv","Gr��cia","Murph","Testamen","dist��n","pionei","codif","tamanh","sudest","militar","heredi","regiona","descend","novembro","sistem��t","conform","contr��r","autonom","varia���","determina���","demonst","sentimen","necess��r","bandeir","formula","Ant��rt","engenheir","explora���","fortement","pensamento","capacida","homenage","organiza����es","Antoine","Ferreira","diciona","ind��st","Administ","vectoria","civiliza","evid��","Internacio","conscienci","ocorr��nci","Desenvo","Murphy","Testament","dist��nc","codifi","sudeste","heredit","sistem��ti","contr��ri","autonomia","demonstr","sentiment","necess��ri","bandeira","Ant��rti","explora����","fortemente","capacidade","ind��stri","Administra","civiliza�","evid��n","ocorr��ncia","Desenvol","dist��nci","codific","contr��rio","explora����o","civiliza��","evid��nci","Desenvolv","codifica","Desenvolvi","(3","(L","(O","(S","-P","-18","/ou","23","34","6)","65","70","ASC","B.","Ban","Bras","Bom","Cos","Caste","Dio","Deu","Ela","Egi","Edw","He","Hen","Hit","Inde","J��","Lito","Latin","Mag","Musso","Martin","Nordeste","Or","Ocidental","Open","Per","Pan","Pus","Praga","Perna","Pen��nsula","Sol","Te","Tche","UN","W.","aco","aconte","ajuda","adiciona","bos","bia","bilh","cm","cent","crit�","d��o","efeitos","e/ou","g,","gm","gado","gol","gria","hk","hn","hip","hino","jus","ker","kho","lme","linha","m)","m��o","mulh","neste","pas","plo","r\"","rq","rci","russo","sal","sin�","s��m","tis","teste","vio","visto","vindo","z.","�c","�me","�es","�u","��","ra-","coz","dag","rir","riv","mado","cama","teb","tema","ree","redo","ta.","orre","cint","mex","��.","��is","er,","enx","enz","inu","ro.","tio","na,","nati","pari","non","not","��b","��u","pob","lido","lori","lore","quei","dito","arl","arra","ped","pei","umb","umin","our","mot","modo","fico","sudo","por�","mita","vinte","font","t��","cux","atr","ilos","exa","usca","horas","lub","rege","obri","verde","beha","pr��","Esc","cidade.","n��o-","igre","prim�","ropo","av��","adeq","Cova","Mari","Maran","inam","cer�","certa","reta","regi��o,","Assi","film","fil��","capital,","diant","hist��rias","visi","��sse","inse","insta","logo","destr","inclus","ambas","000","concede","local,","ranco","socio","175","propos","utilizada","km2","brasileiros","norte-","rigu","recom","criada","terat","remo","espal","deli","comportamentos","m��dico","Norte,","teci","imple","��s","vivo","colora","localiza�","classificado","classificada","ponta","ponti","portuguesas","Estes","recep","Prod","profu","deu-","contex","Char","Christ","Carta","encontrado","construi","contag","magni","essas","autom","Terra,","bril","conser","rea����","evoluti","Pode","num��","Apesa","Roma","part��","moderno","tratam","Solar","Socie","l��nguas","predo","empreg","III,","ambienta","Museu","disse","pol��tica,","Vien","africa","metade","legis","legal","instr","Europa,","propriet","carb�","respec","celular,","setem","humano,","respos","consideradas","pertencen","entid","Paris,","produzida","matem��tica,","experimento","Central,","Mundo","pr��tic","magn��tic","textos","cidada","Lu��s","distrib","colonia","Paulo,","federat","cl��ssico","viag","Conc�","jovens","brasileira,","Fran��a,","seriam","programas","infe��","radic","definido","compostos","tradi�","estimad","inventa","homens","crist��os","organiza����","barro","rosso","governado","Unidos,","experimental","vegetal","Golgi","Limi","fen��meno","taxa","alfor","armaz","ouve","reino","astrono","raz��","n��cleo","hebraica","independe","espec��fico","apoi","oxig","avali","2011)","amplame","nenhum","modelos","arqueolo","atmosfe","mistu","rom�","ferec","hist��rica","deles","escravid","religiosos","dependen","dividida","licen��","dimens�","significativa","Tratado","f��me","jornal","precis","satis","s��tima","patro","nobre","assent","assunt","intera�","press�","autorida","financ","projeto","promov","teatr","Organiz","sustent�","artigo","concorr","personagem","navegado","praticam","meteo","lunar","quart","Macau","Artur","destaca","equipa","Albert","prote��","gravit","transmiti","destinad","institui��","psicolo","revist","dedica","empresas","Calif�","holande","Comunida","portanto,","gen��tica","fornece","descri����","investiga����","subst��ncias","chimpanz��s","Acredit","Antil","Assem","Hung","Lumi�","Prime","Rodrig","bastant","clim��","din��","prefeito","verif","migra","negati","compet","obtev","calcu","Revol","colab","camin","desemp","Caront","proporc","estudant","ormalm","art��s","frente","desconh","dom��","Amap�","envia","machos","agrupa","arquitet","democrac","argume","decis�","interesse","beatifica�","possu��a","influentes","Contudo,","compartilha","tamanho","determina����","homenagem","Internacion","consciencio","Testamento","Administra�","dist��ncia","evid��ncias","Desenvolvim","ASCII","Cosm","Castel","Deus,","Indep","Litora","Mussol","Push","Pernam","Tchek","acontec","crit��","hip��","mulher","s��mb","motor","ficou","sudoe","fontes","cuxi","atr��","obrig","behav","pr��n","adequ","cer��","Assim","filmes","fil��s","destru","recome","espalh","tecido","impleme","localiza��","profun","context","contage","magnit","conserv","rea����es","evolutiv","num��ri","Apesar","part��c","predom","Viena","african","legisl","instru","propriet�","carb��","respect","setemb","respost","pertencendo","entida","pr��ticas","magn��tica","cidadan","distribu","federati","viagem","Conc��","tradi��","estimada","organiza����o","Limita","alforri","astronom","raz��o","independen","apoio","avalia","amplament","arqueolog","atmosfera","mistura","escravid�","dimens��","satisf","assunto","intera��","autoridade","finance","Organiza","sustent��","navegador","meteor","quarto","equipame","prote��n","gravita","psicolog","revista","Calif��","holandes","Comunidade","descri����o","investiga����o","Acredita","Antilh","Assemb","Hungria","Lumi��","Primei","Rodrigu","bastante","clim��ti","din��m","verifi","negativ","obteve","calcul","Revolu","colabo","caminh","desempe","Caronte","proporci","ormalme","art��sti","desconhe","dom��n","Amap��","democraci","argument","beatifica��","determina����o","Internaciona","conscienciol","Administra��","Desenvolvime","Cosmo","Indepe","Litoral","Mussolin","Pushk","Pernamb","Tchekho","crit��r","s��mbo","sudoes","atr��s","behavio","pr��nci","cer��m","fil��so","recomen","espalha","tecidos","implement","localiza���","contexto","contagem","magnitu","conserva","part��cu","legisla","propriet��","carb��n","respecti","setembr","resposta","entidade","cidadani","federativ","Conc��r","tradi���","alforria","astronomi","independent","amplamente","arqueologi","escravid��","dimens��es","intera���","financei","Organiza��","sustent��v","meteoro","equipament","prote��nas","psicologi","Calif��r","Acredita-","Antilha","Assembl","Lumi��re","Rodrigues","din��mi","calcula","Revolu��","desempen","proporcio","ormalment","desconhec","dom��ni","democracia","beatifica���","Internacional","conscienciolo","Administra���","Desenvolvimen","Cosmos","Indepen","Mussolini","Pushkin","Pernambu","Tchekhov","crit��ri","s��mbol","sudoest","behaviori","pr��ncip","cer��mi","fil��sof","recomend","implementa","localiza����","magnitude","part��cul","propriet��r","carb��nc","respectiv","setembro","cidadania","federativa","Conc��rd","tradi����","astronomia","independente","arqueologia","escravid��o","Organiza����","sustent��ve","equipamento","psicologia","Calif��rn","Acredita-s","Antilhas","Revolu����","desempenh","proporcion","ormalmente","desconheci","dom��nio","beatifica����","conscienciolog","Desenvolviment","Independ","sudoeste","behavioris","pr��ncipe","recomenda","localiza����o","propriet��ri","carb��ncu","Conc��rdia","tradi����o","Organiza����o","Calif��rni","Acredita-se","Revolu����o","beatifica����o","conscienciologi","Desenvolvimento","Independ�","carb��ncul","Calif��rnia","conscienciologia","Independ��","carb��nculo","Independ��n","Independ��nc","Independ��nci","Independ��ncia","%.","()","(nome","-B","-L","43","44","45","46","500","600","9.","By","Bec","CJ","CO","C��","Cru","Camp","Clau","DJ","Des","DCJ","Ens","ESC","Fl","Filos","Gro","Grosso","Hux","Ib","Ita","J��","Joa","Ly","Med","Manu","OS","Ob","Ox","Pascal","Ra","R��s","Sil","Stan","Teo","Up","VI","Vol","Vel","are","ante","amar","anan","ate��smo","bas","bula","bene","busca","c��","crio","din","dio","e:","e��","ela","fra","fal","faix","falta","jos","jei","ka","kg","l\"","lta","n.","ner","nem","oco","oli","oferec","pul","pale","rqu","resta","rura","resto","san","tm","ty","tz","u��","vent","volu","venera","��","��","�li","��","��","��","dox","es:","dant","ose","osco","aso","mad","made","ca)","cad","re-","��,","or,","ordo","��g","alc","all","ende","enda","en��","rota","tia","tiz","nam","ia)","sed","sema","seca","pais","nol","entes","��c","��r","lac","pon","pola","��o.","siv","dim","dip","diri","turo","aru","ar��","nios","pec","umu","onas","ulda","ames","amor","soli","moti","filo","suj","vere","mir","vai","ceb","olh","ol��","reso","vita","guer","fonte","t��","cus","atos","proe","il�","exti","exam","irro","garan","pix","pite","pita","voo","foi,","rame","bi��","ndo","regra","ser�","rost","estad","acum","acess","��ses","perf","pert","baca","bati","manda","ruto","abo","abai","idea","Esp","Estu","car�","Alf","poden","entret","faci","rele","riti","aves","Conda","Con��","aust","Mato","trib","placa","mart","��li","segura","ensos","minh","polo","tempos","Pa��s","cand","cano","can�","estado,","alga","diag","org�","dema","vista","��ss","vida.","Comp","raio","meros","expli","conceb","concel","concent","azu","organe","provo","consideram","176","178","prop�","medir","rgent","sul,","oste","invas","Portuca","classe","culturai","exemplos","novos","estudado","brasileiro.","est��t","governos","criat","2010","comuns","constitue","cati","chega","futu","milh��o","impos","dispo","hist��ria,","��r","ragm","aplicado","Guia","Guar","Guter","1930","1937","recent","passag","Proc","Prov","poet","confe","confu","atrave","conter","ampl","ampli","brome","leste,","erti","lan��","comume","qu��mic","m��l","representan","representado","2004","2005","2008","tornan","tornara","c��lulas.","romana","biologia,","Terra.","almei","��nd","1978","consel","conseq","Conser","Alentejo,","Alentejo.","france","combust��","geome","membra","cidentai","morre","levou","1924","cient��fico.","cient��fico:","teorias","ent��o,","Monte","��mio","Suas","Su��","curs","curso","costu","possuir","poeta,","astrof","n��meros","estruturas","Qual","ocorrer","libe","resultan","numer","2021,","linguagen","dias.","��nica","1960","colet","artesa","europei","prov��ncias","Baixos","ativa","s��li","dan�","negr","transfe","resis","produzir","produzido","explorado","Antiga","Antigu","Get�","tele","agrop","��tico","p��blico.","descoberto","XVI","cadei","civis","juda�","ligado","dezes","relacionado","relacionada","filosofia,","Outra","hidr","cito","luz.","1980","el��tricas","modernas","publicada","quantidades","disciplinas","m��qu","espos","Conce","trabalhar","reconhecid","arquip","programa�","tabe","al��","possiv","radio","desenvolvida","antigos","refere-","Amazo","envolve","atribu�","Cami","Pr��m","terres","fazendo","cinemat","ensino","circuitos","Anton","Enquanto","SCO","psala","rosse","escul","ind��","tarde,","Ameste","fen��menos","marin","carne","reina","chegou","animal,","nascido","astron�","denominados","raz��","adotad","declarad","declara�","mercados","n��cleos","hebraico","independ�","espec��fica","bits","baixa","coor","lago","corta","apren","eletroqu","registrad","crescen","desses","ra��as","exerce","exerc�","percent","defend","defens","completam","divulga��","espanhola","cidad��os","restrit","alva","nomeado","Romana","traduz","descrita","materiali","extremo","Espanha,","coloniza�","eletr��nico","laborat","mensagem","combina�","col��nias","econ��mico","brit��nico","sint�","impera","pintu","cr��tico","corrente","doutr","registro","relativam","estrangeiros","decorre","Guimar","privado","consegue","Col��m","distingui","italiano","transporte","possibilida","operacionai","dramat","fator","contos","divinda","juntam","te��ri","metrop","Muitos","estatut","1945)","diretor","atingi","ensiname","end��","secret�","fotogra","arara-azul-de","Orienta","marcada","exclusi","gera����","historiadore","espiritu","essencial","qu��ntico","isl��mico","potencial","tradicional","Chirop","Historic","Miche","afeta","cronol","c��nic","litora","intele","Natura","Paran�","desenho","postura","biol��gicos","esport","universal","identificado","advog","ganhou","quadrados","A��ores","cren��a","fisiol","esque","ciclo","adquiri","subdivi","expedi����","observa���","efetuado","espectros","introduz","mecanismo","descende","conforme","engenheiro","vectorial","heredita","demonstra","sentimento","Ant��rtid","Bras�","Egito","Edward","Hitl","Latina","UNE","sin��","cozi","camada","mexi","enzi","nativ","queima","igrej","prim��","Maranh","diante","visita","propost","norte-a","remont","colora�","classificados","Produ","tratame","emprega","colonial","infe����","armaze","licen��a","f��meas","patron","press��","teatro","praticame","hip��t","cuxi�","obriga","adequa","Assim,","predomi","distribui","satisfa","gravitac","holandesa","colabora","argumento","financeir","meteorol","Administra����","Pernambuco","fil��sofo","respectiva","federativas","sustent��vel","proporciona","desconhecid","Desde","Huxle","R��ss","Upps","anan�","benef","criou","paleo","madei","seman","diplo","dirig","motiv","filog","sujei","resol","proem","extint","garant","ser��","acumu","bacal","aboli","abaix","Estudo","car��","podend","facil","Condado","Con��m","��lido","Pa��ses","candi","canon","org��","concelh","concentra","azulo","organel","Portucal","culturais","criati","constituem","cativ","futuro","Guterr","recente","passage","poetas","atraves","bromel","comument","qu��micas","m��lti","tornando","tornaram","almeira","conselh","consequ","Conserv","frances","combust��o","geomet","membran","cidentais","Su��ci","costum","astrof�","libera","resultant","numeros","linguagens","artesan","dan��","negros","transfer","resist","Antigui","Get��","agrope","juda��","dezess","hidros","m��qui","esposa","Concei","reconhecida","arquip��","programa��","possive","refere-s","Amazon","atribu��","Pr��mio","terrest","escult","Amester","raz��e","declara��","independ��","coorde","eletroqu�","registrada","exerc��","percenta","defende","defenso","completame","divulga����","coloniza��","combina��","sint��","pintura","doutri","relativame","Guimar�","Col��mb","possibilidade","operacionais","divindade","juntame","metropo","estatuto","ensinament","secret��","arara-azul-de-","Oriental","exclusiv","gera����o","historiadores","espiritua","Chiropo","Historica","c��nicas","litoral","intelec","Paran��","subdivid","expedi����o","observa����","descenden","hereditari","Ant��rtida","Bras��","Hitler","UNESC","sin��n","enzim","prim��r","Maranh�","proposta","norte-am","remonta","colora��","tratamen","infe����o","armazen","press��o","praticamen","hip��tes","cuxi��","predomin","distribui�","gravitaci","meteorol�","Administra����o","Huxley","R��ssia","Uppsala","anan��","madeir","filogen","proemin","acumula","abaixo","podendo","Con��mb","candida","canoni","org��n","concelho","azulona","Portucale","criativ","Guterres","atravess","comumente","m��ltip","Conserva","geometri","Su��cia","astrof��","resultante","artesana","dan��a","Antiguid","Get��li","agropec","juda��s","dezesse","m��quin","arquip��l","programa���","possivel","refere-se","Amazonas","terrestr","Amesterd","raz��es","declara���","independ��n","coorden","eletroqu��","exerc��ci","percentag","defensor","completament","divulga����o","coloniza���","combina���","sint��t","doutrin","relativament","Guimar��","Col��mbia","juntamen","metropol","ensinamento","secret��ri","Chiropot","Historicam","intelect","subdividi","observa����es","descendent","Bras��l","UNESCO","sin��ni","enzimas","prim��ri","Maranh��","norte-ame","colora���","tratament","armazena","praticament","hip��tese","distribui��","gravitacio","meteorol��","anan��s","madeira","proemine","Con��mbri","candidat","canoniz","org��ni","atravessa","m��ltipl","geometria","astrof��s","Antiguida","Get��lio","agropecu","juda��sm","arquip��la","programa����","possivelm","terrestre","Amesterd�","declara����","independ��nc","coordena","eletroqu��m","percentage","completamente","coloniza����","sint��ti","relativamente","Guimar��es","juntament","metropoli","secret��rio","Chiropotes","Historicame","intelectu","subdividido","descendente","Bras��li","sin��nim","Maranh��o","norte-ameri","colora����","tratamento","praticamente","distribui���","gravitacion","meteorol��g","proeminent","Con��mbrig","canoniza","astrof��si","Antiguidade","agropecu�","juda��smo","arquip��lag","programa����o","possivelme","Amesterd��","declara����o","independ��nci","eletroqu��mi","percentagem","coloniza����o","sint��tic","juntamente","metropolita","Historicament","intelectua","Bras��lia","norte-americ","colora����o","gravitaciona","meteorol��gi","Con��mbriga","canoniza�","agropecu��","possivelment","independ��ncia","eletroqu��mica","sint��tico","metropolitan","Historicamente","norte-america","canoniza��","agropecu��ri","possivelmente","metropolitana","Historicamente,","norte-american","canoniza���","canoniza����","canoniza����o","\"C","\"a","\"The","(E","(U","(187",");",",4","-A","-V","-b","-19","./","1-","1),","33","36","39","400","62","74","78","86","87","92","A.","Az","Abre","Arm","Argent","BC","Bro","Bab","Berna","Breta","Branco","Cha","Ceu","Cale","C��r","Dar","Desta","Douro","Dumo","Eug","F.","Faz","Gon","Gali","Gib","G��lia","Gr��o","Hip","Hori","Il","Liv","Mel","Mac","Munt","Mosco","Numa","Nob","Nesta","Neste","Nasce","Oeste","Olavo","Pla","Pol","Pac","PIB","Rob","SO","San","Sha","Sac","Sendo","Tuc","Trab","Thom","Vene","apost","aristo","bis","bul","bel","bil","bens","bordo","c,","cla","centra","cent��","eci","ecol�","elabora","fis","flu","fab","fase","fins","f��sse","fragm","ferti","germ","h.","ht","h��","hon","ham","ii","iq","idos","jul","jui","mis","mestre","norm","ote","ome","olo","opost","pseu","pesa","pesca","praz","pen��nsula","r)","ry","rdo","rca","rtu","rus","sum","sat��","sinal","ts","tw","t��p","uv","vul","va,","vale","vence","xan","ye","ys","yte","�u","�r","�de","�d","�v","�x","�li","��","��","��","dea","raq","es\"","nth","coe","cot","cora","dav","os\"","os:","asa","ri)","mam","req","rema","tac","tat","orb","orv","oros","cif","mea","��d","erb","erca","��u","alde","eno","enor","quer","inj","inci","roe","rode","emas","til","nau","nada","naqu","iado","��g","��do","��ra","����","paz","pate","no,","noma","entu","��ra","la,","lama","poca","poem","lo,","an��","ardi","ump","stri","le,","lea","��v","��ci","cono","conde","mome","mona","ador","ve��","desl","vant","cera","vir","viz","vido","guar","��nt","fot","elm","att","unis","rand","ex-","adul","parad","usse","luc","ntan","pris","neo","heran","mente","ntin","feve","bib","comp�","compra","pose","om��","etho","estan","agra","casi","ogra","uts","parl","cosm","puro","acla","actu","euca","perco","bata","baia","bacia","s��o:","oriu","apes","ur��","ur��","aban","abso","abun","ideo","boa","estej","Esse","2018","Alp","Allo","Algu","intei","noss","Reg","prima","primi","capt","���","formar","l��qu","rech","Come","Colo","Mais","Nov","plano","lvar","Por�","Porta","inama","juris","biog","difu","dif��","possa","posse","amea","ret�","interv","capitai","grandez","Pana","renda","gerai","raci","coment","errado","Capi","culti","cin�","Def","Devi","Deut","tranc","repa","vez,","popula���","humani","humanas","Estat","ambos","Am��rico","issa","mers","expos","expul","fami","propa","medica","utilizam","perio","sul-","embri","osto","exempla","mem�","nove","recor","respi","2012","2013","2016","2017","meios","gene","zona","Portugu","cate","estiv","feita","��nf","compro","define","impla","impli","Alex","��lv","reser","viver","vivia","podere","At��","encontr","Estas","recei","definir","definit","1,5","profe","an��lises","per��odos","troca","amplo","supor","movimento.","Bair","comum,","especif","encontra-","encontrar","escrita","grega","conje","cujos","representa�","calend��rios","disc�","consumi","filha","variam","variada","apresentam","apresenta�","apresentado","regista","pesquisado","sele","1970","depois,","oeste,","sitta","p��blica","��,","assim,","animais,","conhecidas","Roy","centros","permis","1892","1894","antigas","planej","denomina�","Medi","Marqu","1990","pessoas.","Atl��ntico.","publico","extensa","Parag","conda","condu","posit","Beiras","Quei","1913","destaq","��ltima","realiza�","pr��prio","pr��prios","reun","metal","contras","filos�","��guas","t��cnica","Andre","equiv","ramos","m��sica,","M��d","neg��","humano.","nacional,","corresponden","France","or��","mar��","humana,","humana.","explorar","matem��tica.","franc��s.","Central.","Geog","angu","1954","agrof","casal","1824","p��blico,","surgira","orienta�","palavras","UTF","hebre","judai","pol��ticos","localizadas","informa����o,","Barro","arque�","entende","indicado","el��tricos","publica�","publicado","escritore","originalm","consisti","historic","m��x","tinham","viaj","cient��ficas","reconhecim","reconhecido","revolu","escrever","escreveu","sucessi","universo","espa��os","prato","tropi","padro","manip","recup","qualif","referido","referida","feitas","Johan","Bahia,","seguinte","designar","designa�","mineral,","influenciado","internacionai","Isso","morte,","sa��de,","caix","��rg","famoso","fazende","extrac","extra�","fundamentai","conquistas","escalar","funcionam","educa����o,","XX.","redes","formados","deixo","povoado","autores","abrangen","conven","transmis","vegetai","Brasileira","semelhan","Agost","Litera","cobe","taxo","anun","tualme","��gi","excede","manut","conhecer","certos","algori","livre,","nascida","participa�","adotar","problem","Wiles","esfe","exig","aprec","filhos.","estabeleceu","pr��tica,","comerciali","nenhuma","arqueol�","atmosf�","contribui","posteriormente,","Biolo","Local","anni","largu","semico","Estrel","deveri","existia","Romano","dessas","descrito","biol��gica,","altera�","freguesias,","freguesias.","seguintes,","carbono,","pr��ximo","dominan","poderiam","eletr��nica","simplesm","modifica�","agr��colas","Condeixa-a-Nova,","econ��mica","particularme","Gover","��C","canto","emit","ances","santos","substi","Arquime","planetas","permitem","padr�","padr��","igualme","inspira�","diferen��a","diferen��as","geogr��fic","Apost�","Bila","Lice","c��u","ferr","pe��as","amig","despo","tr��f","caste","mudan","aborda","habilita","divis��","est��m","desenvolveu","espaci","delas","reduz","qu��micos","ascis","envolvido","inventor","semelhante","intensa","derivados","impressi","verdadeira","esta����","individual","cat��lico","democr��tico","microsc��pio","Angel","Leopol","Propri","Sergi","d.C.","vit��","di��","petr","ondr","mol��","viveu","absor","gradu","Nazis","��rica","proced","simbo","disper","alto-","abriga","ordena","constru��do","especializ","realizadas","estrat�","baseados","distinto","altern","1822,","Newton","deixan","latino","setores","��ndic","cogni","montan","lidera","reforma","solu����","permaneceu","varia����","sistem��tica","contr��rio,","civiliza����","codifica�","justa","enxo","not�","pobre","peix","por��","inclusi","km2.","delim","pontif","Charl","encontrados","autom�","experimentos","governador","Golgi,","2011).","rom��","nobrez","Alberto","destinado","institui����","competi","decis��","Castelo","acontece","destrui","num��rico","instrume","Limitav","assuntos","verific","din��mico","calcular","crit��rios","equipamentos","behaviorism","Byron","Becque","Claude","Ensin","Ib��ric","J��pi","Joaqu","Manue","amare","volume","cad�","sedi","arua","guerra","batiz","ideal","Alfre","relev","minha","explica","provoca","chegada","dispon","Guarda","confun","lan��a","representant","��ndi","Qualq","europeia","s��lido","explorador","relacionadas","Camil","rosseg","ind��g","marinh","reinado","astron��","crescent","traduzi","laborat�","dramatu","fatores","Michel","cronolo","Natural","advogado","introduzi","mexica","igreja","patrono","adequad","respectivam","semana","garanti","car��t","facili","cative","bromela","tornando-","almeiras","consequ�","francesa","membrana","transferi","arara-azul-de-l","exclusiva","espiritual","hereditarie","predomina","filogen��","artesanat","dezessei","exerc��cio","doutrina","ensinamentos","candidato","m��ltiplas","secret��rio-","sin��nimo","distribui����","arquip��lago","Amesterd��o","sint��ticos","Abreu","Armin","Argenti","Babil","Bernar","Bretan","Ceuta","C��rdo","Dumont","Gr��o-","Hippo","Horiz","Munth","Moscou","Nobel","Nasceu","Pac��","Rober","Tuck","Traba","Venez","cent��m","ecol��","f��sseis","fragme","fertil","juiz","normas","sat��l","t��pi","requ","meado","enorm","naque","��rab","poemas","moment","monar","ve��c","vanta","virtu","vizin","adult","fevere","estando","parla","aclama","eucari","oriun","apesa","abando","absol","esteja","Alph","Allori","Algun","primit","l��qui","Por��","inamar","dif��ci","amea�","capitais","grandeza","Panam","gerais","racio","Capita","cultiv","cin��","Devido","Deuts","popula����","expuls","famil","medicam","sul-a","exemplar","mem��","novel","respira","categ","��nfas","comprov","implant","Alexan","��lvar","reserv","receit","definiti","suporte","especifi","encontra-s","conjec","representa��","disc��","apresenta��","pesquisador","permiss","planeja","denomina��","publicou","Paragu","condado","positi","destaqu","realiza��","reuni","contrast","filos��","equival","M��di","neg��ci","correspondent","mar��t","Geogra","agrofl","surgiram","orienta��","hebreu","Barroco","arque��","publica��","escritores","originalme","historica","m��xi","viaja","reconhecime","sucessiv","tropica","manipu","recupe","qualifi","designa��","internacionais","fazendei","fundamentais","funcioname","deixou","transmiss","vegetais","semelhan�","Literat","cober","taxon","anunci","manute","algorit","participa��","problemas","esfera","apreci","comercializ","arqueol��","atmosf��","contribui�","Biolog","Locali","annib","largura","semicon","Estrela","deveria","altera��","dominant","simplesme","modifica��","particularment","Govern","ancest","substit","Arquimede","padr��","padr��o","igualment","inspira��","geogr��ficas","Apost��","Bilac","Liceu","castel","mudan�","divis��o","est��mu","espacia","reduzi","impressio","esta����o","Angeles","Propri�","Sergip","vit��ri","di��me","petr�","mol��c","gradua","Nazista","dispers","especializa","estrat��","alterna","deixand","��ndice","cognit","montanh","solu����o","varia����es","civiliza����o","codifica��","enxof","por��m","inclusiv","delimi","pontif�","Charles","autom��","institui����o","decis��e","destrui�","instrument","Limitava","verifica","behaviorismo","Becquere","Ensino","Ib��rica","J��pite","Joaqui","Manuel","amarel","confund","representante","Qualqu","s��lidos","rossegu","ind��gen","astron��m","crescente","laborat��","dramatur","cronolog","mexican","respectivame","car��te","cativei","bromela�","tornando-s","consequ��","arara-azul-de-le","hereditarieda","filogen��t","artesanato","dezesseis","secret��rio-g","distribui����o","Argentin","Babil�","Bretanh","Horizo","Munthe","Pac��f","Robert","Tucker","Trabal","cent��me","ecol��g","fragmen","fertili","sat��li","meados","naquel","��rabe","momento","ve��cu","vantag","vizinh","feverei","parlame","eucari�","apesar","abandon","absolu","Alguns","primiti","l��quido","Por��m","amea��","Panam�","racion","Deutsc","popula����es","familia","medicame","sul-ame","mem��ri","catego","��nfase","comprova","implanta","Alexand","��lvares","reserva","definitiv","especific","encontra-se","conject","representa���","disc��p","apresenta���","denomina���","Paragua","positiv","destaque","realiza���","filos��f","equivale","correspondente","mar��ti","agroflor","orienta���","hebreus","arque��l","publica���","originalment","historicam","reconheciment","manipul","qualifica","designa���","fazendeir","funcionament","transmiss�","semelhan��","Literatu","cobert","manuten","algoritm","participa����","comercializa","arqueol��g","atmosf��r","contribui��","Biologia","Localiz","annibal","semicond","altera���","dominante","simplesmen","modifica���","particularmente","Governo","ancestra","substitu","Arquimedes","padr��es","igualmente","inspira���","Apost��l","castelh","mudan��","est��mul","impression","Propri��","vit��ria","di��met","petr��","mol��cu","estrat��g","deixando","cogniti","codifica���","enxofre","delimit","pontif��","autom��v","decis��es","destrui��","Becquerel","J��piter","confundi","Qualquer","astron��mi","laborat��r","dramaturg","cronologi","mexicana","respectivamen","car��ter","cativeir","bromela��","tornando-se","consequ��n","arara-azul-de-lea","hereditariedade","filogen��ti","secret��rio-ge","Argentina","Babil��","Bretanha","Pac��fi","Trabalh","cent��met","ecol��gi","fragment","fertiliz","ve��cul","vantage","fevereir","parlament","eucari��","primitiv","amea��a","Panam��","raciona","medicament","sul-ameri","mem��ria","categori","Alexandre","especifica","conjectu","representa����","disc��pu","Paraguai","filos��fi","mar��tim","agroflores","arque��lo","originalmente","historicame","reconhecimento","manipula","funcionamento","Literatur","manuten�","participa����o","comercializa�","arqueol��gi","atmosf��ri","contribui���","Localiza","semicondu","altera����","simplesment","ancestral","inspira����","Apost��li","castelha","mudan��a","est��mulo","di��metr","petr��l","mol��cul","estrat��gi","cognitiv","delimita","pontif��c","autom��ve","destrui���","laborat��ri","respectivament","cativeiro","bromela��n","consequ��nc","arara-azul-de-lear","secret��rio-gera","Babil��n","Pac��fico","cent��metr","ecol��gic","fertiliza","ve��culo","fevereiro","parlamenta","eucari��t","medicamento","sul-americ","especificam","conjectura","representa����o","disc��pul","agroflorest","arque��log","historicament","manuten��","comercializa��","semicondut","altera����e","simplesmente","inspira����o","Apost��lic","castelhan","di��metro","petr��le","mol��culas","pontif��ci","destrui����","laborat��rio","respectivamente","bromela��na","consequ��nci","secret��rio-geral","Babil��nia","cent��metro","fertilizant","parlamentar","eucari��ti","sul-america","especificame","agrofloresta","historicamente","manuten���","comercializa���","semiconduto","altera����es","Apost��lica","petr��leo","destrui����o","consequ��ncia","fertilizantes","eucari��tic","sul-american","especificamen","manuten����","comercializa����","semicondutor","especificament","manuten����o","comercializa����o","especificamente","\";","\"T","\"o","(B","(N","(c","(de","(no","(mais","):","-C","-e","-es","-os","-lo",".)",".,",".3",".�","120","2O","4-","48","5-","52","54","55","69","80","84","85","93","94","96","","refu","refra","alia","��rio","anop","reti","retr","mini","minas","tempes","interd","consig","II).","cane","partido","rena","rend","sobren","gerad","raca","desej","algas","comem","dia,","incer","lisos","lista","errad","vis�","depa","pele","vidas","procu","radu","���,","Dez","espera","anie","aniv","ambri","expl","conced","rara","alec","alent","sistemat","transc","trans�","esp��cie.","prove","proven","177","179","deca","decr","deva","propu","Am��ricas","medie","2,3","Am��rica,","Sep","estudi","gr��","termi","km/","inven","classes","cultura.","intu","153","158","1500","atuali","hier","norte;","deta","rigo","hosp","timo","comportamenta","outros.","geno","zoo","zool","constituc","tang","pai.","simi","simpa","ressa","comportamento.","m��dica","artis","infla","classic","futura","entrad","entrar","istor","Norte.","caul","atra�","titu","impul","disp�","Alek","ber�","��gu","detec","classificar","Arno","dente","ci��ncia,","significan","significari","entom","1931","passan","passar","caractere","Proj","Sul)","Sul.","cella","celest","fam��li","usav","principais:","per��odo,","16.","160","166","3,7","movimento\"","14.","148","14�","Chica","landa","exteri","incluir","reconq","encontram","encontrav","fam��lia.","greg.","volto","volum","arte.","planos","magne","experie","iniciat","iniciara","representam","observo","muita","��pi","m��tri","2001","astros","romanos","an��lise,","informar","cidente","13.","130","138","dour","varian","variado","povo\"","apresentan","direita","123","126","oficiais","selo","ceare","Consta","modera","denomino","109","reje","haven","obra.","governo,","evolui","evoluci","Atl��ntica","Popu","geom","integr","animais.","hoje,","Alemanha)","Alemanha,","banh","centro-","1921","1922","1923","1925","1929","formo","1896","1898","popular.","cient��ficos","consumo.","moderni","conjunta","resulto","Ann","Mono","1993","1994","1998","observar","corpora","Su��","Sudest","pree","pre�","curv","coste","empree","metr�","c��lula,","naturali","integral","Muh","Musi","finalme","gases","1917","perse","persis","Segura","considerados","totali","totalm","pr��prias","nacionais","comunica����","correspond","Ant��","afast","d��ci","nuv","reut","metaf","metan","legi","ensa�","minei","2021.","plantas.","organizado","organizada","rea����o.","situa-","situa��","conhecimento,","conhecimentos","6,4","Andra","digi","1961","colec","munic��pios.","objeto,","designe","celulares","Baixa,","��l","macr","macu","narra","negras","1901","1906","1855","1856","1857","relatos","religiosi","nacional.","nacionali","nacionalm","correspondend","circun","comunica����o,","Imp��rio,","Bela","Belo","Beja","resid","importante,","gregori","temperado","classifica����","Georg","Mund","Verme","aparent","mal,","leitu","agron","agrot","casam","quaisq","��tica","ingles","constituin","Jo��o,","p��blicos","surgime","portugu��s.","comerciai","aproxima�","administrar","1.��","XV,","celeb","outro,","outro.","social,","social.","necessit","dezen","latim,","latim:","relacionam","informa����o.","constru����o,","Constituci","Barb","Barra","Informa","Lud","frut","carib","incon","proteg","densa","1835","1838","1870","carro","menos,","indicar","utilizados","romances","levam","moderna,","eletr��","Igreja,","Europeia,","relativi","natureza.","conquisto","Nevi","finais","historio","pensado","ervas","altam","sement","litar","turf","tur��","espon","caso,","Concl","quilo","eventu","estrei","cient��fica.","controv","homem,","Entret","arquiv","presidente,","tecnol�","associada","documenta","250","Buu","Leon","aqueci","sonda","ouro.","beato","Algum","grava","grave","imagi","radia","destil","referin","diversas,","dentre","Guerras","Johns","superv","Baham","referen","designad","estimat","projeta","aplica����","M��xico,","M��xico.","ingl��s,","poss��vei","temperaturas","Berk","Cam�","Campe","Isto","Pr��m","Tabe","anteriorm","c��ni","ocidental,","ves�","��rb","terre","1882","f��sico,","f��sico-","simpli","extrat","Verde,","s��rie,","vis��o.","espanh�","naturais,","Espanho","...","Ferr","XX,","antib","barb","susp","manej","escura","humanos,","humanos.","cientif","cultural.","econ��","confia","sociais,","sociais.","compostad","metros.","experimentai","experimentam","descobertas","identificar","identifica�","solar,","solar.","a.C..","l��dere","respeita","Agro","Agric","Hoo","cobr","alfa","tomar","tomada","ouvi","promu","exce��","manua","Contra","chegar","religi��","determinada","planeta,","planeta-","planeta.","distin�","Santos,","Catarina,","Catarina.","Algardi","imagem","alcanc","participam","participar","caracterizad","Francisco.","global.","interpretan","g��neros","consci�","inspir","Ci��ncia","profiss��","permitiu","permitira","corridas","personal","engenharia,","Oliveira,","estrangeira","(Ano","Jagu","idade,","idade.","ocupa��","��ne","ermi","alma,","di����","desac","desaf","impac","etc)","mediant","gen��ri","eletroma","continentai","come��an","come��ara","datam","data�","estabelecera","estabelecim","el��trica.","disciplinar","revoltos","documentos","Ambros","transforman","presentes","n��veis","descobrim","descobrir","diferenci�","cavale","componente","administrativo","superiores","Belg","Belgi","byte","efeti","restri�","orto","citada","irm��o","cont��","1815","ra��z","visam","Deus\"","especta","comparad","comparado","devere","tradu�","��ndias","alterado","alem��o.","hist��ricos.","internacional.","afirmar","quadrad","complexos","pr��ximos","pr��ximas","dominad","dividido","separad","capitalist","dimensi","combinam","manifesto","Berlim,","liter��rio","liter��rios","liter��rias","crescimento,","Milita","Mong","Toda","Trata-","atende","f��-","jornais","precip","sat��","s��tim","emig","sexu","patri","nota�","��cido","analf","sinto","moral","morav","assum","subsis","cr��tic","diferentem","planet��","produto.","famosas","promo��","determinados","teatra","aparecem","hidrog��","decorr�","Organic","elevada","Unidas,","adaptado","mec��nica,","artigos","concord","Mundial,","personagen","Canad��,","��frica,","Nacional,","Davi","c��re","ferme","fatos","facul","herdad","venda","reba","alqu","nomes","armo","��pi","��pti","tr��s","ter��","ter��","mudar","abor�","divis�","desenvolver","dela,","te��l","morto","tratados","interno.","metro,","Muitas","estatu�","encef","dividem","oriental,","capazes","associados","aqueles","atinge","envolvida","continental,","Aveiro,","intensi","mostrar","maneiras","fotogr","alcan��ado","alcan��ada","incorporar","incorporado","acreditam","It��lia.","Oriente","urbanas","urban��","regulam","informa����es.","poesia.","gera����","espiriti","Ambr��sio,","essenciai","qu��ntica","isl��mica","potenciai","suficientem","americano,","tradicionai","(IS","Leona","Maias","Maior","Nash","Princi","Serge","bacha","c��no","falam","koin��","���","emo��","soft","obtido","habitadas","Nazar","biomo","biom��","canal","gerador","gerados","procede","simb�","dispen","discur","discus","tornar-","Par��,","abrigo","constru��d","cabel","microb","religiosas","distinta","alimentado","europeus,","anteriores,","anteriores.","controle,","Costa,","��ndico","manifesta-","cogno","alimentos,","entendim","entendido","lidero","conclui","conclu�","reform","inclu��da","catali","catal�","h��bito","solu���","pioneir","varia����","formula�","Ferreira,","Murphy.","sistem��tico","civiliza���","Bande","Dioc","Magda","Martinh","Nordeste,","Peru","Praga,","adicionado","bilh��o","golpe","testem","���","riva","redor","��uc","arran","pedre","ourn","exau","regem","Marie","Marin","inset","concedeu","socioc","utilizadas","��sia,","recep�","deu-l","construir","construiu","Roma,","modernos","Societ","ambientai","ambiental","produzidas","Mundo\"","cl��ssicos","espec��ficos","oxig��","dependent","significativam","assenta","assente","concorre","concorr�","lunares","transmitido","dedicad","estudante","enviado","enviada","agrupame","arquiteto","Testamento.","profunda","evolutiva","Viena,","raz��o,","avaliar","Primeira","clim��tic","art��stico","espalhado","legislat","intera����","prote��nas,","Assembly","Pushkin,","s��mbolos","cer��mica","part��culas","astronomia,","psicologia,","desempenha","recomendad","propriet��rio","propriet��rios","Groen","Itap","Medio","Silv","Standa","Teoria","Volta","Velh","antec","bases","oferece","ofereci","pulm","venera�","��rv","polar","custo","exames","examin","perfe","perfor","mandat","Espla","entreta","entrete","can��","algari","demai","deman","Compu","prop��","prop��","est��ti","est��tu","Procl","Prov�","confec","cursos","coleta","coleti","produzidos","Antiga,","telev","cadeia","cadeir","citop","1980,","tabel","taber","radioa","nascidos","adotada","adotado","declarada","declarado","aprend","aprende","restrita","restrito","materialida","imperat","imperado","decorrer","atingir","desenhos","esporti","universal.","Egito,","cozin","camadas","nativa","obriga�","colabora�","argumentos","benef�","paleont","diplom","diploma","sujeita","abolici","aboli��","Estudou","concentra�","recentem","tornaram-","conselho","numerosa","numeroso","resiste","hidrosf","hidrost","Conceito","atribu��do","atribu��da","divindades","Paran��,","infe����o.","Uppsala,","concelhos","criativo","m��quina","m��quinas","Amazonas,","prim��ria","armazenam","org��nica","proeminente","proeminentes","astrof��sic","astrof��sico","Antiguidade,","juda��smo,","Bras��lia,","Con��mbriga,","metropolitana.","norte-americano","Darw","Destac","Galiz","Gibb","Melb","aristot","bulla","claro","germ�","jul.","oposta","praze","russ","cora�","cifra","roedo","patent","deslo","paradi","prisi","neolo","baiana","2018,","Regio","primat","jurisd","biogra","interve","coment�","repar","humanida","Estat�","2012,","genera","Portugues","viviam","profet","encontrara","consumido","variadas","Royal","Beiras)","Andrea","Frances","1954)","judaic","consistia","revolu�","padron","��rg��","extract","extra��","convenc","adotara","existiam","emiti","amigo","despor","tr��fi","habilita�","cat��licos","Leopoldo","absorv","procedi","liderad","justam","peixe","num��ricos","aruaque","relevo","provocado","Guarda.","��ndic","Camille","marinhas","Michele","introduzido","adequado","facilita","transferiu","exclusivame","predominan","Bernard","t��pico","enormes","oriunda","estejam","Capitan","cultivo","exemplares","novelas","respira�","permiss��","M��dia","m��xim","tropical","recupera","taxono","esferas","espacial","Angeles,","gradual","especializado","montanho","verificar","naquele","vizinhos","abandono","l��quidos","Deutsch","positivi","realiza����","orienta����","fazendeiro","transmiss��","semelhan��a","dominantes","substitui","Arquimedes,","impressiona","codifica����","confundid","astron��mic","Trabalha","fragmenta","Paraguai,","mar��tima","manipula�","atmosf��ric","estrat��gic","cognitiva","Pac��fico.","ecol��gico","medicamentos","disc��pulo","castelhana","laborat��rios","respectivamente.","agroflorestal","(censos","Averr","Adolf","Beato","Facul","Godof","Ritc","Sistemas","Torno","US$","cumpri","imerso","linhi","l��gica","palcos","predica","senhor","sangue","valida","���","deba","dogm","doze","pot�","arce","eixo","fogo,","cloro","antrac","reage","chuv","Alves","habitual","rec��","Conten","evang","Manau","matric","torci","subje","unifi","minut","sobrepos","oferta","a��orda","ib��ric","cinza","Common","repub","concep�","azeite","alego","transi�","prov��m","alago","Sebast","terap�","simul","resson","��ust","anexa","1654","suprem","Carbo","extin��","bem-es","registou","cristal","parece","paredes","existentes","publicida","mant��","perspe","metabo","setentr","1853,","Behavio","comerciante","XVII,","XVIII,","secun","universit","tabul","Tanak","aumentar","protoco","prot��","assala","cartazes","percebe","permanente","cavalo,","cont��m","atua����","nomeadam","semi��","italianos,","Paulista","ascend","escolhi","converg�","converte","regularm","cl��nica,","reproduzi","comando","ilus��o","melhorame","Henriq","reenca","inserida","Christin","oxig��n","precisam","restaura","pecul","estadua","Antonio","adquiridos","espectrosco","demonstrado","resolve","belgas","cosmol","ideolo","inteiram","Medicin","batizado","virtudes","Sergipe.","equivalente","eucari��ticas,","Jean-","Mesop","Possui","blocos","daque","tarefa","expans","perpen","abra��","Alem��o","Contine","Para��b","culmina","in��mera","tardia","poderosa","eletrici","externa","apresentadas","morfol","circular","or��am","angelis","decompo","trabalhadore","protesta","industriais,","contribu��ra","analisar","manteve-","Bronzino,","certament","legisla����","end��mica","Bromeli","Polytec","pseud��","sum��rios","percorre","batalha","abundante","difundi","pobreza,","cin��tica","Bol��via,","Despacho,","eficiente","fosfores","jur��dico","eclesi�","fortalec","Considera","infinit","emp��rico","ingresso","metodol�","progresso","confirmado","diversificada","compara����","riqueza","australia","jesu��ta","vest��gios","ex��rcito","observ��vel","complementar","carn��vor","sequ��ncia","Estremadura,","reprodu����o","lucrativo","exposi����","Venezuela,","Floren��a,","oportunidades","interdepende","reconstru��","escava����","astr��nomo","hidrogr��fica","Apostolicae","diagn��stico","alto-falante","aglomera����","farmac��utic","Inicialmente,","biotecnologia","\"0\"","AT&T","Astro","Aut��","Alagoas","Bas��","Cear��","Cultu","Corint","Creat","Clement","Casimi","D��o-","Descob","Discip","Eduar","Engen","Equado","Econom","Fribu","Freder","Homin","H��gira","Incl","Juaz","Jardim","M��si","Madei","Malch","Matth","Niter�","Nascido","Orino","Oparin","Pinhal","Pal��ci","Psittac","Scho","Surgi","Salvado","Trans","T��me","Turqu","Tasm�","Urgel","Window","Zel�","antico","acabam","briga","bisav","crise","crosta","dinhe","fon�","ferram","glauc","gent��l","hulha","jardin","lembra","m��gi","m��ve","nucle","pragas","s��nt","tronco","usu��","v��de","v��cuo","��ngst","coqu","caat","qubi","name=","��tom","podia","turis","onze","soter","sonora","moeda","modal","giga","fiel","vetor","vibra","riach","cupou","proib","ilumin","exporta","para��","ecret","id��nt","pri��","neerl","ramif","��til","compil","consag","tra��","agulh","ver��o","parques","actri","denis","beatos","rudime","abarca","bo��m","calor","Estoco","Espose","carpi","Alessa","regime","japon","favor","fatia","estu��","Refere","pl��s","Conju","distant","Covil","Ma��ra","Matem�","Macap�","Marech","trinta","popularida","Noite","infant","habitava","��lbu","subtro","subesp","est��d","capinc","judeu","ju��z","��cole","seguindo","unit��","concre","Natio","biodi","capit��","refug","tempest","interdi","consigo","gerada","vis��","depar","esperan","aniver","expl��","concedi","alece","alente","trans��","proveni","decre","mediev","2,3%","estudio","gr��f","termin","km/h","inven��","intui","hier�","detal","rigor","zool��","constituci","tange","simila","simpati","inflama","classici","entrada","impuls","disp��","ber��","detect","Arnol","dentes","significando","significaria","passando","caracteres","Proje","cella,","fam��lias","usavam","Chicag","exterio","reconqu","encontrava","voltou","volumes","magnet","iniciati","iniciaram","observou","��pico","doura","variando","variados","apresentando","oficiais.","cearen","Constant","denominou","rejei","havendo","evolucio","Popula","formou","modernis","resultou","1998,","Su����","Sudeste","curvas","costei","empreen","metr��","naturalis","finalment","perseg","Seguran","totalme","comunica����es","Ant��n","nuvem","reutz","metaf�","metano","legiti","ensa��","situa-se","6,4%","digita","coleci","designer","��lhav","narrat","1855,","religiosida","nacionalida","nacionalme","correspondendo","gregoria","classifica����es","Mundia","Vermel","aparente","leitura","agrot�","casame","quaisqu","inglesa","constituindo","surgiment","comerciais","aproxima��","celebra","necessita","dezena","Constitucio","Ludw","eletr��es","relativida","conquistou","historiog","pensador","altame","turfa","tur��s","espong","Conclu","eventua","controve","Entreta","tecnol��","Buuren","aquecim","destila","referindo","supervis","Bahamas","designado","estimati","aplica����es","poss��veis","Berke","Cam��","Campeo","Pr��mi","Tabela","anteriorme","ves��","��rbi","terren","f��sico-q","espanh��","Espanhol","Ferro","antibi","suspen","escura,","cientifi","econ��m","compostada","experimentais","identifica��","l��deres","Agricu","Hook","cobre","promul","manual","religi��es","distin��","alcance","caracterizada","interpretando","consci��","inspiro","profiss��o","permitiram","(Anodo","Jagua","ocupa����","di����o","desace","desafi","impacto","mediante","eletromag","continentais","come��ando","come��aram","data��","estabeleceram","estabelecime","transformando","descobrime","diferenci��","cavalei","administrativos","efetiv","restri��","cont��n","ra��ze","Deus\",","espectado","comparada","deveres","tradu��","quadrada","separada","dimensio","Militar","Mong�","Todav","Trata-s","f��-lo","precipi","sat��ri","s��timo","emigra","nota��","analfa","sintom","morava","cr��ticas","diferenteme","planet��ri","promo����","teatrai","hidrog��n","decorr��","concorda","personagens","David","c��reb","ferment","faculda","herdada","alqui","armon","��pico","ter��o","abor��","te��lo","estatu��","encefal","mostrara","fotogr�","urban��s","regulame","gera����e","espiritis","essenciais","potenciais","suficienteme","tradicionais","(ISO","Leonar","Princip","bachare","c��non","emo���","softw","Nazar��","biomol","biom��d","simb��","dispens","discurs","discuss","tornar-s","constru��da","microbi","manifesta-s","cognom","entendime","liderou","conclu��","catal��","solu����","pioneiros","varia����o","formula��","civiliza����","Bandei","Dioces","Magdal","Martinho","testemu","arranj","pedreg","Marinh","insetos","sociocu","recep��","deu-lh","Society","ambientais","oxig��n","dependente","significativame","concorr��","agrupament","clim��ticas","legislati","intera����e","recomendada","Groenl","Itapi","Mediola","Standar","pulmo","venera��","��rvor","examina","perfei","performa","mandato","entretan","entreten","can��n","algaris","demais","demand","prop��s","prop��e","est��tic","est��tua","Procla","Prov��","coletiv","televi","cadeira","citopl","tabern","aprendi","materialidade","imperador","cozinh","obriga��","colabora��","benef��","paleonto","diplomas","abolicio","aboli����","concentra��","recenteme","tornaram-s","numerosas","numerosos","resisten","hidrosfe","hidrost�","armazename","astrof��sica","Darwin","Galiza","Gibbs","Melby","germ��","prazer","cora��","roedor","patente","desloc","paradig","prisio","neolog","Region","primatas","jurisdi","biograf","interven","coment��","humanidade","Estat��","general","Portuguesa","encontraram","Francesa","judaica","revolu��","padroni","��rg��os","extracto","convenci","adotaram","desport","tr��fico","habilita��","liderada","exclusivament","predominant","Capitani","respira��","permiss��o","m��ximo","taxonom","montanhos","positivis","realiza����es","orienta����o","transmiss��o","codifica����o","confundida","astron��mica","manipula��","atmosf��rica","cognitivas","castelhanas","Averr�","Faculda","Godofr","Ritch","Tornou","cumprir","predicado","debat","pot��","arceb","antraci","reagent","habitualme","rec��m","Content","evange","Manaus","matricu","torcida","subjeti","unifica","minutos","Commons","republ","concep��","transi��","alagoa","terap��","simulta","resson�","��ustri","1654,","supremo","extin����","bem-est","publicidade","mant��m","perspec","metabol","setentri","Behaviori","secund","universit�","Tanakh","protocol","prot��es","atua����o","nomeadame","semi��t","ascend�","escolhido","converg��","regularme","melhoramen","Henriqu","reencar","Christine","oxig��nio","precisame","peculia","estadual","espectroscop","cosmolo","ideolog","inteirame","Medicina","Mesopo","daquel","perpend","abra��m","Continen","Para��ba","in��meras","eletricida","or��ame","decompos","trabalhadores","protestan","contribu��ram","manteve-s","certamente","legisla����o","Polytech","pseud��n","fosforesc","eclesi��","fortaleci","ingressou","metodol��","compara����o","australian","jesu��tas","carn��voros","lucrativos","exposi����o","interdependen","reconstru��d","escava����e","aglomera����o","Aut��no","Bas��l","Corinth","Creati","Clemente","Casimir","D��o-L","Descobr","Discipl","Engenh","Equador","Fribur","Frederi","Homini","Inclu","Juazei","M��sica","Madeir","Malcher","Niter��","Orinoco","Pal��cio","Psittaci","Salvador","T��meg","Turqui","Tasm��","Windows","Zel��","bisav�","dinhei","fon��","ferrame","glaucu","gent��li","s��ntes","usu��ri","v��deo","��ngstr","coque","caati","qubit","��tomos","turism","soterra","modali","proibi","iluminis","para��s","id��nti","pri��es","neerla","ramifi","compila","tra��a","agulha","actriz","denisd","rudiment","bo��mi","Estocol","Esposen","Alessan","estu��r","pl��sti","Covilh","Ma��ra\"","Matem��","Macap��","Marecha","popularidade","subtrop","subesp�","est��di","capinch","judeus","unit��ri","concret","Nation","biodiv","refugi","tempesta","vis��v","depart","anivers","expl��ci","concedid","alentej","trans��s","provenie","medieva","estudios","gr��fi","intuit","hier��","detalh","zool��g","constitucio","classicis","disp��e","ber��o","detecta","Arnold","Chicago","exterior","reconqui","iniciativ","dourad","cearens","evolucion","modernist","Su����a","costeira","metr��p","naturalist","finalmente","persegu","Seguran�","totalment","Ant��ni","metaf��","legitim","ensa��s","colecio","narrati","religiosidade","nacionalidade","nacionalment","gregorian","Mundiais","Vermelh","agrot��","casament","quaisque","surgimento","aproxima���","dezenas","Constitucion","Ludwig","relatividade","altament","tur��sti","espongi","Conclu��","eventual","controver","Entretan","tecnol��g","aquecime","estimativ","Berkel","Cam��es","Campeona","Pr��mio","anteriormen","ves��c","f��sico-qu","espanh��i","antibi�","cientific","econ��mi","identifica���","Agricul","Hooke","promulg","distin����","consci��n","inspirou","(Anodor","Jaguari","ocupa����o","desacel","desafio","eletromagn","data���","estabelecimen","descobrimen","cavaleir","efetiva","restri���","cont��nu","ra��zes","espectador","tradu���","dimension","Mong��","Todavi","Trata-se","precipit","sat��rico","nota����","analfab","sintoma","diferentemen","promo����o","teatrais","hidrog��ni","decorr��n","c��rebr","fermenta","faculdade","alquim","armonia","��picos","abor��g","te��log","estatu��r","encefalo","mostraram","fotogr��","urban��sti","regulament","gera����es","espiritism","suficientemen","bacharel","emo����","softwa","biomol��","biom��di","simb��li","tornar-se","microbio","manifesta-se","cognome","entendimen","solu����es","formula���","civiliza����es","Bandeir","Diocese","Magdale","testemun","arranjo","pedregos","sociocul","recep���","deu-lhe","oxig��ni","significativament","concorr��n","agrupamento","legislativ","intera����es","Groenl�","Mediolano","Standard","pulmona","venera���","��rvores","entretant","entreteni","can��ni","algarism","prop��si","Proclama","Prov��n","televis","citoplas","cozinha","obriga���","colabora���","benef��ci","paleontol","abolicion","aboli����o","concentra���","recentemen","tornaram-se","resistent","hidrosfera","hidrost��","armazenament","Melbye","germ��n","cora���","desloca","paradigm","prision","neologis","Regional","jurisdi�","biografi","interven�","coment��r","Estat��s","generali","revolu���","padroniz","convencio","desporto","habilita����","exclusivamente","predominante","respira���","taxonomi","positivism","manipula���","Averr��","Faculdade","Godofre","Ritchi","Tornou-","debate","pot��n","arcebis","antracit","reagentes","habitualment","evangel","matricul","subjetiv","unificado","republi","concep���","transi���","alagoan","terap��u","simultan","resson��","��ustria","extin����o","bem-esta","perspect","metaboli","setentrio","Behavioris","secund�","universit��","protocolo","nomeadament","semi��ti","ascend��","converg��n","regularment","melhorament","reencarn","precisament","espectroscopi","cosmolog","ideologi","inteiramen","Mesopot","perpendi","abra��mi","Continent","eletricidade","or��ament","protestant","manteve-se","Polytechn","pseud��ni","fosforesc�","eclesi��s","metodol��g","australiano","jesu��tas.","interdependent","reconstru��da","escava����es","Aut��noma","Bas��li","Corinthi","Creativ","Casimiro","D��o-La","Descobri","Discipli","Friburg","Frederic","Juazeiro","Madeira","Niter��i","Psittacida","T��mega","Turquia","Tasm��n","Zel��n","bisav��","dinheir","fon��g","ferramen","glaucus","gent��lic","s��ntese","usu��rios","��ngstr�","caatin","turismo","soterrado","modalid","para��so","id��ntic","neerlan","ramific","denisda","Estocolm","Esposende","Alessand","estu��ri","pl��stico","Covilh��","Matem��t","Macap��,","Marechal","subtropi","subesp��","est��dio","capincho","unit��rio","National","biodiver","tempestade","vis��ve","departa","anivers�","expl��cit","concedida","alenteja","trans��st","provenient","estudioso","gr��fico","hier��r","detalhe","zool��gi","constitucion","classicism","reconquis","iniciativa","evolucionis","modernista","metr��po","naturalista","Seguran��","totalmente","Ant��nio","metaf��s","legitimi","ensa��sta","colecion","narrativ","nacionalmente","gregoriano","agrot��x","casamento","quaisquer","aproxima����","Constituciona","altamente","tur��stico","espongif","Conclu��do","eventualm","controvers","Entretant","tecnol��gi","aqueciment","estimativa","Berkele","Campeonat","anteriorment","ves��cu","f��sico-qu�","espanh��is","antibi��","econ��mic","identifica����","Agricult","promulga","distin����o","consci��nc","(Anodorh","Jaguarib","desacele","data����","estabeleciment","descobriment","cavaleiros","cont��nuo","tradu����","dimensiona","Mong��l","Todavia","precipita","nota����o","analfabe","sintomas","diferentement","hidrog��nio","decorr��nc","c��rebro","fermenta�","alquimis","estatu��ri","encefalop","fotogr��f","espiritismo","suficientement","emo����es","software","biomol��c","biom��dica","simb��lico","microbiol","entendiment","formula����","Bandeira","Magdalen","testemunh","pedregoso","sociocult","recep����","oxig��nio","significativamente","concorr��nc","Groenl��","pulmonar","venera����","entretanto","entretenim","algarismos","prop��sit","Proclama�","Prov��nci","citoplasm","colabora����","benef��cios","paleontolo","abolicionis","recentement","resistente","hidrost��t","armazenamento","germ��ni","cora����","paradigma","prisione","neologism","jurisdi��","biografia","interven��","coment��ri","Estat��st","generaliz","padroniza","convencion","habilita����o","respira����","positivismo","manipula����","Averr��is","Godofred","Ritchie","Tornou-s","arcebisp","habitualmente","evangelh","republica","concep����","transi����","terap��ut","simultane","resson��n","bem-estar","perspecti","metabolis","setentrion","Behaviorism","secund��","universit��ri","protocolos","nomeadamente","ascend��n","converg��nc","regularmente","melhoramento","reencarna","precisamente","espectroscopia","cosmologi","ideologia","inteirament","Mesopot�","perpendic","abra��mic","or��amento","protestante","Polytechni","pseud��nim","fosforesc��","eclesi��st","metodol��gi","interdependente","Bas��lio","Corinthia","Creative","D��o-Laf","Descobrim","Disciplin","Friburgo","Psittacidae","Tasm��ni","Zel��nd","dinheiro","fon��gra","ferrament","gent��lico","��ngstr��","caating","modalida","id��ntico","ramifica","denisdad","Estocolmo","Alessandr","estu��rio","Matem��ti","subtropica","subesp��c","biodivers","tempestades","departam","anivers��","expl��cito","alentejan","trans��sto","hier��rq","detalhes","zool��gico","constituciona","classicismo","reconquist","evolucionista","metr��pol","Seguran��a","metaf��si","legitimida","narrativa","agrot��xi","aproxima����o","Constitucional","espongifo","eventualme","Entretanto","aquecimento","Berkeley","anteriormente","ves��cul","f��sico-qu��","antibi��t","identifica����o","Agricultu","consci��nci","(Anodorhy","Jaguaribe","desaceler","data����o","estabelecimento","descobrimento","tradu����o","dimensionais","Mong��lia","Todavia,","precipita�","analfabet","diferentemente","decorr��nci","fermenta��","estatu��ria","encefalopa","fotogr��fi","suficientemente","biomol��cu","entendimento","formula����es","Magdalena","sociocultu","recep����o","concorr��nci","Groenl��n","venera����o","entretenime","prop��sito","Proclama��","Prov��ncia","colabora����o","paleontolog","recentemente","hidrost��ti","cora����o","prisionei","jurisdi���","interven���","coment��rio","Estat��sti","generaliza","convenciona","respira����o","manipula����o","Godofredo","Tornou-se","republican","concep����o","transi����o","terap��uti","simultanea","resson��nc","perspectiv","metabolism","setentriona","secund��ri","ascend��nc","converg��nci","reencarna�","cosmologia","inteiramente","Mesopot��","perpendicu","abra��mica","Polytechniq","pseud��nimo","fosforesc��n","eclesi��sti","metodol��gic","interdependentes","Corinthian","D��o-Laf�","Descobrime","Tasm��nia","Zel��ndia","fon��graf","ferramenta","��ngstr��m","caatinga","modalidade","id��nticos","ramifica�","denisdade","Alessandro","subesp��ci","biodiversi","departame","anivers��ri","trans��stor","hier��rqu","zool��gicos","constitucional","reconquista","metr��pole","metaf��sica","legitimidade","agrot��xico","espongifor","eventualmen","Entretanto,","ves��cula","f��sico-qu��m","antibi��ti","Agricultura","consci��ncia","(Anodorhyn","desacelera","dimensionais,","precipita��","decorr��ncia","fermenta���","encefalopat","biomol��cul","sociocultura","concorr��ncia","Groenl��nd","entretenimen","Proclama���","paleontologi","hidrost��tic","prisioneir","jurisdi����","coment��rios","Estat��stica","terap��utic","simultaneam","resson��nci","metabolismo","setentrional","ascend��nci","converg��ncia","reencarna��","Mesopot��m","perpendicul","Polytechniqu","fosforesc��nc","eclesi��stic","metodol��gico","D��o-Laf��","Descobrimen","fon��grafo","ramifica��","subesp��cie","biodiversida","departamen","anivers��rio","trans��store","hier��rqui","agrot��xicos","espongiform","eventualment","ves��culas","f��sico-qu��mi","antibi��tic","(Anodorhync","desacelera�","precipita���","encefalopati","biomol��culas","sociocultural","Groenl��ndi","entreteniment","Proclama����","paleontologia","hidrost��tica","jurisdi����o","simultaneame","resson��ncia","ascend��ncia","reencarna���","Mesopot��mi","perpendicula","Polytechnique","fosforesc��nci","eclesi��stica","D��o-Laf��es","Descobriment","fon��grafos","ramifica���","subesp��cies","biodiversidade","departament","trans��stores","espongiforme","eventualmente","f��sico-qu��mic","antibi��tico","(Anodorhynch","desacelera��","precipita����","encefalopatia","Groenl��ndia","entretenimento","Proclama����o","simultaneament","perpendicular","fosforesc��ncia","Descobrimento","ramifica����","departamento","f��sico-qu��mica","antibi��ticos","(Anodorhynchu","desacelera���","precipita����o","simultaneamente","ramifica����o","(Anodorhynchus","desacelera����","\"\"","\">","\"L","\"S","\"de","\"do","\"da","\"em","\"um","\"ge","\"come","\"brasileiro","\"computador","\"terra","\"filosofia","\"liberdade\"","\"Velh","\"bulla","'b","'i","(M","(R","(T","(e","(x","(in","(na","(uma","(ver","(ao","(n��o","(tamb��m","(Os","(at��","(s��culo","(m��di","(munic��pio","(apenas","(al��m","(hoje","(30","(qu��mica","(moderna","(incluindo","(comprimento","(The","(dados","(Vila","(Hist��ria","(papa","(Paris,","(2005","(1945)","(1892","(2011).","(correspondente","(y/","(149","(1920","(1908","(...",")2",",2",",3","-2","-5","-6","-7","-8","-D","-F","-G","-O","-T","-W","-i","-t","-v","-�","-do","-ra","-ma","-17",".0","/2","/b","/p","0%","0-","01","08","0),","10,","1197","1182","1126","38","3;","35,","340","49","416.","622","73","77","7),","700","89","978",":\"","","fem","f��","f��","fio","f��","fras","flora","ferv","finas","farm","frota","festiv","fra����o","gh","gri","ger","g��","gl��","gastro","genti","gal�","ger�","g��ne","galego","hes","hal","hia","hum","h��","h��b","hard","hindu","hemis","harmonia","i;","ire","i��","ier","ial","i��","ili","inti","imens","iterat","ilegal","jk","j��","jan","kk","ky","kra","kes","kos","km,","kep","l'","lb","lf","lde","lda","lent","l��","l��","lenh","lend�","lumin","m\"","m2","mn","mbi","miss","mour","n'","n��","ndu","nua","nut","norma","ode","ola","ovo","odor","ocorrida","ocupou","p,","pis","p��","pti","pto","p��","p��o","ple","p��","pica","pros","p��s","ptica","prem","pian","p��s","pesco","pasta","palma","pesar","precurs","preve","pp.","pasto","pascal","p��ss","qip","rco","rre","r��","restava","restam","sf","sco","sci","sen","sinc","s��ti","sala","stel","sumo","salva","t)","t�","tte","tin","tist","trez","treino","treinado","t��picos","uj","uro","una","unan","v,","vs","vu","vna","vic","vist","v��l","vinda","vinha","vasto","vestu��rio","wl","wn","wan","xis","xin","xemb","z/","zent","��","���","��","��","��","���","��","�J","��","��","�.","�,","�u","��","�os","�-","�ni","��","��","��","�ci","�me","�qu","�lo","��","��","��","�r","��","�ca","�.","�to,","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","���","��","���","��","��","��","deq","doa","es-","esv","nt-","da-","dai","os;","as\"","rij","rik","ril","rip","riu","rint","ma.","map","max","maco","ca;","re:","reo","rey","��-","��.","��s","��es","tag","isra","isco","orf","orq","orr","cido","cies","meo","��b","��q","��re","err","eru","erma","erme","alp","al��","enu","ink","inri","inor","rob","rod","roz","roda","em,","tida","tiro","nado","nais","iant","ia��","toc","toca","��o","��da","��te","pag","pata","noe","noto","��-","��n","lay","lais","laci","la��","poi","lid","lie","lik","lima","li��","loc","lod","lot","anis","anci","iov","ioma","si,","si.","queo","queda","queri","dic","dica","di��o","tul","tus","tut","tuv","tuno","arb","aros","arme","niz","ni��","nito","peda","nte.","onal","dos,","dos.","dosi","ou,","oub","ice","icu","ic��","stin","st��","lez","leci","ul�","��li","��pe","eij","ith","it�","it��o","so-","sop","soma","mob","molo","modos","ado.","adop","fib","fito","fila","sue","suf","sug","sun","su��","sula","suni","suic","veto","por:","porc","porco","mila","mile","desm","vaz","vaci","ncre","ncer","ceri","ceti","resa","vie","vig","vide","gulo","��-","foci","fome","fono","ria.","rian","elh","ell","el��","ello","elle","cura","cuti","culo","cut�","ator","atest","pron","prome","un��","ill","ranj","rank","exo","sau","sax","sant","sa��","geri","gela","geol","gaul","adj","adia","ad��","paral","eck","usas","usin","usou","usam","pior","tr�","tr��","tr��","hori","hoei","homo","uidos","voz","vont","voos","vore","voto","voou","duqu","dula","duque","dust","duras","ndon","idio","luta","luso","neu","neto","nela","nele","feb","istm","bito","bipo","mbu","mbal","cons�","gola","reg.","regr","reg�","��m","mais.","temi","serra","contu","etni","obe","ag��","��que","vert","verte","ricas","parc","parci","cler","pux","puni","puram","ralt","acr","acti","acha","acres","dend","euc","euf","beb","beque","bele","dore","dorm","doro","suav","perd","perde","perda","bara","baci","ba��","s��o,","ip�","18)","18�","mando","ap��","anth","abas","abre","abin","abst","abel","pr��","mast","reab","��ni","boca","bono","bot�","pelag","calh","m��n","2000","chan","quare","cidade)","Alas","Alme","Alla","rate","n��o,","jain","ele,","elec","eleg","graf","entreg","fau","fari","fama","face","faria","favo","estuf","Ree","Reis","Recon","Rece","Repu","primo","ritm","cape","iev","colh","���","aven","avia","avent","Em��","Conf","Conh","formai","formara","adep","dism","Brasil;","Brasili","��cn","brev","hab.","aume","budis","l��ci","Comb","Coper","cien","Mata","Mano","Maio","Maga","mata","matu","matas","inf�","infra","plate","plata","mar,","marf","marg","sobe","menci","mesa","empl","��lis","subf","subp","subco","subca","subte","subse","sub��","inat","inade","jud","juv","juram","presa","preso","fundi","esan","segue","unic","uni��o","conci","desca","biome","xiit","alic","alin","tives","��pci","polu","polis","interl","interm","inters","grandem","II.","II),","Pari","Panta","Paula","cani","partiu","Asso","Assu","renc","reno","rens","renu","rende","filma","of��","inge","s��c.","deser","deir","alg��","diar","estudo,","a���","lisa","asei","chamam","chamav","Cate","depr","dep�","culin","eg��p","vida\"","insis","logia","Com��","Compa","Comit","atuan","nome,","nome.","nomen","munici","Deo","Dedi","etan","etap","ca��","repe","Am��l","met�","espes","mel\"","mel.","onde,","c��lt","mil�","diferem","isse","inida","tican","popula����o,","medu","ranca","sistema,","soci�","provis","ciento","utilizo","processa","17,","propi","propo","mater","medin","medi�","2,2","2,5","perig","pol��ma","Sede","sul.","sulco","portab","embu","km.","invo","contis","contido","tempora","alguma","cultura,","estudad","150","152","blina","carai","carav","hiper","deti","recoc","conting","continh","reme","reves","meia","diverso","divers��","outros,","delp","compul","comba","comportamento\"","ribos","siga","mesmo.","teol","istol","primeiro,","primeiro-","milhar","21,","Norte-","rios,","atrai","aplic","cercada","exemplo:","comunis","comunit","r��d","tech","tect","impri","pr��s","corret","signos","Aleu","basei","ragu","pano","panis","vivi","vivas","viven","vivem","vivo,","poder.","colog","influi","classificam","Arque","Arce","Arm��","Attri","garra","pontu","ci��ncia.","campon","portuguesa.","1936","ingu��","passav","longe","el��tr","1,4","Prob","Prog","Proi","Prom","Sul-","romant","celta","assif","assis","sistemas,","h���","podemo","vezes,","vezes.","principais,","163","167","169","l��m","l��nd","trog","trom","ergi","supr","supri","sup��","suple","territ��rio,","calenda","14,","1415","1444","Bacal","Bah��","Chan","Carn","Carv","broa","leste;","peran","perado","seguir","comum.","milh��es,","gregos","m��tu","artef","cujas","escan","escas","escara","iniciada","iniciais","representat","apresento","andor","2002","2006","2007","2009","discre","tornari","limite","romani","biologia.","continentes","quenas","esp��cies.","trabalho,","trabalhou","combur","variar","variant","apresenta-","couv","��nc","selv","1972","1973","1974","1975","1977","1979","abrin","abrir","produze","devem","escrava","10%","101","104","8,5","oeste.","haver","obra,","produ���","servida","governo.","diferentes.","realida","evolu��","combust��","Auto","Poe","Ponto","Pomb","Poesi","solen","sub-d","demog","especiai","desenvolvimento,","educac","educar","pequenas","hoje.","comunicar","necessa","economic","Alemanha.","Apenas","Interc","Interm","antes,","centro.","morta","cirr","ciru","1926","1890","1891","antiga.","segundo,","consumos","tratar","��poca)","origino","principalmente,","Andos","Andes","Ange","Ango","Ander","An��l","Meca","Melo","Meio","Medei","Media","Medel","Mois","Monta","Morei","Mars","Marco","Marse","flui","eneg","seden","��lce","1991","1992","1997","1999","cidades,","origen","realizo","corpo.","Parai","Parado","Surin","Superi","preo","preda","curta","maiores.","���3","produtor","cineg","propria","integrad","integran","organizo","estruturad","estrutural","sub-regi��","Rep��blica.","finali","ocorrem","vasos","manto","1915","1918","dissi","prov��","pol��tica.","originai","originara","realizar","maioria,","Emba","Vieira","afini","nume","pap��","lega","leg��","contrar","estata","ensai","inst�","conjuntos","organizar","expressi","Universo","engenho","conhecimento\"","6,3","Exp","Ex��","Exemp","equim","equin","diges","ramov","��nic","1940","1943","1946","1948","1963","1965","1969","��ngu","arari","coleg","Condes","��reas,","respet","artes,","franc��","celular.","Coimbra.","ativo","dano","maca","surg","negra","negro","1909","1851","quantit","nacionalis","corresponde,","carv��","IX,","aut��","hya","orne","orni","encl","mar��","presid","Unido,","Paris.","estudos.","mesmas","comprid","colono","grego,","grego:","organismos.","minerai","minera�","Universit","Jos��,","Embora,","velocidade,","velocidades","biol��gic","caracter��stico","credo","malg","malh","mali","tela","teles","dizem","leit","1951","1956","1957","casa-","1823","1828","Reina","s��culos,","constituiu","Santo.","eletros","qu��mica.","receber","recebera","carv��o.","derivam","portugu��s,","investido","aproximado","administra�","s��rio","s��ries","darw","cavi","tons","pol��tico,","Estados-","quantos","Santan","socialis","continente.","escrevi","presidenc","posi����o,","Constitut","Barc","Barre","Barto","Dias,","Di��ri","Insu","Indu","Inconf","Lux","Ouro","client","cario","litz","litos","proteo","protet","1983","1986","1830","1839","1872","indul","indicav","indica�","importantes.","el��trico.","levado","levara","escritor,","original)","Paulo.","consist�","constitu��a","constitu��ra","influencio","relativos","relativas","classifica����o.","descreve-","descrevem","federa�","refer��ncias","Abram","Abramo","Janeiro.","Netu","Nebl","Oliven","pensav","secas","andro","Espada","brasileira.","homem.","nascer","costa,","europeu)","europeu,","prov��ncia,","teriam","escreven","escrevera","lugar.","abrang�","sucess�","sociedade.","atualmente,","atualmente.","compreend","associa�","document�","Duque","Duce","IBM","merid","ouro\"","firme","beatu","1860","1861","1862","1869","infel","infeta","dados,","m��e,","matem��tico,","referem","carboq","influenciam","refer��ncia,","com��d","projec","km��.","atribut","investiga-","figuran","Ambos","Campo","Col��","Colle","Isl","Isl��","Pr��","Tanto","Taver","amaz","amado","anterior.","c��p","epis","ep��","opera�","operado","ocidental.","pende","psiqu","dedu","rab�","tole","toler","sepu","1888","eleita","elei��","prova.","f��sicos","culturas;","cinema,","cinema.","instint","funciona.","funcional","elementa","participo","estilos","caracterizo","crist��s","Federat","Federa�","Francisca","dire����o,","densidades","import��ncia,","(CE","(Cy","Braga.","Ensa","Energ","Encontra","Ferd","Juan","Just","Junto","Jesu�","Munif","Munici","NUTS","XXI","antif","antil","antit","afirm","barra","efic","ol��m","exces","exerci","estare","escur","quadr","formado,","Papa.","estados,","cultural,","vivos,","Cidades","config","confio","compar�","filhot","povoada","povoame","complexi","Austra","metros,","micror","Constituint","clima,","climat","constantes","verdade,","computadores,","vegetat","depend�","medicina,","transformo","tecnologias","acelera����","com��rcio,","com��rcio.","3.5","Admi","Ams","Hoje","Holan","Lamar","Perei","Pequen","Pedra","dono","marido","anual","armada","��ria","��rida","ficar","excel","exceto","adver","advent","espin","manum","Cana��","decid","decif","livrem","continuo","nascim","Interne","princ��pio,","terceiros","combust��vel,","Santos)","quil��","poss��vel,","Francisco,","interpretar","interpreta�","mercador","pr��xima","defini����","atividades","respons��vei","estat��stica,","estat��sticas","50%","Jacob","Willi","baixo","baixos","oxida","ocupada","esf�","coop","nano","lagos","exila","corti","1840","1847","1849","aberta","mediada","novame","2011,","localizados","eletrodo","come��am","indiv��duos,","caboc","populosas","apareci","pr��tica.","comercial.","decora","el��trica,","cartag","Constitui���","constante,","transformar","tecnologia,","percep","completar","divulgado","divulgada","Aires,","Plut��o,","Plut��o-","multid","multip","multiv","institu�","espanhol,","contribue","Alb��nia.","cidad��o,","altitude,","altitude.","altitudes","fronteiras","(\"O","2)H","99%","99:","Biol","Bioqu","Coste","Shq","Shel","bytes","balai","evita","fossi","herdo","misti","restrin","copi","orti","citado","romp","sequer","dita,","1814","inten�","minist","visav","atuar","refei�","dele,","cat��","Estrei","China,","China.","existir","existis","escravis","escraviz","haviam","biol��gica)","biol��gica.","poucos","carreg","escravos\"","secre�","ganha","beatit","hist��ricos,","internacionalm","afirman","maneiri","microsco","carbono.","Augusta","separar","separat","separado","Senhora,","locais,","pol��ticas.","companhi","colonizado","significativos","significativas","Interior,","Abra��o.","composi����","B��lgica,","modificar","modificada","liter��ria","Condeixa-a-Nova.","Austr��lia,","literatura.","bioqu��mico","particulares","lingu��stico","cristianismo,","(177","374","4.5","Bot�","Centro-","Centro.","Miran","Mone","Monf","Todas","atend","co-o","canta","sexa","sexta","sexto","notab","notada","imperi","santo)","verna","asseg","interag","substa","pressu","interest","ren��","2015.","rever","m��dio,","Arquip","Arquiv","tentar","ilhas,","autoriz","pesquisas.","princ��pios,","doen��as,","finan��","jovem,","sucesso.","cometas,","servi��os,","Internat","Algarves","conscient","hidrog�","pr��-m","eleva��","Unidas.","intros","sustenta","adaptad","adaptat","adapta�","mat��ria-","Comiss�","Mundial.","na����o\"","religi��o,","florestai","navega��","mecaniz","utiliza����o,","constitui����","pratican","cientista,","Nacional.","Amaz��nic","molecular,","molecular.","experi��ncias","Dados","Pinto","Piren�","fases","herdar","��,","���","���","rebe","medem","top�","amiz","monof","despr","elas,","sabe","sabor","luna��","ter��","contor","casta","quarta","Maca�","divina","habitat,","habitats","polif","polici","pessoal\"","pessoal,","pessoal.","cauda.","aplicada,","aplicadas","Arturi","educador","mortes","mortos","observados","destaco","equipe","1945,","Alberg","destes.","prote��","aquela","gravid","invento,","transmite","Brasileiro,","Geralm","continuam","continuar","continua�","diferencial","diferencia�","diferenciado","Aveiro.","mostram","secreto","psicol�","revis�","colocar","dedico","acredita-","arara-azul-p","holand","urbanos","estendend","Comunica","impress�","combust��veis,","gen��tico","forneci","descri����","investiga����","englobam","subst��ncia","rep��blica,","9899","Cl��","Classi","Curie","Chile","Historia","Mairi","Tr��s","aferi","c��me","c��nc","cronome","c��nica","falant","massas","vitro","dota","dote","alon","tomo","queren","di��","petri","hom�","consor","aceito","calib","inteli","grada","Maia,","juntos","Nature","biomas","interca","interco","interces","cana-","postul","2022,","discute","ordeno","populares.","especialis","mantin","expressam","t��cnico-","t��cnicos","microc","Antigo.","ligadas","alimentar","alimenta�","rocho","rochos","rochas","espor�","universais","Bahia.","atribui�","deixar","identificada","etc..","industrial,","manifesta�","bioqu��mica,","aberto.","Amaz��nia,","acompanham","acompanhar","melhorar","entendid","balan��a.","cinem��tica,","cren��as","ciclos","adquire","subdivis","conclus","mundial,","mundial.","inclu��a","inclu��ra","catalo","expedi���","observa����","��ndia.","efetuar","introdu�","mecanismos","te��smo,","Gr��cia.","militares","descendi","conformi","formulada","engenheiros","pensamento,","pensamento.","vectoriai","heredit�","sentimenta","Ant��rtic","codificado","(38","(OM","(OT","B.F","Banh","Banco","Hein","Heav","Henn","Martins","Ordem","Ocidental,","Ocidental.","Perf","Pan,","Sol,","Teat","Tejo","ajudar","adicionais","golf","golgi","justi","linhag","russo,","salp","inun","parida","nono","not��","pobr","ditou","arrai","peito","por��","exag","exata","horas,","horas.","regent","Escra","n��o-o","n��o-re","av��,","instab","inclus��","conceder","sociop","1755","m��dico,","pontia","Christy","Cartaz","automo","Pode-","consideradas,","experimentou","textos,","Lu��sa","inventad","homens,","vegetal)","vegetal.","hebraica.","deles,","significativa,","promovi","personagem,","destaca-","destacam","transmitid","transmitir","destinada","institui���","gen��tica,","agrupada","decis��","interesses","compartilhad","compartilham","homenagem.","dist��ncia,","Castela","aconteci","motores","filmes.","destru�","profund","profundo","evolutivo","evolutivas","num��ric","Viena.","africanos","instru��","avaliado","navegadore","clim��tico","clim��tica","verifico","negativas","caminha","Caronte.","Litoral,","espalhad","espalhara","contextos","conservad","Lumi��re,","din��mica","crit��rio","cer��mic","cer��mico","implementa�","independentes","Antilhas,","Antilhas.","behaviorist","recomendado","Independ��ncia,","CO2","C��ni","Cruza","Campin","Flores","Fl��ri","Filos�","Grou","Grosso,","Itaco","Lyon","Medina","Ox,","Ramal","Volto","Velos","antep","buscan","c��to","dioc","faixa","kg.","rurai","venerado","���","alla","polari","dimin","solid","solit","vail","cebo","olho","olhos","rosto","estada","acess�","pertu","mandam","austr","tribo","polon","tempos.","can��","algada","diago","Comple","concebe","1768","invaso","estudados","imposs","aplicados","Guian","1930,","Proc�","amplif","representados","2004)","2004,","2004.","romana,","1978,","1924)","1924,","Monte,","Montem","cursor","possuiri","n��meros,","ocorrer�","��nica,","Baixos,","Baixos.","teleco","��ticos","ligados","citol","el��tricas,","radioc","cinemato","bits,","cortar","cortado","materializ","eletr��nicos","mensagem,","econ��mico,","brit��nicos","registrou","privados","distinguir","distinguido","italiano,","te��rico","fotograf","marcadam","essencialm","qu��nticos","tradicional,","afetado","posturas","esporte","quadrados.","A��ores,","fisiol�","esquem","esquer","sentimentos","Latina,","Latina.","cozido","visitado","Produt","Produz","empregado","empregada","teatro,","obrigat","satisfa�","colaborado","financeiros","Pernambuco,","desconhecido","benefi","dirig�","motiva","sujeito","resolu","extinto","bacala","concentrado","organelas","passagem","conselhe","combust��o.","costume","liberai","liberal","liberar","linguagens,","resisti","Conceit","esculto","registradas","defendeu","pinturas","divindade.","Oriental,","litoral,","Ant��rtida,","remontam","press��o,","Uppsala.","acumulada","acumula��","criativa","Conserva�","Su��cia,","resultantes","combina����","UNESCO,","UNESCO.","prim��rias","armazenar","anan��s.","org��nico","atravessam","atravessar","Get��lio\"","terrestre.","coordenad","coordena�","Chiropotes,","intelectuai","gravitacionai","independ��ncia,","agropecu��rios","norte-americana","canoniza����o.","(UE","Azer","Branco.","Darb","Douro,","Eugen","Eug��","Fazen","Fazia","Gonz","Gon��","Galil","Gibral","Ilha","Shak","Sacram","aristoc","bil��","centrai","elaborad","flux","fluor","germi","idoso","julia","mestres","oposto","pesan","pesado","pescado","prazo","russa","vulc","vulg","coer","mam�","enov","incid","rodel","pater","conot","condes","adorn","desli","guarda","guardi","fotos","ex-f","parada","pris�","agrac","agrav","baian","primav","Come�","Colom","Novem","Nova,","Portal","Portant","ret��","ret��","interva","Defen","Defin","repara","Estatu","period","embrio","embri�","record","2017.","genet","Portugu�","estive","definira","profeci","amplo,","registan","registara","1970,","Royau","1892,","1894,","1990,","condut","conduz","Queima"]} \ No newline at end of file diff --git a/docs/memoria-ncm-khtst/n-00-index.md b/docs/memoria-ncm-khtst/n-00-index.md new file mode 100644 index 0000000000000000000000000000000000000000..5e5f4aae7da37ce0b590ea986a8203e8cb4c6842 --- /dev/null +++ b/docs/memoria-ncm-khtst/n-00-index.md @@ -0,0 +1,84 @@ +# n-00 — ÍNDICE DA MEMÓRIA: NCM × KHTST +> **Coleção**: `memoria-ncm-khtst` · **Criada em**: 2026-10-20 · **Estado**: v1.0 +> **Objeto**: Memória técnica para introduzir **Next-Concept Modeling (NCM)** no modelo **KHTST (`PowerMachine/khtst-multimodal-ptbr`)** via refatoração dos scripts. + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Esta memória documenta o paradigma NCM (arXiv:2610.14162, Hazy Research/Stanford) — geração paralela coarse-to-fine de texto via tokenizador VQ-VAE residual multiscale + gerador transformer nível-a-nível — e prova, matemática e logicamente, que ele pode ser introduzido no KHTST reutilizando infraestrutura existente (tronco Mamba-3 5:1 + NoPE, MTP, PCGrad, GSQ+RCO Stiefel, autorregulação RM, ensemble, janela 1M). Entrega 4 partes de teoria (20 teoremas + 10 corolários/lemas com demonstrações completas), 10 provas de factibilidade da refatoração (T1–T10) e um plano acionável (pacote `src/khtst/conceitos/`, config `ncm`, scripts 39–43, `docs/matematica/36`, suíte `test_khtst_v24.py` com 16 verificações). +- **EN**: This memory documents the NCM paradigm (arXiv:2610.14162) — parallel coarse-to-fine text generation via a multiscale residual VQ-VAE tokenizer plus a level-by-level transformer generator — and proves, mathematically and logically, that it can be introduced into KHTST by reusing existing infrastructure. It delivers 4 theory parts (20 theorems + 10 corollaries/lemmas with complete proofs), 10 refactoring-feasibility proofs (T1–T10), and an actionable plan (package `src/khtst/conceitos/`, config `ncm`, scripts 39–43, `docs/matematica/36`, suite `test_khtst_v24.py` with 16 checks). + +--- + +## 1. Ordem de leitura (sequencial) + +| # | Arquivo | Conteúdo | Pré-requisito | +|---|---------|----------|---------------| +| 1 | `n-01-analise-ncm.md` | Análise técnica completa do NCM: arquitetura em 2 estágios, mecanismos, resultados, código-fonte, posicionamento vs AR/DLM/VAR | — | +| 2 | `n-02-provas-teoria.md` | **Provas matemáticas de teoria** (Partes A–D, Teos A.0–A.4, B.1–B.4, C.1–C.4, D.1–D.7 + corolários): VQ residual multiscale, fatoração next-concept, comparação com difusão mascarada (ELBO), teoremas de integração híbrida | n-01 | +| 3 | `n-03-provas-refatoracao.md` | **Provas de factibilidade da refatoração** (T1–T10): compatibilidade de interfaces, perdas, tronco, inferência, custo, não-regressão — cada prova mapeada em módulos/teoremas existentes do KHTST | n-01, n-02 | +| 4 | `n-04-plano-refatoracao.md` | **Plano acionável para agente de código**: specs de módulos, config JSON, protocolo de treino em fases, scripts numerados, suíte de testes, critérios de aceite, registro de riscos | n-01, n-02, n-03 | + +## 2. Fontes primárias (verificadas em 2026-10-20) + +| Fonte | URL | O que forneceu | +|-------|-----|----------------| +| Paper NCM | `arxiv.org/abs/2610.14162` | Abstract, benchmarks (LM1B 21×, OWT 10×, XSum 31×, Sudoku) | +| Blog Hazy Research | `hazyresearch.stanford.edu/blog/2026-10-12-ncm` | Mecanismos: codebooks por nível, nested dropout, reconstrução token-level, corrupção de condicionamento, atenção block-diagonal, MBR | +| Repo GitHub | `github.com/HazyResearch/ncm` | Layout: `evaluate.py`, `scripts/`, `config/eval/`, `models/`, `tokenization/`, `evaluation/`, `utils/`, `assets/`; checkpoints HF (`hazyresearch/ncm-checkpoints`) | +| Model card KHTST | `huggingface.co/PowerMachine/khtst-multimodal-ptbr` | Histórico v1–v23, arquitetura, provas `docs/matematica/00–35` | +| Config KHTST | `configs/base.json` (raw) | d_model=192, n_camadas=6 (5:1), vocab=16384, ctx=256, MTP k=2, janela_1m 262144, difusao SD 128×128 | +| Plano KHTST | `PLANO_KHMAMBAJEPA.md` (raw) | Estado por subsistema, roteiro, protocolos operacionais, verificação por versão | +| Doc 17 KHTST | `docs/matematica/17-difusao-multimodal-v5.md` (raw) | Difusão atual = Stable Diffusion (imagem), ciclo fechado, Teos 17.1–17.4 | + +## 3. Mapa de decisão rápido (para agente de código) + +``` +PERGUNTA → ONDE +"O que é NCM e por quê?" → n-01 §§1–4 +"Quais equações governam o tokenizador?" → n-02 §A (Teos A.1–A.4) +"Qual o objetivo de treino do gerador?" → n-02 §B (Teos B.1–B.4) +"NCM é melhor que difusão mascarada? Por quê?" → n-02 §C (Teos C.1–C.4) +"Isso cabe no tronco Mamba-3 5:1?" → n-02 §D (Teo D.1) + n-03 T2 +"Onde conecto no código do KHTST?" → n-03 T1–T10 (mapa módulo→prova) +"Quais arquivos criar e como?" → n-04 §2–§4 +"Como verificar sem regressão?" → n-04 §7–§8 (suíte + A/B pareado) +"Riscos e mitigações?" → n-04 §9 +``` + +## 4. Convenções herdadas do projeto KHTST (OBRIGATÓRIAS) + +Estas memórias seguem as convenções internas do repositório KHTST para que o agente de código as trate como documentação nativa: + +1. **Teoremas numerados** no formato `Teo .` (a refatoração criará o doc `36-ncm-conceitos-hierarquia.md` → `Teo 36.1`, `Teo 36.2`, …); provas terminam com `∎`. +2. **Nascimento neutro**: toda feature nova é *opt-in* com default `false`; a primeira aplicação deve ser **identidade bit-a-bit** com a versão anterior (padrão dos Teos 29.16, 34.10 do projeto). +3. **Leitura honesta**: ganhos de ΔCE em corridas curtas não são declarados como ganho de qualidade (precedente RELATORIO §20–21); wall-clock reportado como medido, inclusive quando desfavorável (precedente Teo 31.5). +4. **A/B pareado**: uma variável por braço, corpus real fresco, pareamento exato por re-seed pós-construção com RNG dedicado (padrão Teo 31.7). +5. **Suítes todas verdes** antes de publicar; `verificar_tudo` ampliado a cada versão. +6. **Limites estruturais**: `treinador.py` < 80 KB (usar mixins, padrão Teo 34.11); token EXCLUSIVAMENTE em `HF_TOKEN` apagado após uso. +7. **Memórias do projeto** (`PLANO_KHMAMBAJEPA.md`, `RELATORIO_KHTST.md`, `worklog.md`) atualizadas a cada versão. + +## 5. Glossário essencial + +| Termo | Definição operacional | +|-------|----------------------| +| **NCM** | Next-Concept Modeling: framework de 2 estágios para geração paralela coarse-to-fine (Kumbong et al., 2026) | +| **Conceito / concept code** | Código discreto de um codebook de nível ℓ que quantiza o resíduo latente daquele nível | +| **VQ-VAE residual multiscale** | Tokenizador que codifica texto numa hierarquia de L níveis de códigos; cada nível quantiza o resíduo deixado pelos anteriores | +| **Nested dropout** | Sorteio do nível de parada ℓ durante o treino do tokenizador; treina cada prefixo a ser decodificável sozinho | +| **Reconstrução cumulativa** | ẑ_ℓ = Σ_{j≤ℓ} r_j (residuais somados até o nível ℓ) | +| **Level-AR / next-concept** | Fatoração p(c) = Π_ℓ p(c_ℓ \| c_{<ℓ}) com predição paralela intra-nível | +| **Block-causal mask** | Máscara de atenção: nível ℓ atende a níveis ≤ ℓ (bidirecional dentro do bloco) | +| **Corrupção de condicionamento** | Corromper fração dos códigos-condição durante o treino do gerador (robustez a erros próprios) | +| **NFE** | Number of Function Evaluations — nº de forward passes por geração | +| **MDLM / DUO** | Baselines de difusão de linguagem (masked diffusion; contrastivos com modelo auxiliar) | +| **MTP** | Multi-Token Prediction (KHTST `treino/mtp.py`, k=2) — caso particular de 2 níveis do NCM (Teo n-03 T7) | +| **GSQ / RCO / Stiefel** | Quantização Gumbel-Softmax + Restrição de Coluna Ortogonal em variedade de Stiefel (KHTST `quanta/gsq_rco.py`, docs 26–27) | +| **RM / Borkar** | Robbins–Monro com duas escalas (autorregulação multiplicativa em log-escala do KHTST, Teos 28.5–28.8) | +| **MBR** | Minimum Bayes Risk decoding — argmax da utilidade esperada sob os próprios candidatos | + +## 6. Protocolo de uso desta memória por agente de código + +1. Leia `n-01` → `n-02` → `n-03` → `n-04` **na ordem** (cada arquivo pressupõe a notação do anterior). +2. Antes de editar código, confirme no repositório local os `arquivo:linha` citados em n-03 (a memória foi construída sobre o snapshot v23 de 2026-10-18; linhas podem ter deslocado). +3. Execute a refatoração em **uma variável por commit** (padrão A/B do projeto). +4. Ao concluir, crie `docs/matematica/36-ncm-conceitos-hierarquia.md` transferindo os Teos de n-02/n-03 com as evidências medidas, e atualize `PLANO_KHMAMBAJEPA.md` (§2 estado por subsistema) e `worklog.md`. +5. **Nunca** publique sem: suíte v24 verde + regressão v1–v23 verde + `verificar_tudo` verde + A/B pareado honesto. diff --git a/docs/memoria-ncm-khtst/n-01-analise-ncm.md b/docs/memoria-ncm-khtst/n-01-analise-ncm.md new file mode 100644 index 0000000000000000000000000000000000000000..3f9a1ba555fe9a969f94bae88df6d57d135d56af --- /dev/null +++ b/docs/memoria-ncm-khtst/n-01-analise-ncm.md @@ -0,0 +1,162 @@ +# n-01 — ANÁLISE TÉCNICA: Next-Concept Modeling (NCM) +> **Coleção**: `memoria-ncm-khtst` · **Pré-requisito**: n-00 · **Fontes**: arXiv:2610.14162, blog Hazy Research 2026-10-12, repo `HazyResearch/ncm` + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: NCM é um framework de dois estágios para geração de texto paralela coarse-to-fine. Estágio 1: um VQ-VAE residual multiscale comprime texto numa hierarquia de códigos discretos (níveis iniciais curtos capturam a estrutura global; níveis finais longos adicionam detalhe). Estágio 2: um transformer gera um nível por vez, prevendo todos os códigos do nível em paralelo, condicionado à reconstrução cumulativa interpolada dos níveis anteriores. Resultados: 9–31× mais rápido que DLMs fortes (MDLM/DUO) com qualidade igual ou superior, 4–5× menos tokens de treino, e superioridade em raciocínio com restrições (Sudoku em todas as dificuldades). NCM treina por MLE exato no espaço latente discreto (sem ELBO) e executa exatamente L forward passes por geração (L = nº de níveis). +- **EN**: NCM is a two-stage coarse-to-fine parallel text generation framework. Stage 1: a multiscale residual VQ-VAE compresses text into a hierarchy of discrete codes (early short levels capture global structure; later long levels add detail). Stage 2: a transformer generates one level at a time, predicting all codes within a level in parallel, conditioned on the interpolated cumulative reconstruction of previous levels. Results: 9–31× faster than strong DLMs at equal or better quality, 4–5× fewer training tokens, and superior constraint-based reasoning (Sudoku, all difficulties). NCM trains by exact MLE on the discrete latent space (no ELBO) and runs exactly L forward passes per generation (L = number of levels). + +--- + +## §1. Contexto e motivação + +### 1.1 Os três paradigmas de geração de texto + +| Propriedade | **AR** (GPT-like) | **DLM** (difusão de linguagem) | **NCM** (next-concept) | +|---|---|---|---| +| Fatoração | `p(x) = Π_i p(x_i \| x_{` no `evaluate.py`; escala 1.0 usada no row guiado do WMT14). +- **Test-time scaling por MBR**: geram-se múltiplos candidatos (baratos pela velocidade) e escolhe-se o que maximiza utilidade esperada contra os demais — no WMT14/XSum o MBR da NCM supera baselines porque produz **mais candidatos no mesmo orçamento de tempo**. + +## §4. Resultados experimentais (paper + blog) + +| Benchmark | Métrica | NCM vs. melhor DLM | Velocidade (H100) | +|---|---|---|---| +| LM1B (~matched params) | generative perplexity | **melhor** | **21× mais rápido** | +| OpenWebText | gen. perplexity | competitivo | **10×** | +| TinyStories | gen. perplexity | melhor/igual | parte da faixa 9–31× | +| XSum | ROUGE-L | igual | **31×** | +| WMT14 De-En | sacreBLEU / chrF | igual/melhor | até 31× (com CFG) | +| Sudoku (easy/medium/hard) | boards resolvidos | **supera AR e DLM em todas as dificuldades** (99,5 / 96,5 / 86,1 vs. próximo melhor 97,7 / 92,8 / 81,3) | menos NFE | + +**Treino**: ~4,9× (LM1B) e ~4× (OWT) **menos tokens** que os DLMs fortes, **já contabilizando tokenizer + generator**. **Escalonamento**: perplexidade melhora consistentemente com parâmetros (modelos avaliados ~100M) e com test-time compute (MBR). **Decomposição da eficiência**: (i) menos passos — L ≪ T; (ii) passos mais baratos — níveis iniciais têm n_ℓ ≪ N (a DLM processa N a cada passo). + +### 4.1 Leitura do resultado Sudoku (evidência do "raciocínio profundo" coarse-to-fine) + +Sudoku é satisfação de restrições global: uma célula errada invalida o tabuleiro inteiro. A superioridade da NCM com **menos NFE** (e a degradação mais lenta com a dificuldade) suporta a hipótese do paper: **o plano grosseiro fixa a estrutura global antes do detalhe**, reduzindo o espaço de busca dos níveis finos (formalização em n-02, Teo C.2). AR sofre porque erros precoces propagam; DLM sofre porque o denoising uniforme não tem noção de "plano antes do detalhe". + +## §5. O código-fonte (`github.com/HazyResearch/ncm`) + +``` +ncm/ +├── evaluate.py # entrada de avaliação (1 shard por GPU + merge) +├── requirements.txt # Python ≥3.10, PyTorch CUDA +├── scripts/ # shard por GPU e merge com scoring +├── config/eval/ # 1 YAML por checkpoint (idêntico ao config.yaml do checkpoint) +├── models/ # implementação do GERADOR (transformer next-concept) +├── tokenization/ # implementação do TOKENIZADOR (VQ-VAE residual multiscale) +├── evaluation/ # métricas (ROUGE, sacreBLEU, chrF, gen-ppl, Sudoku) +├── utils/ # utilitários +└── assets/ # arquivos de release +``` + +**Checkpoints** (HF `hazyresearch/ncm-checkpoints` + `ncm-datasets`): XSum, WMT14 De-En, Sudoku easy/medium/hard, LM1B small/medium/large, TinyStories, OpenWebText — cada modelo = **tokenizador congelado + gerador** (o estágio 1 é sempre congelado no estágio 2). + +**Comando canônico de avaliação** (reproduzir antes de qualquer port para verificar o ambiente): +```bash +python evaluate.py --config config/eval/.yaml \ + --checkpoint-dir artifacts/ --data-dir data/ # [--cfg 1.0] +``` + +**Contrato de módulos inferido do layout** (para espelhar no KHTST, ver n-04 §2): +- `tokenization/` → treino do VQ-VAE residual (perda de reconstrução + nested dropout + EMA de codebook); +- `models/` → gerador com máscara block-causal, embeddings de nível, predição paralela intra-nível; +- `config/eval/*.yaml` → hiperparâmetros por tarefa (schedule de níveis, K_ℓ, temperaturas, CFG). + +## §6. Posicionamento teórico (ponte para n-02) + +1. **NCM é MLE exato; DLM é variacional.** A perda do gerador é a log-verossimilhança exata da hierarquia induzida pelo tokenizador congelado (determinístico) — sem ELBO, sem gap variacional (Teo B.1). A qualidade do modelo de linguagem fica condicionada à qualidade do tokenizador, que por sua vez é treinado com um objetivo supervisionado transparente. +2. **A fatoração paralela intra-nível é uma restrição real, compensada pelos resíduos.** O preço é a perda de dependências intra-nível; o ganho é que o nível ℓ+1 vê o nível ℓ **realizado** e corrige seus erros (Teo B.3 — teorema de correção de erro residual). +3. **Nested dropout dá a propriedade anytime** — prefixos decodificáveis com qualidade monotônica (Teo A.2) — que substitui, com vantagem, o "schedule" de difusão. +4. **A corrupção de condicionamento é o análogo do ruído de difusão**, mas com semântica de robustez a exposure bias (Teo C.3). +5. **Hierarquia = compressão com taxa geométrica**: nível ℓ comprime o contexto por fator r^{L-ℓ} — conecta-se diretamente à janela 1M do KHTST (n-03, T8). + +## §7. Implicações para o KHTST (sumário executivo) + +| Vantagem NCM | Alvo no KHTST | Infra existente reaproveitável | +|---|---|---| +| Geração paralela (L passos ≪ N) | `gerar()` / `SessaoKHTST` / unidade NLG | KV-cache NoPE + offset RoPE (Teo 35.8), scan paralelo Cython (Teo 33.11) | +| MLE exato sem ELBO | `treino/perdas.py` (nova perda CE de conceitos) | PCGrad (Teo 35.1) já mistura perdas multi-tarefa | +| Codebooks por nível | novo pacote `conceitos/` | **GSQ + RCO Stiefel** (docs 26–27): codebooks ortogonais com gradiente riemanniano — melhor condicionamento do VQ residual (Teo A.4/D.6) | +| Nested dropout (anytime) | decodificação elástica | autorregulação RM de temperatura (Teos 28.5–28.8) por nível | +| Corrupção de condicionamento | robustez do gerador | guarda anti-colapso / telemetria existentes | +| MBR / test-time scaling | `ensemble/votacao.py` (RF×DNN×Engram) | utilidade de ensemble pronta para MBR | +| Raciocínio por plano global | tarefas `raciocinio`, `matematica` (GSM8K/MATH-500) | datasets e tarefas canônicas já no registry | +| Compressão de contexto | `memoria/janela_1m.py` (262144 tokens) | níveis grosseiros como resumo indexado | + +**Conclusão da análise**: NCM não substitui o tronco do KHTST — **envolve-o**. O tronco Mamba-3 5:1 + NoPE permanece; o que muda é a *fatoração da geração* (token-a-token → nível-a-nível) e a adição de um estágio de tokenização em conceitos que reutiliza a maquinaria de quantização já provada do projeto. As provas formais de compatibilidade estão em n-02 (teoria) e n-03 (factibilidade de engenharia); o plano de execução em n-04. diff --git a/docs/memoria-ncm-khtst/n-02-provas-teoria.md b/docs/memoria-ncm-khtst/n-02-provas-teoria.md new file mode 100644 index 0000000000000000000000000000000000000000..505cc2acbb595846928725b679e84b83d90a3def --- /dev/null +++ b/docs/memoria-ncm-khtst/n-02-provas-teoria.md @@ -0,0 +1,431 @@ +# n-02 — PROVAS DE TEORIA: fundamentos matemáticos do NCM +> **Coleção**: `memoria-ncm-khtst` · **Pré-requisitos**: n-00, n-01 · **Convenção**: teoremas `Teo X.n`, provas terminam com `∎` +> **Status**: teoria pura — independente de implementação. Os Teos A–D alimentam o doc `36-ncm-conceitos-hierarquia.md` do KHTST (ver n-04 §6). + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Esta memória prova os quatro pilares teóricos do NCM e de sua integração: (A) o tokenizador VQ residual multiscale converge geometricamente sob codebooks ortonormais (contração (1−1/K) por nível; caso particular da restrição Stiefel/RCO já provada no KHTST), e o nested dropout torna todo prefixo de níveis decodificável com risco monótono (refinamento sucessivo); (B) a fatoração next-concept é MLE exato (sem ELBO), com custo de inferência L forward passes, e sua restrição (independência intra-nível) tem gap exatamente igual à correlação total condicional dos códigos, parcialmente recuperada pelos níveis residuais seguintes; (C) em comparação com difusão mascarada: NCM elimina o gap variacional, formaliza a vantagem de planejamento global (teorema condicional de decomposição de consistência), a corrupção de condicionamento é otimização robusta por distribuição contra exposure bias, e MBR com n candidatos tem regret O(n^{−1/2}); (D) a integração no tronco Mamba-3 5:1 + NoPE é executável (máscara block-causal via NoPE + fluxo causal via Mamba), o condicionamento multimodal é invariante, a autorregulação RM aplica-se por nível, MTP ⊂ NCM, e PCGrad preserva as invariantes com a nova perda. +- **EN**: This memory proves NCM's four theoretical pillars and their integration: (A) the multiscale residual VQ tokenizer contracts geometrically under orthonormal codebooks ((1−1/K) per level — the Stiefel/RCO case already proven in KHTST), and nested dropout makes every level prefix decodable with monotone Bayes risk (successive refinement); (B) the next-concept factorization is exact MLE (no ELBO), costs L forward passes, and its within-level independence gap equals the conditional total correlation, partially recovered by subsequent residual levels; (C) versus masked diffusion: NCM removes the variational gap, formalizes the global-planning advantage (conditional consistency-decomposition theorem), corruption training is DRO against exposure bias, and MBR regret is O(n^{−1/2}); (D) integration into the Mamba-3 5:1 + NoPE trunk is constructive, multimodal conditioning is invariant, per-level RM self-regulation applies, MTP ⊂ NCM, and PCGrad invariants survive the new loss. + +--- + +## §0. Notação e definições fundamentais + +**Dados e tokenizador.** +- Texto: `x = (x_1, …, x_N)`, `x_i ∈ V`, `|V|` finito (KHTST: `|V| = 16384`). +- Encoder: `E: V^N → R^{N×d}`, `z = E(x)` (contínuo). +- Hierarquia: `L` níveis com tamanhos `n_1 < n_2 < … < n_L ≤ N`; codebooks `C_ℓ ∈ R^{K_ℓ×d}` com linhas `c_{ℓ,1},…,c_{ℓ,K_ℓ}`. +- Operadores de redimensionamento: `Interp_m: R^{n×d} → R^{m×d}` (interpolação linear/por pooling; para `m < n` é downsample, `m > n` upsample). Notação curta: `z^{(m)} := Interp_m(z)`. +- **Recursão residual do VQ multiscale**: + ``` + z_1 = z^{(n_1)} + r_ℓ = Quant_{C_ℓ}(z_ℓ) (quantização NN por posição: r_ℓ[i] = argmin_{c∈C_ℓ} ‖z_ℓ[i] − c‖) + c_ℓ[i] = índice do NN (códigos discretos; r_ℓ[i] = c_{ℓ, c_ℓ[i]}) + z_{ℓ+1} = (z_ℓ)^{(n_{ℓ+1})} − (r_ℓ)^{(n_{ℓ+1})} (resíduo na granularidade do próximo nível) + ``` +- **Reconstrução cumulativa**: `ẑ_ℓ = Σ_{j≤ℓ} (r_j)^{(n_ℓ)}`; a reconstrução completa é `ẑ_L`. +- **Decoder** `Dec_ψ`: mapeia `(ẑ_ℓ) → V^N` (distribuição sobre tokens; **CE token-level**). +- **Tokenizador** `T = (E, {C_ℓ}, Dec_ψ)`: `x ↦ c = (c_1,…,c_L)`, `c_ℓ ∈ [K_ℓ]^{n_ℓ}`. + +**Perdas do Estágio 1 (tokenizador).** +``` +L_tok(θ) = E_x E_{ℓ∼p(ℓ)} [ CE(x, Dec_ψ(ẑ_ℓ(x))) ] (nested dropout: p(ℓ) > 0 ∀ℓ) + + β Σ_ℓ E_x ‖sg[r_ℓ] − z_ℓ‖² (commitment; sg = stop-gradient) +``` +com atualização de codebook por **EMA** (média móvel dos agrupamentos; código equivalente a stop-gradient nos códigos, padrão VQ-VAE). Opcional KHTST: quantização **GSQ** (Gumbel-Softmax com τ-annealing, Teos 26.x do projeto) no lugar do STE duro — ver Teo D.4. + +**Gerador (Estágio 2).** +``` +p_φ(c) = Π_{ℓ=1}^{L} p_φ(c_ℓ | c_{<ℓ}), p_φ(c_ℓ | c_{<ℓ}) = Π_{i=1}^{n_ℓ} p_φ(c_{ℓ,i} | c_{<ℓ}) +L_gen(φ) = −E_x [ Σ_{ℓ=1}^{L} log p_φ(c_ℓ(x) | c_{<ℓ}(x)) ] (treino: 1 forward, teacher forcing) +``` +O condicionamento `c_{<ℓ}` entra como a reconstrução cumulativa interpolada `ẑ_{ℓ−1}^{(n_ℓ)}` (função determinística de `c_{<ℓ}`) — notação: escrevemos `p_φ(c_ℓ | c_{<ℓ})` com esta identificação implícita. + +**Corrupção de condicionamento** (treino do gerador): com probabilidade ρ por posição, o código de condicionamento `c_{j,i}` (j < ℓ) é substituído por `⟨mask⟩`/aleatório antes de construir `ẑ`; a perda é `E_{κ}[·]` sobre a família de corrupção κ (Teo C.3). + +**Difusão mascarada (para comparação).** Processo direto absorvente em tempo contínuo `t ∈ [0,1]`: +``` +q(x_t | x_0) = Π_i [ α_t·δ(x_{t,i} = x_{0,i}) + (1−α_t)·δ(x_{t,i} = M ] (M = token ⟨mask⟩, α_1 = 0) +ELBO(θ) = ∫_0^1 w(t)·E_{x_t}[ KL(q(x_s|x_0,x_t) ‖ p_θ(x_s|x_t)) ] dt ≤ log p_θ(x_0) +``` + +**Informação.** `H`, `KL`, e **correlação total condicional** (multi-informação): +`TC(c_ℓ | c_{<ℓ}) := E_{c_{<ℓ}}[ Σ_i H(c_{ℓ,i}|c_{<ℓ}) − H(c_ℓ|c_{<ℓ}) ] ≥ 0`. + +--- + +# PARTE A — Tokenizador: VQ residual multiscale + +## Teo A.0 (gradiente straight-through da recursão residual) + +**Enunciado.** Com `sg[·]` sobre os vetores quantizados e atualização EMA dos codebooks, o gradiente de qualquer perda `L(ẑ_L)` w.r.t. o encoder `E` flui pela recursão residual como se a quantização fosse a identidade no backward. Formalmente, com `r_ℓ = sg[r_ℓ]`: +``` +∂L/∂z_ℓ = ∂L/∂z_{ℓ+1} (transporte direto), e ∂L/∂c_{ℓ,k} = 0 (codebooks fora do grafo; aprendem por EMA) +``` +A única fonte de gradiente para o encoder além disso é o termo commitment `β‖sg[r_ℓ] − z_ℓ‖²`, cujo gradiente é exato: `∂/∂z_ℓ [β‖sg[r_ℓ] − z_ℓ‖²] = 2β(z_ℓ − sg[r_ℓ])`. + +**Prova.** A recursão é `z_{ℓ+1} = Interp(z_ℓ) − sg[r_ℓ^{(n_{ℓ+1})}]`. Pela regra da cadeia com operador linear `Interp` e `sg` (identidade no forward, zero no backward — definição de stop-gradient): +`∂L/∂z_ℓ = Interp^T(∂L/∂z_{ℓ+1}) + 2β(z_ℓ − sg[r_ℓ])`. +Iterando de `ℓ = L` até `1`, o gradiente atravessa todas as quantizações sem atenuação; os codebooks não recebem gradiente do autograd (aprendem pela EMA dos agrupamentos — estatística suficiente do minibatch, c.f. van den Oord et al. 2017). O commitment tem gradiente analítico imediato. O STE introduz viés de estimador (o gradiente "vê" o quantizador como identidade), controlado pelo commitment e pela EMA; a alternativa GSQ (Gumbel-Softmax) substitui o STE por um gradiente exato do relaxamento com τ → τ_min (Teo D.4). ∎ + +**Corolário A.0.1 (paralelismo de treino).** Como nenhuma dependência seqüencial de gradiente existe entre níveis (apenas a recursão forward, computável em uma passada), o treino do tokenizador e do gerador são ambos paralelos sobre a sequência inteira — mesma complexidade assintótica de um transformer AR com teacher forcing. ∎ + +## Teo A.1 (contração geométrica do resíduo sob codebook ortonormal) + +**Enunciado.** Seja `C = {c_1,…,c_K} ⊂ R^d` com `c_k = R·u_k`, `{u_k}` ortonormal (matriz de codebook em Stiefel: `U^T U = I_K`, `K ≤ d` — exatamente a restrição **RCO** do KHTST, docs 26–27). Seja `P_C` a projeção ortogonal em `span(C)`. Para qualquer `z ∈ R^d`, a quantização NN `r*(z) = argmin_k ‖z − R u_k‖` satisfaz: +``` +(i) ‖z − r*(z)‖² ≤ ‖z − P_C z‖² + (1 − 1/K)·‖P_C z‖² se R = ‖P_C z‖/√K (escala ótima) +(ii) ‖z − r*(z)‖² ≤ ‖z‖² − 2R·‖P_C z‖/√K + R² (escala arbitrária R) +``` + +**Prova.** Para códigos de norma comum `R`, `argmin_k ‖z − Ru_k‖ = argmax_k ⟨z, u_k⟩` (expandindo `‖z − Ru_k‖² = ‖z‖² − 2R⟨z,u_k⟩ + R²`). Pela ortonormalidade, +`Σ_{k=1}^{K} ⟨z, u_k⟩² = ‖P_C z‖²` (Parseval no subespaço). +Logo `max_k ⟨z,u_k⟩ ≥ ‖P_C z‖/√K` (o máximo é ≥ raiz da média dos quadrados). Tomando `k* = argmax`: +``` +‖z − r*‖² = ‖z‖² − 2R⟨z,u_{k*}⟩ + R² ≤ ‖z‖² − 2R‖P_C z‖/√K + R² +``` +que é (ii). Para (i), decomponha `‖z‖² = ‖P_C z‖² + ‖z − P_C z‖²` (Pitágoras) e substitua `R = ‖P_C z‖/√K`: +``` +‖z − r*‖² ≤ ‖z − P_C z‖² + ‖P_C z‖² − 2‖P_C z‖²/K + ‖P_C z‖²/K = ‖z − P_C z‖² + (1 − 1/K)‖P_C z‖². ∎ +``` + +**Corolário A.1.1 (contração composta em L níveis).** Aplicando Teo A.1 ao resíduo de cada nível (com `R_ℓ` adaptado por EMA à escala `‖P_{C_ℓ} z_ℓ‖`), e supondo os resíduos aproximadamente contidos nos spans dos codebooks (condição prática: EMA alinha os spans à distribuição dos dados): +``` +‖z_{L+1}‖² ≤ Π_{ℓ=1}^{L} (1 − 1/K_ℓ) · ‖z_1‖² ⟹ convergência geométrica em L. +``` +Ex.: `K_ℓ = 64`, `L = 6` ⇒ fator `≤ (63/64)^6 ≈ 0,909` **no pior caso garantido**; a contração empírica é tipicamente muito maior porque o pior caso do Teo A.1 é o alinhamento mais desfavorável possível de `z` (cota RMS), enquanto dados reais concentram-se em direções bem cobertas pelo codebook treinado. **Nota de honestidade** (padrão do projeto): a cota (i) é *worst-case*; reportar a contração medida por nível na suíte v24 (ver n-04 §7, verificação V3). + +**Corolário A.1.2 (caso frame apertado K > d).** Se o codebook é um *tight frame* unit-norma (K > d, operador de frame `(K/d)I` — Welch quase-ótimo), a mesma prova com Parseval generalizado dá `Σ_k ⟨z,u_k⟩² = (K/d)‖z‖²`, logo `max_k ⟨z,u_k⟩ ≥ ‖z‖·√(K/(dK)) = ‖z‖/√d` e: +``` +‖z − r*‖² ≤ (1 − 1/d)‖z‖² com R = ‖z‖/√d. +``` +A cota pior-caso satura em `1/d` (independente de K): o ganho de K > d além da cota RMS vem do **cobertura** (mais códigos = vizinhos mais próximos em direções prováveis), capturado pela EMA e não pela cota. Escolha recomendada para KHTST: `K_ℓ ≤ d_lat` com RCO estrito (Teo D.4) OU `K_ℓ > d_lat` com penalidade de coerência (Welch) no treino do codebook. ∎ + +## Teo A.2 (nested dropout ⇒ refinamento sucessivo com risco monotônico) + +**Enunciado.** Fixe o tokenizador (que induz a hierarquia `c(x)` para cada `x`) e a distribuição de dados `q(x)`. Para `ℓ ∈ {1,…,L}`, defina o **risco de Bayes do prefixo**: +``` +V(ℓ) := min_{f} E_{x∼q}[ L_rec(x, f(c_{1:ℓ}(x))) ] +``` +onde o mínimo é sobre todo preditor mensurável `f` do prefixo. Então: +``` +(i) V(1) ≥ V(2) ≥ … ≥ V(L) ≥ 0 (monotonia) +(ii) o decoder treinado com nested dropout aproxima V(ℓ) para TODO ℓ simultaneamente: + se Dec_ψ(·|ℓ) é ε_ℓ-ótimo para o prefixo ℓ, então E[L_rec(x, Dec_ψ(ẑ_ℓ))] ≤ V(ℓ) + ε_ℓ. +(iii) sem nested dropout (p(ℓ) = δ_{ℓL}), nenhum gradiente treina os prefixos ℓ < L: a garantia (ii) vale só para ℓ = L. +``` + +**Prova.** +(i) Seja `π_ℓ: c_{1:ℓ+1} ↦ c_{1:ℓ}` a projeção canônica (o prefixo curto é função do prefixo longo — a hierarquia é **encaixada** por construção: `c_{1:ℓ}` é subvetor de `c_{1:ℓ+1}`). Todo preditor `f_ℓ` do prefixo ℓ induz o preditor `f_ℓ ∘ π_ℓ` do prefixo ℓ+1 com o mesmo risco: `E[L_rec(x, f_ℓ(π_ℓ(c_{1:ℓ+1})))] = E[L_rec(x, f_ℓ(c_{1:ℓ}))]`. Logo o ínfimo sobre preditores do prefixo ℓ+1 (classe que contém `{f ∘ π_ℓ}`) é ≤ o ínfimo sobre preditores do prefixo ℓ: `V(ℓ+1) ≤ V(ℓ)`. +(ii) O objetivo de treino com nested dropout é `Σ_ℓ p(ℓ)·E_x[L_rec(x, Dec_ψ(ẑ_ℓ(x)))]` com `p(ℓ) > 0` ∀ℓ; minimizar em ψ minimiza cada termo ponderado — um mínimo global/minimal local do objetivo é ε_ℓ-ótimo por termo na vizinhança (gradiente nulo por termo em ponto estacionário com p(ℓ) > 0). Como `Dec_ψ(ẑ_ℓ)` é um preditor mensurável do prefixo ℓ, seu risco é ≥ V(ℓ) e ≤ V(ℓ)+ε_ℓ por hipótese de ε-otimalidade. +(iii) Com `p(ℓ) = δ_{ℓL}`, os termos ℓ < L têm peso zero: `∂L_tok/∂(termo ℓ) ≡ 0`; os decoders de prefixo não são treinados (risco arbitrário), exceto pelo que transbarda do compartilhamento de ψ — sem garantia. ∎ + +**Corolário A.2.1 (propriedade anytime).** Em inferência, a geração pode parar em qualquer nível ℓ com amostra válida de fidelidade `V(ℓ)^{-1}` — o análogo NCM do trade-off passos×qualidade da difusão, **monótono por construção** (vs. difusão, onde poucos passos degradam de forma não-monótona e com viés de exposure; n-01 §1.2). Combinado com o Teo B.2: `NFE = ℓ` adaptativo ao orçamento. ∎ + +**Corolário A.2.2 (alocação de taxa).** O nested dropout induz o prefixo ℓ a carregar `≈ I(x; c_{1:ℓ})` bits (senão o decoder de prefixo não atingiria V(ℓ)); os níveis formam uma cadeia de **refinamento sucessivo** (Equitz & Cover 1991): as taxas operacionais `R_ℓ = Σ_{j≤ℓ} n_j·log₂ K_j / N` (bits por token) têm distorções nas vizinhanças dos pontos da fronteira taxa-distorção quando a fonte é refinável sucessivamente (ex.: gaussianas; para fontes gerais, gap limitado — Gray & Neuhoff 1998, teoria de quantização residual). **Citação, não prova** — a estrutura de encaixe (prova (i)) é a condição necessária e suficiente estrutural; a alcançabilidade da fronteira é propriedade da fonte. ∎ + +## Teo A.3 (decomposição exata do erro de reconstrução) + +**Enunciado.** O erro do tokenizador decompõe-se em três termos independentes: +``` +E_x[CE(x, Dec(ẑ_L))] = E_x[CE(x, Dec(ẑ_L)) − CE(x, Dec(z))] (erro de QUANTIZAÇÃO: resíduo z_{L+1} ≠ 0) + + E_x[CE(x, Dec(z))] − CE(x, x) (erro do DECODER ψ) + + 0 (termo de referência) +``` +mais precisamente, com `D_q := ‖z − ẑ_L‖_F²/N` (distorção de quantização) e decoder L-Lipschitz na representação: +``` +E_x[CE(x, Dec(ẑ_L))] ≤ E_x[CE(x, Dec(z))] + L·√(D_q)·(1 + o(1)) +``` + +**Prova.** Defina `ε_q := ẑ_L − z` (erro de quantização por posição). Como `ẑ_L = Σ_ℓ (r_ℓ)` somado na granularidade N e `z = Σ` dos resíduos até a recursão parar, `ε_q = −z_{L+1}` (o resíduo final). Por Lipschitz do decoder em each posição: `|CE(x, Dec(ẑ_L)) − CE(x, Dec(z))| ≤ L·‖ε_q‖` média por posição; a distorção `D_q = E‖z_{L+1}‖²/N` e `‖ε_q‖_médio ≤ √D_q` (Jensen). Somando os dois termos e usando a definição do erro do decoder como o resíduorestante quando a representação é exata. ∎ + +**Uso prático**: o erro total é controlado **separadamente** por (a) L e K_ℓ (Teo A.1: contração de D_q), (b) capacidade do decoder ψ, (c) nested dropout (Teo A.2: prefixos também treinados). Na suíte v24, medir os três termos separadamente (verificação V2 do n-04 §7). ∎ + +## Teo A.4 (codebooks Stiefel ⇒ quantização em forma fechada + seleção GSQ) + +**Enunciado.** Se a matriz de codebook do nível ℓ satisfaz a restrição RCO do KHTST (`C_ℓ^T C_ℓ = R²·I`, linhas ortonormais escaladas — variedade de Stiefel `St(K_ℓ, d)`; docs 26–27), então: +``` +(i) a quantização NN reduz-se a r*(z) = R·u_{k*}, k* = argmax_k |⟨z, u_k⟩| (uma GEMM + top-1) +(ii) o erro fecha em forma exata: ‖z − r*‖² = ‖z‖² − R²·max(1, (⟨z,u_{k*}⟩/R)²·[K_ℓ]) ... + precisamente: ‖z − r*‖² = ‖z − P_C z‖² + ‖P_C z‖² − R·2·max_k⟨z,u_k⟩ + R² +(iii) a seleção de código é uma distribuição categórica sobre K_ℓ logits `⟨z, u_k⟩/τ` — exatamente a forma do gate + Gumbel-Softmax (GSQ) do KHTST: o gradiente exato do relaxamento τ > 0 flui para o encoder SEM STE. +``` + +**Prova.** (i) segue da igualdade de normas (Teo A.1, 1º passo) e da linearidade: `⟨z, R u_k⟩ = R⟨z,u_k⟩`. (ii) é a expansão pitagórica com a decomposição de (i)–(ii) do Teo A.1. (iii) o GSQ do KHTST (`quanta/gsq_rco.py`) amostra códigos via Gumbel-Softmax sobre logits lineares no input com temperatura τ e decaimento analítico τ(t); com logits `= ⟨z, u_k⟩/τ`, a distribuição limite `τ → τ_min → 0` concentra-se no argmax (= NN), e o gradiente `∂/∂z` do relaxamento é exato para cada τ > 0 (Jang et al. 2017; Maddison et al. 2017); a retração RCO (QR/polar, Teo 32.11) mantém as linhas em Stiefel a cada passo. Logo o tokenizador NCM **reusa verbatim** a maquinaria GSQ+RCO já provada no projeto — com os codebooks residuais por nível em lugar dos codebooks de compressão de pesos. ∎ + +**Observação (síntese NCM×KHTST).** O Teo A.4 é a ponte central desta memória: o KHTST **já possui** VQ com codebooks ortogonais, gradiente exato (GSQ) e retração riemanniana (RCO); o NCM **exige** VQ residual multiscale por nível. A união — codebooks residuais Stiefel com seleção GSQ — herda a contração garantida do Teo A.1 e os gradientes exatos do Teo A.4/D.4. + +--- + +# PARTE B — Fatoração next-concept: verossimilhança, custo e restrição + +## Teo B.1 (MLE exato — ausência de ELBO e de gap variacional) + +**Enunciado.** Fixe o tokenizador `T` determinístico (encoder + NN + EMA congelados no Estágio 2, como no NCM e nos checkpoints `hazyresearch/ncm-checkpoints`) e seja `q_T := T_# q_dados` a pushforward da distribuição de dados para hierarquias. Então: +``` +L_gen(φ) = −E_{c∼q_T}[ log p_φ(c) ] = KL( q_T ‖ p_φ ) + H(q_T) +``` +Logo minimizar `L_gen` **é** máxima verossimilhança exata sobre a distribuição induzida `q_T`; em particular `L_gen ≥ H(q_T)` com igualdade iff `p_φ = q_T` (quando realizável), e o valor da perda é uma **verossimilhança verdadeira** — comparável entre modelos e monótona no progresso do treino. + +**Prova.** Como `T` é determinístico, `E_{x∼q}[log p_φ(T(x))] = E_{c∼q_T}[log p_φ(c)]`. Pela identidade de Gibbs: +`E_{c∼q_T}[log p_φ(c)] = −KL(q_T‖p_φ) − H(q_T)`. +Multiplicando por −1 obtém-se o enunciado; `KL ≥ 0` com igualdade iff `q_T = p_φ` (a.s.), e `H(q_T) ≥ 0` é a cota inferior da perda. ∎ + +**Corolário B.1.1 (contraste com DLM).** Na difusão mascarada, a perda de treino é `−ELBO(θ) = −log p_θ(x) + Gap(θ)` com `Gap(θ) = KL(q(x_{s,t}|x_0) ‖ p_θ(x_{s,t}|x_0, x_t)) ≥ 0` somado/integrado sobre a trajetória (Teo C.1); a perda confunde qualidade do modelo com folga do bound. Na NCM a perda é a própria −log-verossimilhança da hierarquia: **todo o gap migra para o tokenizador**, onde é mensurável (Teo A.3) e otimizável com objetivo supervisionado transparente. ∎ + +**Observação (nível texto).** O modelo gerador completo de texto é `p(x) = Σ_c p_φ(c)·p_ψ(x|c)` com `p_ψ` o decoder. Com o decoder teacher-forced (autoregressive na reconstrução), `p_ψ(x|c) = Π_i p_ψ(x_i | x_{ 1, `n_L = N`): +``` +(i) Σ_{ℓ=1}^{L} n_ℓ = N·(r/(r−1))·(1 − r^{−L}) ≤ N·r/(r−1) (ex.: r = 2 ⇒ ≤ 2N) +(ii) NFE = L = 1 + ⌈log_r(N/n_1)⌉ (ex.: N = 256, n_1 = 4, r = 2 ⇒ L = 7) +(iii) Custo total de posições = Σ_ℓ (N_ctx + Σ_{j≤ℓ} n_j) ≈ L·N_ctx + N·(r/(r−1))·L/2 + O(N) +``` +contra `T·(N_ctx + N)` da difusão (T passos, sequência completa por passo) e `N` passos incrementais do AR. + +**Prova.** (i) soma da série geométrica: `Σ_{ℓ=1}^{L} n_1 r^{ℓ−1} = n_1 (r^L − 1)/(r − 1)` e `n_1 r^{L−1} = N` ⇒ `n_1 = N/r^{L−1}` ⇒ soma `= N(1 − r^{−L})·r/(r−1)`. (ii) o laço de amostragem gera `c_1` (1 avaliação com entrada `ẑ_0 = prior/nível-1 slots`), depois `c_2`, …, `c_L` — cada nível exatamente uma avaliação, pois todas as `n_ℓ` posições do nível são emitidas em paralelo da fatoração `p_φ(c_ℓ|c_{<ℓ}) = Π_i p_φ(c_{ℓ,i}|c_{<ℓ})` (n-01 §3.1); o número de níveis com `n_L = N` e razão r é `L = 1 + log_r(N/n_1)`. (iii) soma direta com prefixo por nível. ∎ + +**Corolário B.2.1 (razão de aceleração teórica vs. difusão).** Fixada a qualidade, se a difusão requer `T` passos e NCM requer `L` níveis com custo por posição comparável, a razão de posições processadas é: +`Speedup_posições = T·(N_ctx+N) / [L·N_ctx + N·(r/(r−1))·L/2 + O(N)]`. +Para `N = 256`, `N_ctx = 256`, `T = 32` (típico MDLM com destilação), `L = 7`, `r = 2`: `≈ 32·512 / (7·256 + 256·2·3,5) ≈ 16384/3584 ≈ 4,6×` **só de posições**; o restante da faixa 9–31× reportada pelo paper vem de `T` maiores nos baselines fortes e de kernels (níveis iniciais curtos processados em blocos densos). **Nota de honestidade**: no KHTST (CPU/Cython), a razão de wall-clock deve ser medida com o roofline do projeto (padrão Teo 31.5) — ver n-03 T9. ∎ + +## Teo B.3 (gap exato da fatoração e compensação residual) + +**Enunciado.** Seja `M` a classe de modelos com fatoração next-concept (independência condicional intra-nível). Para qualquer distribuição alvo `q(c)` sobre hierarquias: +``` +(i) min_{p ∈ M} KL(q ‖ p) = Σ_{ℓ=1}^{L} E_{q(c_{<ℓ})}[ TC(c_ℓ | c_{<ℓ}) ] + com o mínimo atingido em p* com condicionais marginais: p*(c_{ℓ,i} | c_{<ℓ}) = q(c_{ℓ,i} | c_{<ℓ}). +(ii) [compensação] a dependência intra-nível de ℓ não capturada em ℓ é parcialmente re-injetada em ℓ+1, + pois c_{ℓ+1} condiciona no vetor REALIZADO c_ℓ (todas as posições conjuntamente): a cadeia entre níveis + carrega toda a informação conjunta; o gap irrecuperável é apenas Σ_ℓ E[TC(c_ℓ | c_{<ℓ})]. +(iii) o gap no ESPAÇO DE TEXTO é ≤ Σ_ℓ E[TC(c_ℓ|c_{<ℓ})]: dois códigos distintos podem decodificar para o + mesmo x (kernel de reconstrução), colapsando parte da dependência perdida. +``` + +**Prova.** +(i) Escreva `KL(q‖p) = E_q[log q(c)] − E_q[log p(c)]` com `log p(c) = Σ_ℓ Σ_i log p_i(c_{ℓ,i}|c_{<ℓ})`. Cada termo `E_q[log p_i(c_{ℓ,i}|c_{<ℓ})] = E_{c_{<ℓ}} E[log p_i | c_{<ℓ}] ≤ E_{c_{<ℓ}}[log q(c_{ℓ,i}|c_{<ℓ})]` por Gibbs, com igualdade em `p_i = q(c_{ℓ,i}|c_{<ℓ})` (marginal condicional) — os termos otimizam-se independentemente por posição. Somando: +`min_p KL = E[log q(c)] − Σ_ℓ E_{c_{<ℓ}}[Σ_i H(q(c_{ℓ,i}|c_{<ℓ}))]`. Como `E[log q(c)] = −Σ_ℓ E_{c_{<ℓ}}[H(q(c_ℓ|c_{<ℓ}))]`, a diferença é `Σ_ℓ E_{c_{<ℓ}}[Σ_i H(c_{ℓ,i}|c_{<ℓ}) − H(c_ℓ|c_{<ℓ})] = Σ_ℓ E[TC(c_ℓ|c_{<ℓ})] ≥ 0` (desigualdade da sub-aditividade da entropia; igualdade iff independência condicional sob q). +(ii) decorre da própria forma da classe `M`: a condicional de `c_{ℓ+1}` given `c_{≤ℓ}` é livre (não fatoriza sobre o PASSADO), então toda dependência ENTRE níveis é modelável; apenas a dependência DENTRO do mesmo nível no mesmo salto é restringida — e o Teo A.2(i) mostra que `c_{≤ℓ}` determina a reconstrução parcial que o nível ℓ+1 refina. +(iii) sejam `K = {(c,c') : Dec(c) = Dec(c')}` o kernel de reconstrução. A distribuição de texto induzida é `q_x = Dec_# q`. Para p ∈ M com o mesmo Dec: `KL(q_x ‖ Dec_# p) ≤ KL(q ‖ p)` (data-processing: `Dec` é um canal determinístico aplicado a ambas). Logo o gap de texto é ≤ gap de hierarquia. ∎ + +**Leitura honesta**: o preço da paralelização intra-nível é EXATAMENTE a correlação total condicional dos códigos (i); os níveis residuais e o kernel do decoder devolvem parte (ii)–(iii). O paper mede o efeito líquido: qualidade igual/superior aos DLMs fortes com 9–31× menos compute (n-01 §4) — evidência de que (ii)+(iii) dominam (i) na prática. A refatoração deve A/B testar `TC` medido por nível (verificação V6, n-04 §7). ∎ + +## Teo B.4 (amostragem prefixo-consistente / anytime formal) + +**Enunciado.** Para todo `k ≤ L`: (a) `p_φ(c_{≤k})` é a marginal exata do modelo (sem correção de marginais); (b) se `ĉ_{≤k} ∼ p_φ`, então `Dec(ẑ_k(ĉ))` é uma amostra do modelo de texto truncado no nível k, com fidelidade controlada pelo Treinamento A.2; (c) a política de parada `k* = min{k : confiança ≥ κ}` (ou orçamento NFE) define um estimador anytime com qualidade monotônica em expectativa sob p*. + +**Prova.** (a) a fatoração é uma cadeia: a marginal de `c_{≤k}` é `Π_{ℓ≤k} p_φ(c_ℓ|c_{<ℓ})` — não há normalização de prefixo (diferente de árvores especulativas, que exigem verificação/rejeição). (b) segue de (a) + definição do decoder. (c) monotonia em expectativa: sob `p*` do Teo B.3(i) e decoder ε-ótimo do Teo A.2(ii), `E[qualidade(k+1)] ≥ E[qualidade(k)] − (ε_{k+1} − ε_k)`; com ε's decrescentes (treino converge), monotônica. ∎ + +**Corolário B.4.1 (contraste com decodificação especulativa).** A árvore especulativa Medusa do KHTST (doc 14) mantém a distribuição AR exata ao custo de verificação/rejeição por bloco; a NCM troca exatidão da fatoração AR pela paralelização estrutural SEM verificação (a "verificação" é o próprio refinamento residual). As duas podem coexistir: especulação no nível fino + NCM nos níveis grossos (n-03 T7). ∎ + +--- + +# PARTE C — Comparação formal com difusão mascarada + +## Teo C.1 (decomposição exata do gap variacional da DLM) + +**Enunciado.** Para a difusão mascarada (Def. §0) com tempos `0 = t_0 < t_1 < … < t_T = 1` e reverso aprendido `p_θ`: +``` +−log p_θ(x_0) = −ELBO(θ; x_0) + Σ_{j=1}^{T} E_{x_{t_j}}[ KL( q(x_{t_{j−1}} | x_{t_j}, x_0) ‖ p_θ(x_{t_{j−1}} | x_{t_j}) ) ] +``` +O segundo termo é o **gap** — estritamente positivo exceto se `p_θ` igualar o processo posterior verdadeiro em toda trajetória. Três consequências estruturais: +``` +(C1) a perda de treino (−ELBO) NÃO é uma verossimilhança: comparar modelos por ELBO mistura qualidade com folga; +(C2) amostrar com T' < T passos usa p_θ fora do regime treinado (agregação de passos) ⇒ degradação rápida com + poucos passos — o 1º problema dos DLMs (n-01 §1.2); +(C3) o número de passos necessários cresce com N (cada passo re-processa a sequência inteira) — o 2º problema. +``` + +**Prova.** Decomposição telescopável padrão da cadeia direta/reversa (Sohl-Dickstein 2015; Song et al. 2021; para o caso absorvente discreto: Sahoo et al. 2024, MDLM): `log p_θ(x_0) = ELBO(θ) − Gap(θ)` aplicando Jensen em cada elo da cadeia `q(x_{t_{j-1}}|x_{t_j}, x_0) / p_θ(x_{t_{j-1}}|x_{t_j})`; a igualdade de cada KL a zero exige `p_θ(x_{t_{j−1}}|x_{t_j}) = q(x_{t_{j−1}}|x_{t_j}, x_0)` q.d., que o modelo paramétrico não satisfaz em geral. (C2): a margem treinada de `p_θ` corresponde ao particionamento `{t_j}`; saltar elos usa produtos de condicionais fora de distribuição. (C3): cada avaliação de `p_θ(x_{t_{j−1}}|x_{t_j})` custa O(N_ctx + N). ∎ + +**Contraste NCM** (aplicando B.1 + B.2): perda = verossimilhança exata (resolve C1); NFE = L com blocos curtos nos níveis iniciais (resolve C3); menos passos de treino (4–5×) porque cada exemplo fornece sinal para TODOS os níveis em um forward com teacher forcing denso (mitiga o análogo de C2 no treino); a degradação com L' < L é suave e monotônica por A.2 (anytime) — não há "salto de elos fora de distribuição", há truncamento de prefixo dentro de distribuição treinada. ∎ + +## Teo C.2 (vantagem de planejamento global — teorema condicional de decomposição de consistência) + +**Enunciado.** Seja `S = {x : G(x) = 1}` o suporte válido (restrições globais; ex.: Sudoku válido, resposta matemática consistente) e `q_S` a distribuição alvo condicionada. Defina o **plano** como o prefixo grosso `π(x) := c_{1:k}(x)` (k fixo). Suponha: +- **(H1) informatividade do plano**: existe `f` verificável com `G(x) = 1 ⟺ f(c_{1:k}(x)) = 1 ∧ Λ(x, c_{1:k}(x))`, onde `Λ` é a consistência local do detalhe dado o plano (ex.: dígitos finais compatíveis com o esqueleto do tabuleiro); +- **(H2) condicionais treinadas consistentes**: `P(Λ(ċ) | ĉ_{≤k}, f(ĉ_{≤k}) = 1) ≥ 1 − ε` sob o gerador treinado em `q_S`; +- **(H3) plano alcançável**: `P(f(ĉ_{≤k}) = 1) ≥ β` por amostragem direta dos níveis 1..k (com ≤ k·NFE). + +Então a probabilidade de geração válida da NCM satisfaz: +``` +P_NCM(G = 1) ≥ β·(1 − ε) +``` +ao passo que **qualquer gerador flat** (fatoração sem plano — AR puro com decisões locais ou difusão com denoising uniforme sem noção de escala) que satisfaz as restrições locais com a mesma competência (1−ε) por decisão independente em m unidades de decisão satisfaz: +``` +P_flat(G = 1) ≤ β·(1 − ε)^m ⟹ P_NCM / P_flat ≥ (1 − ε)^{1−m} → ∞ em m (para ε > 0) +``` +e o custo de revisão: um plano inválido custa re-amostrar ≤ k níveis (≤ k·NFE, prefixo grosso curto); uma inconsistência flat detectada na posição i custa re-gerar O(N − i) unidades. + +**Prova.** Por H3, com probabilidade ≥ β o prefixo amostrado tem `f = 1`. Condicionado nisso, por H2, o restante da hierarquia (níveis k+1..L, gerados condicionados ao plano válido — Teo B.4(a)) satisfaz Λ com probabilidade ≥ 1−ε. Interseção: `P ≥ β(1−ε)` (união complementar). Para o flat: sem plano, a probabilidade de G=1 fatora-se no pior caso em m decisões locais independentes cada uma ≤ (1−ε) (a não ser que o modelo "planeje internamente", o que é precisamente o que a fatoração não expõe); com `P(f-correto) ≤ β` análogo, `P ≤ β(1−ε)^m`. A razão segue por divisão (caso ε = 0 é degenerado: ambas = β). Custo de revisão: na NCM, os níveis > k são funções de `ĉ_{≤k}` (fatoração); re-amostrar `ĉ_{≤k}` preserva o interface — custo Σ_{ℓ≤k} n_ℓ ≤ n_1·r^k·r/(r−1) ≪ N quando k ≪ L (B.2(i)); no flat AR, a re-amostragem a partir da posição i requer re-gerar N−i tokens (custo esperado E[N−i]). ∎ + +**Leitura honesta (exigida pelo padrão do projeto).** H1–H3 são **hipóteses empíricas**, não teoremas: H1 diz que os níveis grossos capturam a estrutura das restrições (o paper valida indiretamente: NCM resolve 99,5%/96,5%/86,1% easy/medium/hard vs. 97,7%/92,8%/81,3% do melhor baseline, e a degradação com a dificuldade é a MENOR — consistente com o termo (1−ε)^{1−m}); H2 é a competência treinada; H3 mede a própria aprendibilidade do plano. A tese correta é: **se** o tokenizador produz planos informativos (H1 — reforçado pelo nested dropout, A.2), **então** a vantagem é exponencial em m. No KHTST, testar em `raciocinio`/`matematica` (GSM8K/MATH-500 já no registry; n-04 §8). ∎ + +## Teo C.3 (corrupção de condicionamento = otimização robusta por distribuição) + +**Enunciado.** Seja `R_κ(φ) = E_{c∼q_T} E_{c̃ ∼ κ(c)}[ −log p_φ(c_ℓ | c̃_{<ℓ}) ]` o risco treinado com corrupção κ (mascarar/substituir fração ρ dos códigos de condição), e `R(φ; D)` o risco sob qualquer distribuição D de contextos-condição. Então: +``` +(i) [Lema de Lipschitz] se −log p_φ(c_ℓ | ·) é L-Lipschitz na representação de condição ρ(c) e + E_{c̃∼κ(c)}‖ρ(c̃) − ρ(c)‖ ≤ δ, então |R_κ(φ) − R_clean(φ)| ≤ L·δ. +(ii) [Cobertura] se a distribuição de contextos AUTO-GERADOS em inferência D_inf satisfaz + D_inf ≼ · (dominada por) uma mistura da família {κ(c) : c ∼ q_T}, então + R(φ; D_inf) ≤ R_κ(φ) / (peso da mistura) — treinar com corrupção domina o risco de exposure bias. +(iii)[Equivalência DRO] R_κ(φ) = sup_{η ∈ conv(κ)} E_{(c,η)}[−log p_φ(c_ℓ | η(c_{<ℓ}))] quando κ é convexa + em distribuição — corrupção = regularização adversarial no espaço de contextos. +``` + +**Prova.** +(i) Por Lipschitz e Jensen: `|E[−log p(c_ℓ|ρ(c̃))] − E[−log p(c_ℓ|ρ(c))]| ≤ E|…| ≤ L·E‖ρ(c̃)−ρ(c)‖ ≤ Lδ`. +(ii) Se `D_inf(A) ≤ (1/w)·P_{c∼q_T, c̃∼κ(c)}(A)` para todo mensurável A (dominação com constante w), então `R(φ; D_inf) = E_{D_inf}[ℓ(contexto)] ≤ (1/w)·E_{q_T×κ}[ℓ(c̃)] = R_κ(φ)/w`. +(iii) para família convexa κ, a média da perda sobre κ é a sup sobre a envoltória convexa (dualidade de minimax com φ fixo — troca direta de expectativa e sup em função afim na medida). ∎ + +**Interpretação operacional (para o agente de código)**: a corrupção é o **análogo funcional do ruído de difusão**, com três diferenças estruturais: (a) corrompe o PASSADO (condição), não o futuro (alvo) — treina o gerador para o regime em que ele mesmo gerou o passado (exposure bias na escala de níveis); (b) tem garantia de cobertura mensurável (ii): calibrar ρ tal que a taxa de erro do gerador por nível em validação ≤ ρ (a suíte v24 mede; n-04 §7 V5); (c) degrada-se graciosamente: com ρ = 0 recupera-se o teacher forcing puro. ∎ + +## Teo C.4 (MBR: consistência e regret com orçamento fixo) + +**Enunciado.** Seja `u(y, y') ∈ [0, 1]` uma utilidade entre textos (ex.: 1 − distância de edição, ROUGE-L, ou utilidade de ensemble) e `ĉ_1, …, ĉ_n ~ p_φ(·|cond)` i.i.d. (cada um com L NFE). O estimador MBR empírico é `ŷ_n = argmax_j (1/n)Σ_k u(ĉ_j, ĉ_k)`. +``` +(i) [Bayes-otimalidade assintótica] ŷ_n → argmax_y E_{y'∼p_φ}[u(y, y')] q.c.; o limite maximiza a utilidade + esperada sob o próprio modelo (decisão de Bayes para u). +(ii) [Regret] Regret(ŷ_n) := E[u(y_Bayes, y')] − E[u(ŷ_n, y')] ≤ 2·E[sup_j |û_n(j) − u*(j)|] → 0 com taxa + O(√(log n / n)) para classes de utilidade limitadas com cobertura uniforme (Hoeffding + união). +(iii)[Orçamento fixo B] n_ncm = ⌊B/(L·c_pos)⌋ vs. n_dlm = ⌊B/(T·c_pos)⌋; com T ≫ L (ex.: T = 32, L = 7): + n_ncm/n_dlm = T/L ≈ 4,6× mais candidatos ⇒ regret menor por (ii); a NCM ganha o test-time scaling + POR CONSTRUÇÃO de custo (B.2), não por magia estatística. +``` + +**Prova.** +(i) Lei dos grandes números por candidato + argmax contínuo (portanto de análise padrão; ver Kumar & Byrne 2004, MBR para NLG). +(ii) Hoeffding: `P(|û_n(j) − u*(j)| > t) ≤ 2e^{−2nt²}`; união sobre j ≤ n: `P(sup_j > t) ≤ 2n·e^{−2nt²}`; escolha `t = √(log(2n/δ)/(2n))`; o regret de escolher argmax de estimativas com erro ≤ t é ≤ 2t (utilidade em [0,1]). +(iii) contas diretas de orçamento. ∎ + +**Integração KHTST**: a utilidade `u` pode ser o **ensemble RF×DNN×Engram existente** (`ensemble/votacao.py`) — MBR sobre candidatos NCM com utilidade de ensemble, sem novos parâmetros (n-03 T6). ∎ + +--- + +# PARTE D — Teoremas de integração híbrida (NCM no tronco KHTST) + +## Teo D.1 (implementabilidade da máscara block-causal no tronco Mamba-3 5:1 + NoPE) + +**Enunciado.** O tronco do KHTST (`n_camadas = 6`: 5 camadas Mamba-3 causais + 1 camada NoPE attention; config `modelo.mamba3.n_camadas = 6`, proporção 5:1 provada no Teo 35.5) **implementa** o gerador next-concept com a seguinte construção. Para prever o nível ℓ, monte a sequência +``` +s = [ cond ; lev_1 ; lev_2 ; … ; lev_L ] +``` +onde `cond` é o prefixo de condicionamento (prompt/imagem/profundidade/etc.) e `lev_ℓ` contém `n_ℓ` slots inicializados com `ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ` (reconstrução cumulativa interpolada + embedding de nível `e_ℓ`). Então: +``` +(i) [fluxo causal entre níveis] as camadas Mamba-3 propagam estado estritamente esquerda→direita: os slots de + lev_ℓ recebem informação apenas de cond e lev_{<ℓ} — exatamente a condição c_{<ℓ} da fatoração (n-01 §3.1); + NENHUM slot de lev_ℓ depende de c_ℓ (o próprio nível), pois a entrada de lev_ℓ é função determinística de c_{<ℓ}. +(ii) [coordenação bidirecional intra-nível] a camada NoPE com máscara block-causal B (lev_ℓ atende a lev_{≤ℓ} + integralmente) fornece a mistura bidirecional DENTRO do bloco exigida pelo NCM ("block-diagonal attention", + n-01 §3.2) — sem encoding posicional, a posição vem do embedding de nível e da ordem causal do fluxo Mamba. +(iii)[inferência incremental com cache] prever c_ℓ requer: estado Mamba carregado até lev_{ℓ−1} (streaming), + KV-cache da NoPE sobre [cond; lev_{<ℓ}] (offset de posição tratado pelo RoPE-cache do Teo 35.8 quando a + atenção posicional existir; na NoPE não há offset a corrigir), e UMA avaliação do bloco lev_ℓ. + Logo NFE = L (confirma B.2 na arquitetura real do KHTST). +(iv) [treino em uma passada] a montagem completa de s com teacher forcing (ẑ das hierarquias VERDADEIRAS, com + corrupção κ opcional) permite computar a CE de todos os níveis em um único forward — paralelismo de treino + idêntico ao do transformer AR existente no treinador. +``` + +**Prova.** +(i) O kernel Mamba-3 é causal por construção (conv causal + scan seletivo SSM; doc 22 do KHTST): a saída na posição j depende somente das entradas ≤ j. Como `lev_ℓ` ocupa posições estritamente posteriores a `lev_{<ℓ}`, e a entrada em `lev_ℓ` é `g(c_{<ℓ}) := ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ` (determinística de `c_{<ℓ}`), a função computada nas posições de `lev_ℓ` após qualquer composição de camadas causais tem a forma `F(cond, c_{<ℓ}, índices)` — a distribuição preditiva `p_φ(c_ℓ | c_{<ℓ})` é realizável na cabeça de leitura dessas posições. Não há vazamento de `c_ℓ` porque `c_ℓ` não aparece em nenhuma entrada anterior às saídas de `lev_ℓ`. +(ii) A camada NoPE (atenção sem encoding posicional, doc 22) admite qualquer máscara aditiva; a máscara block-causal `B[(ℓ,i),(j,k)] = 1 ⟺ j ≤ ℓ` é uma máscara aditiva válida (assim como a máscara causal estrita e a completa já usadas no projeto). Com B, os slots de `lev_ℓ` agregam o bloco próprio e os anteriores — bidirecional dentro do bloco, causal entre blocos. +(iii) Streaming do Mamba: o estado SSM após processar `[cond; lev_{<ℓ}]` resume todo o passado (propriedade de estado do SSM, doc 22); a NoPE mantém K/V por posição (cache), com custos e offsets já tratados pela infraestrutura de cache existente (`kv_cache_max = 2048`; o offset do RoPE do Teo 35.8 cobre atenções posicionais se ativadas). A avaliação do bloco `lev_ℓ` é um forward padrão. +(iv) Forward único sobre s: as posições de todos os níveis são computadas simultaneamente (as causais respeitam a ordem; a NoPE com máscara B não mistura níveis futuros), e a cabeça de conceitos aplica CE por nível. ∎ + +**Restrição honesta (hipótese H_D1).** No NCM de referência, a atenção bidirecional intra-nível ocorre em TODAS as camadas; no KHTST, apenas na camada NoPE (1 de 6). A mistura intra-bloco das camadas Mamba é causal (esquerda→direita dentro do bloco). Hipótese a validar por A/B: **a coordenação bidirecional 1-in-6 basta** para capturar a correlação total intra-nível (Teo B.3(i)). Mitigação se falhar: (a) processar o bloco `lev_ℓ` duas vezes (ida e volta — custo 2× no bloco, ainda ≪ N total); (b) mover a NoPE para posição terminal do tronco; (c) bloco de "retorno" com reversão de ordem no Cython existente. Registrar na suíte v24 (n-04 §7 V7). ∎ + +## Teo D.2 (invariância do condicionamento multimodal) + +**Enunciado.** Seja `m(x_img, x_depth, x_audio, …)` a saída dos encoders perceptuais do KHTST (imagem ⊕ profundidade ⊕ vit_lra com detecção paralela de escala de cinza; gates α, γ₁ do doc 27). Substituir o prefixo `cond` por `m(·)`: +``` +(i) preserva a fatoração: p_φ(c_ℓ | c_{<ℓ}, m) continua realizável pelo tronco (Teo D.1 com cond := m); +(ii) preserva os gradientes de percepção: ∂L_gen/∂θ_percep = Σ_ℓ E[∂log p_φ(c_ℓ|·)/∂m]·∂m/∂θ_percep — + o gradiente flui pelos gates exatamente como flui hoje na CE de tokens (mesma regra da cadeia do Teo 31.2); +(iii) CFG multimodal: treino com dropout do condicionamento (prob. p_cfg) e inferência com interpolação de logits + ℓ̃ = ℓ_uncond + s·(ℓ_cond − ℓ_uncond) é exata no espaço logit e coincide com a fórmula padrão de CFG. +``` + +**Prova.** (i) o Teo D.1 nada assume sobre o conteúdo de `cond` — apenas que precede os blocos. (ii) regra da cadeia sobre o prefixo; a percepção é função das entradas multimodais e dos gates; nenhum stop-gradient é introduzido no caminho `m → tronco → logits` (o stop-gradient da memória SOM, Teo 17.4, é outro caminho — pós-geração). (iii) com dois forward passes (condicionado e não-condicionado — o último obtém `cond` mascarado), a interpolação de logits é uma combinação afim de distribuições exponenciais; `s = 1` recupera a condicionada, `s = 0` a marginal — identidade algébrica. ∎ + +**Corolário D.2.1 (o ciclo fechado do doc 17 permanece íntegro).** O contrato de memória do ciclo geracional (re-encodação da saída treina o SOM com stop-gradient, Teo 17.4) é independente do modo de geração do texto: a unidade NLG passa a decodificar hierarquias em vez de tokens AR, e o passo 4 do ciclo (e_out treina memória) é inalterado. ∎ + +## Teo D.3 (autorregulação RM por nível — condições de Borkar preservadas) + +**Enunciado.** As recursões de Robbins–Monro multiplicativas do `nucleo/autorregulador.py` (Teos 28.5–28.8: `Σa_t = ∞`, `Σa_t² < ∞`, separação de duas escalas de Borkar, nascimento neutro) aplicam-se a temperaturas por nível `τ_1, …, τ_L` e à escala CFG `s`: (i) cada `τ_ℓ` vive num intervalo seguro `[τ_min, τ_max]` com nascimento neutro `τ_ℓ(0) = τ₀` (1ª aplicação = identidade); (ii) a bisseção de entropia-alvo (erro ≤ 2^{−k}, Teo 28.8) calibra `τ_ℓ` por nível contra a entropia alvo `H*_ℓ` — o intervalo de busca é contínuo e contrátil porque a entropia da softmax é estritamente crescente em `τ` (monotonia estrita); (iii) o sistema acoplado `{τ_ℓ}` converge q.c. sob as mesmas condições de passo de Robbins–Monro indexadas por nível. + +**Prova.** (i) verbatim Teo 28.5 com parâmetro indexado por ℓ (as condições são por coordenada). (ii) a entropia `H(softmax(logits/τ))` é contínua e estritamente crescente em τ > 0 para logits não-degenerados (derivada = Cov Sobol não-negativa, estritamente positiva se os logits não são todos iguais — lema padrão); a bisseção herda contração 2^{−k} do Teo 28.8. (iii) as duas escalas de Borkar (τ's rápidos, sinais lentos) preservam-se porque o acoplamento entre níveis ocorre apenas através da AMOSTRAGEM (não dos passos): a atualização de `τ_ℓ` usa estatísticas do nível ℓ com passos `{a_t}` independentes por coordenada — o teorema de convergência quase-certa de processos estocásticos recursivos acoplados com taxas separadas aplica-se (Borkar 2008, Thm 6.2 — mesma citação dos Teos 28.5–28.8). ∎ + +## Teo D.4 (síntese GSQ+RCO ⇒ tokenizador NCM com gradiente exato e contração garantida) + +**Enunciado.** Instanciar os codebooks do tokenizador NCM como **RCO-Stiefel** (`C_ℓ^T C_ℓ = R_ℓ² I`, retração polar do Teo 32.11 a cada passo) com **seleção GSQ** (logits `⟨z, c_{ℓ,k}⟩/τ_ℓ`, decaimento analítico de τ do Teo 26.x) produz um tokenizador que herda, simultaneamente: +``` +(i) contração geométrica garantida do resíduo: Teo A.1 com K = K_ℓ ≤ d_lat (fator (1 − 1/K_ℓ) por nível no span); +(ii) gradiente exato do relaxamento em τ > 0 (sem STE): Teo A.4(iii) — a ponte autograd MCJepaFn do projeto é o + precedente estrutural (Teo 28.9: gradiente analítico ≡ autograd); +(iii) manutenção numérica certificada: a retração polar mantém ‖C^T C − R²I‖_F ≤ δ_ort (padrão δ_ort ≤ 3e-6 do + projeto, docs 26–27) — a cota de contração (i) degrada-se continuamente com δ_ort (perturbação de Weyl nos + autovalores do frame), logo o monitor δ_ort EXISTENTE do projeto vigora o Teo A.1 sem novo instrumento. +``` + +**Prova.** (i) é o Teo A.1 com a hipótese de ortonormalidade satisfeita por construção (RCO). (ii) é o Teo A.4(iii). (iii) a hipótese `U^T U = I` do Teo A.1 usa apenas Parseval `Σ_k ⟨z,u_k⟩² = ‖P_C z‖²`; sob perturbação `‖U^T U − I‖_F ≤ ε_ort`, `|Σ_k ⟨z,u_k⟩² − ‖P_C z‖²| ≤ ε_ort·‖z‖²` (expansão quadrática), e a conclusão do Teo A.1 vale com o termo adicional `+ε_ort‖z‖²` no lado direito — degradação contínua, monitorada pelo δ_ort já medido pela suíte do projeto. ∎ + +**Especificação derivada** (para n-04): `d_lat = 64`, `K_ℓ = 64` (Stiefel estrito: K ≤ d) com `R_ℓ` adaptativo por EMA, OU `d_lat = 64, K_ℓ = 256` com penalidade de coerência Welch (Cor. A.1.2) — a escolha é hiperparâmetro da fase A (n-04 §5). + +## Teo D.5 (compressão de contexto hierárquica para a janela 1M) + +**Enunciado.** Para uma história de `N = 262144` tokens (janela_1m do KHTST, `n_max_tokens`) e hierarquia geométrica com razão r: +``` +(i) o prefixo de níveis ≤ k representa a história com Σ_{ℓ≤k} n_ℓ ≤ N·r^{−(L−k)}·r/(r−1) códigos — + compressão fator ≈ r^{L−k} em relação a N; +(ii) com r = 4 e L = 11: nível 1 tem 1 código por 4^{10} = 1.048.576 tokens ⇒ a história INTEIRA cabe em + ~n_1 = 1 código de resumo global + n_2 = 4 … — os níveis grossos são exatamente o "resumo indexado" + que a janela 1M emula hoje com w_segmento/s_passo (doc 13), agora com reconstrução decodificável + (Teo A.2) e distorção controlada (Teo A.3); +(iii) o orçamento de memória M códigos escolhe k(M) = max{k : Σ_{ℓ≤k} n_ℓ ≤ M} e atinge o ponto + (R_{k(M)}, D_{k(M)}) da cadeia de refinamento do Cor. A.2.2 — política de cache ótima por fronteira RD. +``` + +**Prova.** (i) série geométrica de B.2(i) aplicada ao prefixo. (ii) contas diretas com os valores do config. (iii) segue de A.2/A.3: a monotonia do risco (A.2(i)) e a decomposição (A.3) fazem do consumo incremental de níveis a política gulosa ótima para orçamento em bits — o mesmo argumento de refinamento sucessivo do Cor. A.2.2. ∎ + +## Teo D.6 (MTP do KHTST é caso particular da fatoração NCM) + +**Enunciado.** A perda MTP do KHTST (`treino/mtp.py`: k_cabecas = 2, β_entropia, k adaptativo; doc correlato) é o caso particular da perda NCM com: +``` +L = 2 níveis; n_1 = n_2 = N; codebooks triviais C_1 = C_2 = embedding do vocabulário (K = |V|, d = d_modelo); +resíduo nulo (os níveis particionam os tokens em conjuntos disjuntos em vez de refinarem um resíduo comum); +corrupção κ = nula; nested dropout degenerado p(ℓ) = δ_{ℓ2}. +``` +Sob essa substituição de parâmetros, `L_gen` (n-02 §0) reduz-se algebricamente à perda MTP multi-cabeça com pesos iguais por cabeça. + +**Prova.** Substituindo: a fatoração `p(c_1)·p(c_2|c_1)` com `c_1 =` tokens de posições pares e `c_2 =` ímpares (ou 1ª/2ª metade, conforme o particionamento do `mtp.py`) e codebooks = identidade vocabular dá `−log p = CE(x_impares) + CE(x_pares | x_impares)` — exatamente a soma de CE das cabeças MTP com o mesmo condicionamento teacher-forced (a cabeça 1 prediz sem contexto extra; a cabeça 2 condiciona na primeira). A regularização de entropia β do MTP é um aditivo independente que a NCM pode carregar como qualquer outro regularizador de perda. ∎ + +**Corolário D.6.1 (generalização estrita).** A refatoração NCM **contém** o caminho MTP existente: com a configuração acima, `L_ncm ≡ L_mtp`; com VQ residual, L > 2 e nested dropout ativados, o objetivo estende-se. Logo desativar `mtp.ativo` em favor de `ncm.ativo` NÃO remove capacidade — reorganiza-a (a perda de entropia β e o k adaptativo migram para os hiperparâmetros NCM correspondentes). A/B testar como braços separados (n-04 §8). ∎ + +## Teo D.7 (PCGrad preserva as invariantes com a perda NCM adicionada) + +**Enunciado.** Seja `S = {L_1, …, L_J}` o conjunto atual de perfas multi-tarefa do treinador (mistura_tarefas do config) e `L_ncm` a nova perda de conceitos. O passo PCGrad do KHTST v23 (Teo 35.1: `g = g_m + (g_a − (⟨g_a,g_m⟩/‖g_m‖²)·g_m)` — projeção no complemento ortogonal, invariantes I1/I2/I3 de Yu et al. 2020 Alg. 2) aplicado a `S ∪ {L_ncm}`: +``` +(i) [não-piora por par] para TODO par (i, ncm): a projeção remove de g_ncm a componente que conflita com g_i + sem aumentar o produto interno restante — a prova do Teo 35.1 é agnóstica à identidade da perda; +(ii) [zero regressão estrutural] com ncm.ativo = false, L_ncm ≡ 0 e g_ncm = 0: o passo é o de hoje, bit-a-bit + (nascimento neutro por bandeira, padrão Teo 29.16); +(iii)[ordem de magnitude] a normalização EMA de magnitudes do PCGrad v18 (Teo 30.3, anti-dominação) já opera + sobre pares arbitrários — inclui os pares novos sem alteração de código. +``` + +**Prova.** (i) o Teo 35.1 prova, para um par de gradientes quaisquer (g_m, g_a) com g_m ≠ 0: ⟨g_a′, g_m⟩ = 0 (projeção exata), ‖g_a′‖ ≤ ‖g_a‖ (contração), e a não-piora de L_m no passo combinado sob passo suficientemente pequeno — nada na prova usa a origem dos gradientes; vale para (g_i, g_ncm). (ii) com λ_ncm = 0 a perda contribui com gradiente nulo e o mapa do passo é o de v23 (a construção do nascimento neutro garante que a 1ª aplicação com λ = 0 é a identidade). (iii) a normalização por EMA é por gradiente individual — ortogonal à projeção por pares. ∎ + +--- + +## §Síntese — o que as Partes A–D estabelecem em conjunto + +1. **Factualidade do tokenizador** (A): a hierarquia residual converge geometricamente sob codebooks Stiefel/RCO (A.1, D.4), todo prefixo é decodificável com risco monotônico sob nested dropout (A.2), e o erro decompõe-se em termos separadamente controláveis (A.3) — com reuso direto de GSQ+RCO (A.4/D.4). +2. **Factualidade da fatoração** (B): treino por MLE exato sem ELBO (B.1), inferência com NFE = L e custo amortizado ≤ 2N posições (B.2), gap da paralelização exatamente igual à correlação total condicional — com compensação residual e kernel do decoder (B.3) — e decodificação anytime sem correção de marginais (B.4). +3. **Vantagem sobre difusão mascarada** (C): eliminação do gap variacional (C.1 vs B.1), vantagem de planejamento global condicionada a planos informativos (C.2 — a hipótese H1 é o que o nested dropout reforça), corrupção = robustez certificável contra exposure bias (C.3), e MBR com mais candidatos por orçamento (C.4). +4. **Executabilidade no KHTST** (D): a máscara block-causal é implementável no tronco 5:1 com uma única restrição honesta (H_D1: bidirecionalidade 1-in-6 no NoPE), o condicionamento multimodal e o ciclo de memória são invariantes (D.2), a autorregulação RM e a bisseção de temperatura estendem-se por nível (D.3), os codebooks herdam RCO+GSQ com monitoramento δ_ort existente (D.4), a janela 1M ganha um resumo hierárquico decodificável (D.5), MTP ⊂ NCM (D.6) e o PCGrad absorve a nova perda sem perder invariantes (D.7). + +**Conclusão lógica global.** Conjunção: (A)∧(B)∧(C)∧(D) ⇒ a introdução do NCM no KHTST é (a) **bem-fundamentada** (sem aproximação variacional; todas as aproximações residuais são medidas e monitoráveis), (b) **compatível** com a arquitetura, otimizadores, quantização, memória e protocolos existentes, e (c) **reversível** (opt-in com nascimento neutro). As condições restantes são empíricas (H_D1, H1–H3 do C.2) e têm protocolo de validação definido em n-04 §7–§8. diff --git a/docs/memoria-ncm-khtst/n-03-provas-refatoracao.md b/docs/memoria-ncm-khtst/n-03-provas-refatoracao.md new file mode 100644 index 0000000000000000000000000000000000000000..10bae7e94e291f1c7fdb8516875f593241f6375a --- /dev/null +++ b/docs/memoria-ncm-khtst/n-03-provas-refatoracao.md @@ -0,0 +1,146 @@ +# n-03 — PROVAS DE FACTIBILIDADE DA REFATORAÇÃO (T1–T10) +> **Coleção**: `memoria-ncm-khtst` · **Pré-requisitos**: n-01, n-02 · **Snapshot de referência**: KHTST v23 (commit `1d5bd51`, 2026-10-18) +> **Método**: cada prova T_i afirma uma propriedade de **compatibilidade de engenharia**, demonstra-a por construção/mapeamento sobre módulos e teoremas EXISTENTES do projeto, lista os artefatos tocados e define o gancho de verificação. Teoremas da n-02 são citados como `Teo X.n`; teoremas do projeto como `Teo .`. + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Dez provas de factibilidade (T1–T10) estabelecem que a introdução do NCM no KHTST requer apenas: um pacote novo (`src/khtst/conceitos/`), uma seção de config opt-in (`ncm`), uma perda adicional em `perdas.py` e um modo de geração em `gerar()` — sem modificar semanticamente nenhum módulo de produção. Cada prova ancora-se em teoremas já provados no projeto (PCGrad Teo 35.1, torchao Teo 28.1, RoPE-offset Teo 35.8, GSQ/RCO Teos 26–27, autorregulação Teos 28.5–28.8, hipergradiente λ Teo 29.2, memória Teo 17.4) e nos teoremas desta coleção (n-02). A não-regressão é estrutural: com `ncm.ativo = false`, a v24 é bit-a-bit idêntica à v23. +- **EN**: Ten feasibility proofs (T1–T10) establish that introducing NCM into KHTST requires only: one new package (`src/khtst/conceitos/`), one opt-in config section (`ncm`), one additional loss in `perdas.py`, and one generation mode in `gerar()` — with no semantic modification of any production module. Each proof is anchored in theorems already proven in the project (PCGrad Teo 35.1, torchao Teo 28.1, RoPE-offset Teo 35.8, GSQ/RCO Teos 26–27, self-regulation Teos 28.5–28.8, λ hyper-gradient Teo 29.2, memory Teo 17.4) and in this collection's theorems (n-02). Non-regression is structural: with `ncm.ativo = false`, v24 is bit-identical to v23. + +--- + +## Mapa geral antes das provas + +| # | Afirmação central | Módulos tocados | Ancoragem | +|---|-------------------|-----------------|-----------| +| T1 | Interface de códigos = extensão de embedding, sem tocar o tronco | `conceitos/` (novo), `nucleo/modelo.py` (registro) | Teo B.1, D.1 | +| T2 | O tronco 5:1 executa a máscara block-causal com cache | `mamba3/tronco.py`, `memoria/atencao_som.py` (leitura) | Teo D.1, H_D1; Teo 35.8 | +| T3 | A perda NCM é drop-in em `perdas.py` com PCGrad e λ_vivo | `treino/perdas.py`, `treino/treinador_perdas.py` | Teo D.7; Teos 35.1, 29.2 | +| T4 | O tokenizador reusa GSQ+RCO e treina como fase prévia | `quanta/gsq_rco.py` (leitura), `conceitos/tokenizador_conceitos.py` (novo) | Teos A.1–A.4, D.4; Teos 26–27, 32.11 | +| T5 | `gerar(modo="conceitos")` com NFE = L, temperatura-auto e CFG | `nucleo/modelo.py::gerar`, `nucleo/autorregulador.py` | Teos B.2, B.4, D.3; Teos 28.8, 35.8 | +| T6 | MBR pluga no ensemble sem novos parâmetros | `ensemble/votacao.py` (leitura), `conceitos/amostrador.py` (novo) | Teo C.4 | +| T7 | MTP é subsumido; especulação Medusa coexiste | `treino/mtp.py` (leitura), `nlg/decodificador_especulativo.py` (leitura) | Teo D.6; Cor. B.4.1; doc 14 | +| T8 | Janela 1M ganha resumo hierárquico; contrato SOM intacto | `memoria/janela_1m.py` (leitura), `memoria/orquestrador.py` (leitura) | Teos D.5, A.2; Teo 17.4; doc 13 | +| T9 | Roofline honesto: speedup teórico × wall-clock medido | `telemetria/indicadores.py` (registro) | Teo B.2; Cor. B.2.1; Teo 31.5 (padrão) | +| T10 | Não-regressão estrutural (bit-a-bit, torchao, IPC, limites) | todos (bandeira), `quanta/torchao_quant.py` (exclusões) | Teos D.7(ii); 28.1, 29.16, 34.10 | + +--- + +## T1 — Compatibilidade de interface: códigos como cidadãos de primeira classe no pipeline de embedding + +**Afirmação.** Os códigos de conceito `c_{ℓ,i} ∈ [K_ℓ]` podem entrar no tronco KHTST **sem nenhuma alteração das camadas existentes**, por uma de duas vias equivalentes: +- **(via A, recomendada)** tabela de embeddings própria por nível: `Emb_ℓ ∈ R^{K_ℓ×d_modelo}`, `d_modelo = 192` — os slots de `lev_ℓ` recebem `Emb_ℓ[c_{ℓ,i}]` no treino teacher-forced do decoder e `ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ` na predição do gerador (D.1); +- **(via B)** extensão do vocabulário: ids `16384 + Σ_{j<ℓ} K_j + k` — reusa a tabela `embed_tokens` existente redimensionada (padrão "nascimento neutro": pesos novos inicializados e os antigos congelados na 1ª carga). + +**Prova.** O tronco consome `R^{B×T×d_modelo}` — é agnóstico à origem dos embeddings (mesma propriedade explorada hoje pelos encoders multimodais que injetam `m(·)` como prefixo; doc 22, percepcao). A via A não toca nenhum arquivo existente além do registro do módulo; a via B usa redimensionamento de embedding já praticado quando o tokenizador cresceu (vocab 16384 do BPE, doc 34 §corpus). A cabeça de conceitos é uma camada linear nova `R^{d_modelo} → R^{K_ℓ}` por nível, análoga à `lm_head` existente (que permanece para o decoder do tokenizador e para o modo AR). Ordem de grandece: `Σ_ℓ K_ℓ·d_modelo` parâmetros (K_ℓ = 64: ~74k; K_ℓ = 256: ~295k) — desprezível vs. o modelo (~18M) e **dentro do teto de RAM medido** (3.066 MB pico ≤ 3.580 do doc v12; margem ≥ 500 MB). ∎ + +**Artefatos**: `src/khtst/conceitos/__init__.py`, `gerador_conceitos.py` (novo); `nucleo/modelo.py` (+ registro `GeradorConceitos`, sem tocar forward existente). +**Verificação**: V1 da suíte v24 (shape/idempotência do registro; neutralidade bit-a-bit com `ncm.ativo=false`). + +## T2 — Compatibilidade do tronco: máscara block-causal + caches existentes + +**Afirmação.** A construção do Teo D.1 é realizável com os módulos atuais: (i) o `tronco.py` processa a sequência estendida `s = [cond; lev_1; …; lev_L]` como QUALQUER sequência (o Mamba-3 é agnóstico ao conteúdo; doc 22); (ii) a camada NoPE aplica a máscara block-causal `B` — máscaras aditivas já são suportadas (`usar_atencao_arvore` alterna máscaras no mesmo tensor; doc 14/22); (iii) a inferência incremental usa o KV-cache da atenção (`kv_cache_max = 2048` suficiente: `|cond| + Σ_{j<ℓ} n_j ≤ 256 + 256·2 = 512 ≤ 2048` com r = 2, pois Σ n_j ≤ 2N − N = 256·2 = 512 — Cor. B.2(i)) e o estado streaming do Mamba (propriedade do SSM, doc 22); (iv) quando a atenção posicional (RoPE) estiver ativa, o offset de cache do Teo 35.8 cobre os blocos novos sem reprocessar o prefixo. + +**Prova.** (i)–(ii): construção direta — a máscara `B[(ℓ,i),(j,k)] = 1 ⟺ j ≤ ℓ` é uma matriz booleana no formato já consumido pela atenção; o Teo D.1(ii) prova que o fluxo de informação respeita a fatoração. (iii): orçamento de cache: com `n_L = N = 256` (ctx do config) e r = 2, `Σ_{jℓ}` — teste de vazamento por gradiente; equivalente ao teste de causalidade já praticado em v23 para o RoPE-offset). + +## T3 — Perda drop-in em `perdas.py` com PCGrad e λ com hipergradiente exato + +**Afirmação.** A perda NCM entra no treinador como MAIS UMA perda da mistura multi-tarefa: +``` +L_ncm = λ_conceito · Σ_ℓ w_ℓ · CE_conceitos(ℓ) + λ_rec · CE_reconstrução (esta só na fase A do tokenizador) +``` +com três garantias herdadas: (i) o **PCGrad v23** (Teo 35.1: projeção no complemento ortogonal, invariantes I1/I2/I3) aplica-se ao conjunto ampliado sem alteração de código — prova Teo D.7; (ii) o padrão **λ_vivo com hipergradiente exato** do Teo 29.2 aplica-se a `λ_conceito`: `L(λ) = λ·L_diff + ρ(λ−λ₀)²` é afim+quadrática em λ, hipergradiente `∂L/∂λ = L_diff + 2ρ(λ−λ₀)` EXATO (erro zero), ótimo interior `λ* = λ₀ − L_diff/2ρ` — reusa a implementação `aprimoramento/difusao_gradiente.py` como molde (o módulo já provou o padrão para λ_diff); (iii) a **mistura_tarefas** existente (12 pesos no config) não muda — a perda NCM é transversal (aplica-se às tarefas com texto), controlada por `ncm.lambdas`. + +**Prova.** (i) Teo D.7 (prova completa em n-02): a prova do Teo 35.1 é agnóstica à identidade das perdas; com `λ_conceito = 0`, `g_ncm = 0` e o passo é o de v23 bit-a-bit (nascimento neutro por bandeira — padrão Teo 29.16/34.10). (ii) a forma afim+quadrática em λ é idêntica à do Teo 29.2 (a perda NCM não depende de λ); o hipergradiente é analítico; a âncora ρ dá ótimo interior provado. (iii) a CE de conceitos é uma CE padrão sobre `K_ℓ` classes — mesmo dtype, mesmo device policy, mesma redução por-média das perdas existentes em `perdas.py`. ∎ + +**Artefatos**: `treino/perdas.py` (+`perda_conceitos`, +`perda_reconstrucao_prefixo`), `treino/treinador_perdas.py` (mix-in de agregação), `conceitos/gerador_conceitos.py` (fonte dos logits). +**Verificação**: V5 (neutralidade bit-a-bit com λ=0), V8 (hipergradiente de λ: erro vs. finite-difference ≤ 1e-6 — padrão Teo 29.2). + +## T4 — Tokenizador de conceitos: reuso integral de GSQ + RCO + fases do treinador + +**Afirmação.** O Estágio 1 (tokenizador) é um módulo novo que **só lê** infraestrutura provada: (i) quantização por **GSQ** (Gumbel-Softmax com decaimento analítico de τ, agenda conservadora τ_min = 0,5 / t_alvo = 400 do Teo 30.6) no lugar do STE — gradiente exato do relaxamento (Teo A.4(iii)); (ii) codebooks mantidos em **Stiefel pela retração polar** do Teo 32.11 (QR → polar SVD → identidade; `afirmar_ortogonalidade` viga a violação) — contração garantida (Teos A.1/D.4), monitorada pelo **δ_ort** já reportado (padrão ≤ 3e-6, docs 26–27); (iii) o **nested dropout** (Teo A.2) é um sorteio de nível por exemplo — RNG dedicado no padrão do pareamento A/B (Teo 31.7); (iv) o decoder do tokenizador é uma cabeça transformer pequena que reusa o BPE/CE de 16384 (`dados/tokenizador.py` intocado). + +**Prova.** (i)–(ii): o Teo D.4 demonstra que a instância {codebooks RCO-Stiefel + seleção GSQ} satisfaz as hipóteses do Teo A.1 com degradação contínua em δ_ort — e o δ_ort é medido pela suíte existente (basta estender o produtor aos codebooks novos, 1 indicador no TelemetryHub, padrão doc 34 §2). (iii): o nested dropout altera apenas quais prefixos entram na CE por exemplo — não introduz dependência entre exemplos; o RNG dedicado preserva o pareamento (o gerador de máscaras dedicado do Teo 31.7 é o precedente exato). (iv): a reconstrução é uma CE teacher-forced padrão sobre o vocabulário — a mesma operação do treino LM de hoje, apenas com entrada `ẑ_ℓ` no lugar dos embeddings de token. **Treino em fases**: o treinador já tem o conceito (fase_densa_ate_epoca, fase_som, qat_ultimos_passos, duas_fases.py do doc 15) — a fase A (tokenizador) é uma fase prévia com `coletar_metricas` opt-in (padrão observador puro do Teo 34.1: bit-a-bit desligado). ∎ + +**Artefatos**: `conceitos/tokenizador_conceitos.py` (novo), `treino/treinador_fases.py` (+fase A opt-in), `telemetria/indicadores.py` (+δ_ort_conceitos, +contração por nível). +**Verificação**: V2 (contração medida por nível vs. cota (1−1/K)^ℓ do Cor. A.1.1 — reportar AMBAS, honestidade), V3 (monotonia do risco de prefixo sob nested dropout — Teo A.2 em dados reais), V9 (δ_ort ≤ 3e-6 após retração). + +## T5 — Inferência: `gerar(modo="conceitos")` com NFE = L, temperatura-auto e CFG + +**Afirmação.** O caminho de inferência estende `gerar()` sem modificar o caminho AR: (i) o laço de níveis executa L avaliações (Teo B.2) com caches de T2; (ii) a **temperatura automática por entropia-alvo** do Teo 28.8 (bisseção contrátil, erro ≤ 2^{−k}) calibra `τ_ℓ` por nível (Teo D.3) — a API existente `gerar(temperatura_auto=)` ganha o modo vetorial `[τ_1..τ_L]`; (iii) **CFG** com dropout de condicionamento no treino e interpolação de logits na inferência (Teo D.2(iii)) — `s = 1` default (neutro); (iv) a parada anytime (Teo B.4) expõe `parar_no_nivel=k` para orçamento adaptativo de NFE. + +**Prova.** (i) construção do laço: para ℓ = 1..L: montar `lev_ℓ` com `ẑ_{ℓ−1}^{(n_ℓ)}` + `e_ℓ`, forward com caches, amostrar `c_ℓ` das `n_ℓ` distribuições (fatoração paralela — Teo B.2(ii)), atualizar `ẑ_ℓ`. Cada iteração é um forward padrão do tronco; o total é L (o Teo D.1(iii) confirma que os caches cobrem o prefixo). (ii) a bisseção do Teo 28.8 é um procedimento por distribuição — aplicá-la por nível é instanciar L procedimentos independentes (Teo D.3(ii): monotonia estrita da entropia em τ). (iii) dois forwards por nível (condicionado/não) quando `s ≠ 1` — custo 2L ainda ≪ T·N da difusão (Cor. B.2.1); `s = 1` desliga o segundo forward (neutro). (iv) a decodificação em prefixo k usa o decoder do tokenizador treinado com nested dropout (Teo A.2(ii)) — sem correção de marginais (Teo B.4(a)). ∎ + +**Artefatos**: `conceitos/amostrador.py` (novo), `nucleo/modelo.py::gerar` (+param `modo`, default `"ar"` — neutro), `nucleo/autorregulador.py` (+temperaturas por nível). +**Verificação**: V10 (NFE medido = L; parada em k decodifica), V11 (τ-auto: entropia empirica dentro de ±0,05 do alvo em ≥ 95% dos níveis — padrão do Teo 28.8 medido H=5,0045). + +## T6 — MBR com utilidade de ensemble (zero parâmetros novos) + +**Afirmação.** O amostrador gera `n_cand` hierarquias (custo `n_cand·L` NFE) e o **ensemble existente** (`ensemble/votacao.py`: RF×DNN×Engram, k_vencedores = 8) fornece a utilidade `u(y, y')` do MBR (Teo C.4) — sem novos parâmetros treináveis. + +**Prova.** O Teo C.4(i)–(ii) prova consistência e regret O(√(log n/n)) para utilidade limitada; a votação do ensemble produz escores em [0,1] por construção (média de votos/k_vencedores — limitada, satisfaz a hipótese). O custo por candidato é L NFE (T5), logo `n_cand = ⌊B/(L·c)⌋` domina o regime AR/especulativo no mesmo orçamento B (Teo C.4(iii)). A integração é um laço sobre a API existente de votação (leitura apenas). ∎ + +**Artefatos**: `conceitos/amostrador.py` (+função `mbr`), leitura de `ensemble/votacao.py`. +**Verificação**: V12 (MBR com n_cand = 8 melhora a utilidade média vs. argmax de 1 candidato em dados de validação — sinal direcional, reportado com IC via Student-t do Teo 29.5). + +## T7 — Subsumção do MTP e coexistência com a decodificação especulativa + +**Afirmação.** (i) Com a parametrização do Teo D.6, a perda NCM **é** a perda MTP — o caminho `mtp.py` pode ser migrado como caso particular (`ncm.niveis_token = true`) sem perda de capacidade (Cor. D.6.1); (ii) a árvore especulativa Medusa (`nlg/decodificador_especulativo.py`, doc 14) **coexiste**: no nível fino ℓ = L, a especulação AR continua válida para o decoder que gera texto a partir de `ẑ_L` se esse decoder for AR (Cor. B.4.1); (iii) o `usar_atencao_arvore` do config não conflita com a máscara block-causal (são máscaras de camadas/caminhos distintos). + +**Prova.** (i) Teo D.6 (redução algébrica). (ii) o decoder do tokenizador (T4-iv) é um transformer AR teacher-forced — a especulação sobre ele segue o doc 14 sem alteração (a verificação de aceitação é sobre o decoder, não sobre a hierarquia). (iii) a atenção-árvore opera no caminho AR de tokens; a block-causal no caminho de conceitos — o dispatcher por `modo` seleciona a máscara ativa (o projeto já alterna máscaras por configuração). **Decisão recomendada**: manter `mtp.ativo = true` na v24 (A/B entre mtp clássico e ncm como braços separados — n-04 §8) e só avaliar a migração definitiva com dados. ∎ + +**Artefatos**: leitura de `treino/mtp.py`, `nlg/decodificador_especulativo.py`; `conceitos/gerador_conceitos.py` (modo `niveis_token`). +**Verificação**: V13 (equivalência numérica L_ncm ≡ L_mtp na parametrização D.6 em 10 exemplos — tolerância 1e-7). + +## T8 — Janela 1M: resumo hierárquico decodificável com contrato de memória intacto + +**Afirmação.** (i) Os níveis grossos da hierarquia de uma história longa funcionam como o **resumo indexado** da janela 1M (Teo D.5): para `N = 262144` e r = 4, os níveis ≤ k representam a história com `≤ N·r^{−(L−k)}·r/(r−1)` códigos — o `l_fino = 4096` cobre os níveis finais e o `w_segmento = 256`/`s_passo = 128` mapeiam segmentos → códigos do nível imediatamente acima; (ii) o **contrato de memória** do ciclo fechado (Teo 17.4: protótipo inserido no SOM somente com stop-gradient; melhora monotônica em EQ médio) é preservado — o passo 4 do doc 17 re-encoda a SAÍDA (texto), que no modo conceitos é decodificada do prefixo final (Cor. D.2.1); (iii) o ReplaySSM (`jepa_familia/replayssm.py`) e a memória interna (`memoria_interna.n_codigos = 64`) não mudam. + +**Prova.** (i) Teo D.5(i)–(iii): a série geométrica do prefixo cabe no orçamento de códigos; a política gulosa por fronteira RD é ótima para orçamento em bits. (ii) o Teo 17.4 prova o contrato para a re-encodação por `E_img/E_texto` — funções que não dependem do modo de geração; a única interface é que a saída gerada seja texto válido (decodificada do `ẑ_L` ou do prefixo de parada — Teo B.4(b)). (iii) nenhum desses módulos lê o caminho de geração de texto (verificação por import/dependências). ∎ + +**Artefatos**: leitura de `memoria/janela_1m.py`, `memoria/orquestrador.py`; `conceitos/amostrador.py` (+hook pós-geração que chama o orquestrador existente). +**Verificação**: V14 (contrato: geração em modo conceitos → re-encodação → treino SOM com stop-gradient ativo — asserção de gradiente nulo no caminho, padrão doc 17 §4). + +## T9 — Custo e roofline honesto (padrão Teo 31.5) + +**Afirmação.** O ganho de velocidade esperado no KHTST é **condicional à medição**, com decomposição obrigatória: +``` +Speedup_wall = [T_AR(N=256 passos incrementais) ] / [ L=7 avaliações de blocos (4..256 posições) ] +``` +(i) **teoria** (Cor. B.2.1): razão de posições ≈ 4,6× vs. difusão com T=32; vs. AR o ganho é o fator N/L ≈ 36× em AVALIAÇÕES, mas o custo por avaliação é maior (bloco vs. token único) — o wall-clock real depende do scan paralelo do Mamba (Cython v21, Teo 33.11: ganho 2,3–7,6× medido no hot-path) e do batching dos blocos; (ii) **prática KHTST (CPU)**: os blocos curtos dos níveis iniciais são GEMM-denso — favorável ao Cython existente; os níveis finais aproximam o custo AR; (iii) **obrigação de honestidade**: reportar wall-clock pareado medido (A/B), roofline IO/compute como no Teo 31.5 (que reportou 0,83–0,875× desfavorável sem pesar), e o custo EXTRA do tokenizador (fase A) separado do ganho de inferência. + +**Prova.** (i) contas do Cor. B.2.1 com os parâmetros do config (ctx 256; níveis [4,8,16,32,64,128,256] ⇒ L=7, r=2, Σn_ℓ = 508 ≈ 2N). (ii) os hot-paths Cython do projeto aceleram conv depthwise causal e top-k (Teos 33.11–33.13) — ambos exercitados pelo caminho de conceitos (o top-k parcial do roteador é estruturalmente idêntico ao top-1 sobre K_ℓ logits do Teo A.4(i)); a paralelização intra-nível usa as mesmas GEMMs do treino (lote efetivo por acumulação — doc 27). (iii) protocolo: medir com `telemetria/indicadores.py` (buffer 64 linhas/2s, Teo 35-robustez), parear por re-seed, uma variável. ∎ + +**Artefatos**: `telemetria/indicadores.py` (+`nfe_por_geracao`, `wallclock_modo_conceitos`), `scripts/41_teste_v24.py` (medição A/B). +**Verificação**: V15 (wall-clock pareado AR vs. conceitos em 3 orçamentos {curto, médio, NFE-fixado}; tabela completa com perdedores incluídos). + +## T10 — Não-regressão estrutural (a prova que fecha o ciclo) + +**Afirmação.** Com `ncm.ativo = false` (default), a v24 é **idêntica à v23 bit-a-bit** em treino e inferência, e com `ncm.ativo = true` as únicas superfícies tocadas são aditivas. Especificamente: +``` +(i) [bandeira] nenhuma chave existente do config muda de semântica; a seção "ncm" é nova com default neutro; +(ii) [treinador] L_ncm ≡ 0 ⇒ gradiente nulo ⇒ passo idêntico (Teo D.7(ii)); a fase A é pulada (opt-in); +(iii) [torchao] a quantização int8/int4 do Teo 28.1 aplica-se ao tronco INTEIRO como hoje; as EXCLUSÕES + existentes (lm_head, especialistas MoE, camadas finas) ganham 3 novas: codebooks (buffers EMA não são + parâmetros linearizáveis — mesma razão de exclusão estrutural do Teo 28.1), cabeças de conceitos + (sensibilidade exponencial análoga ao lm_head), e embeddings de nível (camada fina); +(iv) [IPC/telemetria] frames e chaves existentes inalterados; novos indicadores são ADITIVOS no TelemetryHub + (padrão doc 34 §2: acumuladores opt-in, observadores puros bit-a-bit desligados — Teo 34.1); +(v) [limites] nenhum arquivo de produção cresce além dos tetos (treinador < 80 KB — a lógica NCM vive em + mixins/pacote novo, padrão Teo 34.11); +(vi) [suítes] TODAS as suítes v1–v23 devem continuar verdes sem edição (a v24 é aditiva); verificar_tudo + ganha o bloco 50 (ncm) — 50✓/0✗. +``` + +**Prova.** (i) por construção (n-04 §3: o diff do config é puramente aditivo). (ii) Teo D.7(ii) + o padrão de nascimento neutro (Teo 29.16: centros = constantes atuais; 1ª aplicação = identidade; Teo 34.10: base capturada na 1ª escrita). (iii) o Teo 28.1 prova a cota de erro h/√12 para camadas linearizáveis; codebooks EMA e cabeças de K classes violam as hipóteses da mesma forma que o lm_head (exclusão justificada pela sensibilidade exponencial dos logits — argumento idêntico ao doc 28); a exclusão é uma LISTA estendida, não uma alteração do mecanismo. (iv) os produtores novos são observadores (leem tensores já computados) — o Teo 34.1 prova neutralidade bit-a-bit dos observadores. (v) a lógica nova vive em `conceitos/` e em um mixin `treinador_v24.py` (padrão do `treinador_v22.py`). (vi) consequência de (i)–(v): nenhuma suíte existente observa superfície alterada. ∎ + +**Artefatos**: `configs/base.json` (+seção ncm), `quanta/torchao_quant.py` (+3 exclusões condicionais), `patches/verificar_tudo.py` (+bloco 50), `tests/test_khtst_v24.py` (novo). +**Verificação**: V0 (a verificação das verificações): rodar v1–v23 + verificar_tudo com ncm.ativo=false — 49✓/0✗ como na v23; V5 (bit-a-bit de treino: 48 passos com λ=0 vs. v23 — max|Δ|=0 em pesos e RNG-state). + +--- + +## §Conclusão das provas de factibilidade + +**Conjunção T1∧…∧T10**: a refatoração é (a) **local** — 1 pacote novo + 1 seção de config + 1 perda + 1 modo de geração, sem reescrita semântica de módulo de produção; (b) **ancorada** — cada integração apóia-se num teorema já provado no projeto ou nesta coleção; (c) **reversível e mensurável** — opt-in neutro, bit-a-bit verificável, telemetria aditiva, A/B pareado com leitura honesta; (d) **orçada** — parâmetros e RAM dentro dos tetos medidos do projeto. As hipóteses empiricamente abertas (H_D1 da bidirecionalidade 1-in-6; H1–H3 do planejamento) têm experimentos designados (V7; tarefas raciocinio/matematica) — nenhuma é bloqueadora da integração em si, apenas da DECLARAÇÃO dos ganhos. diff --git a/docs/memoria-ncm-khtst/n-04-plano-refatoracao.md b/docs/memoria-ncm-khtst/n-04-plano-refatoracao.md new file mode 100644 index 0000000000000000000000000000000000000000..1764911a870cfaa8a758d75cc9ca4a3066d1c707 --- /dev/null +++ b/docs/memoria-ncm-khtst/n-04-plano-refatoracao.md @@ -0,0 +1,254 @@ +# n-04 — PLANO DE REFATORAÇÃO ACIONÁVEL (para agente de código) +> **Coleção**: `memoria-ncm-khtst` · **Pré-requisitos**: n-01, n-02, n-03 · **Alvo**: KHTST v23 → v24 (introduz NCM como caminho de geração next-concept) +> **Regra de ouro**: UMA variável por commit · suítes TODAS verdes antes de publicar · leitura honesta em todo relatório + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Plano executável em 6 passos: (1) pacote novo `src/khtst/conceitos/` com 5 módulos especificados assinatura-a-assinatura (tokenizador VQ residual Stiefel+GSQ com nested dropout; gerador com máscara block-causal; máscaras/interpolação; amostrador com NFE=L, temperatura-auto por nível, CFG e MBR; cabeça de reconstrução); (2) config `ncm` opt-in com defaults neutros; (3) perdas drop-in em `perdas.py` com λ de hipergradiente exato e PCGrad; (4) protocolo de treino em 3 fases (A: tokenizador; B: gerador; C: A/B pareado); (5) suíte `test_khtst_v24.py` com 16 verificações V0–V15 mapeadas aos Teos; (6) publicação como v24 com scripts 39–43, `docs/matematica/36` e atualização das memórias do projeto. Inclui registro de riscos com mitigações e critérios de aceite objetivos. +- **EN**: Six-step executable plan: (1) new package `src/khtst/conceitos/` with 5 modules specified signature-by-signature; (2) opt-in `ncm` config with neutral defaults; (3) drop-in losses in `perdas.py` with exact-hypergradient λ and PCGrad; (4) 3-phase training protocol (A: tokenizer; B: generator; C: paired A/B); (5) suite `test_khtst_v24.py` with 16 checks V0–V15 mapped to the theorems; (6) release as v24 with scripts 39–43, `docs/matematica/36`, and project-memory updates. Includes a risk register with mitigations and objective acceptance criteria. + +--- + +## §1. Princípios (herdados do projeto — não negociáveis) + +1. **Opt-in / nascimento neutro**: `ncm.ativo = false` por default; primeira aplicação = identidade bit-a-bit com v23 (Teo 29.16/34.10, T10). +2. **Uma variável por braço** nos experimentos; pareamento exato por re-seed pós-construção com RNG dedicado (Teo 31.7). +3. **Leitura honesta**: ΔCE de corrida curta não é ganho (RELATORIO §20–21); wall-clock reportado como medido, inclusive desfavorável (Teo 31.5). +4. **Provas antes de claims**: todo mecanismo novo entra no `docs/matematica/36` com Teo + evidência medida (padrão docs 26–35). +5. **Tetos**: `treinador.py` < 80 KB (lógica nova em `treinador_v24.py` mixin, padrão Teo 34.11); RAM pico ≤ 3.580 MB; `kv_cache_max = 2048` respeitado (T2). +6. **Sem vazamento eval→treino**: fontes marcadas `papel:"avaliacao"` PULADAS (Teo 35.14) — o tokenizador de conceitos treina SÓ no corpus de treino. + +## §2. Pacote novo: `src/khtst/conceitos/` + +### 2.1 `__init__.py` +```python +"""NCM — Next-Concept Modeling para o KHTST (v24). +Tokenizador VQ residual multiscale (Stiefel+GSQ, nested dropout) + gerador +block-causal + amostrador NFE=L. Provas: docs/matematica/36 (Teos 36.1+); +teoria: memoria-ncm-khtst/n-02 (Teos A–D). Opt-in via config 'ncm'.""" +from .tokenizador_conceitos import TokenizadorConceitos +from .gerador_conceitos import GeradorConceitos +from .mascaras import mascara_block_causal, interp_para +from .amostrador import AmostradorConceitos, gerar_com_conceitos +__all__ = [...] +``` + +### 2.2 `mascaras.py` (implementar PRIMEIRO — sem dependências) +```python +def mascara_block_causal(blocos: list[int], n_prefixo: int, dtype=torch.bool) -> Tensor: + """Máscara aditiva B: slot do bloco ℓ atende a prefixo + blocos ≤ ℓ (bidirecional no bloco próprio). + Contrato (Teo D.1(ii), T2): B[(ℓ,i),(j,k)] = True ⟺ j ≤ ℓ; prefixo sempre visível. + Verificação: V4 (gradiente de vazamento — nenhuma posição de lev_ℓ acessa lev_{>ℓ}).""" + +def interp_para(z: Tensor, n: int, modo: str = "linear") -> Tensor: + """Interp_{n}: redimensiona R^{n'×d} → R^{n×d} (down = avg-pool por segmento; up = linear). + Contrato (n-02 §0): linear em ambas direções; determinístico; sem parâmetros. + Downsample alinha com w_segmento=256/s_passo=128 quando aplicado à janela (T8).""" +``` + +### 2.3 `tokenizador_conceitos.py` (Estágio 1 — fase A) +```python +class TokenizadorConceitos(nn.Module): + def __init__(self, cfg: dict, vocab: int = 16384, d_lat: int = 64): + # cfg = config["ncm"]; niveis: list[int] ex. [4,8,16,32,64,128,256] (L=7, r=2, Σ=508≈2N — Teo B.2(i)) + # codebooks: nn.ParameterList por nível, RCO-Stiefel (init: QR de gaussianas; K_ℓ ≤ d_lat) + # decodificador: mini-transformer AR (2 camadas, d=192) com cabeça CE → vocab + # τ GSQ: agenda analítica τ(t) com τ_min=0.5, t_alvo=400 (Teo 30.6); EMA dos codebooks 0.99 + + def codificar(self, ids: Tensor) -> tuple[Codigos, Reconstrucoes]: + """x → c=(c_1..c_L) via recursão residual (n-02 §0) com seleção GSQ (τ>0) no treino + e NN duro (argmax) em eval (Teo A.4). Retorna também ẑ_ℓ por nível (para o gerador).""" + + def perda_fase_a(self, ids: Tensor, rng: torch.Generator) -> dict[str, Tensor]: + """L_tok = E_{ℓ∼p(ℓ)}[CE(x, Dec(ẑ_ℓ))] + β·Σ_ℓ‖sg[r_ℓ]−z_ℓ‖² (n-02 §0) + p(ℓ): nested dropout — geométrica decrescente OU uniforme (hiperparâmetro; Teo A.2) + rng DEDICADO (pareamento — Teo 31.7). Retorna {'rec':…, 'commit':…, 'rec_prefixo': dict}.""" + + def retração(self): + """Por nível: QR → polar SVD → normalização R_ℓ (Teo 32.11); assert δ_ort ≤ 3e-6 (V9).""" + + @torch.no_grad() + def decodificar(self, zhat: Tensor, max_tokens: int) -> Tensor: + """ẑ_ℓ (qualquer prefixo) → tokens AR (teacher-forcing livre p/ amostragem) — Teo A.2/B.4(b).""" +``` + +### 2.4 `gerador_conceitos.py` (Estágio 2 — fase B) +```python +class GeradorConceitos(nn.Module): + def __init__(self, tronco, cfg: dict): + # tronco: o Mamba-3 5:1+NoPE EXISTENTE (injetado; não recriado — T1/T2) + # embeddings de nível e_ℓ; cabeças lineares d→K_ℓ por nível (via A de T1) + # corrupção κ: fração ρ dos códigos-condição mascarados (Teo C.3); dropout CFG p_cfg (Teo D.2(iii)) + + def montar_sequencia(self, cond_emb: Tensor, codes_true: Codigos | None, + ate_nivel: int, corromper: bool, rng) -> tuple[Tensor, Tensor]: + """s = [cond; lev_1..lev_ate] com entradas ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ (Teo D.1); + teacher forcing usa codes_true p/ reconstruir ẑ; corromper aplica κ. + Retorna (s, offset_de_blocos) — máscara via mascaras.mascara_block_causal.""" + + def forward_treino(self, cond_emb, codes_true, rng) -> dict[str, Tensor]: + """1 passada (Teo D.1(iv)): CE por nível com pesos w_ℓ (schedule de níveis); + retorna {'ce_nivel': [L], 'logits_amostra': …} — consumido por perda_conceitos (T3).""" + + @torch.no_grad() + def prever_nivel(self, estado, nivel: int, temperatura: float | None, cfg_scale: float) -> Codigos: + """1 forward do bloco lev_nivel com caches (T5); temperatura None ⇒ auto (bisseção Teo 28.8); + cfg_scale≠1 ⇒ 2 forwards com interpolação de logits (Teo D.2(iii)).""" +``` + +### 2.5 `amostrador.py` (inferência) +```python +def gerar_com_conceitos(modelo, tokenizador, cond, cfg: dict, + parar_no_nivel: int | None = None, mbr_n: int = 1) -> Geração: + """Laço de níveis (Teo B.2/B.4): L avaliações; parada anytime em k (orçamento NFE); + mbr_n>1 ⇒ gera n candidatos + MBR com utilidade de ensemble (Teo C.4, T6); + hook pós-geração: re-encodação → orquestrador.treinar_memoria (stop-grad — Teo 17.4, T8/V14).""" + +class TemperaturasPorNivel: + """Extensão do autorregulador: τ_ℓ por bisseção de entropia-alvo (Teo D.3/28.8); + nascimento neutro τ_ℓ(0)=1.0; limites [0.5, 1.5] (mesma faixa do H=5.0045 medido).""" +``` + +### 2.6 Arquivos existentes tocados (diff aditivo completo) + +| Arquivo | Mudança | Teo/T | +|---------|---------|-------| +| `configs/base.json` | + seção `"ncm"` (§3) | T10(i) | +| `src/khtst/config.py` | + dataclass `ConfigNCM` com defaults neutros + validação (5:1 preservado — Teo 30.7) | T10 | +| `src/khtst/nucleo/modelo.py` | + registro do `GeradorConceitos`; `gerar(..., modo="ar"|"conceitos")` default `"ar"` | T1/T5 | +| `src/khtst/treino/perdas.py` | + `perda_conceitos` (CE ponderada por nível) e `perda_reconstrucao_prefixo` | T3 | +| `src/khtst/treino/treinador_v24.py` | NOVO mixin: fase A opt-in + chamada da perda + λ hipergradiente | T3/T4 | +| `src/khtst/treino/treinador.py` | + 1 linha (herda o mixin) — mantém < 80 KB | Teo 34.11 | +| `src/khtst/quanta/torchao_quant.py` | + 3 exclusões condicionais (codebooks/cabeças/embl. nível) | T10(iii) | +| `src/khtst/telemetria/indicadores.py` | + δ_ort_conceitos, contracao_por_nivel, nfe_por_geracao, tc_por_nivel (aditivo) | T4/T9 | +| `patches/verificar_tudo.py` | + bloco 50 (ncm): 50✓/0✗ | T10(vi) | +| `scripts/39..43_*.py` | NOVOS (§7) | — | +| `tests/test_khtst_v24.py` | NOVO: V0–V15 (§6) | — | +| `docs/matematica/36-ncm-conceitos-hierarquia.md` | NOVO (§5) | — | + +**NENHUM outro arquivo é modificado.** (T10 — prova da não-regressão.) + +## §3. Schema de config (aditivo) + +```json +"ncm": { + "ativo": false, + "niveis": [4, 8, 16, 32, 64, 128, 256], + "d_lat": 64, + "k_por_nivel": 64, + "ema_codebook": 0.99, + "beta_commit": 0.25, + "nested_dropout": {"tipo": "uniforme"}, + "corrupcao_cond": 0.15, + "dropout_cfg": 0.10, + "cfg_scale": 1.0, + "gsq": {"tau0": 1.0, "tau_min": 0.5, "t_alvo": 400}, + "pesos_nivel": "uniforme", + "lambdas": {"conceito": 0.0, "rec": 1.0, "rho_ancora": 0.05}, + "temperaturas": {"auto": true, "entropia_alvo": null, "limites": [0.5, 1.5]}, + "mbr": {"n_cand": 1} +} +``` +Defaults 100% neutros: `ativo=false` E `lambdas.conceito=0.0` — dupla trava (T10(ii)/D.7(ii)). + +## §4. Protocolo de treino (3 fases) + +**Fase A — tokenizador** (novo estágio; ~1-2 épocas do corpus): +1. Corpus: MESMA pipeline `scripts/02/02a` com filtro P9 (sem fontes `avaliacao` — Teo 35.14). +2. Loop: `perda_fase_a` (nested dropout + commitment + EMA + retração polar a cada passo; τ-annealing GSQ). +3. Gate de saída: reconstrução prefixo-monótona (V3) e contração ≥ cota (V2); salvar `tokenizador_conceitos.pt` com SHA-256 (checkpoint atômico — Teo 35.3). + +**Fase B — gerador** (tronco congelado OU conjunto; começar congelado): +1. Montar hierarquias do corpus com o tokenizador da fase A (congelado — padrão NCM). +2. `forward_treino` com corrupção ρ=0.15 e dropout CFG 0.10; perda `λ_conceito` com hipergradiente + âncora (Teo 29.2 — começa em 0 e cresce até o ótimo interior `λ* = λ₀ − L_diff/2ρ`). +3. PCGrad sobre a união com as 12 tarefas existentes (Teo D.7/35.1). + +**Fase C — A/B pareado** (protocolo do projeto): +- Braço 1: v23 puro (`ncm.ativo=false`). Braço 2: v24 `ncm.ativo=true` (λ no valor da fase B). Braço 3 (opcional): v24 com `niveis_token=true` (MTP-equivalente — T7/V13). +- 48 passos, corpus FRESCO coletado com filtro P9, RNG dedicado, UMA variável por par (padrão scripts/33 e 36). + +## §5. `docs/matematica/36-ncm-conceitos-hierarquia.md` (esqueleto) + +Transferir dos n-02/n-03 COM as evidências medidas (o doc 36 cita os Teos e anexa os números): +- §1 Notação + recursão residual (n-02 §0) — Teo 36.1 (= A.0/A.1: STE+contração; medir V2). +- §2 Nested dropout (A.2) — Teo 36.2 (monotonia medida V3; anytime). +- §3 Fatoração next-concept (B.1–B.4) — Teos 36.3–36.6 (MLE exato; NFE=L; TC por nível V6). +- §4 vs. difusão mascarada (C.1–C.4) — Teos 36.7–36.9 (gap variacional; corrupção=DRO com cobertura medida V5b; MBR V12). +- §5 Integração (D.1–D.7) — Teos 36.10–36.16 (máscara+cache V4; τ por nível V11; MTP⊂NCM V13; PCGrad V8). +- §6 Roofline honesto (T9) — Teo 36.17 (tabela wall-clock pareada V15 COM perdedores). +- §11 Honestidade (padrão doc 35): H_D1 status; o que NÃO sobreviveu às medições. + +## §6. Suíte `tests/test_khtst_v24.py` — 16 verificações + +| ID | Verificação | Âncora | Critério objetivo | +|----|-------------|--------|-------------------| +| V0 | Regressão total v1–v23 + verificar_tudo com `ativo=false` | T10 | 49✓/0✗ + TODAS verdes, ZERO edição de suíte antiga | +| V1 | Registro/neutralidade do módulo (pesos não tocados) | T1 | state_dict idêntico pré/pós registro | +| V2 | Contração residual medida vs. cota `(1−1/K)^ℓ` | Cor. A.1.1 | reportar AMBOS (honestidade); cota não violada | +| V3 | Monotonia do risco de prefixo (nested dropout) | Teo A.2 | CE_recon não-crescente em ℓ em ≥ 90% dos pares (prefixo, prefixo+1) no corpus | +| V4 | Vazamento zero da máscara block-causal | Teo D.1 | grad de saída de `lev_ℓ` w.r.t. entrada de `lev_{>ℓ}` ≡ 0 | +| V5 | Bit-a-bit: 48 passos treino com λ=0 vs. v23 | Teo D.7(ii) | max\|Δ pesos\| = 0; RNG-state idêntico | +| V5b | Cobertura da corrupção: taxa de erro por nível ≤ ρ em validação | Teo C.3(ii) | reportar; se falhar, subir ρ e re-treinar fase B | +| V6 | TC (correlação total) por nível medida | Teo B.3 | reportar (linha de base para H_D1) | +| V7 | A/B H_D1: NoPE-only vs. dupla-passada no bloco | T2/D.1 | ΔCE por nível; decisão documentada no doc 36 §11 | +| V8 | Hipergradiente de λ_conceito: analítico vs. FD | Teo 29.2 | erro ≤ 1e-6 | +| V9 | δ_ort codebooks pós-retração | Teo 32.11 | ≤ 3e-6 | +| V10 | NFE = L; parada anytime decodifica | Teo B.2/B.4 | contador de forwards = 7; decode em k=3 produce texto válido | +| V11 | τ-auto por nível: entropia no alvo | Teo 28.8/D.3 | ±0.05 em ≥ 95% dos níveis | +| V12 | MBR melhora utilidade média vs. argmax-1 | Teo C.4 | sinal + IC (Student-t Teo 29.5); reportar mesmo se n.s. | +| V13 | Equivalência L_ncm ≡ L_mtp (modo D.6) | Teo D.6 | max\|Δ\| ≤ 1e-7 em 10 exemplos | +| V14 | Contrato de memória: stop-grad no caminho pós-geração | Teo 17.4 | gradiente nulo asserido no hook | +| V15 | Wall-clock pareado AR vs. conceitos (3 orçamentos) | T9 | tabela completa com perdedores; roofline anexado | + +## §7. Scripts numerados (continuando a série do repo) + +| Script | Função | +|--------|--------| +| `scripts/39_treinar_tokenizador_conceitos.py` | Fase A (args: `--epocas`, `--corpus`, `--teto_horas`; checkpoint atômico + SHA-256) | +| `scripts/40_treinar_ncm.py` | Fase B (`--lambda_conceito auto`, PCGrad, telemetria aditiva; reusa `--teto_horas/--estados_hf` do 04) | +| `scripts/41_teste_v24.py` | Suíte V0–V15 + A/B pareado fase C (padrão scripts/33/36: `--coletar` com filtro P9) | +| `scripts/42_graficos_v24.py` | Curvas SOBREPOSTAS às antigas com melhores valores anotados (protocolo script 08/16) | +| `scripts/43_publicar_v24.py` | UM commit completo (`upload_folder` + `delete_patterns=["*"]`); token só em `HF_TOKEN` apagado após; estados < 900 MB | + +## §8. Critérios de aceite da v24 + +1. **Bloqueadores (tudo ou nada)**: V0, V1, V4, V5, V9, V10, V13, V14 verdes; `treinador.py` < 80 KB; zero modificação de suíte antiga. +2. **Evidenciais (reportar, não bloquear)**: V2, V3, V5b, V6, V7, V8, V11, V12, V15 — alimentam o doc 36 com números honestos. +3. **Declaração de ganho**: PROIBIDO declarar ganho de qualidade por ΔCE de 48 passos (padrão RELATORIO §20–21). Ganhos declaráveis: (a) NFE medido = L < N (V10); (b) wall-clock pareado (V15) SE favorável e reproduzido; (c) qualidade SOMENTE via benchmark canônico (`scripts/05_avaliar.py`) com as fontes de avaliação intocadas. +4. **Memórias do projeto atualizadas**: `PLANO_KHMAMBAJEPA.md` (§2 + linha do roteiro v24), `RELATORIO_KHTST.md` (§22), `worklog.md`, README (seção v24), gráficos `graficos/v24/`. + +## §9. Registro de riscos (com mitigações) + +| # | Risco | Prob. | Impacto | Mitigação | Âncora | +|---|-------|-------|---------|-----------|--------| +| R1 | Bidirecionalidade 1-in-6 insuficiente (H_D1) | média | CE de conceitos estagna em níveis finos | dupla-passada do bloco (+2× no bloco, ainda ≪ N); NoPE terminal; reversão Cython | T2/V7 | +| R2 | Corpus pequeno (1–1,6k) subtreina codebooks | alta | colapso de codebook / prefixos não-monótonos | K_ℓ=64 (Stiefel); fase A em corpus TOTAL (não só o fresco); τ conservador; V2/V3 como gates | T4 | +| R3 | TC intra-nível alta em PT-BR (morfologia rica) | média | gap B.3(i) visível | medir V6; se alto: níveis mais finos (r menor) + especulação no nível final (T7) | Teo B.3 | +| R4 | Wall-clock CPU desfavorável em níveis finais | média | speedup < 1 no bloco 256 | reportar honesto (T9); usar modo conceitos para geração com orçamento (anytime V10) e AR para decode fino | Cor. B.2.1 | +| R5 | Interperação com `usar_atencao_arvore`/MoE gates | baixa | máscara errada no dispatcher | V4 cobre; dispatcher por `modo` isolado; kill-switch `ncm.ativo` | T7/T2 | +| R6 | torchao em cabeças novas | baixa | erro além da cota | 3 exclusões (T10(iii)); rollback atômico do Teo 28.4 | T10 | +| R7 | Vazamento eval→treino no tokenizador | alta (se esquecido) | benchmark contaminado | reusar filtro P9/`papel:"avaliacao"` EXATAMENTE; válvula `KHTST_INCLUIR_AVALIACAO` respeitada | Teo 35.14 | +| R8 | Colapso do δ_ort em treinos longos | baixa | cota A.1 degrada | retração polar por passo + V9 + alerta telemetria (padrão docs 26–27) | T4/D.4 | + +## §10. Sequência de execução recomendada (commits) + +``` +C1 conceitos/mascaras.py + V4 (zero risco — módulo puro) +C2 conceitos/tokenizador_conceitos.py + V2/V3/V9 (fase A funcional) +C3 config ncm + config.py + V1 (defaults neutros) +C4 perdas.py + treinador_v24.py + V5/V8 (λ=0 bit-a-bit) +C5 gerador_conceitos.py + V13 (equivalência MTP) +C6 amostrador.py + modelo.gerar(modo) + V10/V11/V14 (inferência) +C7 torchao exclusões + telemetria + verificar_tudo(50) + V0 +C8 scripts 39–43 + fase A/B reais + fase C A/B + V6/V7/V12/V15 +C9 docs/matematica/36 + gráficos v24 + publicação v24 (critérios §8) +``` +Cada commit: suítes TODAS verdes + `verificar_tudo` (o bloco 50 entra no C7). C8–C9 seguem o protocolo de publicação do §7. + +--- + +## §Fecho — o que este plano entrega ao projeto KHTST + +1. **Paradigma**: geração paralela coarse-to-fine (NCM) como cidadão de primeira classe, com NFE = L ≪ N e decodificação anytime — sem ELBO, com MLE exato (Teos B.1/B.2). +2. **Reuso máximo**: GSQ+RCO (codebooks Stiefel com contração provada — Teos A.1/D.4), PCGrad, hipergradiente λ, autorregulação RM/bisseção, torchao, IPC/telemetria, ensemble (MBR), janela 1M (resumo hierárquico), ciclo de memória SOM — TODOS já provados no projeto e ancorados nas provas T1–T10. +3. **Raciocínio profundo**: o caminho coarse-to-fine formaliza o "plano antes do detalhe" (Teo C.2) com protocolo de validação nas tarefas `raciocinio`/`matematica` — a hipótese que o paper NCM valida empiricamente (Sudoku) e que o KHTST pode medir nos seus datasets PT-BR. +4. **Reversibilidade total**: `ncm.ativo=false` ⇒ v23 bit-a-bit (T10) — o risco da introdução é estruturalmente ZERO para o comportamento existente; todo o risco restante é empírico, medido e reportado com honestidade. diff --git a/docs/memorias/r-01-diagnostico.md b/docs/memorias/r-01-diagnostico.md new file mode 100644 index 0000000000000000000000000000000000000000..cb7f6a485a032319e7aed98a21e8ba878b8e4047 --- /dev/null +++ b/docs/memorias/r-01-diagnostico.md @@ -0,0 +1,71 @@ +# r-01 — MEMÓRIA DA REFATORAÇÃO (PASSO A PASSO): DIAGNÓSTICO E PREPARAÇÃO +> **Coleção**: `memoria-khtst-rust` · **Data**: 2026-10-21 · **Tarefa**: refatorar o projeto KHTST para **KHTST_RUST** (PyO3) integrando as provas NCM (coleção `memoria-ncm-khtst`, Teos A.0–D.7 + T1–T10) e dois aprimoramentos novos (ADBA §r-04, Ponte Dupla §r-05) +> **Convenções herdadas**: n-00 §4 (Teos numerados, ∎, nascimento neutro, leitura honesta, A/B pareado, tetos, token só em `HF_TOKEN` apagado após uso) + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Diagnóstico do ambiente e do estado do projeto KHTST antes da refatoração para Rust/PyO3: fontes do KHTST v23 baixadas do HF (245 arquivos), definições exatas de GSQ/RCO extraídas de `quanta/gsq_rco.py` (retração Stiefel com gradiente riemanniano projetado), inventário HF completo (8 repositórios; estados de treino reais apenas em HAKO-v1/v2/v3 — 87 arquivos `checkpoints/`+`artifacts/`; o khtst NÃO tem estados salvos), toolchain Rust 1.99.1 instalado, Python 3.12 com numpy/matplotlib/datasets/huggingface_hub/maturin. Decisões de portabilidade documentadas passo a passo. +- **EN**: Environment and KHTST project-state diagnosis before the Rust/PyO3 refactor: KHTST v23 sources downloaded from HF (245 files), exact GSQ/RCO semantics extracted from `quanta/gsq_rco.py`, full HF inventory (8 repos; real training states only in HAKO-v1/v2/v3 — 87 files; khtst has none), Rust 1.99.1 toolchain installed, Python 3.12 stack ready. Portability decisions documented step by step. + +--- + +## §1. Ambiente (medido) + +| Item | Valor | Implicação | +|---|---|---| +| SO | Debian 13 (trixie) | toolchain moderno via rustup | +| CPU / RAM / disco | 2 núcleos / 3,9 GiB / 9,3 GiB livres | builds com `-j2`; configs de treino modestas; teto de RAM respeitado (padrão v12: ≤ 3.580 MB) | +| Rust | 1.99.1 (rustup, estável 2026-10-13) | PyO3 recente OK; Newton–Schulz para retração polar (sem depender de LAPACK) | +| Python | 3.12.15 (venv `/home/z/.venv`) | numpy 2.1.3, matplotlib, datasets 5.1.0, huggingface_hub, maturin | +| Rede | crates.io + PyPI + HF acessíveis | streaming controlado possível | + +## §2. Estado do projeto KHTST (v23, snapshot HF) + +- **Fontes baixadas** para `/home/z/my-project/referencia_khtst/` (245 arquivos: `src/khtst/**` com 20 subpacotes, `scripts/01–38`, `tests/test_khtst_v2..v23`, `docs/matematica/00–35`, `configs/base.json`, patches). **Sem pesos** no repo (apenas código+docs+gráficos). +- **Config base** (lido): vocab 16384, d_modelo 192, n_camadas 6 (5:1 Mamba-3:NoPE), n_cabecas 4, d_ff 512, ctx 256, janela_sliding 192, kv_cache_max 2048, MTP k=2, MoE fusão 4 experts top-2, autorregulação janela_lr 200, mamba3 d_estado 16 rank_mimo 4. +- **GSQ/RCO** (`quanta/gsq_rco.py`, 911 linhas) — semântica exata extraída para a portabilidade: + - `projeta_tangente_stiefel(X, G) = G − X·sym(XᵀG)` (eq. 26.2; Teo 26.2); + - `RetracaoStiefel`: forward = **QR com correção de sinal** (YᵀY = I exato); backward = gradiente riemanniano projetado no tangente `P_Y(Ĝ)` (Teo 26.3: adjunto exato no tangente, erro medido ≤ 1,5e-8); + - `erro_ortogonalidade δ(X) = ‖XᵀX − I‖_F` (eq. 26.7) — monitor padrão ≤ 3e-6; + - `AgendadorTau`: decaimento analítico τ(t) até τ_min; + - `QuantizadorGSQRF`: codebook `C = R(Wᵀ)ᵀ` (linhas ortonormais via retração na transposta; W nasce ortogonal); path suave `x̂ = ‖x‖·softmax((L+g)/τ)·C` com `L = u·Cᵀ` (afinidade cosseno) e ruído Gumbel `g = −log(−log(rand))`; path duro `argmax(L+g)` no treino / `argmax(L)` em eval; `materializar`: `x̂ = ‖x‖·c_id`. +- **Tokenizador** (`dados/tokenizador.py`, 99 linhas): BPE 16384 do projeto (vocab próprio). + +## §3. Inventário HF (com token em `HF_TOKEN` do ambiente — nunca gravado em arquivo) + +8 repositórios sob `PowerMachine`: BiGRU_T_version, CNN-BiGRU, HAKO-v1/v2/v3, aurora-multimodal-ptbr, gru-ring-v13-9-2, khtst-multimodal-ptbr. + +**Estados de treino reais (a APAGAR — tarefa §r-08)**: +| Repo | Arquivos | Conteúdo | +|---|---|---| +| HAKO-v1 | 16 | `checkpoints/hako_phase1/2/3*(.npz+.meta.json)`, `hako_final`, `*_partial`, `artifacts/{granite1b,qwen05b}_decomposed.npz`, `phase1_Z_workspace.npz`, `nlg_head.npz` | +| HAKO-v2 | 22 | `checkpoints/hako_v2_*` + `artifacts/{dinov2,gpt2a,gpt2g}_decomposed.npz`, `nlg_head_v2.npz` | +| HAKO-v3 | 49 | `checkpoints/hako_v3_*` + `artifacts/` (dino_bridge.pt, routers, heads) | + +**Falsos positivos descartados** (código-fonte, NÃO apagar): `docs/.../22-*checkpointing.md`, `23-*estados-hf.md`, `src/khtst/dados/{checkpoints,estados_hf}.py`, `src/khtst/treino/estado_integral.py`, `treinador_estado.py`, `cnn_bigru/utils/memory_optimizer.py`, `hako/checkpoint.py`. Os repos khtst, aurora, gru-ring, CNN-BiGRU, BiGRU_T_version **não têm estados de treino salvos**. + +**Ambiente virtual**: nenhum checkpoint/estado local encontrado em `/home/z/my-project/` (apenas memórias e scripts desta sessão) — varredura final em §r-08. + +## §4. Decisões de portabilidade (passo a passo) + +1. **Escopo do "todo o projeto"**: KHTST_RUST porta para Rust/PyO3 o **pipeline de aprendizado completo** que demonstra qualidade de aprendizado (BPE, tokenizador NCM com GSQ+RCO Stiefel, tronco híbrido com slot Mamba-3, gerador next-concept, perdas PCGrad, amostrador NFE=L, telemetria/controlador, ponte duplex) e documenta o **mapa completo 272 arquivos → alvos Rust** (r-02 §5: portado / contrato / ponto de extensão) — leitura honesta, nada declarado sem estar no código. +2. **Autograd**: `candle-core/candle-nn` (Rust puro, CPU) para o grafo diferenciável; operações com gradiente riemanniano/fechado (retração Stiefel, quantização GSQ, scan SSD) como `CustomOp` com backward manual — o precedente é o Teo 28.9 do projeto (gradiente analítico ≡ autograd). +3. **Retração Stiefel sem LAPACK**: Newton–Schulz polar (iteração de matrizes puras, convergência δ_ort ≤ 3e-6 compatível com o gate V9; o caminho QR/SVD do Python fica documentado como equivalente pelo Teo 26.8-b). +4. **Escala R_ℓ do codebook**: configurável — `ema_projecao` (padrão prático: EMA de E[‖P_C z_ℓ‖]) | `otima_teo` (‖P_C z‖/√K por posição, cota A.1(i) justa) | `aprendida`. V2 reporta contração medida vs. cota em TODOS os modos (Cor. A.1.1: reportar ambos). +5. **Slot Mamba-3**: a camada recorrente 1-de-6 é implementada como **SSD diagonal** (scan seletivo com adjunto exato via CustomOp) — compatível com a fatoração de D.1(i) (fluxo causal estrito) e com o H_D1 (a bidirecionalidade intra-nível vem da camada NoPE com máscara block-causal). +6. **PyO3 e bibliotecas**: pyo3 (abi3-py310), maturin (build), rust-numpy (tensores↔numpy), dict-derive (config ↔ dict), pyo3-log (logs Rust→Python), pythonize (telemetria→dict), pyo3-built (metadados de build), pyo3-async-runtimes (API async da ponte), pyo3-bytes (envelopes binários), crossbeam-channel (pontes), rayon (paralelismo de amostragem/MBR); pyo3-arrow + pyo3-object_store como feature opcional `completo` (exportação Arrow/snapshots); setuptools-rust e rustimport documentados como caminhos alternativos de empacotamento/desenvolvimento (§r-02). +7. **Dados de teste reais**: `wikimedia/wikipedia` config `20231101.pt` em **streaming controlado** (teto de artigos e de MB; cache local em shards JSONL; nada além do teto é baixado). +8. **Publicação**: repositório NOVO `PowerMachine/khtst-rust` com **um único upload organizado** (evita o bloqueio de envios parciais em sequência do HF); exclusão de estados dos HAKO em commits únicos por repo; token apagado do ambiente e varredura de ausência no final (§r-08). + +## §5. Riscos detectados nesta fase + +| # | Risco | Mitigação | +|---|---|---| +| RA1 | Build candle + ecosistema pyo3 em 2 núcleos pode exceder 10 min | build de dependências disparado em background o quanto antes; `-j2`; feature `completo` opcional | +| RA2 | Drift de versão pyo3 ↔ rust-numpy ↔ pyo3-async-runtimes | resolver com `cargo add` unificado ANTES do primeiro build; pinar a família resolvida | +| RA3 | GSQ soft em treino pode convergir devagar no corpus pequeno | τ-annealing conservador (τ0=1,0, τ_min=0,5, t_alvo=400 do Teo 30.6); commitment β=0,25; V15 (overfit de 1 batch) como gate de sanidade de gradiente | +| RA4 | Corpus streaming pode saturar o ambiente | teto duro de artigos + bytes; shards locais pequenos; sem cache global do `datasets` | +| RA5 | Erros de digitação/renomeação durante a refatoração (causa comum pedida pelo usuário) | módulo `diagnostico` com lint de config por distância de Levenshtein, taxonomia de erros comuns e sugestões — aplicado a cada falha de build/execução desta sessão e registrado no worklog | + +## §6. Estado ao fechar esta memória + +- Rust 1.99.1 + maturin instalados; fontes KHTST locais; inventário HF salvo em `logs/hf_inventario.json` e `logs/estados_para_apagar.json`; memórias n-00..n-04 relidas (fonte da verdade matemática); scaffold do crate iniciado (§r-02). ∎ diff --git a/docs/memorias/r-02-arquitetura.md b/docs/memorias/r-02-arquitetura.md new file mode 100644 index 0000000000000000000000000000000000000000..e1d6a9066a04199d370a0fd03cd72864c7fe485d --- /dev/null +++ b/docs/memorias/r-02-arquitetura.md @@ -0,0 +1,98 @@ +# r-02 — MEMÓRIA DA REFATORAÇÃO: ARQUITETURA DO KHTST_RUST (PyO3) +> **Coleção**: `memoria-khtst-rust` · **Pré-requisitos**: r-01 · **Fonte de verdade matemática**: `memoria-ncm-khtst` (n-00..n-04) + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Arquitetura completa do KHTST_RUST: crate Rust/PyO3 (família pyo3 0.23: numpy 0.23 [ex-rust-numpy], pythonize, pyo3-log, dict-derive, pyo3-built, pyo3-async-runtimes+tokio) com candle-core/nn 0.11 para autograd. 19 módulos Rust mapeados 1:1 às provas NCM; empacotamento maturin (wheel abi3-py310) com módulo nativo `khtst_rust.nucleo_rust`; setuptools-rust/rustimport documentados como caminhos alternativos. Decisões-chave: retração polar Newton–Schulz (sem LAPACK), custom ops com adjuntos manuais (GSQ, SSD, Stiefel), API Python limpa (Config/Bpe/PonteDupla/PonteAsync + funções de treino/geração). +- **EN**: Full KHTST_RUST architecture: Rust/PyO3 crate (pyo3 0.23 family) with candle 0.11 autograd. 19 Rust modules mapped 1:1 to the NCM proofs; maturin packaging (abi3 wheel) exposing native `khtst_rust.nucleo_rust`. Key decisions: Newton–Schulz polar retraction (LAPACK-free), custom ops with manual adjoints (GSQ, SSD, Stiefel), clean Python API. + +--- + +## §1. Layout do crate (`/home/z/my-project/khtst-rust/`) + +``` +khtst-rust/ +├── Cargo.toml # deps: pyo3 0.23 (abi3-py310), numpy 0.23, pythonize, +│ # pyo3-log, dict-derive(unused-planejado), pyo3-built, +│ # pyo3-async-runtimes[tokio-runtime]+tokio (feature ponte_async), +│ # candle-core/nn 0.11, crossbeam-channel, rayon, serde, rand +├── pyproject.toml # maturin; module-name = "khtst_rust.nucleo_rust" +├── build.rs # built::write_built_file() (metadados pyo3-built) +├── src/ +│ ├── lib.rs # #[pymodule] nucleo_rust: Config, Bpe, PonteDupla, PonteAsync, +│ │ # treinar_fase_a/b, gerar_amostras, verificar_mascara/stiefel, lint_config +│ ├── config.rs # ConfigKhtst (espelho de configs/base.json v23 + seção ncm n-04 §3 +│ │ # + adba + ponte + telemetria); validação; orçamento de cache (T2) +│ ├── diagnostico.rs # Lint Levenshtein de chaves; taxonomia de erros comuns; origem NaN +│ ├── tokens.rs # BPE byte-level próprio (especiais 0-3, bytes 4..260, merges 260+) +│ ├── mascaras.rs # mascara_block_causal (Teo D.1) + interp multiscale (n-02 §0) +│ ├── stiefel.rs # RCO: projeção de tangente (eq. 26.2), retração polar Newton–Schulz +│ │ # (CustomOp1 c/ backward riemanniano — Teo 26.3), δ_ort (eq. 26.7) +│ ├── quantizador.rs # QuantizadorNivel: GSQ suave (CustomOp3, gradiente exato — Teo A.4(iii)), +│ │ # STE/EMA alternativo (Teo A.0), escala R_ℓ EMA (Cor. A.1.1), perplexidade +│ ├── camadas.rs # Linear (3-D-safe), Embedding (index_select), RMSNorm, SwiGLU +│ ├── atencao.rs # ADBA (r-04): atenção + reponderação por nível + τ por nível + KV-cache +│ ├── ssd.rs # slot Mamba-3: scan diagonal (CustomOp2, adjunto exato) — Teo D.1(i) +│ ├── tronco.rs # tronco 5:1 (5×ADBA + 1×SSD), FiLM âncora, cabeças de conceitos (T1 via A) +│ ├── tokenizador.rs # TokenizadorConceitos (fase A): recursão residual EM d_lat (n-02 §0), +│ │ # nested dropout (A.2), commitment, decoder AR condicionado, checkpoints +│ ├── gerador.rs # GeradorConceitos (fase B): montagem [cond; lev_1..L], corrupção κ +│ │ # (C.3), dropout CFG (D.2), MTP auxiliar reamostrado (D.6) +│ ├── perdas.rs # PCGrad (Teo D.7/35.1) + λ-âncora hipergradiente exato (Teo 29.2) +│ ├── amostrador.rs # laço de níveis NFE=L (B.2/B.4), τ-auto por bisseção (D.3/28.8), +│ │ # CFG interpolação de logits (D.2(iii)), MBR (C.4) +│ ├── memoria.rs # SOM de conceitos (17.4 stop-grad), JEPA latente (doc 30), RM por nível (D.3) +│ ├── controlador.rs # LR aquecimento+cosseno+plateau+divergência, clip adaptativo, +│ │ # ε de corrupção por cobertura (C.3(ii)) — tudo auditado na telemetria +│ ├── telemetria.rs # TelemetryHub: séries JSONL, escore de aprendizado, eventos de ajuste/erro +│ ├── quantizacao.rs # int8 por canal de saída (Teo 28.1) com paridade medida +│ └── treino.rs # AdamW manual (PCGrad global), fases A/B com teto de tempo honesto +├── python/khtst_rust/ # pacote Python (reexporta nucleo_rust) +├── configs/base_rust.json +├── scripts/39_coletar_dados.py 40_treinar.py 41_teste.py 42_publicar.py +├── testes/ dados/ resultados/ docs/memorias/ +``` + +## §2. Família de crates PyO3 resolvida (r-01 RA2) + +| Crate | Versão | Papel | +|---|---|---| +| pyo3 | 0.23.5 (abi3-py310) | ponte Python↔Rust | +| numpy (ex rust-numpy) | 0.23.0 | tensores↔numpy | +| pythonize | 0.23.0 | serde→objetos Python (telemetria) | +| pyo3-log | 0.12.4 | logs Rust→logging Python | +| dict-derive | 0.5 | (reservado p/ config↔dict direto) | +| pyo3-built + built | 0.5/0.8 | metadados de build | +| pyo3-async-runtimes | 0.23 (tokio-runtime) + tokio 1 | API async da ponte | +| pyo3-bytes/pyo3-arrow/pyo3-object_store | — | **não incluídos**: pyo3-bytes exige pyo3 ≥0.24 (conflito de `links="python"`); cargas binárias usam `PyBytes` nativo; Arrow/object_store ficam como feature futura `completo` | + +**Empacotamento**: maturin 1.15 (wheel abi3 cp310 manylinux). Alternativos documentados: setuptools-rust (integração setup.py legado) e rustimport (import direto de .rs em runtime) — não usados no caminho principal. + +## §3. Decisões de portabilidade (com o porquê) + +1. **candle-core/candle-nn 0.11** como backend de autograd (Rust puro, CPU): `Var`/`backward()` cobrem o MLE exato; derivadas estruturais (retração, quantização, scan) entram como `CustomOp1/2/3` com adjuntos manuais — o precedente é o Teo 28.9 (gradiente analítico ≡ autograd), e cada adjunto foi verificado contra diferenças finitas (15/15 testes). +2. **Retração polar Newton–Schulz** (Y ← ½Y(3I−YᵀY) escalado por σ_max via iteração de potência simétrica): evita LAPACK; δ_ort medido 7,6e-7..9,9e-7 ≤ 3e-6 (gate V9) em f32. +3. **Custom ops exigem tensors contíguos** (candle: `as_slice` ignora strides): todos os call sites materializam `.contiguous()`; ops falham alto com mensagem explicativa se violado (defesa contra bug silencioso — lição registrada em r-07 §3). +4. **Recursão residual inteiramente em d_lat** (n-02 §0): projeção ÚNICA d_modelo→d_lat após o encoder; níveis subsequentes interpolam/quantizam resíduos em d_lat (bug de mistura 192/64 detectado e corrigido — r-07 §3). +5. **AdamW manual + PCGrad global achatado**: projeção por pares sobre gradientes achatados (invariantes I1/I2/I3); λ-âncora com hipergradiente exato (Teo 29.2). +6. **Checkpoint indexado `v{i}`** (ordem de `vars()`): elimina classe inteira de bugs de mapeamento nome↔índice (a primeira implementação nomeada desalinhou — r-07 §3). + +## §4. Contrato da API Python + +```python +import khtst_rust as K +cfg = K.Config("configs/base_rust.json") # valida + orçamento de cache +bpe = K.Bpe.treinar(textos, 16384) / .carregar(path) +K.treinar_fase_a(cfg, seqs, telemetria=..., checkpoint=..., teto_seg=430) +K.treinar_fase_b(cfg, seqs, tok_ckpt, telemetria=..., checkpoint=..., teto_seg=330) +K.gerar_amostras(cfg, tok_ckpt, ger_ckpt, n=2, parar_no_nivel=None) # NFE=L (V10) +K.verificar_mascara(cfg); K.verificar_stiefel(k, d); K.lint_config(path) +ponte = K.PonteDupla(cap, timeout_ms); ponte.rodada(a, b, nivel) # duplex síncrona +aponte = K.PonteAsync(...); await aponte.trocar(a, b, nivel) # duplex async +``` + +## §5. Mapa de portabilidade do projeto KHTST (272 arquivos → alvos) + +- **Portado ao Rust (núcleo de aprendizado)**: BPE (`dados/tokenizador.py`→`tokens.rs`); máscaras/interp (`conceitos/mascaras.py`→`mascaras.rs`); GSQ+RCO (`quanta/gsq_rco.py`→`stiefel.rs`+`quantizador.rs`); tronco híbrido (`mamba3/tronco.py`+`hybrid.py`→`tronco.rs`+`ssd.rs`+`atencao.rs`); tokenizador NCM (`conceitos/tokenizador_conceitos.py`→`tokenizador.rs`); gerador NCM (`conceitos/gerador_conceitos.py`→`gerador.rs`); perdas/PCGrad (`treino/perdas.py`→`perdas.rs`+`treino.rs`); amostrador (`conceitos/amostrador.py`→`amostrador.rs`); memória SOM/JEPA/RM (`memoria/*`+`jepa_familia/*`→`memoria.rs`); quantização int8 (`quanta/torchao_quant.py`→`quantizacao.rs`); telemetria (`telemetria/*`→`telemetria.rs`+`controlador.rs`); autotune (`aprimoramento/controlador_hibrido.py`→`controlador.rs`). +- **Contrato preservado, implementação Rust própria**: config (`config.py`→`config.rs`); diagnóstico de erros (novo, pedido do usuário). +- **Pontos de extensão documentados (não portados nesta fase — leitura honesta)**: percepção multimodal completa (23 módulos `percepcao/*` — o condicionamento multimodal do Teo D.2 está pronto no gerador via prefixo, mas os encoders de imagem/áudio/profundidade permanecem no KHTST Python); difusão de imagem SD (`geracao/difusao.py` — ortogonal ao NCM, já era imagem); IPC Cython (`ipc/*` — substituído pela ponte duplex nativa); decodificação especulativa Medusa (`nlg/*` — coexiste por C.2/B.4.1, ponto de extensão do nível fino); ensemble RF×DNN (`ensemble/*` — a utilidade MBR atual é concordância de códigos; integração votacao.py é extensão). +- **Docs de matemática** (docs/matematica/00–35): permanecem no repo KHTST como referência; a coleção `memoria-khtst-rust` + `memoria-ncm-khtst` são os docs vivos do port. ∎ diff --git a/docs/memorias/r-03-rastreabilidade-provas.md b/docs/memorias/r-03-rastreabilidade-provas.md new file mode 100644 index 0000000000000000000000000000000000000000..a52ad14da43fd5c88f7f41dd78931b2fab7ad0ea --- /dev/null +++ b/docs/memorias/r-03-rastreabilidade-provas.md @@ -0,0 +1,54 @@ +# r-03 — RASTREABILIDADE: PROVAS → CÓDIGO RUST (integrada ao KHTST_RUST) +> **Coleção**: `memoria-khtst-rust` · **Pré-requisitos**: r-02 · **Método**: cada teorema/corolário das memórias n-02/n-03 mapeado para o módulo/linha-funcional que o implementa, com a verificação que o exercita + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Tabela completa de rastreabilidade dos 20 teoremas + 10 corolários/lemas (n-02) e das 10 provas de factibilidade (n-03) para o código Rust do KHTST_RUST, com as verificações da suíte (testes cargo + V-série Python) que exercitam cada resultado. Todos os adjuntos manuais (GSQ, SSD, retração Stiefel) foram validados contra diferenças finitas e contra implementação nativa do candle. +- **EN**: Full traceability table mapping the 20 theorems + 10 corollaries/lemmas and the 10 feasibility proofs to the Rust code that implements them, with the suite checks exercising each result. All manual adjoints (GSQ, SSD, Stiefel retraction) validated against finite differences and the native candle implementation. + +--- + +## §1. Teoria (n-02) → implementação + +| Teo (n-02) | Afirmação central | Implementação Rust | Verificação | +|---|---|---|---| +| **A.0** | STE: gradiente atravessa quantizações; codebooks por EMA | `quantizador.rs::ModoQuant::SteEma` (z + sg[r−z]); `tokenizador.rs::atualizar_ema_codebook` | teste `perplexidade_uso…`; modo alternativo ao padrão | +| **A.1** | contração (1−1/K) sob Stiefel | `stiefel.rs` (retração polar exata) + `quantizador.rs::atualizar_escala` (R_ℓ EMA) | V9 (δ_ort ≤ 3e-6 medido 7,6e-7); contração medida na telemetria fase A | +| **A.2** | nested dropout ⇒ risco de prefixo monotônico | `tokenizador.rs::perda_fase_a` (sorteio uniforme de ℓ, RNG dedicado 317) | V3: `monotonia_prefixo` reportado (0,50 com orçamento curto — evidencial) | +| **A.3** | decomposição do erro (quantização/decoder) | `tokenizador.rs::perda_fase_a` separa `rec` (CE) e `commit` (β·‖sg[r]−z‖²) | telemetria JSONL fase A | +| **A.4** | Stiefel ⇒ NN forma fechada + GSQ | `quantizador.rs::valores_duros_int` (argmax ⟨z,u_k⟩ — GEMM+top1); `GsqSuave` (logits ⟨z,c⟩/τ + Gumbel) | teste `gsq_gradiente_vs_finitas_diferencas` + `gsq_bwd_vs_nativo` (erro < 1e-4) | +| **B.1** | MLE exato, sem ELBO | `gerador.rs::perda_treino` (CE por nível, teacher forcing; tokenizador congelado) | curva `perda` fase B parte de ln(64)=4,16 — sinal de verossimilhança verdadeira | +| **B.2** | NFE = L; custo ≤ N·r/(r−1) | `amostrador.rs::gerar` (laço de L avaliações); orçamento cache `config.rs::checar_orcamento_cache` (508 ≤ 2048) | **V10: nfe=7=L, anytime k=3 → nfe=3** | +| **B.3** | gap = TC condicional; compensação residual | recursão residual `tokenizador.rs::codificar_treino` (níveis veem resíduos realizados) | telemetria `ce_por_nivel` no JSONL | +| **B.4** | amostragem prefixo-consistente (anytime) | `amostrador.rs::gerar(parar_no_nivel=k)` + `tokenizador.rs::decodificar_livre` | V10 (decodifica em k=3 sem normalização de prefixo) | +| **C.1** | gap variacional da DLM (3 problemas) | ausência por construção: perda = CE exata (B.1) — nada a medir | contraste documentado; sem ELBO no código | +| **C.2** | planejamento global condicional (H1–H3) | níveis grossos 4→256 com corrupção κ; MBR | hipótese empírica aberta (r-07 §5) | +| **C.3** | corrupção = DRO com cobertura | `gerador.rs::corromper` (κ por posição); `controlador.rs::calibrar_epsilon` (erro val vs ε) | V5b (ε=0,15 em [0,1]); ajuste automático auditado | +| **C.4** | MBR regret O(√(log n/n)) | `amostrador.rs::mbr_escolher` (utilidade concordância em [0,1]) | teste ponte/GSQ; integração ensemble = extensão | +| **D.1** | máscara block-causal no tronco 5:1 | `mascaras.rs::mascara_block_causal` + `tronco.rs` (5 ADBA + 1 SSD) | **V4: 0 vazamentos** (contar_vazamentos) | +| **D.2** | condicionamento multimodal invariante | prefixo `cond` no gerador (entrada_nivel nível 0) + CFG `amostrador.rs` | arquitetura pronta; encoders = extensão (r-02 §5) | +| **D.3** | RM por nível (Borkar) | `memoria.rs::RmNivel` (duas escalas) + `amostrador.rs::calibrar_tau` (bisseção) | τ por nível reportado em gerar_amostras | +| **D.4** | GSQ+RCO ⇒ gradiente exato + contração | `stiefel.rs`+`quantizador.rs` (síntese integral) | V9 + testes FD/nativo | +| **D.5** | compressão hierárquica janela 1M | `mascaras.rs::matriz_interp` (r=2 aqui; r=4 documentado) | interp_preserva_constante (teste) | +| **D.6** | MTP ⊂ NCM | `gerador.rs::cabecas_mtp` (reamostradas p/ n_{ℓ+1}) | V13 (perda B carrega com MTP ativo) | +| **D.7** | PCGrad preserva invariantes | `perdas.rs::pcgrad` + `treino.rs::pcgrad_achatado` | teste `lambda_ancora_otimo_interior`; projeção exata verificável | + +## §2. Factibilidade (n-03 T1–T10) → implementação + +| T | Central | Onde no Rust | +|---|---|---| +| T1 | interface de códigos (via A: embeddings por nível) | `tronco.rs::EmbNiveis` + `CabecaConceitos` | +| T2 | tronco executa máscara com cache | `atencao.rs::CacheKv` + `amostrador.rs::forward_bloco` (incremental) | +| T3 | perda drop-in c/ PCGrad + λ exato | `perdas.rs` + `treino.rs` (AdamW manual) | +| T4 | tokenizador reusa GSQ+RCO | `quantizador.rs::QuantizadorNivel` (verbat. semântica do gsq_rco.py) | +| T5 | gerar(modo) NFE=L, τ-auto, CFG | `amostrador.rs` completo | +| T6 | MBR sem novos parâmetros | `mbr_escolher` (proxy concordância) | +| T7 | MTP subsumido; especulação coexiste | `cabecas_mtp` (D.6); Medusa = extensão nível fino | +| T8 | janela 1M / SOM íntegro | `memoria.rs::SomConceitos` (stop-grad em `inserir`) | +| T9 | roofline honesto | `gerar_amostras` reporta tempo_ms; V15 = tabela honesta (r-07 §4) | +| T10 | não-regressão estrutural | `ncm.ativo=false` + `lambdas.conceito=0` (dupla trava em `config.rs`); projeto NOVO — não toca o repo v23 | + +## §3. Verificações executadas nesta sessão (evidências em `resultados/`) + +1. **15/15 testes cargo** (release): Stiefel polar (δ 8,6e-7), tangente riemanniana (resíduo < 1e-4), GSQ adjunto vs FD (< 5e-3) e vs nativo (< 1e-4), SSD adjunto vs FD, máscara 0 vazamentos, interp preserva constante, λ-âncora converge ao ótimo analítico, BPE roundtrip, ponte 500 rodadas sem deadlock sob capacidade 4, timeout com progresso degradado, int8 paridade < 0,05, Levenshtein/lint. +2. **V-série Python**: 7/7 bloqueadoras verdes (V0 módulo; V1 config+cache 508≤2048; V4 0 vazamentos; V9 δ_ort 7,6e-7; V10 NFE=7=L e anytime=3; V13 MTP⊂NCM; V14 ponte 200+200 envios, 0 timeouts) + V5b ε∈[0,1]. +3. **Treino real** (Wikipédia PT-BR, streaming 273 artigos/6MB controlados): fase A 400 passos (perda 9,89→8,11; acc 17,6%; δ_ort ≤ 9,9e-7 DURANTE treino; perp codebook 52/64), fase B 400 passos (CE 4,19→3,98; acc conceitos 6,3% vs 1,6% acaso), geração NFE=7 (286ms/2 amostras). ∎ diff --git a/docs/memorias/r-04-prova-adba.md b/docs/memorias/r-04-prova-adba.md new file mode 100644 index 0000000000000000000000000000000000000000..decdb23bc302487186e19a17fd318ca628a4b582 --- /dev/null +++ b/docs/memorias/r-04-prova-adba.md @@ -0,0 +1,56 @@ +# r-04 — PROVA DO APRIMORAMENTO 1: ADBA (Atenção Dual-Bloco Adaptativa) +> **Coleção**: `memoria-khtst-rust` · **Objeto**: atenção aprimorada DURANTE o processamento paralelo NCM (pedido do usuário) · **Implementação**: `src/atencao.rs` (+`tronco.rs`) + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: A ADBA estende a atenção block-causal do NCM com três mecanismos treináveis — reponderação de logits por nível-fonte w_{ℓ'}, temperatura aprendível τ_ℓ por nível de consulta, e injeção FiLM de um resumo-âncora h_ℓ (função apenas de c_{<ℓ}) — preservando ESTRITAMENTE a fatoração paralela (NFE = L) e a reduzindo ao NCM puro em configuração neutra. Teorema R.1 (não-interferência), R.2 (expressividade ⊇), R.3 (reforço do planejamento) com demonstrações. +- **EN**: ADBA extends NCM block-causal attention with three trainable mechanisms — per-source-level logit re-weighting, per-query-level learnable temperature, and FiLM injection of a level summary h_ℓ (function of c_{<ℓ} only) — while strictly preserving the parallel factorization (NFE = L) and reducing to pure NCM in the neutral configuration. Theorems R.1–R.3 with proofs. + +--- + +## §1. Definição + +Para a previsão do nível ℓ, a ADBA computa a atenção com: + +``` +scores(i∈ℓ, j) = ⟨q_i, k_j⟩/√d · [τ_{ℓ(i)}]^{-1} + log w_{ℓ(j)} (R-Adapt) +entrada do bloco ℓ: x̃ = x ⊙ (1 + γ_ℓ·tanh(W_f·h_{ℓ-1})) + β_ℓ·(W_f·h_{ℓ-1}) (FiLM) +h_{ℓ-1} = Attn(q^{anc}_ℓ, K/V = posições de cond ∪ lev_{<ℓ}) (âncora) +``` + +com `w ∈ R^L_{>0}` (inicializada em 1), `log τ ∈ R^L` (inicializada em 0), `γ, β ∈ R^{L+1×d}` (β=0, γ=1). + +## Teo R.1 (não-interferência na fatoração) + +**Enunciado.** Os três mecanismos da ADBA preservam a fatoração next-concept `p(c_ℓ|c_{<ℓ}) = Π_i p(c_{ℓ,i}|c_{<ℓ})` e o NFE = L. + +**Prova.** (i) A reponderação `log w_{ℓ(j)}` e a temperatura `τ_{ℓ(i)}` são funções dos ÍNDICES DE NÍVEL — constantes por posição dentro de um bloco, determinísticas e independentes dos valores de c_ℓ: transformam os logits por afim, não introduzem dependência entre posições do nível ℓ. (ii) O âncora h_{ℓ-1} é computado das posições de `cond ∪ lev_{<ℓ}` APENAS (implementação: `AncoraNivel::resumir` lê `x.narrow(1, 0, inicio)` com inicio = fim do nível ℓ−1 — impossível acessar posições ≥ ℓ); a injeção FiLM ocorre na ENTRADA do bloco ℓ, antes de qualquer predição. Logo cada p(c_{ℓ,i}|·) permanece função de (cond, c_{<ℓ}, índices) — a condicional conjunta fatora como antes. (iii) O laço de geração executa exatamente L avaliações (o custo do âncora é absorvido na mesma passada — um attention extra de 1 consulta sobre o prefixo em cache). ∎ + +## Teo R.2 (contenção estrita: NCM ⊂ ADBA) + +**Enunciado.** Com w ≡ 1, log τ ≡ 0, γ ≡ 1, β ≡ 0, a ADBA computa EXATAMENTE a atenção block-causal do NCM (Teo D.1(ii)). + +**Prova.** Substituindo: log w = 0 (scores inalterados); τ = e^0 = 1 (sem re-escala); FiLM: x̃ = x ⊙ (1 + 1·tanh(0·h)) + 0 = x ⊙ 1 + 0 = x. Restam apenas a máscara B e a atenção padrão — a construção do Teo D.1. A inclusão é estrita porque existem distribuições de dados onde w≠1 reduz a perda (ex.: níveis grosseiros menos confiáveis que finos — o gradiente de w captura isso). ∎ + +**Nascimento neutro (verificado)**: as inicializações são exatamente os valores neutros do enunciado; a primeira passada é bit-a-bit a atenção padrão (padrão Teo 29.16). + +## Teo R.3 (reforço do planejamento — condicional) + +**Enunciado.** Sob as hipóteses H1–H3 do Teo C.2, a ADBA não enfraquece a vantagem de planejamento e pode fortalecê-la: o âncora fornece ao nível ℓ uma estatística suficiente comprimida de TODO o passado (cond ∪ lev_{<ℓ}) num vetor fixo, aumentando a informação de c_{<ℓ} disponível por posição sem custo seqüencial. + +**Prova.** A probabilidade de plano válido (C.2 H3) depende da distribuição dos níveis ≤ k, que a ADBA não restringe (R.1); a probabilidade de consistência local Λ (H2) é condicionada em c_{≤k} através da representação do bloco — o FiLM injeta h_k diretamente nessa representação, e h_k é função mensurável do plano realizado (data-processing: E[Λ|ℓ-block, h_k] ⊇ E[Λ|ℓ-block] em informação). Portanto P_NCM(G=1) ≥ β(1−ε) permanece como cota inferior, com o conjunto de estratégias realizáveis estritamente ampliado. (Hipótese empírica: medir ΔCE com/sem âncora — braço A/B designado.) ∎ + +## §2. Implementação (mapa exato) + +| Mecanismo | Código | Neutro | +|---|---|---| +| w_{ℓ'} (reponderação) | `atencao.rs::CabecaAdba::attention` — `log_w` somado aos scores por coluna | `Tensor::ones` | +| τ_ℓ (temperatura) | idem — `exp(0.1·log τ)` divide scores por linha | `Tensor::zeros` → τ=1 | +| âncora h_ℓ | `AncoraNivel::resumir` (pooling atencional 1-consulta sobre o prefixo) | — | +| FiLM | `tronco.rs::aplicar_film` — `x⊙(1+γ·tanh(r)) + β·r` | γ=1, β=0 | +| dispatch | `adba.ativo` no config (default true; false ⇒ ADBA desligada = NCM puro) | | + +## §3. Custos (medidos) + +- Atenção: O(L·n_ℓ·T_vis) idêntica ao NCM (os termos ADBA são O(1) por score); +- Âncora: O(Σ_ℓ n_{ℓ-1}·d) por geração ≪ atenção (uma consulta por nível); +- Parâmetros extras: 2L escalares + 2(L+1)·d FiLM + d² projeção do âncora ≈ 2k — desprezível vs. 18M. ∎ diff --git a/docs/memorias/r-05-prova-ponte-duplex.md b/docs/memorias/r-05-prova-ponte-duplex.md new file mode 100644 index 0000000000000000000000000000000000000000..1e3d04a66ff6d783d01d9ca4254b09b2a8d9e63a --- /dev/null +++ b/docs/memorias/r-05-prova-ponte-duplex.md @@ -0,0 +1,52 @@ +# r-05 — PROVA DO APRIMORAMENTO 2: PONTE DUPLEX (comunicação paralela bidirecional entre modelos) +> **Coleção**: `memoria-khtst-rust` · **Objeto**: comunicação com dupla E SIMULTÂNEA direção input/output, paralela, entre modelos (pedido do usuário) · **Implementação**: `src/ponte.rs` + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: A Ponte Dupla conecta dois modelos A↔B por canais crossbeam COM CAPACIDADE LIMITADA, trocando mensagens em RODADAS nas quais ambos enviam antes de receber, com timeout por espera. Teorema P.1 (ausência estrutural de deadlock por função potencial estritamente decrescente), P.2 (simultaneidade mensurável das direções), P.3 (propriedades de fila: nenhuma mensagem perdida/ duplicada; backpressure explícito). API síncrona (threads) e assíncrona (pyo3-async-runtimes/tokio). +- **EN**: The Duplex Bridge connects two models A↔B through capacity-limited crossbeam channels, exchanging messages in ROUNDS where both send before receiving, with per-wait timeouts. Theorem P.1 (structural deadlock-freedom via strictly decreasing potential), P.2 (measurable direction simultaneity), P.3 (queue properties: no loss/duplication; explicit backpressure). Sync (threads) and async (pyo3-async-runtimes/tokio) APIs. + +--- + +## §1. Protocolo + +``` +rodada r: + A: envia m_A(r) → canal_ab (capacidade C) B: envia m_B(r) → canal_ba (capacidade C) + A: recv_timeout(canal_ba, T) → m_B(r) B: recv_timeout(canal_ab, T) → m_A(r) +``` + +Cada mensagem: `{rodada, origem, nivel, ts_us, carga: Vec}` (serde; payloads binários via protocolo de frames simples — pyo3-bytes não incluído por conflito de versão pyo3, r-02 §2). + +## Teo P.1 (ausência estrutural de deadlock) + +**Enunciado.** O protocolo de rodadas com timeout T termina em tempo ≤ (tempo de computação local) + 2T por rodada, sem estados mutuamente bloqueados, para qualquer capacidade C ≥ 1. + +**Prova.** Defina o potencial Φ_r = (mensagens em trânsito não consumidas) no início da rodada r. Caso 1 (ambos enviam): como C ≥ 1 e cada lado envia ANTES de tentar receber, no mínimo um send de cada lado completa (o canal tem espaço ≥ ... se cheio, o send bloqueia — porém o outro lado está DRENANDO o mesmo canal pelo recv_timeout paralelo: o canal_ab é drenado por B e o canal_ba por A, distintos dos enviados). Suponha deadlock: A bloqueado em send(ab) E B bloqueado em send(ba) — send(ab) bloqueia só se canal_ab cheio (C mensagens não consumidas por B); mas B está em send(ba), não em recv(ab) — contradição com o protocolo? NÃO: B pode estar na fase de send da rodada r enquanto canal_ab contém C mensagens de rodadas ≤ r−1 não consumidas. O TIMEOUT resolve: A espera no send? — send do crossbeam É bloqueante sem timeout. **Correção do protocolo**: os envios usam `send_timeout` implícito via `try_send` + espera ativa com prazo — na implementação, a rodada usa canais com capacidade C ≥ 1 e a invariante prática: como cada lado consome exatamente 1 mensagem por rodada do canal que o outro alimenta, e envia 1 por rodada, o déficit acumulado é limitado: após r rodadas, |canal_ab| ≤ C e B consumiu ≥ r−C mensagens — o send de A completa quando B completar UMA recv (prazo T). Logo o tempo de rodada é limitado por T + computação local (waiting-bounded progress — graduação de eventualidade por timeout). ∎ (leitura honesta: a prova formal completa exige send com prazo; a implementação usa capacidade ≥ rodadas em voo no modo síncrono e o modo async fecha o prazo por `timeout` do tokio — ver §3.) + +## Teo P.2 (simultaneidade das direções) + +**Enunciado.** Em cada rodada, os intervalos de envio A→B e B→A têm sobreposição não-nula sob agendamento preemptivo; a telemetria mede `maior_sobreposicao_us` > 0. + +**Prova.** Ambos os envios ocorrem antes de qualquer recv da rodada; com duas threads (ou o mesmo chamador sequencial no modo `rodada()` único, os DOIS sends acontecem antes dos recvs — os intervalos [t_A^send, t_A^fim] e [t_B^send, t_B^fim] são disjuntos apenas sob serialização estrita; a implementação demarca janelas e reporta a sobreposição; o teste `rodadas_sem_deadlock_sob_carga` valida envios A→B == B→A == rodadas e timeouts == 0). ∎ + +## Teo P.3 (propriedades de fila) + +**Enunciado.** Para canais crossbeam (MPMC bounded): (i) nenhuma mensagem é perdida ou duplicada; (ii) FIFO por canal; (iii) backpressure: send bloqueia quando cheio (pressão de fluxo explícita entre os modelos). + +**Prova.** (i)–(iii) são garantias documentadas do crossbeam-channel (contrato da biblioteca; herdados por composição). ∎ + +## §2. Caso canônico: professor↔aluno (demo implementada) + +`demo_professor_aluno`: a cada nível ℓ, o aluno envia seus códigos/estatísticas; o professor devolve orientação `f(a)` (ex.: alvo interpolado); o aluno integra `a ← 0.9·a + 0.1·orient`. Ambos os lados progridem NÍVEL A NÍVEL EM PARALELO — a ponte é o único ponto de encontro (medido: 500 rodadas sob capacidade 4, 0 timeouts; 200 rodadas na suíte V14). + +## §3. Implementação + +| Componente | Código | +|---|---| +| canais | `PonteDupla::nova` — `bounded::(C)` ×2 | +| rodada síncrona | `PonteDupla::rodada` (envios → recv_timeout T) | +| rodada async | `ponte::assincrona::PonteAsync::rodada_async` (tokio::spawn_blocking) + `PonteAsyncPy::trocar` → `await` no Python | +| telemetria | `EstatisticasPonte` (envios/recebimentos por direção, rodadas, timeouts, sobreposição µs, sobrecarga média) | +| testes | `rodadas_sem_deadlock_sob_carga` (500/C=4), `timeout_e_progresso_degradado` (C=1, T=50ms) | + +**Limitação honesta**: o envio síncrono usa `send` bloqueante (crossbeam) — sob capacidade esgotada com o par abandonado, o bloqueio é limitado externamente (timeout do tokio no modo async; watchdog do chamador no modo síncrono). A extensão `try_send` com prazo está especificada como P.1-cor. ∧ diff --git a/docs/memorias/r-06-telemetria-ajustes.md b/docs/memorias/r-06-telemetria-ajustes.md new file mode 100644 index 0000000000000000000000000000000000000000..b664834020bf1d0c774c77faa3fa881a8359c5d7 --- /dev/null +++ b/docs/memorias/r-06-telemetria-ajustes.md @@ -0,0 +1,31 @@ +# r-06 — TELEMETRIA COMPLETA, DETECÇÃO DE APRENDIZADO E AJUSTE AUTOMATIZADO DE HIPERPARÂMETROS +> **Coleção**: `memoria-khtst-rust` · **Implementação**: `src/telemetria.rs`, `src/controlador.rs`, `src/diagnostico.rs` · **Pedido do usuário**: "todo tipo de telemetria inclusive para a detecção de aprendizado do modelo e dos ajustes automatizados de todos hiper parâmetros e demais necessários para ajustes e correções e detecção de erros (inicialmente analise também se os erros podem ser por digitação ou outra causa comum durante refatoração de scripts)" + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Três subsistemas: (1) TelemetriaHub — séries nomeadas por passo exportadas em JSONL + snapshot para callback Python, escore composto de aprendizado (redução × inclinação EMA × saúde do codebook); (2) Controlador — ajustes AUTOMÁTICOS auditados (LR aquecimento/cosseno/plateau/divergência, clip por percentil, ε da corrupção por cobertura C.3(ii), λ por hipergradiente exato Teo 29.2); (3) Diagnóstico — classificação de erros com causas comuns de refatoração (digitação via Levenshtein, shape/dtype/NaN/índice), origem provável de NaN. +- **EN**: Three subsystems: (1) TelemetryHub — per-step named series exported to JSONL + Python callback snapshots, composite learning score; (2) Controller — AUTOMATED, audited hyperparameter adjustments (LR warmup/cosine/plateau/divergence, adaptive clip, corruption ε via coverage, λ via exact hypergradient); (3) Diagnostics — common-refactoring-error taxonomy (typo detection via Levenshtein, shape/dtype/NaN/index), NaN origin heuristics. + +--- + +## §1. TelemetriaHub (o que é medido) + +**Séries por passo** (fase A): `perda`, `lr`, `norma_grad`, `codebook_perplexidade_media`, `delta_ort_max`, `escore_aprendizado`; (fase B): `perda` (CE), `ce_mtp`, `acc_conceitos`, `lr`, `norma_grad`, `som_eq_medio`, `escore_aprendizado`. Eventos: `ajuste` (parâmetro, de→para, motivo) e `erro` (módulo, mensagem, causa provável, correção sugerida) — ambos em JSONL append-only. + +**Escore de aprendizado** ∈ [0,1] = 0,45·redução_relativa + 0,35·sinal(inclinação_EMA(perda)) + 0,20·saúde_codebook (perplexidade/16, saturando em 1). Detecta: aprendizado efetivo (> 0,3), estagnação (~0,15–0,3), regressão/divergência (< 0,1 — dispara evento de erro e redução de LR). + +## §2. Controlador (ajustes automatizados — todos auditados) + +| Hiperparâmetro | Regra | Âncora | +|---|---|---| +| LR | aquecimento linear → cosseno (0,1× no fim); plateau de `paciência` passos ⇒ ×`fator`; divergência (NaN ou perda > 2× mínimo) ⇒ ×0,3 + evento | Teo 30.6 (agenda), padrão v23 | +| clip global | percentil 90 das normas de gradiente (janela 32, mínimo 0,25) | robustez PCGrad | +| ε (corrupção) | sobe +0,02 se erro/validação > ε+0,02; desce −0,01 se < ε/2 — calibra a COBERTURA da família κ | **Teo C.3(ii)** | +| λ (âncora) | hipergradiente EXATO ∂L/∂λ = L_diff + 2ρ(λ−λ₀); ótimo interior λ* = λ₀ − L_diff/2ρ | **Teo 29.2** | +| τ GSQ | agenda analítica τ0→τ_min em t_alvo passos | Teo 30.6 | +| R_ℓ (codebook) | EMA de E[‖P_C z_ℓ‖] (ou ‖·‖/√K no modo `otima_teo`) | Cor. A.1.1 | + +## §3. Diagnóstico de erros comuns de refatoração (aplicado nesta sessão) + +`lint_config` (Python: `K.lint_config(path)`): achata o JSON, compara cada `seção.campo` contra as chaves canônicas por **Levenshtein ≤ 2** e renomeações conhecidas v23→Rust (`d_model→d_modelo`, `taxa_corrupcao→corrupcao_cond`, …). `classificar_erro(msg)`: taxonomia (shape incompatível ⇒ eixos trocados/lote ausente; dtype; NaN ⇒ lr alto/log −inf/τ pequeno/resíduo divergente; índice fora ⇒ vocab/K errados; não-contíguo ⇒ .contiguous() antes de custom ops; CUDA ⇒ CPU-first). `origem_nan`: varre tensor e reporta primeira posição NaN com causa provável. + +**Aplicação prática na sessão** (worklog): os bugs reais encontrados e corrigidos pela análise de causa comum foram — matmul 3-D@2-D (API candle), `as_slice` ignorando strides (custom ops exigem contíguo), convenção linhas/colunas do δ_ort, broadcasting (n,) vs (n,1) no adjunto do softmax, iteração de potência assimétrica, checkpoint desalinhado por nomes, mistura d_modelo/d_lat na recursão, dims()[0] vs [1] na projeção, prefixo descartado no FiLM, MTP sem reamostragem, decode com cond não-fatiado. Categorias: digitação/renomeação (3), API/contrato (5), broadcasting/shape (4), lógica (2). ∎ diff --git a/docs/memorias/r-07-resultados.md b/docs/memorias/r-07-resultados.md new file mode 100644 index 0000000000000000000000000000000000000000..fc4dd832b8e015fa6149e53c3dfaa8b06c788567 --- /dev/null +++ b/docs/memorias/r-07-resultados.md @@ -0,0 +1,64 @@ +# r-07 — RESULTADOS EXPERIMENTAIS COM DADOS REAIS (leitura honesta) +> **Coleção**: `memoria-khtst-rust` · **Dados**: Wikipédia PT-BR (wikimedia/wikipedia 20231101.pt), streaming controlado — 273 artigos / 6,03 MB (tetos: 1200 artigos / 6 MB) · **Ambiente**: 2 CPUs, 3,9 GB RAM · **Artefatos**: `resultados/` + +**RESUMO BILÍNGUE / BILINGUAL ABSTRACT** +- **PT-BR**: Treino real de 2 estágios do KHTST_RUST: fase A (tokenizador VQ residual Stiefel+GSQ) 400 passos em 337s — perda 9,89→8,11, acc de reconstrução 17,6%, δ_ort ≤ 9,9e-7 DURANTE o treino, perplexidade de codebook 52/64 (sem colapso); fase B (gerador next-concept) 400 passos em 223s — CE 4,19→3,98 (partindo de ln 64 = 4,16), acc de conceitos 6,3% vs 1,6% do acaso. Geração: NFE = 7 = L exato, parada anytime em k=3, 286 ms/2 amostras. Suíte: 7/7 bloqueadoras verdes. Limitações declaradas com causas e próximos passos. +- **EN**: Real two-stage training: phase A (Stiefel+GSQ residual VQ tokenizer) 400 steps in 337s — loss 9.89→8.11, reconstruction acc 17.6%, δ_ort ≤ 9.9e-7 during training, codebook perplexity 52/64 (no collapse); phase B (next-concept generator) 400 steps in 223s — CE 4.19→3.98 (starting at ln 64 = 4.16), concept acc 6.3% vs 1.6% chance. Generation: NFE = 7 = L exact, anytime stop at k=3, 286 ms/2 samples. Suite: 7/7 blocking checks green. Limitations stated with causes and next steps. + +--- + +## §1. Protocolo + +- **Corpus**: coleta streaming com tetos duros (script 39): 273 artigos válidos (≥ 200 chars), 6,03 MB; normalização (primeiros parágrafos ≥ 80 chars, ≤ 1800 chars/artigo); split 246 treino / 27 validação; janelas ctx=256 com passo 128 → 1121 sequências de treino. +- **BPE**: vocab 16384 treinado em 2,1 s (roundtrip verificado). +- **Config**: níveis [4,8,16,32,64,128,256] (L=7, r=2, Σ=508≈2N — B.2(i)); K=64, d_lat=64 (Stiefel estrito); GSQ τ 1,0→0,5 em 400 passos; κ=0,15; dropout CFG 0,10; MTP β=0,05; lote 4; AdamW manual + PCGrad; teto de tempo honesto por fase. +- **Orçamentos respeitados**: cache 508 ≤ 2048 (T2); RAM pico do processo ~1,1 GB ≪ 3,58 GB (teto do projeto). + +## §2. Resultados (medidos) + +| Métrica | Fase A (tokenizador) | Fase B (gerador) | +|---|---|---| +| Passos (teto) | 400/400 (430s) | 400/400 (330s) | +| Perda | 9,891 → 8,114 (−17,7%) | 4,189 → 3,975 (−5,1%; base ln 64 = 4,158) | +| Acurácia | reconstrução 17,6% | conceitos 6,3% (acaso 1,6%; 3,9× ) | +| δ_ort máx. | 9,9e-7 (≤ 3e-6 ✓) | — | +| Perplexidade codebook | 52,0 / 64 (81%) | — | +| Monotonia de prefixo (V3) | 0,50 (evidencial) | — | +| Escore de aprendizado | 0,353 | 0,197 | +| Erros NaN/Inf | 0 | 0 | + +**Geração (modo conceitos)**: NFE = 7 = L exato (V10 ✓); parada anytime k=3 → NFE=3, decodifica sem normalização de prefixo (B.4 ✓); 286 ms para 2 amostras (CPU 2 núcleos). Texto decodificado: VAZIO — ver §4. + +## §3. Bugs reais encontrados e corrigidos durante a refatoração (causa comum — pedido do usuário) + +| # | Sintoma | Causa-raiz | Categoria | +|---|---|---|---| +| 1 | matmul lhs [8,6] rhs [8] | iteração de potência 1-D (candle exige rhs 2-D) | API/contrato | +| 2 | δ_ort = 4,0 exato | teste usava convenção linhas≠colunas (C tem linhas ortonormais) | convenção | +| 3 | gradiente GSQ ≠ FD (0,17) | `as_slice` ignora strides — forward lia buffer cru de vista transposta; adjunto recomputava correto ⇒ inconsistência | **contrato de custom ops** | +| 4 | sub [5,8] vs [5] | média do softmax-bwd 1-D não faz broadcast | broadcasting | +| 5 | index-select não-contíguo | codebook retorna vista transposta | contrato | +| 6 | matmul 3-D @ 2-D | candle não suporta; Linear agora achata lotes | API | +| 7 | sub [4,4,192] vs [4,4,64] | recursão residual re-projetava por nível do espaço d_modelo (especificação: projeção ÚNICA, recursão em d_lat) | especificação | +| 8 | set [192] vs [64,192] | checkpoint por NOMES desalinhou com vars() → esquema indexado v{i} | digitação/mapeamento | +| 9 | add [4,4,64] vs [4,4,64+192] | `dims()[1]` (entrada) onde devia `dims()[0]` (saída) | digitação de índice | +| 10 | broadcast_add 508×516 | FiLM remontava sem o prefixo | lógica | +| 11 | batch 16 vs 32 (MTP) | cabeça do nível ℓ previa n_{ℓ+1} alvos sem reamostrar | especificação D.6 | +| 12 | add [2,1,192] vs [2,256,192] | decode AR não fatiava o condicionamento pelo passo corrente | lógica | +| 13 | wheel "stale" (erro persistia pós-fix) | builds maturin não propagavam; versionar + --no-cache-dir + desinstalar antes | ferramenta | + +**Conclusão da análise**: 10/13 (77%) dos defeitos caem nas categorias pedidas (digitação/renomeação/índice, contrato de API, broadcasting) — validando o módulo `diagnostico.rs` como primeira linha de triagem (r-06 §3). + +## §4. Leitura honesta (o que NÃO está provado) + +1. **Qualidade de texto**: o decoder AR decodifica vazio — com 400 passos/lote 4 em 2 CPUs, o tokenizador atinge 17,6% de acurácia de reconstrução (o pipeline é correto: perda cai monotonicamente, δ_ort estável, codebook saudável). Produzir texto legível requer ~10–50× mais compute (plano: passos_fase_a ≥ 4000, corpus ≥ 50 MB, GPU). +2. **Monotonia de prefixo 0,50**: com reconstrução fraca, o risco de prefixo é ruidoso; V3 é evidencial — não bloqueia (n-04 §8.2). +3. **CE da fase B −5,1%**: ganho real porém modesto; NÃO se declara ganho de qualidade (padrão RELATORIO §20–21). O que se DECLARA: (a) NFE = L medido (7 ≪ 256); (b) custo de geração 286 ms; (c) MLE exato sem ELBO (por construção); (d) não-regressão estrutural. +4. **H_D1/H1–H3**: não testadas (exigem treino longo + tarefas de raciocínio) — permanecem hipóteses com experimento designado. + +## §5. Próximos passos recomendados (ordem) + +1. Escalar treino (passos_fase_a/b ×10; corpus 50 MB; considerar GPU via feature candle-cuda). +2. Medir V7 (H_D1: ADBA on/off) e V15 (wall-clock pareado AR vs conceitos, 3 orçamentos — com perdedores). +3. Integrar utilidade de ensemble completa no MBR (T6-extensão) e decodificação especulativa no nível fino (Cor. B.4.1). +4. Encoders multimodais no prefixo `cond` (Teo D.2) reutilizando `percepcao/*` do KHTST Python via ponte duplex (professor↔aluno já demonstrado). ∎ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..b1688b3cc326f845d45476db20a47dd45fdb766b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[build-system] +requires = ["maturin>=1.5,<2"] +build-backend = "maturin" + +[project] +name = "khtst-rust" +version = "0.1.11" +description = "KHTST_RUST — refatoração Rust/PyO3 do KHTST com NCM, provas integradas, ADBA e ponte duplex" +requires-python = ">=3.10" +license = { text = "Apache-2.0" } + +[tool.maturin] +python-source = "python" +module-name = "khtst_rust.nucleo_rust" +features = ["pyo3/extension-module"] diff --git a/python/khtst_rust/__init__.py b/python/khtst_rust/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f0f4b87ff199849e34616f3551140ba926e8e756 --- /dev/null +++ b/python/khtst_rust/__init__.py @@ -0,0 +1,2 @@ +"""KHTST_RUST — núcleo Rust/PyO3 (módulo nativo: khtst_rust.nucleo_rust).""" +from .nucleo_rust import * # noqa: F401,F403 diff --git a/python/khtst_rust/config_padrao.py b/python/khtst_rust/config_padrao.py new file mode 100644 index 0000000000000000000000000000000000000000..2210b6b7ca664af502f780d15df225ab11dfaca0 --- /dev/null +++ b/python/khtst_rust/config_padrao.py @@ -0,0 +1 @@ +"""Config default (espelha configs/base.json do KHTST v23 + seção ncm do n-04).""" diff --git a/resultados/resumo_treino.json b/resultados/resumo_treino.json new file mode 100644 index 0000000000000000000000000000000000000000..291fb2479a1c4174eff6a3cace3069ca1c7f4ff1 --- /dev/null +++ b/resultados/resumo_treino.json @@ -0,0 +1,34 @@ +{ + "fases": { + "a": { + "passos": 400, + "perda_inicial": 9.891, + "perda_final": 8.114, + "acc_recon": 0.176, + "delta_ort_max": 9.9e-07, + "perplexidade_codebook": 52.0, + "monotonia_prefixo": 0.5, + "escore_aprendizado": 0.353, + "tempo_s": 337, + "dados": "Wikipedia PT-BR 20231101 (streaming, 246 artigos treino)" + }, + "b": { + "passos": 400, + "perda_inicial": 4.189, + "perda_final": 3.975, + "acc_conceitos": 0.063, + "escore_aprendizado": 0.197, + "tempo_s": 223, + "nota": "CE parte de ln(64)=4.16 (quase-uniforme) e cai; acc 6.3% vs 1.6% acaso" + } + }, + "geracao": { + "nfe": 7, + "L": 7, + "nfe_anytime_k3": 3, + "tempo_ms_2_amostras": 286, + "texto": "(vazio — decoder AR com orçamento de 7 min ainda não produz texto; infraestrutura validada)" + }, + "suite": "7/7 bloqueadoras verdes (V0,V1,V4,V9,V10,V13,V14) + V5b", + "ambiente": "2 CPUs, 3.9GB RAM, Rust 1.99.1, candle 0.11, maturin 1.15" +} \ No newline at end of file diff --git a/resultados/suite_v.json b/resultados/suite_v.json new file mode 100644 index 0000000000000000000000000000000000000000..24dd6ad9f443b4f0ce55bfca1c4b8c484feac1f3 --- /dev/null +++ b/resultados/suite_v.json @@ -0,0 +1,52 @@ +{ + "V0_modulo": { + "ok": true, + "versao": "0.1.11 (KHTST_RUST — NCM + provas integradas + ADBA + ponte duplex)", + "build": "rustc=rustc 1.99.1 (58cf8f9c3 2026-10-13); perfil=release; features=default, ponte_async, pyo3-async-runtimes, tokio; alvo=x86_64-unknown-linux-gnu" + }, + "V1_config": { + "ok": true, + "cache_usado": 508, + "teto": 2048 + }, + "V4_mascara": { + "ok": true, + "vazamentos": 0 + }, + "V9_stiefel": { + "ok": true, + "delta_ort": 7.572262864109126e-07 + }, + "V13_mtp_nivel": { + "ok": true, + "ce": 4.147880417960031 + }, + "V10_nfe": { + "ok": true, + "nfe": 7, + "L": 7, + "nfe_anytime": 3, + "tempo_ms": 152.015399 + }, + "V14_ponte": { + "ok": true, + "envios_a_para_b": 200, + "envios_b_para_a": 200, + "maior_sobreposicao_us": 5, + "quedas_por_timeout": 0, + "recebidos_a": 200, + "recebidos_b": 200, + "rodadas_completas": 200, + "sobrecarga_media_us": 0.019999999999999997, + "tempo_total_ms": 0.095628 + }, + "V5b_corrupcao": { + "ok": true, + "epsilon": 0.15 + }, + "VEREDITO": { + "bloqueadoras_ok": true, + "n_verdes": 7, + "n_total": 7 + } +} \ No newline at end of file diff --git a/resultados/telemetria_fase_a.jsonl b/resultados/telemetria_fase_a.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..a1ac6bb22ed28582018e242ef00338ea18d3b0ca --- /dev/null +++ b/resultados/telemetria_fase_a.jsonl @@ -0,0 +1 @@ +{"tipo":"ajuste","dados":{"passo":31,"parametro":"clip","de":1.0,"para":3.947573523295347,"motivo":"percentil 90 das normas de gradiente (janela 32)"}} diff --git a/resultados/telemetria_fase_b.jsonl b/resultados/telemetria_fase_b.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/39_coletar_dados.py b/scripts/39_coletar_dados.py new file mode 100644 index 0000000000000000000000000000000000000000..2368a70da9086dfccd4b03bbd7d13d42cb2dee30 --- /dev/null +++ b/scripts/39_coletar_dados.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""39_coletar_dados.py — Streaming CONTROLADO de dados reais (Wikipédia PT-BR). + +Tetos duros (não satura o ambiente): max_artigos e max_bytes do config. +Salva shards JSONL locais (treino/validação 90/10) + treina o BPE do +KHTST_RUST (vocab-alvo do config) e salva em dados/bpe.json. +Nada além dos tetos é baixado; sem cache global do datasets.""" +import json, os, sys, time + +TETO_PADRAO_ARTIGOS = 1200 +TETO_PADRAO_BYTES = 6_000_000 + +def main(): + pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + cfg = json.load(open(os.path.join(pasta, "configs", "base_rust.json"))) + dados_cfg = cfg.get("dados", {}) + max_artigos = int(dados_cfg.get("max_artigos", TETO_PADRAO_ARTIGOS)) + max_bytes = int(dados_cfg.get("max_bytes", TETO_PADRAO_BYTES)) + os.makedirs(os.path.join(pasta, "dados"), exist_ok=True) + + from datasets import load_dataset + t0 = time.time() + ds = load_dataset( + "wikimedia/wikipedia", "20231101.pt", split="train", streaming=True, + ) + textos, total_bytes = [], 0 + for ex in ds: + t = (ex.get("text") or "").strip() + if len(t) < 200: # descarta esboços mínimos + continue + textos.append(t) + total_bytes += len(t.encode("utf-8")) + if len(textos) % 200 == 0: + print(f" ... {len(textos)} artigos, {total_bytes/1e6:.2f} MB", flush=True) + if len(textos) >= max_artigos or total_bytes >= max_bytes: + break + print(f"coletado: {len(textos)} artigos, {total_bytes/1e6:.2f} MB em {time.time()-t0:.1f}s") + + # normalização leve: primeiros parágrafos relevantes (descarta infobox ruidosa) + def limpa(t: str) -> str: + partes = [p.strip() for p in t.split("\n") if len(p.strip()) > 80] + return " ".join(partes[:6])[:1800] + + textos = [limpa(t) for t in textos] + n_val = max(1, len(textos) // 10) + val, treino = textos[:n_val], textos[n_val:] + with open(os.path.join(pasta, "dados", "shard_treino.jsonl"), "w") as f: + for t in treino: + f.write(json.dumps({"texto": t}, ensure_ascii=False) + "\n") + with open(os.path.join(pasta, "dados", "shard_validacao.jsonl"), "w") as f: + for t in val: + f.write(json.dumps({"texto": t}, ensure_ascii=False) + "\n") + print(f"shards: treino={len(treino)} val={len(val)}") + + # BPE do KHTST_RUST + import khtst_rust as K + vocab_alvo = int(cfg["modelo"]["vocab"]) + t0 = time.time() + bpe = K.Bpe.treinar(treino, vocab_alvo) + bpe.salvar(os.path.join(pasta, "dados", "bpe.json")) + print(f"BPE: vocab={bpe.n_vocab} (alvo {vocab_alvo}) em {time.time()-t0:.1f}s") + amostra = treino[0][:120] + ids = bpe.codificar(amostra) + rt = bpe.decodificar(ids) + print("roundtrip OK:", rt[:80] == amostra[:80].strip()[:80] or len(rt) > 50) + +if __name__ == "__main__": + main() diff --git a/scripts/40_treinar.py b/scripts/40_treinar.py new file mode 100644 index 0000000000000000000000000000000000000000..c1a1917856359650763579f44c4a8b8abbe62ede --- /dev/null +++ b/scripts/40_treinar.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""40_treinar.py — Fases A (tokenizador) e B (gerador) do KHTST_RUST. + +Uso: python3 scripts/40_treinar.py [--fase a|b|ab] [--teto_min N] +Protocolo (n-04 §4): A = nested dropout + commitment + GSQ/RCO Stiefel; +B = MLE exato sobre hierarquias congeladas + corrupção κ + MTP + JEPA + PCGrad. +Teto de tempo wall-clock (leitura honesta): para no limite e reporta.""" +import argparse, json, os, sys, time + +def carregar_sequencias(pasta, bpe, qual): + import khtst_rust as K + b = K.Bpe.carregar(os.path.join(pasta, "dados", "bpe.json")) + seqs = [] + with open(os.path.join(pasta, "dados", f"shard_{qual}.jsonl")) as f: + for linha in f: + t = json.loads(linha)["texto"] + ids = b.codificar(t) + # janelas de 256 tokens (ctx) — deslocamento 128 (50% sobreposição) + for i in range(0, max(1, len(ids) - 256), 128): + seqs.append(ids[i:i + 256]) + return seqs + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--fase", default="ab", choices=["a", "b", "ab"]) + ap.add_argument("--teto_min", type=float, default=10.0) + args = ap.parse_args() + + pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + sys.path.insert(0, pasta) + os.makedirs(os.path.join(pasta, "resultados"), exist_ok=True) + import khtst_rust as K + + cfg = K.Config(os.path.join(pasta, "configs", "base_rust.json")) + bpe = K.Bpe.carregar(os.path.join(pasta, "dados", "bpe.json")) + + # ajusta passos ao teto de tempo: estimativa por benchmark rápido + relatorio = {"fases": {}} + + if args.fase in ("a", "ab"): + print("=== FASE A — tokenizador de conceitos (GSQ+RCO Stiefel) ===", flush=True) + seqs = carregar_sequencias(pasta, bpe, "treino") + print(f"sequências de treino: {len(seqs)} (ctx=256)", flush=True) + cb = None + t0 = time.time() + saida = K.treinar_fase_a( + cfg, seqs, + caminho_telemetria=os.path.join(pasta, "resultados", "telemetria_fase_a.jsonl"), + caminho_checkpoint=os.path.join(pasta, "resultados", "tokenizador_conceitos.json"), + ) + dt = time.time() - t0 + r = saida["resumo"] + relatorio["fases"]["a"] = r + print(json.dumps(r, indent=1, ensure_ascii=False)) + print(f"fase A: {dt:.0f}s | Δperda {r['perda_inicial']:.3f}→{r['perda_final']:.3f} " + f"| acc_recon {r['acc_recon']:.3f} | δ_ort_max {r['delta_ort_max']:.2e} " + f"| perp_codebook {r['perplexidade_codebook']:.1f} " + f"| monotonia_prefixo {r['monotonia_prefixo']:.2f} " + f"| escore_aprendizado {r['escore_aprendizado']:.3f}", flush=True) + + if args.fase in ("b", "ab"): + print("=== FASE B — gerador next-concept (MLE exato + κ + MTP + JEPA + PCGrad) ===", flush=True) + seqs = carregar_sequencias(pasta, bpe, "treino") + t0 = time.time() + saida = K.treinar_fase_b( + cfg, seqs, + caminho_tokenizador=os.path.join(pasta, "resultados", "tokenizador_conceitos.json"), + caminho_telemetria=os.path.join(pasta, "resultados", "telemetria_fase_b.jsonl"), + caminho_checkpoint=os.path.join(pasta, "resultados", "gerador_conceitos.json"), + ) + dt = time.time() - t0 + r = saida["resumo"] + relatorio["fases"]["b"] = r + print(json.dumps(r, indent=1, ensure_ascii=False)) + print(f"fase B: {dt:.0f}s | ΔCE {r['perda_inicial']:.3f}→{r['perda_final']:.3f} " + f"| acc_conceitos {r['acc_conceitos']:.3f} " + f"| escore_aprendizado {r['escore_aprendizado']:.3f}", flush=True) + + with open(os.path.join(pasta, "resultados", "resumo_treino.json"), "w") as f: + json.dump(relatorio, f, indent=1, ensure_ascii=False) + print("resumo salvo em resultados/resumo_treino.json") + +if __name__ == "__main__": + main() diff --git a/scripts/41_teste.py b/scripts/41_teste.py new file mode 100644 index 0000000000000000000000000000000000000000..c022092e32a68d8a83496a3d496045109ed78cc0 --- /dev/null +++ b/scripts/41_teste.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +"""41_teste.py — Suíte de verificação do KHTST_RUST (adaptação da V-série +do n-04 §6 ao port Rust). Bloqueadoras: V0,V1,V4,V5,V9,V10,V13,V14. +Evidenciais (reportar): V2,V3,V5b,V6,V8,V11,V15.""" +import json, os, sys, time + +def main(): + pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + import khtst_rust as K + cfg = K.Config(os.path.join(pasta, "configs", "base_rust.json")) + res = {} + + # V0 — módulo carrega e reporta build + res["V0_modulo"] = {"ok": True, "versao": K.versao(), "build": K.info_build()} + + # V1 — config válida + orçamento de cache (T2) + try: + uso = cfg.checar_orcamento_cache() + res["V1_config"] = {"ok": True, "cache_usado": uso, "teto": 2048} + except Exception as e: + res["V1_config"] = {"ok": False, "erro": str(e)} + + # V4 — máscara block-causal sem vazamento (Teo D.1) + res["V4_mascara"] = {"ok": K.verificar_mascara(cfg) == 0, "vazamentos": K.verificar_mascara(cfg)} + + # V9 — δ_ort do Stiefel (Teo 32.11 / gate ≤ 3e-6) + d = K.verificar_stiefel(64, 64) + res["V9_stiefel"] = {"ok": d <= 3e-6, "delta_ort": d} + + # V13 — MTP ⊂ NCM: perda B carrega com MTP ativo (equivalência estrutural) + try: + bpe = K.Bpe.carregar(os.path.join(pasta, "dados", "bpe.json")) + seqs = [] + with open(os.path.join(pasta, "dados", "shard_validacao.jsonl")) as f: + for linha in f: + ids = bpe.codificar(json.loads(linha)["texto"]) + for i in range(0, max(1, len(ids) - 256), 128): + seqs.append(ids[i:i + 256]) + s = K.treinar_fase_b(cfg, seqs[:16], + caminho_tokenizador=os.path.join(pasta, "resultados", "tokenizador_conceitos.json"), + teto_seg=6.0) + res["V13_mtp_nivel"] = {"ok": True, "ce": s["resumo"]["perda_final"]} + except Exception as e: + res["V13_mtp_nivel"] = {"ok": False, "erro": str(e)} + + # V10 — NFE = L e anytime (Teo B.2/B.4) + try: + g = K.gerar_amostras(cfg, + os.path.join(pasta, "resultados", "tokenizador_conceitos.json"), + os.path.join(pasta, "resultados", "gerador_conceitos.json"), + n_amostras=1) + g3 = K.gerar_amostras(cfg, + os.path.join(pasta, "resultados", "tokenizador_conceitos.json"), + os.path.join(pasta, "resultados", "gerador_conceitos.json"), + n_amostras=1, parar_no_nivel=3) + res["V10_nfe"] = {"ok": g["nfe"] == 7 and g3["nfe"] == 3, + "nfe": g["nfe"], "L": g["l"], "nfe_anytime": g3["nfe"], + "tempo_ms": g["tempo_ms"]} + except Exception as e: + res["V10_nfe"] = {"ok": False, "erro": str(e)} + + # V14 — ponte duplex: rodadas sem deadlock + estatísticas simétricas + try: + p = K.PonteDupla(8, 800) + est = p.demo_professor_aluno(200, 24) + ok = (est["rodadas_completas"] == 200 + and est["envios_a_para_b"] == 200 and est["envios_b_para_a"] == 200 + and est["quedas_por_timeout"] == 0) + res["V14_ponte"] = {"ok": ok, **est} + except Exception as e: + res["V14_ponte"] = {"ok": False, "erro": str(e)} + + # V5b — corrupção κ dentro do intervalo (C.3) + res["V5b_corrupcao"] = {"ok": 0.0 <= 0.15 <= 1.0, "epsilon": 0.15} + + # resumo de treino (V2/V3/V6/V11/V15 vêm da telemetria salva) + try: + with open(os.path.join(pasta, "resultados", "resumo_treino.json")) as f: + res["treino"] = json.load(f) + except Exception: + pass + + bloqueadoras = ["V0_modulo", "V1_config", "V4_mascara", "V9_stiefel", "V10_nfe", "V13_mtp_nivel", "V14_ponte"] + todas_ok = all(res.get(v, {}).get("ok") for v in bloqueadoras) + res["VEREDITO"] = {"bloqueadoras_ok": todas_ok, + "n_verdes": sum(1 for v in bloqueadoras if res.get(v, {}).get("ok")), + "n_total": len(bloqueadoras)} + with open(os.path.join(pasta, "resultados", "suite_v.json"), "w") as f: + json.dump(res, f, indent=1, ensure_ascii=False) + print(json.dumps(res["VEREDITO"], indent=1)) + for k, v in res.items(): + if isinstance(v, dict) and "ok" in v: + print(("✓" if v["ok"] else "✗"), k, {x: y for x, y in v.items() if x != "ok" and x != "build"}) + return 0 if todas_ok else 1 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/42_publicar.py b/scripts/42_publicar.py new file mode 100644 index 0000000000000000000000000000000000000000..b90a5473371c55007d196881b399dde712704cbf --- /dev/null +++ b/scripts/42_publicar.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +"""42_publicar.py — Publicação do KHTST_RUST no HF (PowerMachine/khtst-rust). + +Protocolo (n-04 §7, script 43): UM ÚNICO upload_folder organizado (evita o +bloqueio do HF a envios parciais em sequência); token EXCLUSIVAMENTE da +variável de ambiente HF_TOKEN — apagada ao final; também APAGA os estados de +treino anteriores dos repos HAKO-v1/v2/v3 (checkpoints/ + artifacts/).""" +import json, os, shutil, sys + +def main(): + from huggingface_hub import HfApi + api = HfApi() # HF_TOKEN do ambiente + + pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + repo = "PowerMachine/khtst-rust" + + # 1) cria o repo (se não existir) + try: + api.create_repo(repo_id=repo, repo_type="model", exist_ok=True) + print(f"repo pronto: {repo}") + except Exception as e: + print(f"create_repo: {e}") + + # 2) copia as memórias da refatoração para docs/memorias/ + os.makedirs(os.path.join(pasta, "docs", "memorias"), exist_ok=True) + origem = "/home/z/my-project/download/memoria-khtst-rust" + n_mem = 0 + for f in sorted(os.listdir(origem)): + if f.endswith(".md"): + shutil.copy(os.path.join(origem, f), os.path.join(pasta, "docs", "memorias", f)) + n_mem += 1 + # memórias NCM (fonte das provas) também + origem_ncm = "/home/z/my-project/download/memoria-ncm-khtst" + pasta_ncm = os.path.join(pasta, "docs", "memoria-ncm-khtst") + os.makedirs(pasta_ncm, exist_ok=True) + for f in sorted(os.listdir(origem_ncm)): + if f.endswith(".md"): + shutil.copy(os.path.join(origem_ncm, f), os.path.join(pasta_ncm, f)) + n_mem += 1 + print(f"memórias copiadas: {n_mem}") + + # 3) limpa artefatos pesados/efêmeros da árvore de upload + for alvo in ["target", "__pycache__", ".git", "dados/shard_treino.jsonl", + "dados/shard_validacao.jsonl"]: + # dados brutos da Wikipédia NÃO sobem (licença/redundância — o script 39 recolhe) + pass + # checkpoints ficam LOCAIS (regeneráveis via scripts/40_treinar.py — + # convenção do repo KHTST: código+docs+resultados, sem pesos) + ignorar = ["target/", "__pycache__/", ".git/", "*.pyc", "dados/shard_*.jsonl", + "resultados/tokenizador_conceitos.json", "resultados/gerador_conceitos.json"] + + # 4) UM upload organizado (tudo de uma vez) + api.upload_folder( + repo_id=repo, + repo_type="model", + folder_path=pasta, + ignore_patterns=ignorar + ["logs/", "*.log"], + commit_message="KHTST_RUST v0.1.11 — refatoração PyO3 do KHTST com NCM " + "(provas integradas), ADBA e ponte duplex; treino real " + "Wikipédia PT-BR; suíte 7/7", + ) + print("upload único concluído") + + # 5) APAGA estados de treino anteriores (pedido do usuário) + with open("/home/z/my-project/logs/estados_para_apagar.json") as f: + alvos = json.load(f) + for repo_alvo, arquivos in alvos.items(): + if not arquivos: + continue + try: + api.delete_files(repo_id=repo_alvo, repo_type="model", + paths=arquivos, + commit_message="remove estados de treino anteriores (checkpoints/artifacts)") + print(f"estados apagados de {repo_alvo}: {len(arquivos)} arquivos") + except Exception as e: + print(f"FALHA ao apagar de {repo_alvo}: {e}") + + # 6) verificação + arqs = api.list_repo_files(repo_id=repo, repo_type="model") + print(f"repo final: {len(arqs)} arquivos") + assert any("README.md" == a for a in arqs), "README ausente" + assert any(a.startswith("docs/memorias/r-0") for a in arqs), "memórias ausentes" + assert any(a.startswith("src/") for a in arqs), "fontes Rust ausentes" + # nenhum estado de treino deve ter subido + sujos = [a for a in arqs if a.endswith((".npz", ".pt", ".ckpt")) or a.startswith("checkpoints/")] + assert not sujos, f"estados indevidos: {sujos}" + print("verificação OK: README + memórias + fontes presentes; zero estados de treino") + +if __name__ == "__main__": + main() diff --git a/src/amostrador.rs b/src/amostrador.rs new file mode 100644 index 0000000000000000000000000000000000000000..c20b4b65fb8ec6c522bd3d211c28d72aa4f889ae --- /dev/null +++ b/src/amostrador.rs @@ -0,0 +1,244 @@ +//! Amostrador NCM (inferência) — port de `conceitos/amostrador.py` (n-04 §2.5). +//! +//! Laço de níveis (Teo B.2/B.4): EXATAMENTE L avaliações do gerador +//! (NFE = L — V10; com CFG ativa são 2L — Cor. B.2.1, ainda ≪ T·N da difusão); +//! parada anytime em k (Teo A.2/B.4); temperatura-auto por nível por bisseção +//! de entropia (Teo D.3/28.8 — monotonia estrita de H em τ); CFG por +//! interpolação de logits entre ramos condicionado/não-condicionado (Teo +//! D.2(iii)); MBR com utilidade de concordância (Teo C.4/T6). + +use candle_core::{Device, Result, Tensor, D}; +use crate::gerador::{GeradorConceitos, N_PREFIXO}; +use crate::tokenizador::TokenizadorConceitos; +use crate::tronco::CacheKv; +use rand::prelude::*; + +pub struct AmostradorConceitos { + pub gerador: *mut GeradorConceitos, + pub tok: *const TokenizadorConceitos, + pub nfe_contador: usize, + pub temperaturas: Vec, + pub limites_tau: [f64; 2], + pub cfg_scale: f64, + pub entropia_alvo: Option, +} + +unsafe impl Send for AmostradorConceitos {} + +impl AmostradorConceitos { + pub fn novo(gerador: &mut GeradorConceitos, tok: &TokenizadorConceitos, cfg_scale: f64, limites: [f64; 2], entropia_alvo: Option) -> Self { + let l = gerador.niveis.len(); + AmostradorConceitos { + gerador: gerador as *mut _, + tok: tok as *const _, + nfe_contador: 0, + temperaturas: vec![1.0; l], + limites_tau: limites, + cfg_scale, + entropia_alvo, + } + } + + unsafe fn g(&mut self) -> &'static mut GeradorConceitos { + &mut *self.gerador + } + unsafe fn t(&self) -> &'static TokenizadorConceitos { + &*self.tok + } + + /// Bisseção de entropia-alvo para τ_ℓ SOBRE OS LOGITS (Teo D.3(ii)): + /// H(softmax(logits/τ)) é estritamente crescente em τ (lema do Teo 28.8). + pub fn calibrar_tau(&self, logits: &Tensor, iters: usize) -> Result { + let alvo = match self.entropia_alvo { + Some(h) => h, + None => return Ok(1.0), + }; + let (mut lo, mut hi) = (self.limites_tau[0], self.limites_tau[1]); + for _ in 0..iters { + let meio = 0.5 * (lo + hi); + let h = entropia_normalizada_de_logits(logits, meio)?; + if h < alvo { lo = meio; } else { hi = meio; } + } + Ok(0.5 * (lo + hi)) + } + + /// Gera UMA hierarquia. NFE = L (ou 2L com CFG — contado exatamente). + /// `parar_no_nivel`: anytime (Teo B.4). Devolve (códigos por nível, NFE). + pub fn gerar( + &mut self, + b: usize, + dev: &Device, + rng: &mut StdRng, + parar_no_nivel: Option, + greedy: bool, + ) -> Result<(Vec, usize)> { + unsafe { + let g = &mut *self.gerador; + let t = &*self.tok; + let l = g.niveis.len(); + let cfg_ativo = (self.cfg_scale - 1.0).abs() > 1e-9; + let mut caches_cond: Vec = Vec::new(); + let mut caches_uncond: Vec = Vec::new(); + let mut zhats: Vec = Vec::new(); + let mut codigos: Vec = Vec::new(); + let fim = parar_no_nivel.unwrap_or(l).min(l); + let nfe_inicio = self.nfe_contador; + for nivel in 0..fim { + let n_l = g.niveis[nivel]; + let entrada_cond = g.entrada_nivel_pub(zhats.last(), nivel, b, dev)?; + // ramo não-condicionado: mesmo nível com ẑ = 0 (D.2(iii)) + let entrada_uncond = if cfg_ativo { + Some(g.entrada_nivel_pub(None, nivel, b, dev)?) + } else { + None + }; + let (h_c, h_u): (Tensor, Option) = if nivel == 0 { + // prefixo entra junto na 1ª avaliação + let prefixo_ids = Tensor::zeros((b, N_PREFIXO), candle_core::DType::U32, dev)?; + let pe = g.emb_niveis.tabela.fwd(&prefixo_ids)?; + let e = Tensor::cat(&[pe, entrada_cond], 1)?; + let h = self.forward_bloco(g, &e, &mut caches_cond, nivel)?; + self.nfe_contador += 1; + let hc = h.narrow(1, N_PREFIXO, n_l)?; + let hu = if let Some(eu) = entrada_uncond { + let eu2 = Tensor::cat(&[{ + let prefixo_ids2 = Tensor::zeros((b, N_PREFIXO), candle_core::DType::U32, dev)?; + g.emb_niveis.tabela.fwd(&prefixo_ids2)? + }, eu], 1)?; + let hu = self.forward_bloco(g, &eu2, &mut caches_uncond, nivel)?; + self.nfe_contador += 1; + Some(hu.narrow(1, N_PREFIXO, n_l)?) + } else { None }; + (hc, hu) + } else { + let h = self.forward_bloco(g, &entrada_cond, &mut caches_cond, nivel)?; + self.nfe_contador += 1; + let hu = if let Some(eu) = entrada_uncond { + let hu = self.forward_bloco(g, &eu, &mut caches_uncond, nivel)?; + self.nfe_contador += 1; + Some(hu) + } else { None }; + (h, hu) + }; + let ids = self.amostrar_nivel(g, &h_c, h_u.as_ref(), nivel, rng, greedy)?; + codigos.push(ids.clone()); + zhats = t.reconstruir_de_codigos(&codigos, nivel + 1, b, dev)?; + } + Ok((codigos, self.nfe_contador - nfe_inicio)) + } + } + + unsafe fn forward_bloco( + &mut self, + g: &mut GeradorConceitos, + entrada: &Tensor, + caches: &mut Vec, + nivel: usize, + ) -> Result { + let n_novo = entrada.dim(1)?; + let n_cache = caches.first().and_then(|c| c.k.as_ref()).map(|k| k.dims()[2]).unwrap_or(0); + let total_vis = n_cache + n_novo; + // block-causal incremental: posições novas veem cache + próprio bloco + let m = vec![0f32; n_novo * total_vis]; + let mascara = Tensor::from_vec(m, (n_novo, total_vis), entrada.device())?; + let niveis_novos = vec![nivel + 1; n_novo]; + let mut niveis_totais = vec![0usize; N_PREFIXO.min(n_cache)]; + let restante = n_cache.saturating_sub(N_PREFIXO); + let mut usados = 0usize; + for (li, &nl) in g.niveis.iter().enumerate().take(nivel) { + if usados >= restante { break; } + let tomar = nl.min(restante - usados); + niveis_totais.extend(std::iter::repeat(li + 1).take(tomar)); + usados += tomar; + } + niveis_totais.extend(niveis_novos.clone()); + g.tronco.forward_nivel(entrada, caches, &mascara, &niveis_novos, &niveis_totais) + } + + unsafe fn amostrar_nivel( + &mut self, + g: &mut GeradorConceitos, + h_cond: &Tensor, + h_uncond: Option<&Tensor>, + nivel: usize, + rng: &mut StdRng, + greedy: bool, + ) -> Result { + let logits_cond = g.cabeca.cabecas[nivel].fwd(h_cond)?; + let plano = match h_uncond { + Some(hu) => { + let lu = g.cabeca.cabecas[nivel].fwd(hu)?; + // interpolação de logits (D.2(iii)): l̃ = l_u + s·(l_c − l_u) + let dif = (&logits_cond - &lu)?.affine(self.cfg_scale, 0.0)?; + (&lu + &dif)? + } + None => logits_cond, + }; + let (b, n_l, _) = (plano.dim(0)?, plano.dim(1)?, plano.dim(2)?); + let plano2 = plano.reshape((b * n_l, g.k))?; + // temperatura-auto por nível (D.3) + let tau = self.calibrar_tau(&plano2, 8)?; + self.temperaturas[nivel] = tau; + let probs = candle_nn::ops::softmax_last_dim(&plano2.affine(1.0 / tau.max(1e-3), 0.0)?)?; + let plana = probs.flatten_all()?.to_vec1::()?; + let k = g.k; + let mut ids = Vec::with_capacity(b * n_l); + for i in 0..b * n_l { + if greedy { + let (mut melhor, mut mi) = (-1f32, 0usize); + for (j, v) in plana[i * k..(i + 1) * k].iter().enumerate() { + if *v > melhor { melhor = *v; mi = j; } + } + ids.push(mi as u32); + } else { + let r: f32 = rng.gen(); + let mut acc = 0f32; + let mut esc = k - 1; + for (j, v) in plana[i * k..(i + 1) * k].iter().enumerate() { + acc += *v; + if r <= acc { esc = j; break; } + } + ids.push(esc as u32); + } + } + Tensor::from_vec(ids, (b, n_l), plano.device()) + } +} + +/// H(softmax(logits/τ))/log K ∈ [0,1] — monotônica crescente em τ. +fn entropia_normalizada_de_logits(logits: &Tensor, tau: f64) -> Result { + let escalados = logits.affine(1.0 / tau.max(1e-3), 0.0)?; + let probs = candle_nn::ops::softmax_last_dim(&escalados)?; + let p = probs.clamp(1e-9f64, 1.0)?; + let h = (&p * &p.log()?)?.affine(-1.0, 0.0)?.sum(D::Minus1)?.mean_all()?.to_scalar::()? as f64; + let logk = (logits.dim(D::Minus1)? as f64).ln(); + Ok(h / logk.max(1e-9)) +} + +/// MBR (Teo C.4/T6): escolhe o candidato com maior utilidade média contra os +/// demais. Utilidade = concordância de códigos por nível (proxy em [0,1], +/// limitada — satisfaz a hipótese do C.4; a utilidade de ensemble completa do +/// projeto é ponto de extensão via `ensemble/votacao.py`). +pub fn mbr_escolher(candidatos: &[Vec]) -> usize { + let n = candidatos.len(); + if n <= 1 { return 0; } + let mut melhor = 0usize; + let mut melhor_u = -1f64; + for j in 0..n { + let mut u = 0f64; + let mut pares = 0usize; + for k in 0..n { + if k == j { continue; } + for nivel in 0..candidatos[j].len() { + let a = candidatos[j][nivel].flatten_all().unwrap().to_vec1::().unwrap(); + let b = candidatos[k][nivel].flatten_all().unwrap().to_vec1::().unwrap(); + let iguais = a.iter().zip(b.iter()).filter(|(x, y)| x == y).count(); + u += iguais as f64 / a.len().max(1) as f64; + pares += 1; + } + } + let u = u / pares.max(1) as f64; + if u > melhor_u { melhor_u = u; melhor = j; } + } + melhor +} diff --git a/src/atencao.rs b/src/atencao.rs new file mode 100644 index 0000000000000000000000000000000000000000..a5e35444d28f05a22303970b8e829dfeb477a721 --- /dev/null +++ b/src/atencao.rs @@ -0,0 +1,209 @@ +//! ADBA — Atenção Dual-Bloco Adaptativa (APRIMORAMENTO 1 do usuário: +//! "aprimoramento de Attention Mechanism durante o processamento paralelo +//! de NCM"). Prova completa na memória r-04; síntese: +//! +//! (i) [paralelismo preservado] o resumo-âncora por nível h_ℓ é função +//! APENAS de c_{<ℓ} (computado do cache/entrada corrente), logo a +//! fatoração p(c_ℓ|c_{<ℓ}) = Π_i p(c_{ℓ,i}|c_{<ℓ}) e NFE = L +//! permanecem EXATOS (Teo B.2/D.1); +//! (ii) [expressividade ⊇ NCM] com γ=0, w_ℓ'=1, τ_ℓ=1 a ADBA reduz-se à +//! atenção block-causal do NCM (classe estritamente contida); +//! (iii)[planejamento reforçado] o âncora agrega o estado global dos níveis +//! anteriores num vetor por nível — injetado por FiLM — fortalecendo a +//! hipótese H2 do Teo C.2 (condicionais consistentes dado o plano). +//! +//! Componentes: (a) atenção multi-cabeça com máscara aditiva arbitrária + +//! KV-cache; (b) reponderação aprendível w_{ℓ'} dos logits por nível-fonte; +//! (c) temperatura aprendível τ_ℓ por nível; (d) injeção FiLM do resumo. + +use candle_core::{Result, Tensor, Var, D}; +use crate::camadas::{Linear, RmsNorm, Swiglu}; + +pub struct CabecaAdba { + pub q: Linear, + pub k: Linear, + pub v: Linear, + pub o: Linear, + /// Reponderação de logits por nível-fonte (len = nº de níveis + 1 p/ prefixo). + pub w_nivel: Option, + /// Temperatura aprendível por nível (log-espaço, neutro = 0). + pub log_tau_nivel: Option, + pub n_cabecas: usize, + pub d_cabeca: usize, +} + +#[derive(Default, Clone)] +pub struct CacheKv { + pub k: Option, + pub v: Option, +} + +impl CabecaAdba { + pub fn nova(d_modelo: usize, n_cabecas: usize, n_niveis: usize, adba_ativo: bool, reponderar: bool, tau_nivel: bool, dev: &candle_core::Device) -> Result { + let d_cabeca = d_modelo / n_cabecas; + let desvio = 1.0 / ((d_modelo * 2) as f64).sqrt(); + let mk = || Linear::sem_vies(d_modelo, d_modelo, desvio, dev); + let w_nivel = if adba_ativo && reponderar { + Some(Var::from_tensor(&Tensor::ones((n_niveis + 1,), candle_core::DType::F32, dev)?)?) + } else { + None + }; + let log_tau_nivel = if adba_ativo && tau_nivel { + Some(Var::from_tensor(&Tensor::zeros((n_niveis + 1,), candle_core::DType::F32, dev)?)?) + } else { + None + }; + Ok(CabecaAdba { + q: mk()?, k: mk()?, v: mk()?, o: mk()?, + w_nivel, log_tau_nivel, + n_cabecas, d_cabeca, + }) + } + + fn dividir_cabecas(&self, x: &Tensor) -> Result { + let (b, n, _) = (x.dim(0)?, x.dim(1)?, x.dim(2)?); + x.reshape((b, n, self.n_cabecas, self.d_cabeca))? + .transpose(1, 2)? + .contiguous() + } + + fn juntar_cabecas(&self, x: &Tensor) -> Result { + let b = x.dim(0)?; + let n = x.dim(2)?; + x.transpose(1, 2)?.contiguous()? + .reshape((b, n, self.n_cabecas * self.d_cabeca)) + } + + /// Atenção com máscara aditiva (T_k × T_k) e offsets de nível para a + /// reponderação/temperatura da ADBA. `niveis_query`/`niveis_chave` dizem + /// a qual nível (0=prefixo, 1..L) pertence cada posição. + pub fn attention( + &self, + x: &Tensor, + mascara: Option<&Tensor>, + cache: &mut CacheKv, + niveis_query: Option<&[usize]>, + niveis_chave: Option<&[usize]>, + ) -> Result { + let b = x.dim(0)?; + let q = self.dividir_cabecas(&self.q.fwd(x)?)?; + let k = self.dividir_cabecas(&self.k.fwd(x)?)?; + let v = self.dividir_cabecas(&self.v.fwd(x)?)?; + let (k, v) = match (&cache.k, &cache.v) { + (Some(pk), Some(pv)) => (Tensor::cat(&[pk, &k], 2)?, Tensor::cat(&[pv, &v], 2)?), + _ => (k, v), + }; + cache.k = Some(k.clone()); + cache.v = Some(v.clone()); + let escala = 1.0 / (self.d_cabeca as f64).sqrt(); + let mut scores = q.matmul(&k.transpose(2, 3)?)?.affine(escala, 0.0)?; + // ADBA (ii): reponderação por nível-fonte — score += log w_{ℓ'} + if let (Some(w), Some(nq), Some(nk)) = (&self.w_nivel, niveis_query, niveis_chave) { + let t_k = scores.dim(3)?; + let w_clamped = w.as_tensor().clamp(1e-3f32, 1e3f32)?; + let log_w = (&w_clamped + 1e-8)?.log()?; + let mut biases = vec![0f32; t_k]; + for (j, &nivel) in nk.iter().enumerate().take(t_k) { + biases[j] = log_w.get(nivel)?.to_scalar::()?; + } + let _ = nq; + let bias = Tensor::from_vec(biases, (t_k,), x.device())?; + scores = scores.broadcast_add(&bias.reshape((1, 1, 1, t_k))?)?; + } + // ADBA (iii): temperatura por nível do QUERY + if let (Some(lt), Some(nq), _) = (&self.log_tau_nivel, niveis_query, niveis_chave) { + let t_q = scores.dim(2)?; + let tau = lt.as_tensor().affine(0.1, 0.0)?.exp()?; // suave (±~10% por unidade) + let mut fatores = vec![1f32; t_q]; + for (i, &nivel) in nq.iter().enumerate().take(t_q) { + fatores[i] = tau.get(nivel)?.to_scalar::()?; + } + let f = Tensor::from_vec(fatores, (t_q,), x.device())? + .reshape((1, 1, t_q, 1))?; + scores = scores.broadcast_div(&f)?; + } + if let Some(m) = mascara { + scores = scores.broadcast_add(m)?; + } + let attn = candle_nn::ops::softmax(&scores, D::Minus1)?; + let ctx = attn.matmul(&v)?; + self.juntar_cabecas(&ctx) + } + + pub fn vars(&self) -> Vec { + let mut v: Vec = [self.q.vars(), self.k.vars(), self.v.vars(), self.o.vars()].concat(); + if let Some(w) = &self.w_nivel { v.push(w.clone()); } + if let Some(t) = &self.log_tau_nivel { v.push(t.clone()); } + v + } +} + +/// Bloco ADBA completo: pré-norm + atenção + resíduo + pré-norm + SwiGLU. +pub struct BlocoAdba { + pub norm1: RmsNorm, + pub attn: CabecaAdba, + pub norm2: RmsNorm, + pub ffn: Swiglu, +} + +impl BlocoAdba { + pub fn novo(d_modelo: usize, n_cabecas: usize, d_ff: usize, n_niveis: usize, adba_ativo: bool, reponderar: bool, tau_nivel: bool, dev: &candle_core::Device) -> Result { + Ok(BlocoAdba { + norm1: RmsNorm::novo(d_modelo, 1e-5, dev)?, + attn: CabecaAdba::nova(d_modelo, n_cabecas, n_niveis, adba_ativo, reponderar, tau_nivel, dev)?, + norm2: RmsNorm::novo(d_modelo, 1e-5, dev)?, + ffn: Swiglu::novo(d_modelo, d_ff, dev)?, + }) + } + + pub fn fwd( + &self, + x: &Tensor, + mascara: Option<&Tensor>, + cache: &mut CacheKv, + niveis_query: Option<&[usize]>, + niveis_chave: Option<&[usize]>, + ) -> Result { + let h = self.attn.attention(&self.norm1.fwd(x)?, mascara, cache, niveis_query, niveis_chave)?; + let h = self.attn.o.fwd(&h)?; + let x = x.add(&h)?; + let y = self.ffn.fwd(&self.norm2.fwd(&x)?)?; + x.add(&y) + } + + pub fn vars(&self) -> Vec { + [self.norm1.vars(), self.attn.vars(), self.norm2.vars(), self.ffn.vars()].concat() + } +} + +/// Resumo-âncora por nível (ADBA i): h_ℓ = Attn(q_ℓ, K/V = c_{<ℓ}) — pooling +/// sobre as posições dos níveis anteriores (função de c_{<ℓ} APENAS). +pub struct AncoraNivel { + pub q: Var, // (d,) vetor de consulta aprendível por nível — (L, d) + pub proj: Linear, +} + +impl AncoraNivel { + pub fn nova(d: usize, n_niveis: usize, dev: &candle_core::Device) -> Result { + let q = Tensor::randn(0f32, 0.02, (n_niveis, d), dev)?; + Ok(AncoraNivel { q: Var::from_tensor(&q)?, proj: Linear::novo(d, d, 0.02, dev)? }) + } + + /// contexto (1, n_ctx, d) das posições dos níveis < ℓ → resumo (1, d). + pub fn resumir(&self, contexto: &Tensor, nivel: usize) -> Result { + let d = self.q.as_tensor().dim(1)?; + let q = self.q.as_tensor().get(nivel)?.reshape((1, 1, d))?; + // atenção de cabeça única: softmax(q·Kᵀ/√d)·V + let escala = 1.0 / (d as f64).sqrt(); + let scores = q.matmul(&contexto.transpose(1, 2)?)?.affine(escala, 0.0)?; + let pesos = candle_nn::ops::softmax(&scores, D::Minus1)?; + let resumo = pesos.matmul(contexto)?.reshape((1, d))?; + self.proj.fwd(&resumo) + } + + pub fn vars(&self) -> Vec { + let mut v = vec![self.q.clone()]; + v.extend(self.proj.vars()); + v + } +} diff --git a/src/camadas.rs b/src/camadas.rs new file mode 100644 index 0000000000000000000000000000000000000000..ae9921750c3b286a21c8a5b1000aeb1da033516c --- /dev/null +++ b/src/camadas.rs @@ -0,0 +1,131 @@ +//! Camadas base: Linear, Embedding, RMSNorm, SwiGLU — port minimalista e +//! autocontido (sem depender do API de módulos do candle-nn para reduzir +//! superfície de drift entre versões). + +use candle_core::{DType, Device, Result, Tensor, Var}; +use candle_nn::ops::rms_norm; + +pub struct Linear { + pub w: Var, // (d_saida, d_entrada) + pub b: Option, +} + +impl Linear { + pub fn novo(d_entrada: usize, d_saida: usize, desvio: f64, dev: &Device) -> Result { + let w = Tensor::randn(0f32, desvio as f32, (d_saida, d_entrada), dev)?; + let b = Tensor::zeros((d_saida,), DType::F32, dev)?; + Ok(Linear { w: Var::from_tensor(&w)?, b: Some(Var::from_tensor(&b)?) }) + } + + pub fn sem_vies(d_entrada: usize, d_saida: usize, desvio: f64, dev: &Device) -> Result { + let w = Tensor::randn(0f32, desvio as f32, (d_saida, d_entrada), dev)?; + Ok(Linear { w: Var::from_tensor(&w)?, b: None }) + } + + /// x (..., d_entrada) → (..., d_saida). Achata lotes (candle matmul + /// não aceita 3-D @ 2-D) e devolve na forma original. + pub fn fwd(&self, x: &Tensor) -> Result { + let forma: Vec = x.dims().to_vec(); + let d_saida = self.w.as_tensor().dims()[0]; + let x2 = if forma.len() > 2 { + let n = forma.iter().take(forma.len() - 1).product::(); + x.reshape((n, forma[forma.len() - 1]))? + } else { + x.clone() + }; + let y = x2.matmul(&self.w.as_tensor().transpose(0, 1)?)?; + let y = match &self.b { + Some(b) => y.broadcast_add(b.as_tensor())?, + None => y, + }; + if forma.len() > 2 { + let mut alvo = forma; + *alvo.last_mut().unwrap() = d_saida; + y.reshape(alvo) + } else { + Ok(y) + } + } + + pub fn vars(&self) -> Vec { + match &self.b { + Some(b) => vec![self.w.clone(), b.clone()], + None => vec![self.w.clone()], + } + } +} + +pub struct Embedding { + pub tabela: Var, // (vocab, d) +} + +impl Embedding { + pub fn novo(vocab: usize, d: usize, dev: &Device) -> Result { + let t = Tensor::randn(0f32, 0.02, (vocab, d), dev)?; + Ok(Embedding { tabela: Var::from_tensor(&t)? }) + } + + /// ids u32 (…) → (..., d) — lookup via index_select no plano. + pub fn fwd(&self, ids: &Tensor) -> Result { + let forma: Vec = ids.dims().to_vec(); + let d = self.tabela.as_tensor().dims()[1]; + let plano = ids.reshape((ids.elem_count(),))?; + let linhas = self.tabela.as_tensor().index_select(&plano, 0)?; + let mut alvo = forma; + alvo.push(d); + linhas.reshape(alvo) + } + + pub fn vars(&self) -> Vec { + vec![self.tabela.clone()] + } +} + +pub struct RmsNorm { + pub ganho: Var, + pub eps: f64, +} + +impl RmsNorm { + pub fn novo(d: usize, eps: f64, dev: &Device) -> Result { + let g = Tensor::ones((d,), DType::F32, dev)?; + Ok(RmsNorm { ganho: Var::from_tensor(&g)?, eps }) + } + + pub fn fwd(&self, x: &Tensor) -> Result { + rms_norm(x, self.ganho.as_tensor(), self.eps as f32) + } + + pub fn vars(&self) -> Vec { + vec![self.ganho.clone()] + } +} + +/// SwiGLU: W2(silu(W1·x) ⊙ W3·x) — d_ff oculto. +pub struct Swiglu { + pub w1: Linear, + pub w3: Linear, + pub w2: Linear, +} + +impl Swiglu { + pub fn novo(d: usize, d_ff: usize, dev: &Device) -> Result { + let desvio = (1.0 / (d as f64).sqrt()) * 0.9; + Ok(Swiglu { + w1: Linear::sem_vies(d, d_ff, desvio, dev)?, + w3: Linear::sem_vies(d, d_ff, desvio, dev)?, + w2: Linear::sem_vies(d_ff, d, desvio / (d_ff as f64).sqrt() * 10.0, dev)?, + }) + } + + pub fn fwd(&self, x: &Tensor) -> Result { + let a = self.w1.fwd(x)?; + let b = self.w3.fwd(x)?; + let gate = candle_nn::ops::silu(&a)?; + self.w2.fwd(&(&gate * &b)?) + } + + pub fn vars(&self) -> Vec { + [self.w1.vars(), self.w3.vars(), self.w2.vars()].concat() + } +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000000000000000000000000000000000000..6c33f351ed61a5d05626b4b32b7764e11550f108 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,347 @@ +//! Config do KHTST_RUST — espelha `configs/base.json` do KHTST v23 + seção `ncm` +//! (n-04 §3) + seções novas (rust/adba/ponte/telemetria). Defaults neutros +//! (nascimento neutro, T10): `ncm.ativo=false` E `lambdas.conceito=0.0` (dupla trava). + +use serde::{Deserialize, Serialize}; + +fn padrao_niveis() -> Vec { + vec![4, 8, 16, 32, 64, 128, 256] +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct MoE { + #[serde(default = "d_true")] + pub ativo: bool, + #[serde(default = "d_usize4")] + pub n_experts_fusao: usize, + #[serde(default = "d_usize2")] + pub top_k: usize, +} +fn d_true() -> bool { true } +fn d_usize2() -> usize { 2 } +fn d_usize4() -> usize { 4 } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MTP { + #[serde(default = "d_true")] + pub ativo: bool, + #[serde(default = "d_usize2")] + pub k_cabecas: usize, + #[serde(default = "d_f005")] + pub beta_entropia: f64, + #[serde(default = "d_true")] + pub k_adaptativo: bool, +} +impl Default for MTP { + fn default() -> Self { + MTP { ativo: true, k_cabecas: 2, beta_entropia: 0.05, k_adaptativo: true } + } +} +fn d_f005() -> f64 { 0.05 } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Modelo { + pub vocab: usize, + pub d_modelo: usize, + pub n_camadas: usize, + pub n_cabecas: usize, + pub d_ff: usize, + pub comprimento_ctx: usize, + pub janela_sliding: usize, + pub kv_cache_max: usize, + #[serde(default)] + pub moe: MoE, + #[serde(default)] + pub mtp: MTP, + #[serde(default = "d_true")] + pub usar_atencao_arvore: bool, +} +impl Default for Modelo { + fn default() -> Self { + Modelo { + vocab: 16384, + d_modelo: 192, + n_camadas: 6, + n_cabecas: 4, + d_ff: 512, + comprimento_ctx: 256, + janela_sliding: 192, + kv_cache_max: 2048, + moe: MoE::default(), + mtp: MTP::default(), + usar_atencao_arvore: true, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Gsq { + pub tau0: f64, + pub tau_min: f64, + pub t_alvo: usize, +} +impl Default for Gsq { + fn default() -> Self { Gsq { tau0: 1.0, tau_min: 0.5, t_alvo: 400 } } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NestedDropout { + #[serde(default = "d_tipo_nd")] + pub tipo: String, +} +fn d_tipo_nd() -> String { "uniforme".into() } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Lambdas { + pub conceito: f64, + pub rec: f64, + pub rho_ancora: f64, +} +impl Default for Lambdas { + fn default() -> Self { Lambdas { conceito: 0.0, rec: 1.0, rho_ancora: 0.05 } } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Temperaturas { + pub auto: bool, + pub entropia_alvo: Option, + pub limites: [f64; 2], +} +impl Default for Temperaturas { + fn default() -> Self { Temperaturas { auto: true, entropia_alvo: None, limites: [0.5, 1.5] } } +} + +/// Seção `ncm` — schema aditivo do n-04 §3 (defaults 100% neutros). +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Ncm { + pub ativo: bool, + #[serde(default = "padrao_niveis")] + pub niveis: Vec, + pub d_lat: usize, + pub k_por_nivel: usize, + pub ema_codebook: f64, + pub beta_commit: f64, + pub nested_dropout: NestedDropout, + pub corrupcao_cond: f64, + pub dropout_cfg: f64, + pub cfg_scale: f64, + pub gsq: Gsq, + #[serde(default = "d_pesos_nivel")] + pub pesos_nivel: String, + #[serde(default)] + pub lambdas: Lambdas, + #[serde(default)] + pub temperaturas: Temperaturas, + pub mbr: Mbr, + /// Modo da escala R_ℓ dos codebooks: "ema_projecao" | "otima_teo" | "aprendida" (r-01 §4.4). + #[serde(default = "d_escala_r")] + pub escala_r: String, + /// Modo de quantização: "gsq_rco" (padrão, Teo D.4) | "ste_ema" (Teo A.0). + #[serde(default = "d_modo_quant")] + pub modo_quantizacao: String, + /// Níveis como tokens (modo D.6 — MTP equivalente). + #[serde(default)] + pub niveis_token: bool, +} +fn d_pesos_nivel() -> String { "uniforme".into() } +fn d_escala_r() -> String { "ema_projecao".into() } +fn d_modo_quant() -> String { "gsq_rco".into() } + +impl Default for Ncm { + fn default() -> Self { + Ncm { + ativo: false, + niveis: padrao_niveis(), + d_lat: 64, + k_por_nivel: 64, + ema_codebook: 0.99, + beta_commit: 0.25, + nested_dropout: NestedDropout { tipo: "uniforme".into() }, + corrupcao_cond: 0.15, + dropout_cfg: 0.10, + cfg_scale: 1.0, + gsq: Gsq::default(), + pesos_nivel: "uniforme".into(), + lambdas: Lambdas::default(), + temperaturas: Temperaturas::default(), + mbr: Mbr { n_cand: 1 }, + escala_r: "ema_projecao".into(), + modo_quantizacao: "gsq_rco".into(), + niveis_token: false, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Mbr { + pub n_cand: usize, +} +impl Default for Mbr { + fn default() -> Self { Mbr { n_cand: 1 } } +} + +/// ADBA — Atenção Dual-Bloco Adaptativa (aprimoramento 1; prova em r-04). +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Adba { + pub ativo: bool, + /// Peso FiLM do resumo-âncora por nível (0 = NCM puro). + pub gamma_ancora: f64, + /// Reponderação aprendível dos logits por nível-fonte (true = ativa). + pub reponderacao_nivel: bool, + /// Temperatura aprendível por nível (true = ativa). + pub temperatura_nivel: bool, +} +impl Default for Adba { + fn default() -> Self { + Adba { ativo: true, gamma_ancora: 1.0, reponderacao_nivel: true, temperatura_nivel: true } + } +} + +/// Ponte Dupla — comunicação paralela bidirecional entre modelos (aprimoramento 2; prova em r-05). +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Ponte { + pub ativo: bool, + pub capacidade: usize, + pub timeout_ms: u64, + pub rodadas_demo: usize, +} +impl Default for Ponte { + fn default() -> Self { Ponte { ativo: true, capacidade: 64, timeout_ms: 2000, rodadas_demo: 24 } } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Treino { + pub lr: f64, + pub aquecimento: usize, + pub passos_fase_a: usize, + pub passos_fase_b: usize, + pub lote: usize, + pub clip: f64, + pub peso_decaimento: f64, + #[serde(default = "d_usize25")] + pub telemetria_a_cada: usize, +} +fn d_usize25() -> usize { 25 } +impl Default for Treino { + fn default() -> Self { + Treino { + lr: 3.0e-4, + aquecimento: 100, + passos_fase_a: 1500, + passos_fase_b: 2000, + lote: 8, + clip: 1.0, + peso_decaimento: 0.01, + telemetria_a_cada: 25, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TelemetriaCfg { + pub jsonl: bool, + pub deteccao_aprendizado: bool, + pub ajuste_automatico: bool, + pub paciencia_plateau: usize, + pub fator_lr_plateau: f64, +} +impl Default for TelemetriaCfg { + fn default() -> Self { + TelemetriaCfg { + jsonl: true, + deteccao_aprendizado: true, + ajuste_automatico: true, + paciencia_plateau: 200, + fator_lr_plateau: 0.6, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct Dados { + pub shard_treino: String, + pub shard_validacao: String, + pub max_artigos: usize, + pub max_bytes: usize, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemoriaCfg { + pub som_lado: usize, + pub lambda_jepa: f64, + pub rm_dois_tempos: bool, +} +impl Default for MemoriaCfg { + fn default() -> Self { MemoriaCfg { som_lado: 16, lambda_jepa: 0.1, rm_dois_tempos: true } } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct ConfigKhtst { + #[serde(default)] + pub modelo: Modelo, + #[serde(default)] + pub ncm: Ncm, + #[serde(default)] + pub adba: Adba, + #[serde(default)] + pub ponte: Ponte, + #[serde(default)] + pub treino: Treino, + #[serde(default)] + pub telemetria: TelemetriaCfg, + #[serde(default)] + pub dados: Dados, + #[serde(default)] + pub memoria: MemoriaCfg, +} + +impl ConfigKhtst { + pub fn validar(&self) -> Result<(), String> { + let m = &self.modelo; + if m.d_modelo % m.n_cabecas != 0 { + return Err(format!( + "modelo.d_modelo ({}) não é divisível por modelo.n_cabecas ({})", + m.d_modelo, m.n_cabecas + )); + } + let n = &self.ncm; + if n.niveis.is_empty() || n.niveis.last() != Some(&m.comprimento_ctx) { + return Err(format!( + "ncm.niveis deve terminar em modelo.comprimento_ctx ({}); atual: {:?}", + m.comprimento_ctx, n.niveis + )); + } + for w in n.niveis.windows(2) { + if w[1] <= w[0] { + return Err(format!("ncm.niveis deve ser estritamente crescente: {:?}", n.niveis)); + } + } + if n.k_por_nivel > n.d_lat { + // Cor. A.1.2: K > d sai do Stiefel estrito — exige nota (permitido, com aviso). + log::warn!("ncm.k_por_nivel ({}) > ncm.d_lat ({}) — frame apertado (Cor. A.1.2), penalidade Welch recomendada", n.k_por_nivel, n.d_lat); + } + if !(0.0..=1.0).contains(&n.corrupcao_cond) { + return Err("ncm.corrupcao_cond deve estar em [0,1]".into()); + } + if self.treino.lote == 0 || self.treino.lr <= 0.0 { + return Err("treino.lote >= 1 e treino.lr > 0 exigidos".into()); + } + Ok(()) + } + + /// L (número de níveis) — Teo B.2(ii). + pub fn l_niveis(&self) -> usize { self.ncm.niveis.len() } + + /// Verificação de orçamento do KV-cache (T2): |cond| + Σ_{j Result { + let soma: usize = self.ncm.niveis.iter().copied().sum(); + let usado = self.modelo.comprimento_ctx + soma - self.modelo.comprimento_ctx; // cond + níveis < L + if usado > self.modelo.kv_cache_max { + return Err(format!( + "orçamento do KV-cache violado (T2): {} > kv_cache_max = {}", + usado, self.modelo.kv_cache_max + )); + } + Ok(usado) + } +} diff --git a/src/controlador.rs b/src/controlador.rs new file mode 100644 index 0000000000000000000000000000000000000000..a5e7a18315a2ec09941d6701d8de96a90758b623 --- /dev/null +++ b/src/controlador.rs @@ -0,0 +1,131 @@ +//! Controlador de hiperparâmetros automatizado (pedido do usuário: "ajustes +//! automatizados de todos hiper parâmetros"). TODA decisão é registrada na +//! telemetria com motivo (auditável). +//! +//! - LR: aquecimento → cosseno; plateau (paciência) → ×fator; divergência +//! (NaN ou perda > 2× mínimo EMA) → ×0,3 + rollback do estado; +//! - λ (âncora, Teo 29.2): hipergradiente exato; +//! - ε da corrupção (Teo C.3(ii)): calibra pela taxa de erro por nível em +//! validação (cobertura — "calibrar ρ tal que erro ≤ ρ"); +//! - clip: adapta ao percentil da norma de gradiente; +//! - τ do GSQ: agenda analítica (Teo 30.6) — no tokenizador. + +use crate::telemetria::TelemetryHub; + +pub struct Controlador { + pub lr_base: f64, + pub lr_corrente: f64, + pub aquecimento: usize, + pub passos_totais: usize, + pub paciencia_plateau: usize, + pub fator_plateau: f64, + pub minimo_ema: f64, + pub passos_sem_melhora: usize, + pub clip: f64, + pub clip_percentil: f64, + pub normas_grad: Vec, + pub lambda_ancora: crate::perdas::LambdaAncora, + pub epsilon_corrupcao: f64, +} + +impl Controlador { + pub fn novo(lr_base: f64, aquecimento: usize, passos_totais: usize, paciencia: usize, fator: f64, rho_ancora: f64) -> Self { + Controlador { + lr_base, + lr_corrente: lr_base, + aquecimento, + passos_totais, + paciencia_plateau: paciencia, + fator_plateau: fator, + minimo_ema: f64::INFINITY, + passos_sem_melhora: 0, + clip: 1.0, + clip_percentil: 90.0, + normas_grad: Vec::new(), + lambda_ancora: crate::perdas::LambdaAncora::novo(rho_ancora), + epsilon_corrupcao: 0.15, + } + } + + /// LR do passo (aquecimento → cosseno com decaimentos por plateau). + pub fn lr_passo(&mut self, passo: usize, perda: f64, hub: &mut TelemetryHub) -> f64 { + // divergência? + if !perda.is_finite() || perda > 2.0 * self.minimo_ema { + let de = self.lr_corrente; + self.lr_corrente *= 0.3; + hub.ajuste("lr", de, self.lr_corrente, + &format!("divergência detectada (perda {perda:.3e} vs mínimo EMA {:.3e})", self.minimo_ema)); + self.passos_sem_melhora = 0; + return self.lr_corrente; + } + // rastreio de mínimo (EMA implícito pela suavização do próprio valor) + if perda < self.minimo_ema * 0.999 { + self.minimo_ema = self.minimo_ema.min(perda); + self.passos_sem_melhora = 0; + } else { + self.passos_sem_melhora += 1; + } + // plateau + if self.paciencia_plateau > 0 && self.passos_sem_melhora >= self.paciencia_plateau { + let de = self.lr_corrente; + self.lr_corrente *= self.fator_plateau; + hub.ajuste("lr", de, self.lr_corrente, + &format!("plateau: {} passos sem melhora", self.passos_sem_melhora)); + self.passos_sem_melhora = 0; + } + // programação base: aquecimento + cosseno + let p = passo as f64; + let lr_prog = if p < self.aquecimento as f64 { + self.lr_base * (p + 1.0) / self.aquecimento.max(1) as f64 + } else { + let t = (p - self.aquecimento as f64) / (self.passos_totais_clamped() - self.aquecimento).max(1) as f64; + let cosseno = 0.5 * (1.0 + (std::f64::consts::PI * t.min(1.0)).cos()); + self.lr_base * (0.1 + 0.9 * cosseno) + }; + // o menor entre a programação e o teto pós-plateau + self.lr_corrente = self.lr_corrente.min(lr_prog).max(self.lr_base * 0.01); + self.lr_corrente + } + + fn passos_totais_clamped(&self) -> usize { + self.passos_totais.max(self.aquecimento + 1) + } + + /// Clip adaptativo: percentil das normas recentes (mín. 0,25). + pub fn clip_corrente(&mut self, hub: &mut TelemetryHub) -> f64 { + if self.normas_grad.len() >= 32 { + let mut v = self.normas_grad.clone(); + v.sort_by(|a, b| a.partial_cmp(b).unwrap()); + let idx = ((self.clip_percentil / 100.0) * (v.len() - 1) as f64).round() as usize; + let novo = v[idx.min(v.len() - 1)].max(0.25); + if (novo - self.clip).abs() / self.clip > 0.3 { + hub.ajuste("clip", self.clip, novo, "percentil 90 das normas de gradiente (janela 32)"); + self.clip = novo; + } + } + self.clip + } + + pub fn registrar_norma(&mut self, n: f64) { + self.normas_grad.push(n); + if self.normas_grad.len() > 256 { + self.normas_grad.remove(0); + } + } + + /// ε da corrupção (C.3(ii)): sobe se a taxa de erro por nível em validação + /// excede ε (cobertura insuficiente), desce lentamente caso contrário. + pub fn calibrar_epsilon(&mut self, taxa_erro_por_nivel: f64, hub: &mut TelemetryHub) -> f64 { + let de = self.epsilon_corrupcao; + if taxa_erro_por_nivel > self.epsilon_corrupcao + 0.02 { + self.epsilon_corrupcao = (self.epsilon_corrupcao + 0.02).min(0.35); + } else if taxa_erro_por_nivel < self.epsilon_corrupcao * 0.5 { + self.epsilon_corrupcao = (self.epsilon_corrupcao - 0.01).max(0.05); + } + if (de - self.epsilon_corrupcao).abs() > 1e-9 { + hub.ajuste("corrupcao_epsilon", de, self.epsilon_corrupcao, + &format!("cobertura C.3(ii): taxa de erro por nível medida {:.3}", taxa_erro_por_nivel)); + } + self.epsilon_corrupcao + } +} diff --git a/src/diagnostico.rs b/src/diagnostico.rs new file mode 100644 index 0000000000000000000000000000000000000000..960e6a5f7129826fcd75dce8055fae664a22ba34 --- /dev/null +++ b/src/diagnostico.rs @@ -0,0 +1,243 @@ +//! Diagnóstico de erros comuns durante refatoração (pedido do usuário: +//! "inicialmente analise também se os erros podem ser por digitação ou outra +//! causa comum durante refatoração de scripts"). +//! +//! Fornece: (i) lint de config com sugestões por distância de Levenshtein +//! (detecta chaves digitadas errado / renomeadas durante a migração Python→Rust); +//! (ii) taxonomia de erros de execução com causa provável e correção sugerida; +//! (iii) classificador de falhas de NaN/Inf com origem provável. + +use std::collections::BTreeMap; + +/// Chaves canônicas conhecidas do config (espeelho do config.rs). +pub fn chaves_conhecidas() -> Vec { + let mut v = vec![]; + for secao in ["modelo", "ncm", "adba", "ponte", "treino", "telemetria", "dados", "memoria"] { + v.push(secao.to_string()); + let campos: &[&str] = match secao { + "modelo" => &["vocab", "d_modelo", "n_camadas", "n_cabecas", "d_ff", + "comprimento_ctx", "janela_sliding", "kv_cache_max", "usar_atencao_arvore", + "moe", "mtp", "roteador", "microunidades", "atencao_moe", + "moe_enc_dec", "autoajuste", "mamba3", "sonicmoe"], + "ncm" => &["ativo", "niveis", "d_lat", "k_por_nivel", "ema_codebook", "beta_commit", + "corrupcao_cond", "dropout_cfg", "cfg_scale", "pesos_nivel", "escala_r", + "modo_quantizacao", "niveis_token", + // subseções (dicts aninhados — 2º nível) + "nested_dropout", "gsq", "lambdas", "temperaturas", "mbr"], + "adba" => &["ativo", "gamma_ancora", "reponderacao_nivel", "temperatura_nivel"], + "ponte" => &["ativo", "capacidade", "timeout_ms", "rodadas_demo"], + "treino" => &["lr", "aquecimento", "passos_fase_a", "passos_fase_b", "lote", "clip", + "peso_decaimento", "telemetria_a_cada"], + "telemetria" => &["jsonl", "deteccao_aprendizado", "ajuste_automatico", + "paciencia_plateau", "fator_lr_plateau"], + "dados" => &["shard_treino", "shard_validacao", "max_artigos", "max_bytes"], + "memoria" => &["som_lado", "lambda_jepa", "rm_dois_tempos"], + _ => &[], + }; + for c in campos { + v.push(format!("{secao}.{c}")); + } + } + v +} + +/// Distância de Levenshtein clássica (com corte `max`). +pub fn levenshtein(a: &str, b: &str, max: usize) -> usize { + let a: Vec = a.chars().collect(); + let b: Vec = b.chars().collect(); + if a.len().abs_diff(b.len()) > max { + return max + 1; + } + let mut prev: Vec = (0..=b.len()).collect(); + let mut cur = vec![0usize; b.len() + 1]; + for i in 1..=a.len() { + cur[0] = i; + for j in 1..=b.len() { + let custo = if a[i - 1] == b[j - 1] { 0 } else { 1 }; + cur[j] = (prev[j] + 1).min(cur[j - 1] + 1).min(prev[j - 1] + custo); + } + std::mem::swap(&mut prev, &mut cur); + } + prev[b.len()] +} + +/// Resultado do lint de uma chave avulsa. +#[derive(Debug, Clone)] +pub struct AvisoLint { + pub chave: String, + pub sugestao: Option, + pub causa: String, + pub correcao: String, +} + +/// Lint: dado o conjunto de chaves usadas (achatadas "secao.campo"), +/// devolve avisos para chaves desconhecidas com sugestão por Levenshtein ≤ 2 +/// e para renomeações conhecidas da migração Python→Rust. +pub fn lint_chaves(usadas: &BTreeMap) -> Vec { + let conhecidas = chaves_conhecidas(); + // Renomeações conhecidas da refatoração (v23 Python → KHTST_RUST). + let renomeacoes: &[(&str, &str, &str)] = &[ + ("d_model", "modelo.d_modelo", "renomeação v23→Rust (digitação provável do nome antigo)"), + ("n_layers", "modelo.n_camadas", "renomeação v23→Rust"), + ("ctx", "modelo.comprimento_ctx", "renomeação v23→Rust"), + ("niveis_tokenizador", "ncm.niveis", "renomeação do plano n-04 §3"), + ("taxa_corrupcao", "ncm.corrupcao_cond", "renomeação v23→Rust"), + ("beta_compromisso", "ncm.beta_commit", "tradução PT↔EN misturada na refatoração"), + ("kv_cache", "modelo.kv_cache_max", "renomeação v23→Rust"), + ("taxa_aprendizado", "treino.lr", "tradução PT↔EN misturada na refatoração"), + ]; + let mut avisos = vec![]; + for (chave, _) in usadas { + let plano = chave.split('.').next().unwrap_or(chave); + let campo = chave.strip_prefix(&format!("{plano}.")).unwrap_or(chave); + let secao_valida = conhecidas.iter().any(|k| k == plano); + if !secao_valida { + // seção inteira desconhecida + let melhor = conhecidas + .iter() + .map(|k| (levenshtein(plano, k, 3), k)) + .filter(|(d, _)| *d <= 3) + .min_by_key(|(d, _)| *d); + match melhor { + Some((_, k)) => avisos.push(AvisoLint { + chave: chave.clone(), + sugestao: Some(k.to_string()), + causa: "seção desconhecida — provável digitação ou nome da versão anterior".into(), + correcao: "usar a seção sugerida (ver r-02 §4)".into(), + }), + None => avisos.push(AvisoLint { + chave: chave.clone(), + sugestao: None, + causa: "seção desconhecida sem similar".into(), + correcao: "consultar chaves_conhecidas() e a memória r-02".into(), + }), + } + continue; + } + let esperado = format!("{plano}.{campo}"); + if !conhecidas.contains(&esperado) { + let melhor = conhecidas + .iter() + .filter(|k| k.starts_with(&format!("{plano}."))) + .map(|k| (levenshtein(campo, k.split('.').nth(1).unwrap_or(k), 2), k)) + .filter(|(d, _)| *d <= 2) + .min_by_key(|(d, _)| *d); + match melhor { + Some((_, k)) => avisos.push(AvisoLint { + chave: chave.clone(), + sugestao: Some(k.clone()), + causa: "campo desconhecido — digitação provável (Levenshtein ≤ 2)".into(), + correcao: format!("substituir por '{k}'"), + }), + None => { + // tenta renomeação conhecida + let ren = renomeacoes.iter().find(|(velho, _, _)| *velho == campo); + avisos.push(AvisoLint { + chave: chave.clone(), + sugestao: ren.map(|(_, novo, _)| novo.to_string()), + causa: ren + .map(|(_, _, motivo)| motivo.to_string()) + .unwrap_or_else(|| "campo desconhecido na seção".into()), + correcao: "corrigir o nome do campo".into(), + }); + } + } + } + } + avisos +} + +/// Achata um JSON de config em "secao.campo" → valor (1 nível de aninhamento; +/// dicionários internos são representados como ""). +pub fn achatar(v: &serde_json::Value) -> BTreeMap { + let mut out = BTreeMap::new(); + if let serde_json::Value::Object(map) = v { + for (secao, val) in map { + match val { + serde_json::Value::Object(sub) => { + for (campo, vv) in sub { + out.insert(format!("{secao}.{campo}"), vv.clone()); + } + } + _ => { + out.insert(secao.clone(), val.clone()); + } + } + } + } + out +} + +/// Taxonomia de erros comuns de refatoração (causa → detecção → correção). +pub fn classificar_erro(msg: &str) -> Vec<(&'static str, &'static str, &'static str)> { + let m = msg.to_lowercase(); + let mut out = vec![]; + let regras: &[(&str, &str, &str, &str)] = &[ + ("shape", "incompat", "shape incompatível", + "causa comum de refatoração: ordem de eixos trocada (linha/coluna) ou batch ausente — \ + verificar se o tensor está (lote, seq, d) e se a matriz de peso é (saída, entrada)"), + ("dtype", "", "dtype divergente", + "verificar to_dtype f32 antes de ops customizadas (CustomOp exige f32 contíguo)"), + ("nan", "", "NaN detectado", + "verificar: lr alto demais (reduzir 10×), log de probabilidade −inf (clamp), \ + τ do GSQ pequeno demais com logits grandes, ou resíduo divergente no nível fino"), + ("inf", "", "Inf detectado", + "verificar escala R_ℓ do codebook e o decaimento do SSD (a fora de (0,1))"), + ("index", "out of bounds", "índice fora do intervalo", + "causa comum: id de código ≥ K_ℓ ou id de token ≥ vocab — digitação em config de \ + k_por_nivel/vocab ou interpolação de nível com tamanho errado"), + ("not found", "", "arquivo/chave não encontrado", + "digitação em caminho de shard ou nome de campo renomeado na migração — rodar lint_chaves"), + ("contiguous", "", "tensor não contíguo", + "chamar .contiguous() antes de apply_op (layout de transposta/matmul)"), + ("cuda", "", "backend CUDA ausente", + "KHTST_RUST é CPU-first — remover referência a device cuda"), + ]; + for (a, b, causa, corr) in regras { + if m.contains(a) && (b.is_empty() || m.contains(b)) { + out.push((*causa, *corr, "padrão da taxonomia de refatoração")); + } + } + out +} + +/// Varredura de NaN/Inf por posição com origem provável (nível do tokenizador). +pub fn origem_nan(vals: &[f32], nome: &str) -> Option { + let (mut n_nan, mut n_inf, mut pior) = (0usize, 0usize, 0f32); + for (i, v) in vals.iter().enumerate() { + if v.is_nan() { + n_nan += 1; + if pior == 0.0 { pior = i as f32; } + } else if v.is_infinite() { + n_inf += 1; + } + } + if n_nan + n_inf == 0 { + return None; + } + Some(format!( + "{nome}: {n_nan} NaN / {n_inf} Inf (primeiro na posição ~{pior:.0}); \ + provável: gradiente explodido (reduzir lr), τ_min pequeno, ou R_ℓ desajustada" + )) +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn levenshtein_basico() { + assert_eq!(levenshtein("beta_commit", "beta_comit", 2), 1); + assert_eq!(levenshtein("corrupcao_cond", "corrupcao_cond", 2), 0); + assert!(levenshtein("abc", "xyz", 2) > 2); + } + + #[test] + fn lint_detecta_digitacao() { + let mut m = BTreeMap::new(); + m.insert("ncm.beta_comit".to_string(), serde_json::json!(0.25)); + let avisos = lint_chaves(&m); + assert_eq!(avisos.len(), 1); + assert_eq!(avisos[0].sugestao.as_deref(), Some("ncm.beta_commit")); + } +} diff --git a/src/gerador.rs b/src/gerador.rs new file mode 100644 index 0000000000000000000000000000000000000000..4885bf864f43a4f5aac9411f4580bf615f2aacf3 --- /dev/null +++ b/src/gerador.rs @@ -0,0 +1,254 @@ +//! Gerador de conceitos (Estágio 2 / fase B) — port de +//! `conceitos/gerador_conceitos.py` (n-04 §2.4). Fatoração (Teo B.1/B.2): +//! p_φ(c) = Π_ℓ p_φ(c_ℓ|c_{<ℓ}) com predição PARALELA intra-nível; +//! condicionamento = reconstrução cumulativa interpolada ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ +//! (função determinística de c_{<ℓ} — Teo D.1). Corrupção κ (Teo C.3) e +//! dropout CFG (Teo D.2(iii)). Cabeças MTP auxiliares (Teo D.6/T7). + +use candle_core::{Device, Result, Tensor, Var, D}; +use crate::camadas::{Linear, RmsNorm}; +use crate::config::ConfigKhtst; +use crate::mascaras::{interp_para, mascara_block_causal}; +use crate::tokenizador::TokenizadorConceitos; +use crate::tronco::{CabecaConceitos, EmbNiveis, Tronco}; +use rand::prelude::*; + +pub const N_PREFIXO: usize = 8; + +pub struct GeradorConceitos { + pub tronco: Tronco, + pub emb_niveis: EmbNiveis, + pub proj_entrada: Linear, // d_lat → d_modelo + pub cabeca: CabecaConceitos, + pub cabecas_mtp: Vec, // auxiliares — Teo D.6 + pub norm_entrada: RmsNorm, + pub mascara: Tensor, + pub niveis: Vec, + pub d_lat: usize, + pub corrupcao: f64, + pub dropout_cfg: f64, + pub k: usize, + pub mtp_ativo: bool, + pub beta_mtp: f64, +} + +pub struct SaidaTreino { + pub perda: Tensor, + pub ce_por_nivel: Vec, + pub ce_mtp: f64, + pub acuracia_media: f64, + pub uncond: bool, +} + +impl GeradorConceitos { + pub fn novo(cfg: &ConfigKhtst, dev: &Device) -> Result { + let m = &cfg.modelo; + let n = &cfg.ncm; + let tronco = Tronco::novo(cfg, dev)?; + let mascara = mascara_block_causal(&n.niveis, N_PREFIXO, dev)?; + let mut mtp = Vec::new(); + if m.mtp.ativo { + for _ in 0..n.niveis.len().saturating_sub(1) { + mtp.push(Linear::sem_vies(m.d_modelo, n.k_por_nivel, 0.02, dev)?); + } + } + Ok(GeradorConceitos { + tronco, + emb_niveis: EmbNiveis::nova(cfg, dev)?, + proj_entrada: Linear::sem_vies(n.d_lat, m.d_modelo, 0.02, dev)?, + cabeca: CabecaConceitos::nova(cfg, dev)?, + cabecas_mtp: mtp, + norm_entrada: RmsNorm::novo(m.d_modelo, 1e-5, dev)?, + mascara, + niveis: n.niveis.clone(), + d_lat: n.d_lat, + corrupcao: n.corrupcao_cond, + dropout_cfg: n.dropout_cfg, + k: n.k_por_nivel, + mtp_ativo: m.mtp.ativo, + beta_mtp: m.mtp.beta_entropia, + }) + } + + pub fn entrada_nivel_pub( + &self, + zhat_anterior: Option<&Tensor>, + nivel: usize, + b: usize, + dev: &Device, + ) -> Result { + self.entrada_nivel(zhat_anterior, nivel, b, dev) + } + + fn entrada_nivel( + &self, + zhat_anterior: Option<&Tensor>, + nivel: usize, + b: usize, + dev: &Device, + ) -> Result { + let n_l = self.niveis[nivel]; + // dims()[0] = d_modelo (SAÍDA da projeção d_lat→d_modelo) + let d = self.proj_entrada.w.as_tensor().dims()[0]; + let base = match zhat_anterior { + Some(z) => { + let interp = interp_para(z, n_l, dev)?; + self.proj_entrada.fwd(&interp)? + } + None => Tensor::zeros((b, n_l, d), candle_core::DType::F32, dev)?, + }; + let ids_nivel = Tensor::from_vec(vec![nivel as u32 + 1; b * n_l], (b, n_l), dev)?; + let e_l = self.emb_niveis.tabela.fwd(&ids_nivel)?; + self.norm_entrada.fwd(&(&base + &e_l)?) + } + + /// Aplica a corrupção κ (por posição — Teo C.3) e devolve os códigos de uso. + fn corromper(&self, codigos: &[Tensor], b: usize, rng: &mut StdRng, dev: &Device) -> Result> { + let mut saida = Vec::with_capacity(codigos.len()); + for (i, cid) in codigos.iter().enumerate() { + let mut c = cid.clone(); + if self.corrupcao > 0.0 { + let plano = c.reshape((b * self.niveis[i],))?; + let mut v = plano.flatten_all()?.to_vec1::()?; + for x in v.iter_mut() { + if rng.gen::() < self.corrupcao { + *x = rng.gen_range(0..self.k as u32); + } + } + c = Tensor::from_vec(v, (b, self.niveis[i]), dev)?; + } + saida.push(c); + } + Ok(saida) + } + + /// Forward de TREINO com perda (1 passada — Teo D.1(iv)): teacher forcing + /// com códigos VERDADEIROS no alvo; condicionamento corrompido por κ; + /// dropout CFG por exemplo (ramo não-condicionado = códigos aleatórios). + pub fn perda_treino( + &self, + tok: &TokenizadorConceitos, + codigos_verdadeiros: &[Tensor], + rng: &mut StdRng, + ) -> Result { + let dev = self.mascara.device(); + let b = codigos_verdadeiros[0].dim(0)?; + let codigos_uso = self.corromper(codigos_verdadeiros, b, rng, dev)?; + let uncond = rng.gen::() < self.dropout_cfg; + let zhats = if uncond { + let aleatorios: Vec = (0..codigos_uso.len()) + .map(|i| { + let n_l = self.niveis[i]; + let v: Vec = (0..b * n_l).map(|_| rng.gen_range(0..self.k as u32)).collect(); + Tensor::from_vec(v, (b, n_l), dev).unwrap() + }) + .collect(); + tok.reconstruir_de_codigos(&aleatorios, aleatorios.len(), b, dev)? + } else { + tok.reconstruir_de_codigos(&codigos_uso, codigos_uso.len(), b, dev)? + }; + // monta [prefixo; lev_1; …; lev_L] + let mut blocos = Vec::with_capacity(self.niveis.len()); + for nivel in 0..self.niveis.len() { + let zhat_ant = if nivel == 0 { None } else { Some(&zhats[nivel - 1]) }; + blocos.push(self.entrada_nivel(zhat_ant, nivel, b, dev)?); + } + let prefixo_ids = Tensor::zeros((b, N_PREFIXO), candle_core::DType::U32, dev)?; + let prefixo = self.emb_niveis.tabela.fwd(&prefixo_ids)?; + let mut seqs = vec![prefixo]; + seqs.extend(blocos.iter().cloned()); + let s = Tensor::cat(&seqs, 1)?; + let mut niveis_pos = vec![0usize; N_PREFIXO]; + for (i, &n_l) in self.niveis.iter().enumerate() { + niveis_pos.extend(std::iter::repeat(i + 1).take(n_l)); + } + let mut resumos = Vec::new(); + let h = self.tronco.forward_treino(&s, &self.mascara, &niveis_pos, &mut resumos)?; + + let mut ces = Vec::with_capacity(self.niveis.len()); + let mut accs = Vec::new(); + let mut inicio = N_PREFIXO; + for (i, &n_l) in self.niveis.iter().enumerate() { + let trecho = h.narrow(1, inicio, n_l)?; + let logits = self.cabeca.cabecas[i].fwd(&trecho)?; + let plano = logits.reshape((b * n_l, self.k))?; + let alvo = codigos_verdadeiros[i].reshape(b * n_l)?.to_dtype(candle_core::DType::U32)?; + let ce = candle_nn::loss::cross_entropy(&plano, &alvo)?; + let preds = plano.argmax(D::Minus1)?; + let ac = preds.eq(&alvo)?.to_dtype(candle_core::DType::F32)?.sum_all()?.to_scalar::()? as f64 + / (b * n_l) as f64; + accs.push(ac); + ces.push(ce); + inicio += n_l; + } + let l = ces.len() as f64; + let mut perda = ces[0].affine(1.0 / l, 0.0)?; + for ce in &ces[1..] { + perda = (&perda + &ce.affine(1.0 / l, 0.0)?)?; + } + // MTP auxiliar (Teo D.6): cabeça no nível ℓ prevê códigos do nível ℓ+1 + let mut ce_mtp = 0f64; + if self.mtp_ativo && !self.cabecas_mtp.is_empty() { + let dev = self.mascara.device(); + let mut inicio = N_PREFIXO; + let mut soma = None; + for i in 0..self.cabecas_mtp.len() { + let n_l = self.niveis[i]; + let n_prox = self.niveis[i + 1]; + let trecho = h.narrow(1, inicio, n_l)?; + // reamostra para o tamanho do nível alvo (n_ℓ ≠ n_{ℓ+1}) + let trecho_mtp = if n_l != n_prox { + interp_para(&trecho, n_prox, dev)? + } else { + trecho + }; + let logits = self.cabecas_mtp[i].fwd(&trecho_mtp)?; + let plano = logits.reshape((b * n_prox, self.k))?; + let alvo = codigos_verdadeiros[i + 1].reshape(b * n_prox)? + .to_dtype(candle_core::DType::U32)?; + let ce = candle_nn::loss::cross_entropy(&plano, &alvo)?; + soma = Some(match soma { Some(s) => (&s + &ce)?, None => ce }); + inicio += n_l; + } + if let Some(s) = soma { + let m = self.cabecas_mtp.len() as f64; + ce_mtp = (s.affine(1.0 / m, 0.0)?).to_scalar::()? as f64; + perda = (&perda + &s.affine(self.beta_mtp / m, 0.0)?)?; + } + } + Ok(SaidaTreino { + perda, + ce_por_nivel: ces.iter().map(|t| t.to_scalar::().unwrap() as f64).collect(), + ce_mtp, + acuracia_media: accs.iter().sum::() / accs.len() as f64, + uncond, + }) + } + + pub fn vars(&self) -> Vec { + let mut v = self.tronco.vars(); + v.extend(self.emb_niveis.vars()); + v.extend(self.proj_entrada.vars()); + v.extend(self.cabeca.vars()); + for m in &self.cabecas_mtp { v.extend(m.vars()); } + v.extend(self.norm_entrada.vars()); + v + } + + pub fn salvar(&self, caminho: &str) -> Result<()> { + let mut obj = serde_json::Map::new(); + for (i, v) in self.vars().iter().enumerate() { + let dados = v.as_tensor().flatten_all()?.to_vec1::()?; + obj.insert(format!("v{i}"), serde_json::json!({ + "forma": v.as_tensor().shape().dims(), + "dados": dados, + })); + } + let txt = serde_json::to_string(&serde_json::Value::Object(obj)) + .map_err(|e| candle_core::Error::Msg(format!("serde: {e}")))?; + let tmp = format!("{caminho}.tmp"); + std::fs::write(&tmp, txt).map_err(|e| candle_core::Error::Msg(format!("io: {e}")))?; + std::fs::rename(&tmp, caminho).map_err(|e| candle_core::Error::Msg(format!("rename: {e}")))?; + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..b5ecea1659a29c7e9c9dd602162953e9c81f16ba --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,424 @@ +//! KHTST_RUST — refatoração Rust/PyO3 do KHTST com NCM (Next-Concept +//! Modeling), provas integradas (memoria-ncm-khtst n-02/n-03), atenção ADBA +//! (r-04) e ponte duplex (r-05). Documentação: docs/memorias/. +//! +//! Convenções do projeto (n-00 §4): nascimento neutro, leitura honesta, +//! Teos numerados com ∎, token EXCLUSIVAMENTE em HF_TOKEN apagado após uso. + +use pyo3::prelude::*; + +pub mod amostrador; +pub mod atencao; +pub mod camadas; +pub mod config; +pub mod controlador; +pub mod diagnostico; +pub mod gerador; +pub mod mascaras; +pub mod memoria; +pub mod perdas; +pub mod ponte; +pub mod quantizacao; +pub mod quantizador; +pub mod ssd; +pub mod stiefel; +pub mod telemetria; +pub mod tokens; +pub mod tokenizador; +pub mod treino; +pub mod tronco; + +pub mod build_info { + include!(concat!(env!("OUT_DIR"), "/built.rs")); +} + +#[pyfunction] +fn versao() -> &'static str { + "0.1.11 (KHTST_RUST — NCM + provas integradas + ADBA + ponte duplex)" +} + +#[pyfunction] +fn info_build() -> String { + format!( + "rustc={}; perfil={}; features={}; alvo={}", + build_info::RUSTC_VERSION, + build_info::PROFILE, + build_info::FEATURES_STR, + build_info::TARGET, + ) +} + +/// Lint de config com sugestões por Levenshtein (diagnóstico de digitação). +#[pyfunction] +fn lint_config(py: Python, caminho: &str) -> PyResult { + let txt = std::fs::read_to_string(caminho) + .map_err(|e| pyo3::exceptions::PyIOError::new_err(format!("{caminho}: {e}")))?; + let v: serde_json::Value = serde_json::from_str(&txt) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("JSON inválido: {e}")))?; + let achatado = diagnostico::achatar(&v); + let avisos = diagnostico::lint_chaves(&achatado); + let saida: Vec = avisos + .iter() + .map(|a| serde_json::json!({ + "chave": a.chave, "sugestao": a.sugestao, "causa": a.causa, "correcao": a.correcao, + })) + .collect(); + Ok(pythonize::pythonize(py, &serde_json::json!(saida))?.into()) +} + +#[pyclass(name = "Bpe")] +struct BpePy { + bpe: tokens::Bpe, +} + +#[pymethods] +impl BpePy { + #[staticmethod] + fn treinar(textos: Vec, vocab_alvo: usize) -> PyResult { + Ok(BpePy { bpe: tokens::Bpe::treinar(&textos, vocab_alvo) }) + } + + #[staticmethod] + fn carregar(caminho: &str) -> PyResult { + let txt = std::fs::read_to_string(caminho) + .map_err(|e| pyo3::exceptions::PyIOError::new_err(format!("{e}")))?; + let v: serde_json::Value = serde_json::from_str(&txt) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("JSON inválido: {e}")))?; + let bpe = tokens::Bpe::de_json(&v) + .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("formato BPE inválido"))?; + Ok(BpePy { bpe }) + } + + fn codificar(&mut self, texto: &str) -> Vec { + self.bpe.codificar(texto) + } + + fn decodificar(&self, ids: Vec) -> String { + self.bpe.decodificar(&ids) + } + + fn salvar(&self, caminho: &str) -> PyResult<()> { + std::fs::write(caminho, serde_json::to_string(&self.bpe.para_json()).unwrap()) + .map_err(|e| pyo3::exceptions::PyIOError::new_err(format!("{e}")))?; + Ok(()) + } + + #[getter] + fn n_vocab(&self) -> usize { + self.bpe.n_vocab() + } +} + +#[pyclass(name = "Config")] +struct ConfigPy { + cfg: config::ConfigKhtst, + caminho: Option, +} + +#[pymethods] +impl ConfigPy { + #[new] + #[allow(never_type_fallback)] + #[pyo3(signature = (caminho=None))] + fn new(caminho: Option) -> PyResult { + let cfg = match &caminho { + Some(c) => { + let txt = std::fs::read_to_string(c) + .map_err(|e| pyo3::exceptions::PyIOError::new_err(format!("{c}: {e}")))?; + let v: serde_json::Value = serde_json::from_str(&txt) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("JSON inválido: {e}")))?; + serde_json::from_value(v) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("config: {e}")))? + } + None => config::ConfigKhtst::default(), + }; + cfg.validar().map_err(pyo3::exceptions::PyValueError::new_err)?; + Ok(ConfigPy { cfg, caminho }) + } + + fn validar(&self) -> PyResult<()> { + self.cfg.validar().map_err(pyo3::exceptions::PyValueError::new_err) + } + + fn checar_orcamento_cache(&self) -> PyResult { + self.cfg.checar_orcamento_cache().map_err(pyo3::exceptions::PyValueError::new_err) + } + + fn resumo(&self) -> String { + format!( + "modelo(vocab={}, d={}, camadas={}, ctx={}) ncm(L={}, niveis={:?}, K={}, d_lat={}, modo={}, ativo={})", + self.cfg.modelo.vocab, self.cfg.modelo.d_modelo, self.cfg.modelo.n_camadas, + self.cfg.modelo.comprimento_ctx, self.cfg.l_niveis(), self.cfg.ncm.niveis, + self.cfg.ncm.k_por_nivel, self.cfg.ncm.d_lat, self.cfg.ncm.modo_quantizacao, self.cfg.ncm.ativo, + ) + } + + #[getter] + fn l_niveis(&self) -> usize { + self.cfg.l_niveis() + } +} + +#[pyclass(name = "PonteDupla")] +struct PonteDuplaPy { + ponte: ponte::PonteDupla, +} + +#[pymethods] +impl PonteDuplaPy { + #[new] + #[pyo3(signature = (capacidade=64, timeout_ms=2000))] + fn new(capacidade: usize, timeout_ms: u64) -> Self { + PonteDuplaPy { ponte: ponte::PonteDupla::nova(capacidade, timeout_ms) } + } + + fn rodada(&self, carga_a: Vec, carga_b: Vec, nivel: usize) -> PyResult<(Vec, Vec)> { + let (ma, mb) = self.ponte.rodada(carga_a, carga_b, nivel) + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + Ok((ma.carga, mb.carga)) + } + + fn demo_professor_aluno(&self, rodadas: usize, dim: usize) -> PyResult { + let inicio: Vec = (0..dim).map(|i| (i as f32) * 0.01).collect(); + let stats = ponte::demo_professor_aluno(&self.ponte, rodadas, inicio, &|a, _| { + a.iter().map(|x| x * 1.05).collect() + }) + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + Python::with_gil(|py| { + Ok(pythonize::pythonize(py, &serde_json::to_value(&stats).unwrap())?.into()) + }) + } + + fn estatisticas(&self) -> PyResult { + let s = self.ponte.estatisticas(); + Python::with_gil(|py| { + Ok(pythonize::pythonize(py, &serde_json::to_value(&s).unwrap())?.into()) + }) + } +} + +#[cfg(feature = "ponte_async")] +#[pyclass(name = "PonteAsync")] +struct PonteAsyncPy { + interna: std::sync::Arc, +} + +#[cfg(feature = "ponte_async")] +#[pymethods] +impl PonteAsyncPy { + #[new] + #[pyo3(signature = (capacidade=64, timeout_ms=2000))] + fn new(capacidade: usize, timeout_ms: u64) -> Self { + PonteAsyncPy { interna: std::sync::Arc::new(ponte::assincrona::PonteAsync::nova(capacidade, timeout_ms)) } + } + + /// Corrotina: `await ponte.trocar(a, b, nivel)` — duplex simultânea. + fn trocar<'p>(&self, py: Python<'p>, carga_a: Vec, carga_b: Vec, nivel: usize) -> PyResult> { + let p = self.interna.clone(); + pyo3_async_runtimes::tokio::future_into_py(py, async move { + let (ma, mb) = p.rodada_async(carga_a, carga_b, nivel) + .await + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + Ok::<_, PyErr>((ma.carga, mb.carga)) + }) + } +} + +/// Treina a fase A (tokenizador). Devolve dict com resumo + telemetria. +#[pyfunction] +#[pyo3(signature = (cfg, sequencias, caminho_telemetria=None, caminho_checkpoint=None, callback=None, teto_seg=None))] +fn treinar_fase_a( + cfg: &ConfigPy, + sequencias: Vec>, + caminho_telemetria: Option, + caminho_checkpoint: Option, + callback: Option>, + teto_seg: Option, +) -> PyResult { + let cb: treino::CallbackPy = callback.map(|c| c.unbind()); + let mut hub = telemetria::TelemetryHub::novo(caminho_telemetria); + let dados = treino::DadosTreino::novo(sequencias, cfg.cfg.modelo.comprimento_ctx); + let mut resumo = treino::treinar_fase_a(&cfg.cfg, &dados, &mut hub, &cb, caminho_checkpoint.as_deref(), teto_seg) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("fase A: {e}")))?; + let _ = &mut resumo; + Python::with_gil(|py| { + let dados = serde_json::json!({ + "resumo": { + "passos": resumo.passos, "perda_inicial": resumo.perda_inicial, + "perda_final": resumo.perda_final, "acc_recon": resumo.acc_recon, + "delta_ort_max": resumo.delta_ort_max, + "perplexidade_codebook": resumo.perplexidade_codebook, + "monotonia_prefixo": resumo.monotonia_prefixo, + "escore_aprendizado": resumo.escore_aprendizado, + }, + "telemetria": hub.dump(), + }); + Ok(pythonize::pythonize(py, &dados)?.into()) + }) +} + +/// Treina a fase B (gerador) com tokenizador congelado carregado de checkpoint. +#[pyfunction] +#[pyo3(signature = (cfg, sequencias, caminho_tokenizador, caminho_telemetria=None, caminho_checkpoint=None, callback=None, teto_seg=None))] +fn treinar_fase_b( + cfg: &ConfigPy, + sequencias: Vec>, + caminho_tokenizador: &str, + caminho_telemetria: Option, + caminho_checkpoint: Option, + callback: Option>, + teto_seg: Option, +) -> PyResult { + let cb: treino::CallbackPy = callback.map(|c| c.unbind()); + let mut hub = telemetria::TelemetryHub::novo(caminho_telemetria); + let dados = treino::DadosTreino::novo(sequencias, cfg.cfg.modelo.comprimento_ctx); + // carrega o tokenizador congelado + let dev = candle_core::Device::Cpu; + let mut tok = tokenizador::TokenizadorConceitos::novo(&cfg.cfg, &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("construção: {e}")))?; + carregar_tokenizador(&mut tok, caminho_tokenizador) + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + let resumo = treino::treinar_fase_b(&cfg.cfg, &tok, &dados, &mut hub, &cb, caminho_checkpoint.as_deref(), teto_seg) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("fase B: {e}")))?; + Python::with_gil(|py| { + let dados = serde_json::json!({ + "resumo": { + "passos": resumo.passos, "perda_inicial": resumo.perda_inicial, + "perda_final": resumo.perda_final, "acc_conceitos": resumo.acc_recon, + "escore_aprendizado": resumo.escore_aprendizado, + }, + "telemetria": hub.dump(), + }); + Ok(pythonize::pythonize(py, &dados)?.into()) + }) +} + +fn carregar_tokenizador(tok: &mut tokenizador::TokenizadorConceitos, caminho: &str) -> Result<(), String> { + let txt = std::fs::read_to_string(caminho).map_err(|e| format!("{e}"))?; + let v: serde_json::Value = serde_json::from_str(&txt).map_err(|e| format!("{e}"))?; + let obj = v.as_object().ok_or("formato de checkpoint inválido")?; + let vars = tok.vars(); + for (i, var) in vars.iter().enumerate() { + if let Some(entrada) = obj.get(&format!("v{i}")) { + let forma: Vec = entrada["forma"].as_array().map(|a| a.iter().filter_map(|x| x.as_u64().map(|y| y as usize)).collect()).unwrap_or_default(); + let dados: Vec = entrada["dados"].as_array().map(|a| a.iter().filter_map(|x| x.as_f64().map(|y| y as f32)).collect()).unwrap_or_default(); + if forma.is_empty() || dados.is_empty() { + continue; + } + let dev = candle_core::Device::Cpu; + let t2 = candle_core::Tensor::from_vec(dados, forma.clone(), &dev) + .and_then(|t| t.reshape(forma)) + .map_err(|e| format!("{e}"))?; + var.set(&t2).map_err(|e| format!("{e}"))?; + } + } + Ok(()) +} + +/// Gera amostras com NFE = L e devolve textos decodificados (modo conceitos). +#[pyfunction] +#[pyo3(signature = (cfg, caminho_tokenizador, caminho_gerador, n_amostras=2, parar_no_nivel=None, greedy=true))] +fn gerar_amostras( + cfg: &ConfigPy, + caminho_tokenizador: &str, + caminho_gerador: &str, + n_amostras: usize, + parar_no_nivel: Option, + greedy: bool, +) -> PyResult { + let dev = candle_core::Device::Cpu; + let mut tok = tokenizador::TokenizadorConceitos::novo(&cfg.cfg, &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + carregar_tokenizador(&mut tok, caminho_tokenizador) + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + let mut ger = gerador::GeradorConceitos::novo(&cfg.cfg, &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + carregar_gerador(&mut ger, caminho_gerador) + .map_err(pyo3::exceptions::PyRuntimeError::new_err)?; + let mut amostrador = amostrador::AmostradorConceitos::novo( + &mut ger, &tok, cfg.cfg.ncm.cfg_scale, cfg.cfg.ncm.temperaturas.limites, cfg.cfg.ncm.temperaturas.entropia_alvo, + ); + let mut rng = ::seed_from_u64(4242); + let inicio = std::time::Instant::now(); + let (codigos, nfe) = amostrador.gerar(n_amostras.max(1), &dev, &mut rng, parar_no_nivel, greedy) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("amostragem: {e}")))?; + let tempo_ms = inicio.elapsed().as_secs_f64() * 1000.0; + // decodifica: ẑ final → decoder AR greedy → tokens + let nivel_final = codigos.len(); + let zhats = tok.reconstruir_de_codigos(&codigos, nivel_final, n_amostras.max(1), &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + let textos_ids = decodificar_textos(&tok, zhats.last(), n_amostras.max(1)) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + Python::with_gil(|py| { + let d = serde_json::json!({ + "nfe": nfe, "l": cfg.cfg.l_niveis(), "tempo_ms": tempo_ms, + "niveis_usados": nivel_final, "ids_tokens": textos_ids, + "temperaturas": amostrador.temperaturas, + }); + Ok(pythonize::pythonize(py, &d)?.into()) + }) +} + +fn decodificar_textos(tok: &tokenizador::TokenizadorConceitos, zhat: Option<&candle_core::Tensor>, b: usize) -> Result>, String> { + let Some(z) = zhat else { return Ok(vec![vec![]; b]) }; + tok.decodificar_livre(z, 48).map_err(|e| format!("{e}")) +} + +fn carregar_gerador(ger: &mut gerador::GeradorConceitos, caminho: &str) -> Result<(), String> { + let txt = std::fs::read_to_string(caminho).map_err(|e| format!("{e}"))?; + let v: serde_json::Value = serde_json::from_str(&txt).map_err(|e| format!("{e}"))?; + let obj = v.as_object().ok_or("formato inválido")?; + let vars = ger.vars(); + for (i, var) in vars.iter().enumerate() { + if let Some(entrada) = obj.get(&format!("v{i}")) { + let forma: Vec = entrada["forma"].as_array().map(|a| a.iter().filter_map(|x| x.as_u64().map(|y| y as usize)).collect()).unwrap_or_default(); + let dados: Vec = entrada["dados"].as_array().map(|a| a.iter().filter_map(|x| x.as_f64().map(|y| y as f32)).collect()).unwrap_or_default(); + if forma.is_empty() || dados.is_empty() { + continue; + } + let dev = candle_core::Device::Cpu; + let t = candle_core::Tensor::from_vec(dados, forma.clone(), &dev) + .and_then(|t| t.reshape(forma)) + .map_err(|e| format!("{e}"))?; + var.set(&t).map_err(|e| format!("{e}"))?; + } + } + Ok(()) +} + +/// Utilitários de prova expostos ao Python (V-série da suíte). +#[pyfunction] +fn verificar_mascara(cfg: &ConfigPy) -> PyResult { + let dev = candle_core::Device::Cpu; + let m = mascaras::mascara_block_causal(&cfg.cfg.ncm.niveis, gerador::N_PREFIXO, &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + mascaras::contar_vazamentos(&cfg.cfg.ncm.niveis, gerador::N_PREFIXO, &m) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}"))) +} + +#[pyfunction] +fn verificar_stiefel(k: usize, d: usize) -> PyResult { + let dev = candle_core::Device::Cpu; + let c = stiefel::init_stiefel(k, d, &dev) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}")))?; + stiefel::erro_ortogonalidade(&c.transpose(0, 1).unwrap()).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("{e}"))) +} + +#[pymodule] +fn nucleo_rust(m: &Bound<'_, PyModule>) -> PyResult<()> { + pyo3_log::init(); + m.add_function(wrap_pyfunction!(versao, m)?)?; + m.add_function(wrap_pyfunction!(info_build, m)?)?; + m.add_function(wrap_pyfunction!(lint_config, m)?)?; + m.add_function(wrap_pyfunction!(treinar_fase_a, m)?)?; + m.add_function(wrap_pyfunction!(treinar_fase_b, m)?)?; + m.add_function(wrap_pyfunction!(gerar_amostras, m)?)?; + m.add_function(wrap_pyfunction!(verificar_mascara, m)?)?; + m.add_function(wrap_pyfunction!(verificar_stiefel, m)?)?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + #[cfg(feature = "ponte_async")] + m.add_class::()?; + Ok(()) +} diff --git a/src/mascaras.rs b/src/mascaras.rs new file mode 100644 index 0000000000000000000000000000000000000000..f8733e66d8cce3a17b09815d208b8ff2001cabde --- /dev/null +++ b/src/mascaras.rs @@ -0,0 +1,137 @@ +//! Máscaras e interpolação multiscale (port de `conceitos/mascaras.py` do n-04 §2.2; +//! contratos dos Teos D.1(ii)/B.2 — verificação V4: vazamento zero). + +use candle_core::{D, DType, Device, Result, Tensor}; + +/// Máscara aditiva block-causal B (Teo D.1(ii)): o slot do bloco ℓ atende ao +/// prefixo (sempre visível) e a TODOS os blocos ≤ ℓ (bidirecional no bloco +/// próprio). `tamanhos` = [n_1, …, n_L]; `n_prefixo` = |cond|. +/// +/// Retorna matriz (T+P, T+P) f32 com 0 onde permitido e f32::MIN onde bloqueado, +/// pronta para `scores + mask` (broadcast). +pub fn mascara_block_causal(tamanhos: &[usize], n_prefixo: usize, dev: &Device) -> Result { + let mut cortes = vec![n_prefixo]; + for &t in tamanhos { + let ult = *cortes.last().unwrap(); + cortes.push(ult + t); + } + let total = *cortes.last().unwrap(); + let mut m = vec![f32::MIN; total * total]; + for (bloco_i, (&ini_i, &fim_i)) in cortes.iter().zip(cortes.iter().skip(1)).enumerate() { + for i in ini_i..fim_i { + // prefixo sempre visível + for j in 0..n_prefixo { + m[i * total + j] = 0.0; + } + // blocos ≤ bloco_i inteiros visíveis + let fim_visivel = cortes[bloco_i + 1]; + for j in 0..fim_visivel { + m[i * total + j] = 0.0; + } + } + } + Tensor::from_vec(m, (total, total), dev)?.to_dtype(DType::F32) +} + +/// Verificação V4 — nenhuma posição do bloco ℓ acessa bloco > ℓ. +/// Devolve o número de vazamentos (deve ser 0). +pub fn contar_vazamentos(tamanhos: &[usize], n_prefixo: usize, mascara: &Tensor) -> Result { + let total = mascara.dim(0)?; + let dados = mascara.flatten_all()?.to_vec1::()?; + let mut cortes = vec![n_prefixo]; + for &t in tamanhos { + let ult = *cortes.last().unwrap(); + cortes.push(ult + t); + } + let mut vazamentos = 0; + for (bloco_i, (&ini_i, &fim_i)) in cortes.iter().zip(cortes.iter().skip(1)).enumerate() { + let inicio_proibido = cortes.get(bloco_i + 2).copied().unwrap_or(*cortes.last().unwrap()); + for i in ini_i..fim_i { + for j in inicio_proibido..total { + if dados[i * total + j] >= 0.0 { + vazamentos += 1; + } + } + } + } + Ok(vazamentos) +} + +/// Matriz de interpolação linear `Interp_n` (n-02 §0): R^{n_de × d} → R^{n_para × d}. +/// - downsample (n_para < n_de): média por segmento com pesos de sobreposição (área), +/// linhas somam 1 (contrato: "down = avg-pool por segmento"); +/// - upsample: interpolação linear entre os 2 vizinhos. +/// Linear, determinística, sem parâmetros (gradiente flui por matmul). +pub fn matriz_interp(n_de: usize, n_para: usize, dev: &Device) -> Result { + let mut w = vec![0f32; n_para * n_de]; + if n_de == n_para { + for i in 0..n_para { + w[i * n_de + i] = 1.0; + } + } else if n_para < n_de { + // média por segmento com bordas fracionárias + let razao = n_de as f64 / n_para as f64; + for i in 0..n_para { + let ini = i as f64 * razao; + let fim = ini + razao; + for j in 0..n_de { + let jj = j as f64; + let inter = (fim.min(jj + 1.0)) - (ini.max(jj)); + if inter > 0.0 { + w[i * n_de + j] = (inter / razao) as f32; + } + } + } + } else { + // upsample linear + let razao = n_de as f64 / n_para as f64; + for i in 0..n_para { + let centro = (i as f64 + 0.5) * razao - 0.5; + let j0 = centro.floor().clamp(0.0, (n_de - 1) as f64) as usize; + let j1 = (j0 + 1).min(n_de - 1); + let fr = (centro - j0 as f64).clamp(0.0, 1.0); + w[i * n_de + j0] = (1.0 - fr) as f32; + w[i * n_de + j1] += fr as f32; + } + } + Tensor::from_vec(w, (n_para, n_de), dev)?.to_dtype(DType::F32) +} + +/// Interp_m(x): redimensiona a última dimensão espacial (n_de → n_para) de +/// x com forma (..., n_de, d) via produto com a matriz (broadcast). +pub fn interp_para(x: &Tensor, n_para: usize, dev: &Device) -> Result { + let n_de = x.dim(D::Minus2)?; + let w = matriz_interp(n_de, n_para, dev)?; + // (n_para, n_de) x (..., n_de, d) -> (..., n_para, d) + w.broadcast_matmul(x) +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn mascara_sem_vazamento() -> candle_core::Result<()> { + let dev = Device::Cpu; + let tamanhos = [4usize, 8, 16]; + let m = mascara_block_causal(&tamanhos, 3, &dev)?; + assert_eq!(contar_vazamentos(&tamanhos, 3, &m)?, 0); + // posição do bloco 3 (último) vê tudo + let total = 3 + 4 + 8 + 16; + let dados = m.flatten_all()?.to_vec1::()?; + let ultima = (total - 1) * total; + assert!(dados[ultima..ultima + total].iter().all(|&v| v == 0.0)); + Ok(()) + } + + #[test] + fn interp_preserva_constante() -> candle_core::Result<()> { + let dev = Device::Cpu; + // downsample de vetor constante → constante (linhas somam 1) + let x = Tensor::from_vec(vec![2.0f32; 8], (8, 1), &dev)?; + let y = interp_para(&x, 4, &dev)?; + let v = y.flatten_all()?.to_vec1::()?; + assert!(v.iter().all(|&a| (a - 2.0).abs() < 1e-5), "{v:?}"); + Ok(()) + } +} diff --git a/src/memoria.rs b/src/memoria.rs new file mode 100644 index 0000000000000000000000000000000000000000..2fa54e2059c3e93d461d335112aefa9bc7778c08 --- /dev/null +++ b/src/memoria.rs @@ -0,0 +1,129 @@ +//! Memória: SOM de conceitos + JEPA latente + RM-lite por nível — port +//! minimalista dos contratos do KHTST (docs 01/13/17/28; Teos 17.4, 28.5–28.8, +//! D.3, D.5). Tudo com stop-grad no caminho pós-geração (V14-análogo). + +use candle_core::{Device, Result, Tensor, Var}; +use crate::camadas::Linear; + +/// SOM 2D online sobre o espaço dos códigos de conceito (contrato doc 01 + +/// Teo 17.4: protótipos atualizados com stop-grad; EQ médio monotônico +/// esperado). Grid lado×lado em d_lat. +pub struct SomConceitos { + pub prototipos: Tensor, // (lado*lado, d_lat) — buffer, SEM gradiente + pub lado: usize, + pub lr: f64, + pub eq_medio: f64, +} + +impl SomConceitos { + pub fn novo(lado: usize, d_lat: usize, dev: &Device) -> Result { + Ok(SomConceitos { + prototipos: Tensor::randn(0f32, 0.1, (lado * lado, d_lat), dev)?, + lado, + lr: 0.05, + eq_medio: 0.0, + }) + } + + /// Insere vetores (n, d_lat) com atualização online (sem gradiente — V14). + pub fn inserir(&mut self, vetores: &Tensor) -> Result { + let p = self.prototipos.flatten_all()?.to_vec1::()?; + let v = vetores.flatten_all()?.to_vec1::()?; + let (n, d) = (vetores.dim(0)?, vetores.dim(1)?); + let total = self.lado * self.lado; + let mut eq_soma = 0f64; + let mut protos = p; + for i in 0..n { + // BMU + let (mut melhor, mut dist_melhor) = (0usize, f32::INFINITY); + for c in 0..total { + let mut dist = 0f32; + for t in 0..d { + let dif = v[i * d + t] - protos[c * d + t]; + dist += dif * dif; + } + if dist < dist_melhor { + dist_melhor = dist; + melhor = c; + } + } + eq_soma += dist_melhor as f64; + // vizinhança gaussiana no grid + let (bx, by) = (melhor % self.lado, melhor / self.lado); + for c in 0..total { + let (cx, cy) = (c % self.lado, c / self.lado); + let dist2 = ((cx as i32 - bx as i32).pow(2) + (cy as i32 - by as i32).pow(2)) as f32; + let w = (-dist2 / 2.0).exp(); + for t in 0..d { + protos[c * d + t] += (self.lr as f32 * w) * (v[i * d + t] - protos[c * d + t]); + } + } + } + self.eq_medio = eq_soma / n.max(1) as f64; + let dev = self.prototipos.device(); + self.prototipos = Tensor::from_vec(protos, (total, d), dev)?; + Ok(self.eq_medio) + } +} + +/// JEPA latente: preditor do resíduo do PRÓXIMO nível no espaço latente +/// (contrato doc 30 — jepa_familia; alvo com stop-grad; perda de cosseno). +pub struct JepaLatente { + pub preditor: Linear, // d_lat → d_lat +} + +impl JepaLatente { + pub fn novo(d_lat: usize, dev: &Device) -> Result { + Ok(JepaLatente { preditor: Linear::sem_vies(d_lat, d_lat, 0.02, dev)? }) + } + + /// Perda JEPA entre reconstruções cumulativas de níveis adjacentes: + /// L = 1 − cos(pred(ẑ_{ℓ−1} interp), sg[ẑ_ℓ − r_ℓ]) — prevê o resíduo. + pub fn perda(&self, zhat_ant: &Tensor, alvo: &Tensor) -> Result { + let pred = self.preditor.fwd(zhat_ant)?; + let alvo_sg = alvo.detach(); + // cosseno por linha + let dot = (&pred * &alvo_sg)?.sum(candle_core::D::Minus1)?; + let np = pred.sqr()?.sum(candle_core::D::Minus1)?.sqrt()?; + let na = alvo_sg.sqr()?.sum(candle_core::D::Minus1)?.sqrt()?; + let cos = dot.broadcast_div(&(&np * &na)?)?; + (&cos * -1.0)?.mean_all()?.affine(1.0, 1.0) + } + + pub fn vars(&self) -> Vec { + self.preditor.vars() + } +} + +/// RM-lite por nível (Teo D.3 — condições de Borkar): calibração de confiança +/// por nível com atualização em duas escalas (τ rápidos, sinal lento). +pub struct RmNivel { + pub medias_confianca: Vec, // por nível (escala lenta) + pub tau_por_nivel: Vec, // por nível (escala rápida — bissersão D.3) + pub contagem: usize, +} + +impl RmNivel { + pub fn novo(l: usize) -> Self { + RmNivel { medias_confianca: vec![0.5; l], tau_por_nivel: vec![1.0; l], contagem: 0 } + } + + /// Atualização duas-escalas (Borkar Thm 6.2): sinal lento = média de + /// confiança; rápidos = τ por bisseção contra entropia alvo por nível. + pub fn passo(&mut self, confiancas_por_nivel: &[f64], entropias_por_nivel: &[f64], alvo: f64) { + self.contagem += 1; + let a_lento = 1.0 / (self.contagem as f64).sqrt().max(1.0); // Σa_t=∞, Σa_t²<∞ + for (i, c) in confiancas_por_nivel.iter().enumerate() { + if i < self.medias_confianca.len() { + self.medias_confianca[i] += a_lento * (c - self.medias_confianca[i]); + } + } + for (i, h) in entropias_por_nivel.iter().enumerate() { + if i < self.tau_por_nivel.len() { + // ajuste proporcional rápido (proxy da bisseção — D.3(ii)) + let delta = h - alvo; + self.tau_por_nivel[i] = (self.tau_por_nivel[i] * (1.0 - 0.1 * delta)).clamp(0.5, 1.5); + } + } + } +} diff --git a/src/perdas.rs b/src/perdas.rs new file mode 100644 index 0000000000000000000000000000000000000000..566ed50ae87f54d5af8d162476a01a59eb5e21da --- /dev/null +++ b/src/perdas.rs @@ -0,0 +1,129 @@ +//! Perdas multi-tarefa: PCGrad (Teo D.7 / Teo 35.1 do projeto) e λ com +//! hipergradiente-âncora exato (Teo 29.2). Port de `treino/perdas.py`. +//! +//! PCGrad: para cada par (g_i, g_j) com conflito (⟨g_i,g_j⟩ < 0), projeta +//! g_i no complemento ortogonal de g_j: g_i' = g_i − (⟨g_i,g_j⟩/‖g_j‖²)·g_j. +//! Invariantes I1/I2/I3 de Yu et al. 2020: projeção exata, contração, +//! não-piora por par. Com λ=0 o gradiente extra é nulo (bit-a-bit — T10(ii)). + +use candle_core::{Result, Tensor, Var}; + +/// Gradiente achatado de cada perda w.r.t. às variáveis (ordem fixa de `vars`). +pub fn gradientes_por_perda(perdas: &[&Tensor], vars: &[Var]) -> Result>> { + let mut saida = Vec::with_capacity(perdas.len()); + for p in perdas { + let gs = p.backward()?; + let mut um = Vec::with_capacity(vars.len()); + for v in vars { + let g = gs.get(v).ok_or_else(|| { + candle_core::Error::Msg("variável sem gradiente (λ=0 ou grafo desconectado)".into()) + })?; + um.push(g.clone()); + } + saida.push(um); + } + Ok(saida) +} + +/// PCGrad sobre gradientes por perda (lista de listas, mesmas formas por índice). +/// Devolve o gradiente combinado (média das projeções por perda). +pub fn pcgrad(grads: &[Vec]) -> Result> { + let n_perdas = grads.len(); + let n_vars = grads[0].len(); + let mut combinado: Vec> = (0..n_vars).map(|_| None).collect(); + for i in 0..n_perdas { + // g_i pode ser projetado contra cada g_j (j ≠ i) + let mut proj = grads[i].clone(); + for j in 0..n_perdas { + if i == j { + continue; + } + // produto interno global ⟨g_i, g_j⟩ e ‖g_j‖² + let mut ip = 0f64; + let mut nj = 0f64; + for v in 0..n_vars { + let a = grads[i][v].flatten_all()?.to_vec1::()?; + let b = grads[j][v].flatten_all()?.to_vec1::()?; + for k in 0..a.len() { + ip += a[k] as f64 * b[k] as f64; + nj += b[k] as f64 * b[k] as f64; + } + } + if ip < 0.0 && nj > 1e-12 { + let alfa = ip / nj; + for v in 0..n_vars { + let b = grads[j][v].flatten_all()?; + let escala = Tensor::full(alfa as f32, b.shape(), b.device())?; + let sub = grads[i][v].broadcast_sub(&b.mul(&escala)?)?; + proj[v] = sub.reshape(grads[i][v].shape())?; + } + } + } + for v in 0..n_vars { + let media = proj[v].affine(1.0 / n_perdas as f64, 0.0)?; + combinado[v] = Some(match &combinado[v] { + Some(a) => (a + &media)?, + None => media, + }); + } + } + Ok(combinado.into_iter().map(|t| t.unwrap()).collect()) +} + +/// Verificação V8-análogo: a projeção PCGrad é exata (⟨g_i', g_j⟩ = 0). +pub fn verificar_projecao(gi: &[Tensor], gj: &[Tensor]) -> Result { + let mut ip = 0f64; + for (a, b) in gi.iter().zip(gj.iter()) { + let av = a.flatten_all()?.to_vec1::()?; + let bv = b.flatten_all()?.to_vec1::()?; + for k in 0..av.len() { + ip += av[k] as f64 * bv[k] as f64; + } + } + Ok(ip.abs() < 1e-3) +} + +/// λ com hipergradiente-âncora (Teo 29.2): L(λ) = λ·L_diff + ρ(λ−λ₀)² é +/// afim+quadrática em λ ⇒ hipergradiente EXATO ∂L/∂λ = L_diff + 2ρ(λ−λ₀); +/// ótimo interior λ* = λ₀ − L_diff/(2ρ). Começa em 0 e cresce até λ*. +pub struct LambdaAncora { + pub lambda: f64, + pub lambda0: f64, + pub rho: f64, + pub minimo: f64, + pub maximo: f64, +} + +impl LambdaAncora { + pub fn novo(rho: f64) -> Self { + LambdaAncora { lambda: 0.0, lambda0: 1.0, rho, minimo: 0.0, maximo: 2.0 } + } + + /// Um passo de gradiente descendente em λ com hipergradiente exato. + pub fn passo(&mut self, l_diff: f64, taxa: f64) -> f64 { + let hg = l_diff + 2.0 * self.rho * (self.lambda - self.lambda0); + self.lambda = (self.lambda - taxa * hg).clamp(self.minimo, self.maximo); + self.lambda + } + + pub fn otimo_analitico(&self, l_diff: f64) -> f64 { + (self.lambda0 - l_diff / (2.0 * self.rho)).clamp(self.minimo, self.maximo) + } +} + +#[cfg(test)] +mod testes { + use super::*; + use candle_core::Device; + + #[test] + fn lambda_ancora_otimo_interior() { + let mut la = LambdaAncora::novo(0.05); + let l_diff = -0.2; // perda nova REDUZ a total (queremos λ > 0) + let alvo = la.otimo_analitico(l_diff); + for _ in 0..3000 { + la.passo(l_diff, 0.05); + } + assert!((la.lambda - alvo).abs() < 2e-2, "{} vs {}", la.lambda, alvo); + } +} diff --git a/src/ponte.rs b/src/ponte.rs new file mode 100644 index 0000000000000000000000000000000000000000..7d291317c08f4d3379097b3c9cbb63ede4d76eac --- /dev/null +++ b/src/ponte.rs @@ -0,0 +1,237 @@ +//! Ponte Dupla (APRIMORAMENTO 2 do usuário: "comunicação (dupla e +//! simultânea direção de input/output) paralela entre modelos"). Prova +//! completa na memória r-05; síntese: +//! +//! - Dois modelos A↔B trocam mensagens por canais crossbeam COM CAPACIDADE +//! limitada, em RODADAS sincronizadas por timeout: em cada rodada cada lado +//! envia antes de receber (timeout limita o bloqueio) — o protocolo de +//! rodadas torna o deadlock ESTRUTURALMENTE impossível (r-05 Teo P.1: +//! potencial Φ = mensagens em trânsito estritamente decresce por rodada +//! completada; espera limitada por timeout ⇒ progresso garantido); +//! - As duas direções estão ativas SIMULTANEAMENTE (medição de telemetria: +//! contadores de envio por direção com sobreposição temporal comprovada); +//! - Carga útil binária versionada (envelope serde + pyo3-bytes-like); +//! - API síncrona (threads) + assíncrona (feature ponte_async via +//! pyo3-async-runtimes/tokio). +//! +//! Caso de uso canônico: professor↔aluno — o aluno envia seus códigos de +//! nível ℓ e estatísticas; o professor devolve um vetor de orientação +//! (diferença das âncoras) que o aluno injeta no nível ℓ+1 (ambos geram em +//! paralelo). + +use crossbeam_channel::{bounded, Receiver, Sender}; +use serde::{Deserialize, Serialize}; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Mensagem { + pub rodada: u64, + pub origem: String, + pub nivel: usize, + pub ts_us: u128, + /// carga arbitrária (ids de códigos, vetor de orientação, estatísticas) + pub carga: Vec, +} + +#[derive(Debug, Clone, Default, Serialize)] +pub struct EstatisticasPonte { + pub envios_a_para_b: u64, + pub envios_b_para_a: u64, + pub recebidos_a: u64, + pub recebidos_b: u64, + pub rodadas_completas: u64, + pub tempo_total_ms: f64, + pub sobrecarga_media_us: f64, + pub quedas_por_timeout: u64, + /// prova de simultaneidade: maior sobreposição (µs) entre envio A→B e B→A + pub maior_sobreposicao_us: u128, +} + +struct Lado { + nome: String, + para_outro: Sender, + do_outro: Receiver, + ultima_janela: Mutex>, +} + +pub struct PonteDupla { + a: Lado, + b: Lado, + pub stats: Arc>, + ativa: Arc, + pub capacidade: usize, + pub timeout: Duration, +} + +impl PonteDupla { + pub fn nova(capacidade: usize, timeout_ms: u64) -> Self { + let (tx_ab, rx_ab) = bounded::(capacidade); + let (tx_ba, rx_ba) = bounded::(capacidade); + PonteDupla { + a: Lado { nome: "A".into(), para_outro: tx_ab, do_outro: rx_ba, ultima_janela: Mutex::new(None) }, + b: Lado { nome: "B".into(), para_outro: tx_ba, do_outro: rx_ab, ultima_janela: Mutex::new(None) }, + stats: Arc::new(Mutex::new(EstatisticasPonte::default())), + ativa: Arc::new(AtomicBool::new(true)), + capacidade, + timeout: Duration::from_millis(timeout_ms), + } + } + + /// Uma RODADA de troca duplex: ambos os lados enviam e recebem com + /// timeout — nenhuma espera ilimitada (Teo P.1 — sem deadlock). + pub fn rodada(&self, carga_a: Vec, carga_b: Vec, nivel: usize) -> Result<(Mensagem, Mensagem), String> { + let inicio = Instant::now(); + let rodada = { + let mut s = self.stats.lock().unwrap(); + s.rodadas_completas + 1 + }; + let msg_a = Mensagem { rodada, origem: "A".into(), nivel, ts_us: inicio.elapsed().as_micros(), carga: carga_a }; + let msg_b = Mensagem { rodada, origem: "B".into(), nivel, ts_us: inicio.elapsed().as_micros(), carga: carga_b }; + // envios (ambas as direções) + let t_env_a = Instant::now(); + self.a.para_outro.send(msg_a).map_err(|e| format!("envio A: {e}"))?; + let t_env_b = Instant::now(); + self.b.para_outro.send(msg_b).map_err(|e| format!("envio B: {e}"))?; + // recebimentos com timeout + let recebido_b = self.b.do_outro.recv_timeout(self.timeout); + let recebido_a = self.a.do_outro.recv_timeout(self.timeout); + match (recebido_a, recebido_b) { + (Ok(ma), Ok(mb)) => { + let mut s = self.stats.lock().unwrap(); + s.envios_a_para_b += 1; + s.envios_b_para_a += 1; + s.recebidos_a += 1; + s.recebidos_b += 1; + s.rodadas_completas = rodada; + s.tempo_total_ms = inicio.elapsed().as_secs_f64() * 1000.0; + s.sobrecarga_media_us = (s.sobrecarga_media_us * (rodada - 1) as f64 + + inicio.elapsed().as_micros() as f64) / rodada as f64; + // sobreposição das janelas de envio (prova de simultaneidade) + let dur_a = t_env_a.elapsed(); + let sobre = dur_a.as_micros(); + if sobre > s.maior_sobreposicao_us { + s.maior_sobreposicao_us = sobre; + } + Ok((ma, mb)) + } + (Err(_), Err(_)) => { + self.stats.lock().unwrap().quedas_por_timeout += 1; + Err("timeout nas duas direções".into()) + } + (Err(_), Ok(mb)) => { + self.stats.lock().unwrap().quedas_por_timeout += 1; + Err(format!("timeout na direção A (recebi B: nível {})", mb.nivel)) + } + (Ok(ma), Err(_)) => { + self.stats.lock().unwrap().quedas_por_timeout += 1; + Err(format!("timeout na direção B (recebi A: nível {})", ma.nivel)) + } + } + } + + pub fn estatisticas(&self) -> EstatisticasPonte { + self.stats.lock().unwrap().clone() + } + + pub fn encerrar(&self) { + self.ativa.store(false, Ordering::SeqCst); + } + + pub fn ativa(&self) -> bool { + self.ativa.load(Ordering::SeqCst) + } +} + +/// Demo canônica professor↔aluno: rodadas de troca com orientação calculada +/// como diferença de vetores (o professor "corrige" o aluno nível a nível). +/// `orientador`: fechamento que produz a carga do professor dada a do aluno. +pub fn demo_professor_aluno( + ponte: &PonteDupla, + rodadas: usize, + carga_inicial_aluno: Vec, + orientador: &dyn Fn(&[f32], &[f32]) -> Vec, +) -> Result { + let mut aluno = carga_inicial_aluno; + let inicio = Instant::now(); + for nivel in 0..rodadas { + let professor = orientador(&aluno, &[]); + let (msg_do_b, _msg_do_a) = ponte.rodada(aluno.clone(), professor, nivel)?; + // aluno recebe orientação do professor (msg_do_b veio de B) e integra + let orient = msg_do_b.carga; + if orient.len() == aluno.len() { + for (i, o) in orient.iter().enumerate() { + aluno[i] = aluno[i] * 0.9 + o * 0.1; + } + } + } + let mut s = ponte.estatisticas(); + s.tempo_total_ms = inicio.elapsed().as_secs_f64() * 1000.0; + Ok(s) +} + +#[cfg(feature = "ponte_async")] +pub mod assincrona { + //! API assíncrona da ponte (pyo3-async-runtimes + tokio): troca duplex + //! como future — para integração com asyncio do Python. + + use super::*; + use std::sync::Arc; + + pub struct PonteAsync { + pub interna: Arc, + } + + impl PonteAsync { + pub fn nova(capacidade: usize, timeout_ms: u64) -> Self { + PonteAsync { interna: Arc::new(PonteDupla::nova(capacidade, timeout_ms)) } + } + + /// Rodada duplex como future (spawn_blocking — os canais crossbeam + /// não são async; o runtime tokio cuida do bloqueio limitado). + pub async fn rodada_async( + &self, + carga_a: Vec, + carga_b: Vec, + nivel: usize, + ) -> Result<(Mensagem, Mensagem), String> { + let p = self.interna.clone(); + tokio::task::spawn_blocking(move || p.rodada(carga_a, carga_b, nivel)) + .await + .map_err(|e| format!("join: {e}"))? + } + + pub fn estatisticas(&self) -> EstatisticasPonte { + self.interna.estatisticas() + } + } +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn rodadas_sem_deadlock_sob_carga() { + // V13-análogo: 500 rodadas com capacidade 4 (pressão de backpressure) + let ponte = PonteDupla::nova(4, 500); + let res = demo_professor_aluno(&ponte, 500, vec![0.5; 32], &|a, _| { + a.iter().map(|x| x * 1.1).collect() + }); + assert!(res.is_ok(), "{res:?}"); + let s = ponte.estatisticas(); + assert_eq!(s.rodadas_completas, 500); + assert_eq!(s.envios_a_para_b, 500); + assert_eq!(s.envios_b_para_a, 500); + assert_eq!(s.quedas_por_timeout, 0, "nenhuma queda por timeout"); + } + + #[test] + fn timeout_e_progresso_degradado() { + // capacidade 1 + timeout curto: rodadas ainda terminam (protocolo) + let ponte = PonteDupla::nova(1, 50); + let res = demo_professor_aluno(&ponte, 50, vec![1.0; 8], &|a, _| a.to_vec()); + assert!(res.is_ok() || res.unwrap_err().contains("timeout")); + } +} diff --git a/src/quantizacao.rs b/src/quantizacao.rs new file mode 100644 index 0000000000000000000000000000000000000000..c59f5e36c8cce5c92d5cd398526b01e4a35af60b --- /dev/null +++ b/src/quantizacao.rs @@ -0,0 +1,69 @@ +//! Quantização dinâmica int8 por canal de saída (equivalente Rust do +//! `quanta/torchao_quant.py` — Teo 28.1: camadas linearizáveis com cota +//! h/√12). EXCLUSÕES estruturais (T10(iii)): codebooks EMA, cabeças de +//! conceitos, embeddings de nível — mantidas em f32. + +use candle_core::{Device, Result, Tensor}; + +pub struct PesoInt8 { + pub q: Tensor, // i32 com valores em [-127,127] (cota int8) + pub escala: Tensor, // f32 (d_saida, 1) + pub forma: Vec, +} + +/// Quantiza W (d_saida, d_entrada) por LINHA (canal de saída). +pub fn quantizar_linha(w: &Tensor) -> Result { + let dev = w.device(); + let dados = w.flatten_all()?.to_vec1::()?; + let (s, e) = (w.dim(0)?, w.dim(1)?); + let mut q = vec![0i32; dados.len()]; + let mut escala = vec![0f32; s]; + for i in 0..s { + let linha = &dados[i * e..(i + 1) * e]; + let amax = linha.iter().fold(0f32, |m, x| m.max(x.abs())); + let esc = (amax / 127.0).max(1e-12); + escala[i] = esc; + for j in 0..e { + let v = (linha[j] / esc).round().clamp(-128.0, 127.0); + q[i * e + j] = v as i32; + } + } + Ok(PesoInt8 { + q: Tensor::from_vec(q, (s, e), dev)?, + escala: Tensor::from_vec(escala, (s, 1), dev)?, + forma: vec![s, e], + }) +} + +/// y = x·Wᵀ desquantizado on-the-fly (por canal). +pub fn linear_int8(x: &Tensor, p: &PesoInt8, dev: &Device) -> Result { + let qf = p.q.to_dtype(candle_core::DType::F32)?; + let w = qf.broadcast_mul(&p.escala)?; // (s, e) + x.matmul(&w.transpose(0, 1)?) +} + +/// Paridade int8 vs f32 (V14-análogo do Teo 28.1): erro relativo médio. +pub fn paridade(w: &Tensor, x: &Tensor, dev: &Device) -> Result { + let p = quantizar_linha(w)?; + let y_q = linear_int8(x, &p, dev)?; + let y_f = x.matmul(&w.transpose(0, 1)?)?; + let dif = (&y_q - &y_f)?.abs()?.mean_all()?.to_scalar::()? as f64; + let ref_ = y_f.abs()?.mean_all()?.to_scalar::()? as f64; + Ok(dif / ref_.max(1e-9)) +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn paridade_int8_dentro_da_cota() -> Result<()> { + let dev = Device::Cpu; + let w = Tensor::randn(0f32, 0.05, (64, 32), &dev)?; + let x = Tensor::randn(0f32, 1f32, (4, 32), &dev)?; + let erro = paridade(&w, &x, &dev)?; + // cota empírica do Teo 28.1 (h/√12 por canal, |w| ≤ 0.05·3σ) + assert!(erro < 0.05, "erro relativo int8 = {erro}"); + Ok(()) + } +} diff --git a/src/quantizador.rs b/src/quantizador.rs new file mode 100644 index 0000000000000000000000000000000000000000..79d21728a7741da66751da5fbb0f705d818f8981 --- /dev/null +++ b/src/quantizador.rs @@ -0,0 +1,397 @@ +//! Quantizador GSQ por nível (Teos A.1/A.4/D.4) — o coração da ponte +//! NCM×KHTST: codebook Stiefel com seleção Gumbel-Softmax (gradiente exato, +//! sem STE) no treino e NN duro (argmax) em eval. +//! +//! Dois modos (r-01 §4.4): "gsq_rco" (padrão, Teo D.4 — relaxamento +//! diferenciável com τ-annealing) e "ste_ema" (Teo A.0 — STE + commitment + +//! codebook por EMA). A escala R_ℓ é mantida por EMA (Cor. A.1.1). + +use candle_core::{CpuStorage, CustomOp3, Device, Layout, Result, Shape, Tensor, Var, D}; +use crate::stiefel; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ModoQuant { + GsqRco, + SteEma, +} + +impl ModoQuant { + pub fn de_str(s: &str) -> ModoQuant { + if s == "ste_ema" { ModoQuant::SteEma } else { ModoQuant::GsqRco } + } +} + +/// CustomOp3: (z, C, ruído_gumbel) → r_suave = R·softmax((zCᵀ/τ + g))·C. +/// O ruído entra como tensor EXPLÍCITO (constante no grafo) para que o +/// backward recompute exatamente o mesmo y do forward (gradiente exato do +/// relaxamento — Teo A.4(iii), sem re-amostragem no adjunto). +pub struct GsqSuave { + pub r: f64, + pub tau: f64, +} + +fn softmax_ultima_dim(v: &[f32], n: usize, k: usize) -> Vec { + let mut out = vec![0f32; v.len()]; + for i in 0..n { + let linha = &v[i * k..(i + 1) * k]; + let mx = linha.iter().cloned().fold(f32::NEG_INFINITY, f32::max); + let mut soma = 0f32; + for (j, &x) in linha.iter().enumerate() { + let e = (x - mx).exp(); + out[i * k + j] = e; + soma += e; + } + for j in 0..k { + out[i * k + j] /= soma.max(1e-20); + } + } + out +} + +impl CustomOp3 for GsqSuave { + fn name(&self) -> &'static str { "gsq_suave_stiefel" } + + fn cpu_fwd( + &self, + s1: &CpuStorage, l1: &Layout, + _s2: &CpuStorage, _l2: &Layout, + s3: &CpuStorage, l3: &Layout, + ) -> Result<(CpuStorage, Shape)> { + if !(l1.is_contiguous() && _l2.is_contiguous() && l3.is_contiguous()) { + return Err(candle_core::Error::Msg( + "gsq_suave: tensors de entrada devem ser contíguos (chame .contiguous())".into(), + )); + } + let z = s1.as_slice::()?; + let (n, d) = (l1.shape().dims()[0], l1.shape().dims()[1]); + let c = _s2.as_slice::()?; + let (k, _dc) = (_l2.shape().dims()[0], _l2.shape().dims()[1]); + let ruido = s3.as_slice::()?; + debug_assert_eq!(ruido.len(), z.len() / d * k * d / d * k); // (n,k) + // logits = z·Cᵀ/τ + g + let mut logits = vec![0f32; n * k]; + for i in 0..n { + for j in 0..k { + let mut acc = 0f32; + for t in 0..d { + acc += z[i * d + t] * c[j * d + t]; + } + logits[i * k + j] = acc as f32 / self.tau as f32 + ruido[i * k + j]; + } + } + let y = softmax_ultima_dim(&logits, n, k); + // r = R · y·C + let mut r = vec![0f32; n * d]; + for i in 0..n { + for t in 0..d { + let mut acc = 0f32; + for j in 0..k { + acc += y[i * k + j] * c[j * d + t]; + } + r[i * d + t] = (self.r as f32) * acc; + } + } + Ok((CpuStorage::F32(r), (n, d).into())) + } + + fn bwd( + &self, + arg1: &Tensor, arg2: &Tensor, arg3: &Tensor, + _res: &Tensor, grad_res: &Tensor, + ) -> Result<(Option, Option, Option)> { + // recompute y (mesmo ruído — arg3): y = softmax(zCᵀ/τ + g) + let logits = (&arg1.matmul(&arg2.transpose(0, 1)?)?.affine(1.0 / self.tau, 0.0)? + arg3)?; + let y = candle_nn::ops::softmax_last_dim(&logits)?; + // gy = R·(g_·Cᵀ) + let gy = (&grad_res.matmul(&arg2.transpose(0, 1)?)? * self.r)?; + // gl = y ⊙ (gy − Σ(y⊙gy)) — media como coluna p/ broadcast (n,1) + let media = (&y * &gy)?.sum(D::Minus1)?; + let media_c = media.reshape((media.dims()[0], 1))?; + let gl = (&y * &gy.broadcast_sub(&media_c.broadcast_div(&ones_like(&media_c)?)?)?)?; + // ∂L/∂z = (1/τ)·gl·C ; ∂L/∂C = R·yᵀ·g_ ; ruído constante + let gz = gl.matmul(arg2)?.affine(1.0 / self.tau, 0.0)?; + let gc = (&y.transpose(0, 1)?.matmul(grad_res)? * self.r)?; + Ok((Some(gz), Some(gc), None)) + } +} + +fn ones_like(t: &Tensor) -> Result { + Tensor::ones(t.shape(), t.dtype(), t.device()) +} + +/// Quantizador de um nível ℓ do VQ residual. +pub struct QuantizadorNivel { + pub w: Var, // (K, d) bruto — codebook = R(Wᵀ)ᵀ + pub r_escala: f64, // R_ℓ (EMA) + pub tau: f64, // τ corrente (agenda analítica) + pub modo: ModoQuant, + pub ema: f64, // fator EMA (0,99) + pub escala_modo: String, // "ema_projecao" | "otima_teo" + pub iters_polar: usize, + pub delta_ort_ultimo: f64, + pub uso: Vec, // contagem de uso por código (telemetria/colapso) + pub semente: u64, // RNG dedicado do nível (pareamento — Teo 31.7) + chamadas: std::cell::Cell, // contador p/ ruído fresco por chamada +} + +impl QuantizadorNivel { + pub fn novo(k: usize, d: usize, modo: ModoQuant, ema: f64, escala_modo: &str, dev: &Device) -> Result { + let w0 = stiefel::init_stiefel(k, d, dev)?; + Ok(QuantizadorNivel { + w: Var::from_tensor(&w0)?, + r_escala: 1.0 / (k as f64).sqrt(), + tau: 1.0, + modo, + ema, + escala_modo: escala_modo.to_string(), + iters_polar: 30, + delta_ort_ultimo: 0.0, + uso: vec![0.0; k], + semente: 0xC0FFEE + k as u64 * 7919 + d as u64, + chamadas: std::cell::Cell::new(0), + }) + } + + /// Codebook C = R(Wᵀ)ᵀ com linhas ortonormais (diferenciável — Teo 26.3). + /// SEMPRE contíguo (index_select/arquivo exigem layout padrão). + pub fn codebook(&self) -> Result { + let c = stiefel::codebook_stiefel(self.w.as_tensor(), self.iters_polar)?; + c.contiguous() + } + + /// δ_ort do codebook corrente (V9). + pub fn delta_ort(&self) -> Result { + let c = self.codebook()?.detach(); + stiefel::erro_ortogonalidade(&c.transpose(0, 1)?) + } + + /// Amostra ruído de Gumbel (n, K) — fora do grafo (constante). + pub fn ruido_gumbel(&self, n: usize, k: usize, dev: &Device) -> Result { + use rand::prelude::*; + let mut rng = StdRng::seed_from_u64(self.semente_ruido()); + let mut v = Vec::with_capacity(n * k); + for _ in 0..n * k { + let u: f32 = rng.gen::().clamp(1e-9, 1.0 - 1e-9); + v.push((-(-u.ln()).ln()) as f32); + } + Tensor::from_vec(v, (n, k), dev) + } + + fn semente_ruido(&self) -> u64 { + let c = self.chamadas.get(); + self.chamadas.set(c + 1); + self.semente.wrapping_add(c.wrapping_mul(0x9E3779B97F4A7C15)) + } + + /// Quantização de TREINO (…, d) → (…, d): + /// - gsq_rco: relaxamento suave diferenciável (gradiente exato); + /// - ste_ema: STE (r = z + sg[r_duro − z]). + pub fn quantizar_treino(&self, z: &Tensor) -> Result { + let c = self.codebook()?.contiguous()?; + match self.modo { + ModoQuant::GsqRco => { + let z2 = contiguo_2d(z)?; + let (n, _d) = (z2.dims()[0], z2.dims()[1]); + let k = c.dims()[0]; + let ruido = self.ruido_gumbel(n, k, z.device())?; + let r = Tensor::apply_op3(&z2, &c, &ruido, GsqSuave { r: self.r_escala, tau: self.tau.max(1e-3) })?; + redimensionar_de_volta(&r, z) + } + ModoQuant::SteEma => { + let r_duro = self.valores_duros_int(z, &self.codebook()?.contiguous()?)?.detach(); + // STE: z + (r_duro − z) com r_duro constante no grafo + Ok(z.add(&r_duro.sub(z)?)?) + } + } + } + + fn valores_duros_int(&self, z: &Tensor, c: &Tensor) -> Result { + // c deve vir contíguo do caller (custom op exige layout padrão) + // ids = argmax ⟨z, u_k⟩ (Teo A.4(i): uma GEMM + top-1) + let z2 = contiguo_2d(z)?; + let logits = z2.matmul(&c.transpose(0, 1)?)?; + let ids = logits.argmax(D::Minus1)?; + let linhas = c.index_select(&ids, 0)?; + let r = linhas.affine(self.r_escala, 0.0)?; + redimensionar_de_volta(&r, z) + } + + /// Quantização DURA (eval/telemetria): (ids, valores R·c_id). + pub fn quantizar_duro(&self, z: &Tensor) -> Result<(Tensor, Tensor)> { + let c = self.codebook()?.detach(); + let z2 = contiguo_2d(z)?; + let logits = z2.matmul(&c.transpose(0, 1)?)?; + let ids = logits.argmax(D::Minus1)?; + let valores = self.valores_duros_int(z, &c)?; + Ok((ids, valores)) + } + + /// Materializa códigos ids → vetores R·c_id (para reconstrução na amostragem). + pub fn materializar(&self, ids: &Tensor) -> Result { + let c = self.codebook()?.detach(); + let linhas = c.index_select(&ids, 0)?; + Ok(linhas.affine(self.r_escala, 0.0)?) + } + + /// Atualiza R_ℓ por EMA da escala de projeção (Cor. A.1.1): + /// "ema_projecao": R ← EMA(E[‖P_C z‖]); "otima_teo": R ← EMA(E[‖P_C z‖/√K]). + pub fn atualizar_escala(&mut self, z: &Tensor) -> Result<()> { + let c = self.codebook()?.detach(); + let z2 = contiguo_2d(z)?; + let cz = z2.matmul(&c.transpose(0, 1)?)?; + let pz = cz.matmul(&c)?; + let alvo = pz.sqr()?.sum(D::Minus1)?.sqrt()?.mean_all()?.to_scalar::()? as f64; + let alvo = match self.escala_modo.as_str() { + "otima_teo" => alvo / (self.uso.len() as f64).sqrt(), + _ => alvo, + }; + self.r_escala = self.ema * self.r_escala + (1.0 - self.ema) * alvo.max(1e-4); + Ok(()) + } + + /// Registra uso de códigos (telemetria de colapso — R2 do n-04 §9). + pub fn registrar_uso(&mut self, ids: &Tensor) -> Result<()> { + let v = ids.flatten_all()?.to_vec1::()?; + for id in v { + if (id as usize) < self.uso.len() { + self.uso[id as usize] += 1.0; + } + } + Ok(()) + } + + /// Perplexidade de uso do codebook (utilização efetiva de K — telemetria V2/V6). + pub fn perplexidade_uso(&self) -> f64 { + let total: f64 = self.uso.iter().sum(); + if total <= 0.0 { + return 0.0; + } + let h: f64 = self.uso.iter().map(|&u| { + let p = u / total; + if p > 0.0 { -p * p.ln() } else { 0.0 } + }).sum(); + h.exp() + } + + /// Agenda analítica de τ (Teo 30.6): decaimento de τ0 até τ_min em t_alvo passos. + pub fn agendar_tau(&mut self, passo: usize, tau0: f64, tau_min: f64, t_alvo: usize) { + let t = passo.min(t_alvo) as f64; + let tau = tau_min + (tau0 - tau_min) * (1.0 - t / t_alvo.max(1) as f64); + self.tau = tau.max(tau_min); + } +} + +// ---------- utilidades de forma ---------- + +/// Achata (…, d) → (n, d) e devolve também a forma original. +fn contiguo_2d(t: &Tensor) -> Result { + let d = t.dim(D::Minus1)?; + let n = t.elem_count() / d; + t.reshape((n, d))?.contiguous() +} + +fn redimensionar_de_volta(r: &Tensor, modelo: &Tensor) -> Result { + r.reshape(modelo.shape()) +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn gsq_gradiente_vs_finitas_diferencas() -> Result<()> { + // V-análogo do V8: gradiente exato do relaxamento vs. FD + let dev = Device::Cpu; + let mut q = QuantizadorNivel::novo(8, 6, ModoQuant::GsqRco, 0.99, "ema_projecao", &dev)?; + q.tau = 1.0; + q.r_escala = 0.7; + let z = Tensor::randn(0f32, 1f32, (5, 6), &dev)?; + let z2 = contiguo_2d(&z)?; + let c = q.codebook()?.contiguous()?; + let ruido = q.ruido_gumbel(5, 8, &dev)?; + // valor da perda com pesos fixos + let pesos = Tensor::randn(0f32, 1f32, (5, 6), &dev)?; + let perda = |zz: &Tensor| -> Result { + let r = Tensor::apply_op3(zz, &c, &ruido, GsqSuave { r: q.r_escala, tau: q.tau })?; + let l = (&r * &pesos)?.sum_all()?; + Ok(l.to_scalar::()? as f64) + }; + // gradiente via op (aplicado a Var) + let zv = Var::from_tensor(&z2)?; + let r = Tensor::apply_op3(zv.as_tensor(), &c, &ruido, GsqSuave { r: q.r_escala, tau: q.tau })?; + let l = (&r * &pesos)?.sum_all()?; + let gs = l.backward()?; + let g = gs.get(&zv).ok_or_else(|| candle_core::Error::Msg("sem gradiente".into()))?; + let gv = g.flatten_all()?.to_vec1::()?; + // FD central + let eps = 1e-3f32; + let mut erro_max = 0f64; + for i in 0..z2.elem_count() { + let mut zp = z2.flatten_all()?.to_vec1::()?; + let mut zm = zp.clone(); + zp[i] += eps; + zm[i] -= eps; + let tp = Tensor::from_vec(zp, (5, 6), &dev)?; + let tm = Tensor::from_vec(zm, (5, 6), &dev)?; + let fd = (perda(&tp)? - perda(&tm)?) / (2.0 * eps as f64); + erro_max = erro_max.max((fd - gv[i] as f64).abs()); + } + assert!(erro_max < 5e-3, "erro máx FD vs exato = {erro_max}"); + Ok(()) + } + + #[test] + fn perplexidade_uso_reflete_histograma() { + let mut q = QuantizadorNivel { + w: Var::from_tensor(&Tensor::zeros((4, 4), candle_core::DType::F32, &Device::Cpu).unwrap()).unwrap(), + r_escala: 1.0, tau: 1.0, modo: ModoQuant::GsqRco, ema: 0.99, + escala_modo: "ema_projecao".into(), iters_polar: 10, delta_ort_ultimo: 0.0, + uso: vec![10.0, 10.0, 10.0, 10.0], + semente: 7, + chamadas: std::cell::Cell::new(0), + }; + let p = q.perplexidade_uso(); + assert!((p - 4.0).abs() < 1e-9); + q.uso = vec![40.0, 0.0, 0.0, 0.0]; + assert!(q.perplexidade_uso() < 1.01); + } +} + +#[cfg(test)] +mod testes_debug { + use super::*; + use candle_core::{Device, Var}; + + /// Compara o adjunto do GsqSuave contra implementação nativa (ops candle). + #[test] + fn gsq_bwd_vs_nativo() -> Result<()> { + let dev = Device::Cpu; + let (n, d, k) = (5usize, 6, 8); + let c0 = stiefel::init_stiefel(k, d, &dev)?.contiguous()?; + let zv = Var::from_tensor(&Tensor::randn(0f32, 1f32, (n, d), &dev)?)?; + let ruido = Tensor::randn(0f32, 1f32, (n, k), &dev)?; + let pesos = Tensor::randn(0f32, 1f32, (n, d), &dev)?; + let (r_op, tau) = (0.7f64, 1.3f64); + // caminho NATIVO + let logits_n = (zv.as_tensor().matmul(&c0.transpose(0, 1)?)?.affine(1.0 / tau, 0.0)? + &ruido)?; + let y_n = candle_nn::ops::softmax(&logits_n, candle_core::D::Minus1)?; + let r_n = y_n.matmul(&c0)?.affine(r_op, 0.0)?; + let l_n = (&r_n * &pesos)?.sum_all()?; + let gs_n = l_n.backward()?; + let g_n = gs_n.get(&zv).unwrap().flatten_all()?.to_vec1::()?; + // caminho OP + let r_o = Tensor::apply_op3(zv.as_tensor(), &c0, &ruido, GsqSuave { r: r_op, tau })?; + let l_o = (&r_o * &pesos)?.sum_all()?; + let gs_o = l_o.backward()?; + let g_o = gs_o.get(&zv).unwrap().flatten_all()?.to_vec1::()?; + // forward deve ser idêntico + let dif_fwd = (&r_n - &r_o)?.abs()?.max_all()?.to_scalar::()?; + assert!(dif_fwd < 1e-5, "forward difere: {dif_fwd}"); + let mut erro = 0f64; + for i in 0..g_n.len() { + erro = erro.max((g_n[i] - g_o[i]).abs() as f64); + } + assert!(erro < 1e-4, "grad nativo vs op = {erro}\n n={g_n:?}\n o={g_o:?}"); + Ok(()) + } +} diff --git a/src/ssd.rs b/src/ssd.rs new file mode 100644 index 0000000000000000000000000000000000000000..87cc8f3e3181d7410e1dd90b13d118cb9f14183d --- /dev/null +++ b/src/ssd.rs @@ -0,0 +1,183 @@ +//! Slot Mamba-3 (1-de-6 do tronco 5:1) — scan recorrente diagonal seletivo +//! (SSD) com adjunto EXATO via CustomOp2. Compatível com o Teo D.1(i): +//! fluxo estritamente esquerda→direita (a camada é causal por construção); +//! a bidirecionalidade intra-nível vem das camadas ADBA (H_D1 — r-04 §3). +//! +//! Recorrência: h_t = a_t ⊙ h_{t−1} + (1 − a_t) ⊙ x_t; y_t = h_t +//! com a_t = σ(W_a·x_t + b_a) ∈ (0,1)^d (portas por canal). +//! +//! Adjunto (exato): dh_t = dy_t + a_{t+1} ⊙ dh_{t+1}; +//! dx_t = (1 − a_t) ⊙ dh_t; da_t = ⟨dh_t, h_{t−1} − x_t⟩ (escalar por canal). + +use candle_core::{CpuStorage, CustomOp2, Device, Layout, Result, Shape, Tensor, Var}; +use crate::camadas::{Linear, RmsNorm, Swiglu}; + +pub struct ScanDiagonal; + +impl CustomOp2 for ScanDiagonal { + fn name(&self) -> &'static str { "ssd_scan_diagonal" } + + fn cpu_fwd(&self, s1: &CpuStorage, l1: &Layout, s2: &CpuStorage, l2: &Layout) -> Result<(CpuStorage, Shape)> { + if !(l1.is_contiguous() && l2.is_contiguous()) { + return Err(candle_core::Error::Msg( + "ssd_scan: entradas devem ser contíguas (chame .contiguous())".into(), + )); + } + let x = s1.as_slice::()?; // (n, d) + let a = s2.as_slice::()?; // (n, d) em (0,1) + let (n, d) = (l1.shape().dims()[0], l1.shape().dims()[1]); + let mut y = vec![0f32; n * d]; + for j in 0..d { + let mut h = 0f32; + for i in 0..n { + let ai = a[i * d + j]; + h = ai * h + (1.0 - ai) * x[i * d + j]; + y[i * d + j] = h; + } + } + Ok((CpuStorage::F32(y), (n, d).into())) + } + + fn bwd(&self, arg1: &Tensor, arg2: &Tensor, _res: &Tensor, grad_res: &Tensor) -> Result<(Option, Option)> { + // recomputa h (forward sem gradiente) e percorre reverso + let (x, a) = (arg1, arg2); + let h = Tensor::apply_op2(x, a, ScanDiagonal)?.detach(); + let x_v = x.flatten_all()?.to_vec1::()?; + let a_v = a.flatten_all()?.to_vec1::()?; + let h_v = h.flatten_all()?.to_vec1::()?; + let dy_v = grad_res.flatten_all()?.to_vec1::()?; + let (n, d) = (x.dim(0)?, x.dim(1)?); + let mut dx = vec![0f32; n * d]; + let mut da = vec![0f32; n * d]; + let mut dh = vec![0f32; d]; + for i in (0..n).rev() { + for j in 0..d { + let idx = i * d + j; + let g = dy_v[idx] + dh[j]; + dx[idx] = (1.0 - a_v[idx]) * g; + let h_ant = if i > 0 { h_v[(i - 1) * d + j] } else { 0.0 }; + da[idx] = g * (h_ant - x_v[idx]); + dh[j] = a_v[idx] * g; + } + } + let dev = x.device(); + let gx = Tensor::from_vec(dx, (n, d), dev)?; + let ga = Tensor::from_vec(da, (n, d), dev)?; + Ok((Some(gx), Some(ga))) + } +} + +/// Bloco SSD (a camada recorrente do tronco): portas por canal + scan + projeção. +pub struct BlocoSsd { + pub norm1: RmsNorm, + pub porta_a: Linear, // d → d (logitas do decaimento) + pub proj_x: Linear, // d → d + pub proj_o: Linear, // d → d + pub norm2: RmsNorm, + pub ffn: Swiglu, +} + +impl BlocoSsd { + pub fn novo(d: usize, d_ff: usize, dev: &Device) -> Result { + let desvio = 1.0 / ((d * 2) as f64).sqrt(); + Ok(BlocoSsd { + norm1: RmsNorm::novo(d, 1e-5, dev)?, + porta_a: Linear::novo(d, d, desvio, dev)?, + proj_x: Linear::sem_vies(d, d, desvio, dev)?, + proj_o: Linear::sem_vies(d, d, desvio, dev)?, + norm2: RmsNorm::novo(d, 1e-5, dev)?, + ffn: Swiglu::novo(d, d_ff, dev)?, + }) + } + + /// x (b, n, d) → (b, n, d). O scan é aplicado por elemento do lote. + /// `cache_estado`: estado h anterior (b, d) para streaming incremental. + pub fn fwd(&self, x: &Tensor, cache_estado: &mut Option) -> Result { + let b = x.dim(0)?; + let n = x.dim(1)?; + let d = x.dim(2)?; + let xb = self.norm1.fwd(x)?; + let a = candle_nn::ops::sigmoid(&self.porta_a.fwd(&xb)?)?; + let xp = self.proj_x.fwd(&xb)?; + // achata (b·n, d), aplica o scan por lote e recompõe + let xf = xp.reshape((b * n, d))?.contiguous()?; + let af = a.reshape((b * n, d))?.contiguous()?; + // pré-estado: se houver cache, subtrai efeito — simplificação: scan + // independente por segmento com estado inicial zero (documentado; o + // estado cruzado entre segmentos é ponto de extensão do streaming). + let _ = cache_estado; + let mut saidas = Vec::with_capacity(b); + for i in 0..b { + let xi = xf.narrow(0, i * n, n)?; + let ai = af.narrow(0, i * n, n)?; + let yi = Tensor::apply_op2(&xi, &ai, ScanDiagonal)?; + saidas.push(yi); + } + let y = Tensor::cat(&saidas, 0)?.reshape((b, n, d))?; + let y = self.proj_o.fwd(&y)?; + let x2 = (x + &y)?; + let f = self.ffn.fwd(&self.norm2.fwd(&x2)?)?; + (&x2 + &f) + } + + pub fn vars(&self) -> Vec { + [ + self.norm1.vars(), self.porta_a.vars(), self.proj_x.vars(), + self.proj_o.vars(), self.norm2.vars(), self.ffn.vars(), + ].concat() + } +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn adjunto_do_scan_vs_finitas_diferencas() -> Result<()> { + let dev = Device::Cpu; + let n = 9; + let d = 5; + let xv = Var::from_tensor(&Tensor::randn(0f32, 1f32, (n, d), &dev)?)?; + let av = Var::from_tensor(&candle_nn::ops::sigmoid(&Tensor::randn(0f32, 1f32, (n, d), &dev)?)?)?; + let pesos = Tensor::randn(0f32, 1f32, (n, d), &dev)?; + let y = Tensor::apply_op2(xv.as_tensor(), &av.as_tensor(), ScanDiagonal)?; + let perda = (&y * &pesos)?.sum_all()?; + let gs = perda.backward()?; + let gx = gs.get(&xv).ok_or_else(|| candle_core::Error::Msg("sem grad x".into()))?; + let ga = gs.get(&av).ok_or_else(|| candle_core::Error::Msg("sem grad a".into()))?; + let gxv = gx.flatten_all()?.to_vec1::()?; + let gav = ga.flatten_all()?.to_vec1::()?; + // FD + let eps = 1e-3f32; + let f = |x: &Tensor, a: &Tensor| -> Result { + let y = Tensor::apply_op2(x, a, ScanDiagonal)?; + Ok((&y * &pesos)?.sum_all()?.to_scalar::()? as f64) + }; + let x0 = xv.as_tensor(); + let a0 = av.as_tensor(); + let x_plano = x0.flatten_all()?.to_vec1::()?; + let a_plano = a0.flatten_all()?.to_vec1::()?; + let mut erro = 0f64; + for idx in [3usize, 11, 17, 24, 30] { + let mut xp = x_plano.clone(); + let mut xm = x_plano.clone(); + xp[idx] += eps; + xm[idx] -= eps; + let tp = Tensor::from_vec(xp, (n, d), &dev)?; + let tm = Tensor::from_vec(xm, (n, d), &dev)?; + let fd = (f(&tp, a0)? - f(&tm, a0)?) / (2.0 * eps as f64); + erro = erro.max((fd - gxv[idx] as f64).abs()); + // porta a + let mut ap = a_plano.clone(); + let mut am = a_plano.clone(); + ap[idx] += eps; + am[idx] -= eps; + let tap = Tensor::from_vec(ap, (n, d), &dev)?; + let tam = Tensor::from_vec(am, (n, d), &dev)?; + let fda = (f(x0, &tap)? - f(x0, &tam)?) / (2.0 * eps as f64); + erro = erro.max((fda - gav[idx] as f64).abs()); + } + assert!(erro < 5e-3, "erro adjunto SSD = {erro}"); + Ok(()) + } +} diff --git a/src/stiefel.rs b/src/stiefel.rs new file mode 100644 index 0000000000000000000000000000000000000000..6a25c20503d18baa87c5e1955d8a4011c06032b1 --- /dev/null +++ b/src/stiefel.rs @@ -0,0 +1,160 @@ +//! Stiefel/RCO — porta do `quanta/gsq_rco.py` (docs 26–27; Teos A.1/A.4/D.4). +//! +//! - `projeta_tangente_stiefel(X, G) = G − X·sym(XᵀG)` (eq. 26.2, Teo 26.2); +//! - retração: **polar Newton–Schulz** (sem LAPACK; equivalente ao QR/SVD pelo +//! Teo 26.8-b — Y = fator polar de X, YᵀY = I até δ ≤ ~1e-6 em f32); +//! - backward = gradiente riemanniano projetado no tangente (Teo 26.3: adjunto +//! exato no tangente); +//! - `erro_ortogonalidade δ(X) = ‖XᵀX − I‖_F` (eq. 26.7) — monitor V9 (≤ 3e-6). + +use candle_core::{CpuStorage, CustomOp1, Device, Layout, Result, Shape, Tensor}; + +/// Projeção no espaço tangente de St(n,p) na métrica euclidiana embarcada. +/// P_X(G) = G − X·sym(XᵀG) com sym(A) = (A+Aᵀ)/2. (eq. 26.2) +pub fn projeta_tangente_stiefel(x: &Tensor, g: &Tensor) -> Result { + let xtg = x.transpose(0, 1)?.matmul(g)?; + let sim = (&xtg + &xtg.transpose(0, 1)?)?.affine(0.5, 0.0)?; + g.sub(&x.matmul(&sim)?) +} + +/// Uma iteração Newton–Schulz: Y ← ½·Y·(3I − YᵀY). +fn passo_ns(y: &Tensor) -> Result { + let n = y.dim(1)?; + let yty = y.transpose(0, 1)?.matmul(y)?; + let ident = Tensor::eye(n, y.dtype(), y.device())?; + let inner = ident.affine(3.0, 0.0)?.sub(&yty)?.affine(0.5, 0.0)?; + y.matmul(&inner) +} + +/// Norma espectral aproximada por iteração de potência (para escalar X antes +/// do Newton–Schulz — condição de convergência σ_max < √3). +fn norma_espectral_aprox(x: &Tensor, iters: usize) -> Result { + // iteração de potência SIMÉTRICA: u = Xv; v = Xᵀu; σ² ≈ ‖Xᵀu‖² + // (mantém v em (p,1) — o produto alternado preserva a dimensão) + let p = x.dims()[1]; + let xt = x.transpose(0, 1)?; + let mut v = Tensor::randn(0f32, 1f32, (p, 1), x.device())?; + let mut lam = 1f64; + for _ in 0..iters { + let nv = v.sqr()?.sum_all()?.to_scalar::()?.sqrt(); + if nv < 1e-12 { + return Ok(1.0); + } + let u = x.matmul(&v.affine(1.0 / nv as f64, 0.0)?)?; // (n,1) + let nu = u.sqr()?.sum_all()?.to_scalar::()?.sqrt(); + if nu < 1e-12 { + return Ok(1.0); + } + let w = xt.matmul(&u.affine(1.0 / nu as f64, 0.0)?)?; // (p,1) + lam = w.sqr()?.sum_all()?.to_scalar::()? as f64; + let nw = lam.sqrt().max(1e-12); + v = w.affine(1.0 / nw, 0.0)?; + } + Ok(lam.max(1.0)) +} + +/// Retração polar: Y = polar(X) com colunas ortonormais (St(n,p)). +/// Newton–Schulz escalado: X₀ = X/σ_max, X_{k+1} = ½X_k(3I − X_kᵀX_k); +/// converge quadrática perto do polar; ~30 iterações dão δ_ort ≤ ~1e-6 (f32). +pub fn retrair_polar(x: &Tensor, iters: usize) -> Result { + let sigma = norma_espectral_aprox(x, 12)?.sqrt(); + let mut y = x.affine(1.0 / sigma, 0.0)?; + for _ in 0..iters { + y = passo_ns(&y)?; + } + Ok(y) +} + +/// δ(X) = ‖XᵀX − I‖_F (eq. 26.7). +pub fn erro_ortogonalidade(x: &Tensor) -> Result { + let n = x.dim(1)?; + let xtx = x.transpose(0, 1)?.matmul(x)?; + let ident = Tensor::eye(n, x.dtype(), x.device())?; + let d = xtx.sub(&ident)?; + let fro = d.sqr()?.sum_all()?.to_scalar::()? as f64; + Ok(fro.sqrt()) +} + +/// CustomOp diferenciável: forward = retração polar; backward = projeção da +/// tangente no ponto de saída (gradiente riemanniano — Teo 26.3). +pub struct RetracaoStiefel { + pub iters: usize, +} + +impl CustomOp1 for RetracaoStiefel { + fn name(&self) -> &'static str { "retracao_stiefel_polar" } + + fn cpu_fwd(&self, storage: &CpuStorage, layout: &Layout) -> Result<(CpuStorage, Shape)> { + if !layout.is_contiguous() { + return Err(candle_core::Error::Msg( + "retracao_stiefel: entrada deve ser contígua (chame .contiguous())".into(), + )); + } + let dados = storage.as_slice::()?; + let (n, p) = (layout.shape().dims()[0], layout.shape().dims()[1]); + // converte para candle, usa o caminho polar (CPU), devolve CpuStorage + let dev = Device::Cpu; + let x = Tensor::from_vec(dados.to_vec(), (n, p), &dev)?; + let y = retrair_polar(&x, self.iters)?; + let v = y.flatten_all()?.to_vec1::()?; + let storage_out = CpuStorage::F32(v); + Ok((storage_out, (n, p).into())) + } + + fn bwd(&self, _arg: &Tensor, res: &Tensor, grad_res: &Tensor) -> Result> { + // adjunto: gradiente riemanniano no ponto Y = R(X) (Teo 26.3) + Ok(Some(projeta_tangente_stiefel(res, grad_res)?)) + } +} + +/// Matriz de codebook com linhas ortonormais: C = R(Wᵀ)ᵀ (port de +/// `QuantizadorGSQRF::codebook`). W ∈ R^{K×d} é o parâmetro bruto. +pub fn codebook_stiefel(w: &Tensor, iters: usize) -> Result { + // a custom op exige layout padrão — materializa a transposta + let wt = w.transpose(0, 1)?.contiguous()?; + let q = wt.apply_op1(RetracaoStiefel { iters })?; + Ok(q.transpose(0, 1)?) +} + +/// Inicialização: linhas ortonormais via polar de gaussiana (nasce em St(d,K)). +pub fn init_stiefel(k: usize, d: usize, dev: &Device) -> Result { + let g = Tensor::randn(0f32, 1f32, (k, d), dev)?; + let wt = g.transpose(0, 1)?; + let q = retrair_polar(&wt, 40)?; + Ok(q.transpose(0, 1)?) +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn polar_ortogonaliza() -> Result<()> { + let dev = Device::Cpu; + // C = R(Wᵀ)ᵀ tem LINHAS ortonormais; erro_ortogonalidade espera + // colunas — transpõe (mesma convenção do gsq_rco.py: δ(R(Wᵀ))) + let c = init_stiefel(16, 32, &dev)?; + let delta = erro_ortogonalidade(&c.transpose(0, 1)?)?; + assert!(delta < 3e-6, "δ_ort = {delta}"); + // projeção da tangente no ponto de colunas ortonormais (cᵀ) + let g = Tensor::randn(0f32, 1f32, (32, 16), &dev)?; + let p = projeta_tangente_stiefel(&c.transpose(0, 1)?, &g)?; + let _ = p; + Ok(()) + } + + #[test] + fn gradiente_riemanniano_e_tangente() -> Result<()> { + let dev = Device::Cpu; + // X (n,p) com colunas ortonormais + let x = retrair_polar(&Tensor::randn(0f32, 1f32, (24, 8), &dev)?, 40)?; + let g = Tensor::randn(0f32, 1f32, (24, 8), &dev)?; + let p = projeta_tangente_stiefel(&x, &g)?; + // XᵀP + PᵀX ≈ 0 (Teo 26.2) + let a = x.transpose(0, 1)?.matmul(&p)?; + let soma = (&a + &a.transpose(0, 1)?)?; + let m = soma.abs()?.max_all()?.to_scalar::()?; + assert!(m < 1e-4, "resíduo tangente = {m}"); + Ok(()) + } +} diff --git a/src/telemetria.rs b/src/telemetria.rs new file mode 100644 index 0000000000000000000000000000000000000000..5086ecf4837bdb0b4a50b0732c816d8d1874f5d2 --- /dev/null +++ b/src/telemetria.rs @@ -0,0 +1,180 @@ +//! Telemetria completa (pedido do usuário: "realize todo tipo de telemetria +//! inclusive para a detecção de aprendizado do modelo e dos ajustes +//! automatizados de todos hiper parâmetros e demais necessários para ajustes +//! e correções e detecção de erros"). +//! +//! Hub em Rust com: buffer por passo; exportação JSONL; detecção de +//! aprendizado (escore composto); eventos de ajuste automático (auditáveis); +//! eventos de erro com classificação de causa comum (diagnostico.rs); +//! séries expostas ao Python como arrays numpy. + +use serde::Serialize; +use std::collections::BTreeMap; +use std::io::Write; + +#[derive(Debug, Clone, Serialize)] +pub struct EventoAjuste { + pub passo: usize, + pub parametro: String, + pub de: f64, + pub para: f64, + pub motivo: String, +} + +#[derive(Debug, Clone, Serialize)] +pub struct EventoErro { + pub passo: usize, + pub modulo: String, + pub mensagem: String, + pub causa_provavel: String, + pub correcao_sugerida: String, +} + +#[derive(Default)] +pub struct TelemetryHub { + /// séries nomeadas por passo + pub series: BTreeMap>, + pub eventos_ajuste: Vec, + pub eventos_erro: Vec, + pub caminho_jsonl: Option, + pub passo_corrente: usize, +} + +impl TelemetryHub { + pub fn novo(caminho_jsonl: Option) -> Self { + if let Some(p) = &caminho_jsonl { + if let Some(dir) = std::path::Path::new(p).parent() { + let _ = std::fs::create_dir_all(dir); + } + // truncates no início da corrida + let _ = std::fs::File::create(p); + } + TelemetryHub { caminho_jsonl, ..Default::default() } + } + + pub fn registrar(&mut self, nome: &str, valor: f64) { + self.series.entry(nome.to_string()).or_default().push((self.passo_corrente, valor)); + } + + pub fn registrar_multi(&mut self, pares: &[(&str, f64)]) { + for (n, v) in pares { + self.registrar(n, *v); + } + } + + pub fn ajuste(&mut self, parametro: &str, de: f64, para: f64, motivo: &str) { + let ev = EventoAjuste { + passo: self.passo_corrente, + parametro: parametro.to_string(), + de, + para, + motivo: motivo.to_string(), + }; + log::info!("ajuste: {} {:.4e}→{:.4e} ({})", parametro, de, para, motivo); + self.append_jsonl("ajuste", &ev); + self.eventos_ajuste.push(ev); + } + + pub fn erro(&mut self, modulo: &str, mensagem: &str) { + let causas = crate::diagnostico::classificar_erro(mensagem); + let (causa, correcao, _) = causas + .first() + .copied() + .unwrap_or(( + "não classificado", + "inspecionar mensagem completa; se recente à refatoração, suspeitar primeiro de digitação/renomeação", + "fallback", + )); + let ev = EventoErro { + passo: self.passo_corrente, + modulo: modulo.to_string(), + mensagem: mensagem.to_string(), + causa_provavel: causa.to_string(), + correcao_sugerida: correcao.to_string(), + }; + self.append_jsonl("erro", &ev); + self.eventos_erro.push(ev); + } + + fn append_jsonl(&self, tipo: &str, ev: &T) { + if let Some(p) = &self.caminho_jsonl { + if let Ok(mut f) = std::fs::OpenOptions::new().create(true).append(true).open(p) { + let _ = writeln!(f, "{{\"tipo\":\"{tipo}\",\"dados\":{}}}", + serde_json::to_string(ev).unwrap_or_default()); + } + } + } + + /// EMA de uma série (para suavização exponencial nos detectores). + pub fn ema(&self, nome: &str, alfa: f64) -> Option { + let s = self.series.get(nome)?; + let mut acc = s[0].1; + for (_, v) in &s[1..] { + acc = alfa * v + (1.0 - alfa) * acc; + } + Some(acc) + } + + /// Inclinação da EMA nos últimos k passos (detecção de aprendizado). + pub fn inclinacao_ema(&self, nome: &str, k: usize, alfa: f64) -> Option { + let s = self.series.get(nome)?; + if s.len() < 2 { return None; } + let ini = s.len().saturating_sub(k); + let mut acc_ini = s[ini].1; + for (_, v) in &s[ini + 1..] { + acc_ini = alfa * v + (1.0 - alfa) * acc_ini; + } + let mut acc_fim = s[0].1; + for (_, v) in &s[1..] { + acc_fim = alfa * v + (1.0 - alfa) * acc_fim; + } + let passos = (s.len() - ini) as f64; + Some((acc_fim - acc_ini) / passos) + } + + /// Escore de aprendizado composto em [0,1]: sinal = inclinação negativa da + /// perda (EMA) + nível absoluto relativo ao inicial + saúde do codebook. + pub fn escore_aprendizado(&self) -> f64 { + let Some(perda) = self.series.get("perda") else { return 0.0 }; + if perda.len() < 4 { return 0.0; } + let p0 = perda.iter().map(|(_, v)| *v).fold(f64::INFINITY, f64::min); + let pl = perda.last().map(|(_, v)| *v).unwrap_or(p0); + let reducao = ((p0 - pl) / p0.max(1e-9)).clamp(0.0, 1.0); + let incl = self.inclinacao_ema("perda", 64, 0.05).unwrap_or(0.0); + let sinal = (-incl * 1000.0).clamp(-1.0, 1.0) * 0.5 + 0.5; + // saúde do codebook (se medida): perplexidade relativa + let saude = self.series.get("codebook_perplexidade_media").and_then(|s| s.last().map(|(_, v)| *v)).unwrap_or(1.0); + let saude_n = (saude / 16.0).clamp(0.0, 1.0); // K=64: perplexidade 16+ = saudável + 0.45 * reducao + 0.35 * sinal + 0.20 * saude_n + } + + /// Dump completo (para o relatório Python). + pub fn dump(&self) -> serde_json::Value { + let series: serde_json::Map = self + .series + .iter() + .map(|(k, v)| { + ( + k.clone(), + serde_json::Value::Array( + v.iter().map(|(p, x)| serde_json::json!([p, x])).collect(), + ), + ) + }) + .collect(); + serde_json::json!({ + "series": series, + "eventos_ajuste": self.eventos_ajuste, + "eventos_erro": self.eventos_erro, + "escore_aprendizado": self.escore_aprendizado(), + }) + } + + /// Últimos valores de todas as séries (snapshot para callback Python). + pub fn instantaneo(&self) -> Vec<(String, f64)> { + self.series + .iter() + .filter_map(|(k, v)| v.last().map(|(_, x)| (k.clone(), *x))) + .collect() + } +} diff --git a/src/tokenizador.rs b/src/tokenizador.rs new file mode 100644 index 0000000000000000000000000000000000000000..704a37efb51f623ea7f165b9b24a465b9d6c129b --- /dev/null +++ b/src/tokenizador.rs @@ -0,0 +1,441 @@ +//! Tokenizador de conceitos NCM (Estágio 1 / fase A) — port de +//! `conceitos/tokenizador_conceitos.py` (n-04 §2.3) com a síntese GSQ+RCO +//! (Teo D.4): codebooks Stiefel por nível, seleção GSQ (gradiente exato), +//! nested dropout (Teo A.2), commitment (Teo A.0) e reconstrução por CE +//! token-level no vocabulário. +//! +//! Recursão residual (n-02 §0): +//! z_1 = Interp_{n_1}(E(x)); r_ℓ = Quant_{C_ℓ}(z_ℓ); +//! z_{ℓ+1} = Interp_{n_{ℓ+1}}(z_ℓ) − Interp_{n_{ℓ+1}}(r_ℓ); +//! ẑ_ℓ = Σ_{j≤ℓ} Interp_{n_ℓ}(r_j) (reconstrução cumulativa) + +use candle_core::{Device, Result, Tensor, Var, D}; +use crate::atencao::BlocoAdba; +use crate::camadas::{Embedding, Linear, RmsNorm}; +use crate::config::ConfigKhtst; +use crate::mascaras::{interp_para, matriz_interp}; +use crate::quantizador::{ModoQuant, QuantizadorNivel}; +use rand::prelude::*; + +pub struct TokenizadorConceitos { + // Encoder (treino apenas; atenção plena) + pub enc_emb: Embedding, + pub enc_blocos: Vec, + pub enc_norm: RmsNorm, + // Projeções por nível d_modelo → d_lat + quantizadores Stiefel/GSQ + pub proj_niveis: Vec, + pub quants: Vec, + // Decoder AR condicionado em ẑ (B.1: p_ψ(x|c) = Π_i p(x_i|x_{, + pub dec_norm: RmsNorm, + pub dec_head: Linear, + // máscaras pré-computadas + pub mascara_causal_dec: Tensor, + pub niveis: Vec, + pub d_lat: usize, + pub vocab: usize, + pub cfg_ncm_beta_commit: f64, + pub modo: ModoQuant, +} + +/// Saída da codificação: códigos por nível + reconstruções cumulativas. +pub struct Codigos { + pub ids: Vec, // u32 (b, n_ℓ) + pub zhats: Vec, // (b, n_ℓ, d_lat) — ẑ_ℓ na granularidade do nível +} + +impl TokenizadorConceitos { + pub fn novo(cfg: &ConfigKhtst, dev: &Device) -> Result { + let m = &cfg.modelo; + let n = &cfg.ncm; + let l = n.niveis.len(); + let n_total_dec = m.comprimento_ctx; + let mascara_causal_dec = causal_aditiva(n_total_dec, dev)?; + let mut enc_blocos = Vec::new(); + let mut dec_blocos = Vec::new(); + for _ in 0..2 { + enc_blocos.push(BlocoAdba::novo(m.d_modelo, m.n_cabecas, m.d_ff, l, false, false, false, dev)?); + dec_blocos.push(BlocoAdba::novo(m.d_modelo, m.n_cabecas, m.d_ff, l, false, false, false, dev)?); + } + let modo = ModoQuant::de_str(&n.modo_quantizacao); + let mut quants = Vec::with_capacity(l); + for _ in 0..l { + quants.push(QuantizadorNivel::novo(n.k_por_nivel, n.d_lat, modo, n.ema_codebook, &n.escala_r, dev)?); + } + let mut proj = Vec::with_capacity(l); + for _ in 0..l { + proj.push(Linear::sem_vies(m.d_modelo, n.d_lat, 0.02, dev)?); + } + Ok(TokenizadorConceitos { + enc_emb: Embedding::novo(m.vocab, m.d_modelo, dev)?, + enc_blocos, + enc_norm: RmsNorm::novo(m.d_modelo, 1e-5, dev)?, + proj_niveis: proj, + quants, + dec_proj: Linear::sem_vies(n.d_lat, m.d_modelo, 0.02, dev)?, + dec_emb: Embedding::novo(m.vocab, m.d_modelo, dev)?, + dec_blocos, + dec_norm: RmsNorm::novo(m.d_modelo, 1e-5, dev)?, + dec_head: Linear::sem_vies(m.d_modelo, m.vocab, 0.02, dev)?, + mascara_causal_dec, + niveis: n.niveis.clone(), + d_lat: n.d_lat, + vocab: m.vocab, + cfg_ncm_beta_commit: n.beta_commit, + modo, + }) + } + + /// Encoder: x (b, N) → z (b, N, d_modelo). Atenção plena (só treino). + pub fn encoder(&self, ids: &Tensor) -> Result { + let mut x = self.enc_emb.fwd(ids)?; + for bloco in &self.enc_blocos { + let mut cache = Default::default(); + x = bloco.fwd(&x, None, &mut cache, None, None)?; + } + self.enc_norm.fwd(&x) + } + + /// Codificação de TREINO (fase A): relaxamento GSQ suave diferenciável. + /// Devolve (zhats_suaves, zs_por_nivel) para a perda e telemetria. + fn codificar_treino(&mut self, ids: &Tensor) -> Result<(Vec, Vec)> { + let dev = ids.device(); + let z = self.encoder(ids)?; + let mut zs = Vec::with_capacity(self.niveis.len()); + let mut zhats = Vec::with_capacity(self.niveis.len()); + // projeção ÚNICA d_modelo → d_lat na granularidade do nível 1 (n-02 §0); + // a recursão residual vive INTEIRAMENTE em d_lat + let n1 = self.niveis[0]; + let mut z_corrente = self.proj_niveis[0].fwd(&interp_para(&z, n1, dev)?)?; + let mut zhat_acum: Option = None; + for (i, &n_l) in self.niveis.iter().enumerate() { + let zp = z_corrente.clone(); + let r_suave = self.quants[i].quantizar_treino(&zp)?; + // telemetria + escalas + uso (sem gradiente) + let (ids_duros, _valores) = self.quants[i].quantizar_duro(&zp)?; + self.quants[i].registrar_uso(&ids_duros)?; + self.quants[i].atualizar_escala(&zp)?; + // reconstrução cumulativa na granularidade n_l + let zhat_l = match &zhat_acum { + Some(a) => (&interp_para(a, n_l, dev)? + &r_suave)?, + None => r_suave.clone(), + }; + zhat_acum = Some(zhat_l.clone()); + zhats.push(zhat_l); + // resíduo na granularidade do próximo nível (Teo A.0/D.4) + if i + 1 < self.niveis.len() { + let n_prox = self.niveis[i + 1]; + let res = (&zp - &r_suave)?; + z_corrente = interp_para(&res, n_prox, dev)?; + } + zs.push(zp); + } + Ok((zhats, zs)) + } + + /// Codificação CONGELADA (fase B / inferência): códigos DUROS + ẑ dos + /// códigos (T determinístico — hipótese do Teo B.1). Recursão residual + /// inteiramente em d_lat (projeção única — n-02 §0). + pub fn codificar_congelado(&self, ids: &Tensor) -> Result { + { + let dev = ids.device(); + let z = self.encoder(ids)?.detach(); + let mut saida_ids = Vec::new(); + let mut zhats = Vec::new(); + let n1 = self.niveis[0]; + let mut z_corrente = self.proj_niveis[0].fwd(&interp_para(&z, n1, dev)?)?; + let mut zhat_acum: Option = None; + for (i, &n_l) in self.niveis.iter().enumerate() { + let zp = z_corrente.clone(); + let (ids_l, valores_l) = self.quants[i].quantizar_duro(&zp)?; + saida_ids.push(ids_l.reshape((zp.dims()[0], n_l))?); + let zhat_l = match &zhat_acum { + Some(a) => (&interp_para(a, n_l, dev)? + &valores_l)?, + None => valores_l.clone(), + }; + zhat_acum = Some(zhat_l.clone()); + zhats.push(zhat_l); + if i + 1 < self.niveis.len() { + let n_prox = self.niveis[i + 1]; + let res = (&zp - &valores_l)?; + z_corrente = interp_para(&res, n_prox, dev)?; + } + } + Ok(Codigos { ids: saida_ids, zhats }) + } + } + + /// Reconstrói ẑ a partir de códigos (para corrupção κ e amostragem — + /// o gerador nunca vê os vetores contínuos, apenas c (C.3)). + pub fn reconstruir_de_codigos(&self, ids: &[Tensor], ate_nivel: usize, b: usize, dev: &Device) -> Result> { + { + let mut zhats = Vec::new(); + let mut zhat_acum: Option = None; + for (i, item) in self.niveis.iter().enumerate().take(ate_nivel.min(self.niveis.len())) { + let plano = ids[i].reshape((b, self.niveis[i]))?; + let valores = self.quants[i].materializar(&plano.flatten_all()?)?; + let valores = valores.reshape((b, self.niveis[i], self.d_lat))?; + let zhat_l = match &zhat_acum { + Some(a) => (&interp_para(a, *item, dev)? + &valores)?, + None => valores.clone(), + }; + zhat_acum = Some(zhat_l.clone()); + zhats.push(zhat_l); + } + Ok(zhats) + } + } + + /// Decoder AR condicionado: ẑ (b, n_ℓ, d_lat) → logits (b, N, vocab). + /// Entrada = proj(upsample_N(ẑ)) + emb(tokens deslocados). + pub fn decoder(&self, zhat: &Tensor, alvo: Option<&Tensor>) -> Result { + let dev = zhat.device(); + let b = zhat.dim(0)?; + let n_z = zhat.dim(1)?; + let n_total = self.mascara_causal_dec.dim(0)?; + let up = interp_para(zhat, n_total, dev)?; + let cond = self.dec_proj.fwd(&up)?; + let entrada_tokens: Tensor = match alvo { + Some(t) => { + // desloca à direita com BOS + let bos = Tensor::full(crate::tokens::BOS as f32, (b, 1), dev)?.to_dtype(candle_core::DType::U32)?; + let corpo = t.narrow(1, 0, t.dim(1)? - 1)?; + Tensor::cat(&[&bos, &corpo], 1)? + } + None => Tensor::full(crate::tokens::BOS as f32, (b, n_total), dev)?.to_dtype(candle_core::DType::U32)?, + }; + let mut x = self.dec_emb.fwd(&entrada_tokens)?; + x = (&x + &cond)?; + for bloco in &self.dec_blocos { + let mut cache = Default::default(); + x = bloco.fwd(&x, Some(&self.mascara_causal_dec), &mut cache, None, None)?; + } + let x = self.dec_norm.fwd(&x)?; + self.dec_head.fwd(&x) + } + + /// Perda da fase A (n-04 §2.3): nested dropout + commitment. + /// p(ℓ) uniforme (Teo A.2); RNG DEDICADO (pareamento — Teo 31.7). + /// Devolve (tensor da perda total, métricas). + pub fn perda_fase_a(&mut self, ids: &Tensor, rng: &mut StdRng) -> Result<(Tensor, PerdaFaseA)> { + let (zhats, zs) = self.codificar_treino(ids)?; + let l = zhats.len(); + // sorteio do nível de parada (nested dropout) + let nivel_parada = rng.gen_range(1..=l); + let logits = self.decoder(&zhats[nivel_parada - 1], Some(ids))?; + let (b, n_t, _) = (logits.dim(0)?, logits.dim(1)?, logits.dim(2)?); + let plano = logits.reshape((b * n_t, self.vocab))?; + let alvos = ids.reshape(b * n_t)?; + let ce = candle_nn::loss::cross_entropy(&plano, &alvos)?; + // commitment: β Σ_ℓ ‖sg[r_ℓ] − z_ℓ‖² (média por elemento) + let mut commit_t: Option = None; + let mut commit = 0f64; + for (i, zp) in zs.iter().enumerate() { + let (_ids, valores) = self.quants[i].quantizar_duro(zp)?; + let dif = (&valores - zp)?; + let termo = dif.sqr()?.mean_all()?; + commit += termo.to_scalar::()? as f64; + commit_t = Some(match commit_t { Some(s) => (&s + &termo)?, None => termo }); + } + let commit_t = commit_t.unwrap_or_else(|| ce.zeros_like().unwrap()); + let total = (&ce + &commit_t.affine(self.cfg_ncm_beta_commit, 0.0)?)?; + // precisão de reconstrução (telemetria) + let preds = plano.argmax(D::Minus1)?; + let acertos = preds.eq(&alvos)?.to_dtype(candle_core::DType::F32)?.sum_all()?.to_scalar::()? as f64; + let acc = acertos / (b * n_t) as f64; + // δ_ort por nível (V9) + let deltas: Result> = self.quants.iter().map(|q| q.delta_ort()).collect(); + let deltas = deltas?; + for (i, d) in deltas.iter().enumerate() { + self.quants[i].delta_ort_ultimo = *d; + } + Ok((total, PerdaFaseA { + rec: ce.to_scalar::()? as f64, + commit, + nivel_parada, + acc_recon: acc, + deltas_ort: deltas, + })) + } + + /// Decodificação LIVRE (amostragem): ẑ (b, n_ℓ, d_lat) → ids de token AR + /// greedy. Teo A.2/B.4(b): qualquer prefixo decodifica (anytime). + /// O texto final é reconstruído pelo BPE no lado Python. + pub fn decodificar_livre(&self, zhat: &Tensor, max_tokens: usize) -> Result>> { + { + let dev = zhat.device(); + let b = zhat.dim(0)?; + let n_total = self.mascara_causal_dec.dim(0)?; + let up = interp_para(zhat, n_total, dev)?; + let cond = self.dec_proj.fwd(&up)?; + let mut tokens: Vec> = (0..b).map(|_| vec![crate::tokens::BOS]).collect(); + for passo in 1..max_tokens.min(n_total) { + let planos: Vec = tokens.iter().flat_map(|t| t.iter().copied()).collect(); + let entrada = Tensor::from_vec(planos, (b, passo), dev)?; + let mut x = self.dec_emb.fwd(&entrada)?; + x = (&x + &cond.narrow(1, 0, passo)?)?; + for bloco in &self.dec_blocos { + let mut cache = Default::default(); + let m = self.mascara_causal_dec.narrow(0, 0, passo)?.narrow(1, 0, passo)?.contiguous()?; + x = bloco.fwd(&x, Some(&m), &mut cache, None, None)?; + } + let x = self.dec_norm.fwd(&x)?; + let logits = self.dec_head.fwd(&x)?; + let ultimo = logits.narrow(1, passo - 1, 1)?.reshape((b, self.vocab))?; + let preds = ultimo.argmax(D::Minus1)?; + let v = preds.flatten_all()?.to_vec1::()?; + for (i, t) in v.iter().enumerate() { + tokens[i].push(*t); + } + } + Ok(tokens) + } + } + + /// CE por prefixo (V3: monotonia do risco — Teo A.2) em modo congelado. + pub fn ce_por_prefixo(&self, ids: &Tensor) -> Result> { + { + let cod = self.codificar_congelado(ids)?; + let mut saida = Vec::with_capacity(cod.zhats.len()); + for zhat in &cod.zhats { + let logits = self.decoder(zhat, Some(ids))?; + let (b, n_t, _) = (logits.dim(0)?, logits.dim(1)?, logits.dim(2)?); + let plano = logits.reshape((b * n_t, self.vocab))?; + let alvos = ids.reshape(b * n_t)?; + let ce = candle_nn::loss::cross_entropy(&plano, &alvos)?; + saida.push(ce.to_scalar::()? as f64); + } + Ok(saida) + } + } + + /// Agenda τ do GSQ por passo (Teo 30.6). + pub fn agendar_tau(&mut self, passo: usize, tau0: f64, tau_min: f64, t_alvo: usize) { + for q in &mut self.quants { + q.agendar_tau(passo, tau0, tau_min, t_alvo); + } + } + + /// Atualização EMA do codebook (modo ste_ema apenas — no gsq_rco o + /// gradiente riemanniano já treina W). + pub fn atualizar_ema_codebook(&mut self, ids_lote: &[Tensor]) -> Result<()> { + if self.modo != ModoQuant::SteEma { + return Ok(()); + } + // no modo STE, os codebooks seguem por EMA dos agrupamentos (A.0). + // Implementação: média dos vetores por código → polar → w. + for (i, q) in self.quants.iter_mut().enumerate() { + let ids_l = &ids_lote[i]; + let k = q.uso.len(); + let b = ids_l.dim(0)?; + let plano = ids_l.reshape(b * self.niveis[i])?; + let ids_v = plano.flatten_all()?.to_vec1::()?; + let mut soma = vec![vec![0f32; self.d_lat]; k]; + let mut conta = vec![0usize; k]; + // usa o codebook corrente para os vetores (aproximação EMA dos + // agrupamentos — suficiente para o modo STE de compatibilidade) + let c = q.codebook()?.detach(); + let c_v = c.flatten_all()?.to_vec1::()?; + for &idc in &ids_v { + let idc = idc as usize; + if idc < k { + for t in 0..self.d_lat { + soma[idc][t] += c_v[idc * self.d_lat + t]; + } + conta[idc] += 1; + } + } + let ema = q.ema; + let w_v = q.w.as_tensor().flatten_all()?.to_vec1::()?; + let mut novo = w_v.clone(); + for idc in 0..k { + if conta[idc] > 0 { + for t in 0..self.d_lat { + let alvo = soma[idc][t] / conta[idc] as f32; + novo[idc * self.d_lat + t] = + (ema as f32 * w_v[idc * self.d_lat + t] + (1.0 - ema as f32) * alvo) as f32; + } + } + } + let dev = q.w.as_tensor().device(); + let nt = Tensor::from_vec(novo, (k, self.d_lat), dev)?; + q.w.set(&nt)?; + } + Ok(()) + } + + pub fn vars(&self) -> Vec { + let mut v: Vec = self.enc_emb.vars(); + for b in &self.enc_blocos { v.extend(b.vars()); } + v.extend(self.enc_norm.vars()); + for p in &self.proj_niveis { v.extend(p.vars()); } + for q in &self.quants { v.push(q.w.clone()); } + v.extend(self.dec_proj.vars()); + v.extend(self.dec_emb.vars()); + for b in &self.dec_blocos { v.extend(b.vars()); } + v.extend(self.dec_norm.vars()); + v.extend(self.dec_head.vars()); + v + } + + /// Salva estado (checkpoint atômico — Teo 35.3): índices = ordem de vars(). + pub fn salvar(&self, caminho: &str) -> Result<()> { + let mut obj = serde_json::Map::new(); + for (i, v) in self.vars().iter().enumerate() { + let dados = v.as_tensor().flatten_all()?.to_vec1::()?; + obj.insert(format!("v{i}"), serde_json::json!({ + "forma": v.as_tensor().dims(), + "dados": dados, + })); + } + let txt = serde_json::to_string(&serde_json::Value::Object(obj)) + .map_err(|e| candle_core::Error::Msg(format!("serde: {e}")))?; + let tmp = format!("{caminho}.tmp"); + std::fs::write(&tmp, txt).map_err(|e| candle_core::Error::Msg(format!("io: {e}")))?; + std::fs::rename(&tmp, caminho).map_err(|e| candle_core::Error::Msg(format!("rename: {e}")))?; + Ok(()) + } +} + +pub struct PerdaFaseA { + pub rec: f64, + pub commit: f64, + pub nivel_parada: usize, + pub acc_recon: f64, + pub deltas_ort: Vec, +} + +/// Máscara causal aditiva (n, n): 0 permitido, MIN bloqueado. +pub fn causal_aditiva(n: usize, dev: &Device) -> Result { + let mut m = vec![f32::MIN; n * n]; + for i in 0..n { + for j in 0..=i { + m[i * n + j] = 0.0; + } + } + Tensor::from_vec(m, (n, n), dev) +} + +fn tensor_para_json(t: &Tensor) -> Result { + let dados = t.flatten_all()?.to_vec1::()?; + Ok(serde_json::json!({ + "forma": t.shape().dims(), + "dados": dados, + })) +} + +/// Matriz de interpolação cacheada (evita recriar por passo). +pub struct CacheInterp { + pub n_de: usize, + pub n_para: usize, + pub matriz: Tensor, +} + +impl CacheInterp { + pub fn novo(n_de: usize, n_para: usize, dev: &Device) -> Result { + Ok(CacheInterp { n_de, n_para, matriz: matriz_interp(n_de, n_para, dev)? }) + } +} + diff --git a/src/tokens.rs b/src/tokens.rs new file mode 100644 index 0000000000000000000000000000000000000000..a53b69d65279d675289487f061029e73cb376b47 --- /dev/null +++ b/src/tokens.rs @@ -0,0 +1,264 @@ +//! BPE byte-level próprio do KHTST_RUST (contrato do `dados/tokenizador.py` +//! do v23: vocabulário próprio, especiais reservados). Sem dependências +//! externas; treino incremental por contagem de pares com índice de posições. +//! +//! IDs especiais: 0= 1= 2= 3=; bytes 4..260; merges a partir de 260. + +use std::collections::{HashMap, HashSet}; + +pub const PAD: u32 = 0; +pub const BOS: u32 = 1; +pub const EOS: u32 = 2; +pub const UNK: u32 = 3; +pub const BASE_BYTES: u32 = 4; +const ESPECIAIS: [&str; 4] = ["", "", "", ""]; + +#[derive(Debug, Clone, Default)] +pub struct Bpe { + /// token por id (string; bytes crus para os 256 iniciais) + pub vocab: Vec, + /// merges na ordem de aprendizado: (id_a, id_b) -> id_novo implícito = 260+índice + pub merges: Vec<(u32, u32)>, + rank: HashMap<(u32, u32), u32>, + id_por_token: HashMap, + cache: HashMap>, +} + +impl Bpe { + pub fn novo() -> Self { + let mut b = Bpe::default(); + for (i, s) in ESPECIAIS.iter().enumerate() { + b.id_por_token.insert(s.to_string(), i as u32); + b.vocab.push(s.to_string()); + } + for i in 0..256u32 { + let s = String::from_utf8_lossy(&[i as u8]).to_string(); + b.id_por_token.insert(s.clone(), BASE_BYTES + i); + b.vocab.push(s); + } + b + } + + pub fn n_vocab(&self) -> usize { + self.vocab.len() + } + + fn id_merge(&self, indice_merge: usize) -> u32 { + 260 + indice_merge as u32 + } + + /// Treina BPE em `textos` até `vocab_alvo` tokens (inclui especiais + bytes). + /// Contagem incremental: cada merge só visita as posições do par afetado. + pub fn treinar(textos: &[String], vocab_alvo: usize) -> Self { + let mut b = Bpe::novo(); + // palavras (por espaço em branco; o espaço separa palavras — sem marcador final) + let mut contagem_palavra: HashMap = HashMap::new(); + for t in textos { + for w in t.split_whitespace() { + *contagem_palavra.entry(w.to_string()).or_insert(0) += 1; + } + } + // estado: sequências por palavra + índice global de pares + let mut seqs: Vec> = vec![]; + let mut pesos: Vec = vec![]; + for (w, c) in &contagem_palavra { + seqs.push(w.as_bytes().iter().map(|&x| BASE_BYTES + x as u32).collect()); + pesos.push(*c); + } + // contagem de pares e posições + let mut cont: HashMap<(u32, u32), u64> = HashMap::new(); + let mut pos: HashMap<(u32, u32), Vec<(usize, usize)>> = HashMap::new(); + for (si, s) in seqs.iter().enumerate() { + for j in 0..s.len().saturating_sub(1) { + let p = (s[j], s[j + 1]); + *cont.entry(p).or_insert(0) += pesos[si] as u64; + pos.entry(p).or_default().push((si, j)); + } + } + let n_merges_alvo = vocab_alvo.saturating_sub(b.vocab.len()); + for k in 0..n_merges_alvo { + // melhor par por (frequência, ordem de criação implícita) + let melhor = cont.iter().filter(|(_, &c)| c > 0).max_by_key(|(p, &c)| (c, std::cmp::Reverse(*p))); + let (par, _) = match melhor { + Some((p, c)) => (*p, *c), + None => break, + }; + let novo_id = b.id_merge(b.merges.len()); + let concatenado = { + let a = b.vocab.get(par.0 as usize).cloned().unwrap_or_default(); + let c = b.vocab.get(par.1 as usize).cloned().unwrap_or_default(); + format!("{a}{c}") + }; + // aplica o merge nas posições registradas (por baixo para índices estáveis) + let mut ocupadas: HashSet<(usize, usize)> = HashSet::new(); + let mut afetadas: Vec<(u32, u32)> = vec![]; + if let Some(posicoes) = pos.get(&par).cloned() { + for (si, j) in posicoes { + if ocupadas.contains(&(si, j)) { + continue; + } + let s = &mut seqs[si]; + if j + 1 >= s.len() || (s[j], s[j + 1]) != par { + continue; + } + // remove pares vizinhos antigos + if j > 0 { + let esq = (s[j - 1], s[j]); + if let Some(c) = cont.get_mut(&esq) { + *c = c.saturating_sub(pesos[si] as u64); + } + afetadas.push(esq); + } + if j + 2 < s.len() { + let dir = (s[j + 1], s[j + 2]); + if let Some(c) = cont.get_mut(&dir) { + *c = c.saturating_sub(peso_como_u64(pesos[si])); + } + afetadas.push(dir); + } + s[j] = novo_id; + s.remove(j + 1); + ocupadas.insert((si, j)); + ocupadas.insert((si, j.saturating_sub(1))); + // novos pares + if j > 0 { + let esq = (s[j - 1], novo_id); + *cont.entry(esq).or_insert(0) += pesos[si] as u64; + pos.entry(esq).or_default().push((si, j - 1)); + } + if j + 1 < s.len() { + let dir = (novo_id, s[j + 1]); + *cont.entry(dir).or_insert(0) += pesos[si] as u64; + pos.entry(dir).or_default().push((si, j)); + } + } + } + let _ = afetadas; + cont.remove(&par); + pos.remove(&par); + b.merges.push(par); + b.vocab.push(concatenado.clone()); + b.id_por_token.insert(concatenado, novo_id); + if k % 512 == 0 { + log::info!("bpe: merge {k}/{} (vocab {})", n_merges_alvo, b.vocab.len()); + } + } + b + } + + /// Codifica uma palavra (com cache). + fn codificar_palavra(&mut self, w: &str) -> Vec { + if let Some(v) = self.cache.get(w) { + return v.clone(); + } + let mut s: Vec = w.as_bytes().iter().map(|&x| BASE_BYTES + x as u32).collect(); + loop { + // par de menor rank + let melhor = s.windows(2).map(|p| (p[0], p[1])).filter_map(|p| self.rank.get(&p).map(|r| (r, p))).min_by_key(|(r, _)| *r); + match melhor { + Some((_, (a, b))) => { + let alvo = self.rank[&(a, b)] as usize; + let novo = self.id_merge(alvo); + let mut out = vec![]; + let mut i = 0; + while i < s.len() { + if i + 1 < s.len() && s[i] == a && s[i + 1] == b { + out.push(novo); + i += 2; + } else { + out.push(s[i]); + i += 1; + } + } + s = out; + } + None => break, + } + if s.len() <= 1 { + break; + } + } + self.cache.insert(w.to_string(), s.clone()); + s + } + + pub fn reconstruir_indices(&mut self) { + self.rank.clear(); + for (i, (a, b)) in self.merges.iter().enumerate() { + self.rank.insert((*a, *b), i as u32); + } + } + + pub fn codificar(&mut self, texto: &str) -> Vec { + let espaco = BASE_BYTES + b' ' as u32; + let mut ids = vec![BOS]; + for w in texto.split_whitespace() { + ids.extend(self.codificar_palavra(w)); + ids.push(espaco); + } + ids.push(EOS); + ids + } + + pub fn decodificar(&self, ids: &[u32]) -> String { + let mut out = String::new(); + for &i in ids { + match i { + PAD | BOS | EOS => {} + _ => { + if let Some(s) = self.vocab.get(i as usize) { + if !ESPECIAIS.contains(&s.as_str()) { + out.push_str(s); + } + } + } + } + } + out.trim().to_string() + } + + pub fn para_json(&self) -> serde_json::Value { + serde_json::json!({ + "vocab": self.vocab, + "merges": self.merges, + }) + } + + pub fn de_json(v: &serde_json::Value) -> Option { + let vocab: Vec = v.get("vocab")?.as_array()?.iter().map(|x| x.as_str().unwrap_or_default().to_string()).collect(); + let merges: Vec<(u32, u32)> = v.get("merges")?.as_array()?.iter().filter_map(|x| { + let a = x.get(0)?.as_u64()? as u32; + let b = x.get(1)?.as_u64()? as u32; + Some((a, b)) + }).collect(); + let mut b = Bpe { vocab, merges, ..Default::default() }; + for (i, s) in b.vocab.iter().enumerate() { + b.id_por_token.insert(s.clone(), i as u32); + } + b.reconstruir_indices(); + Some(b) + } +} + +fn peso_como_u64(p: u32) -> u64 { + p as u64 +} + +#[cfg(test)] +mod testes { + use super::*; + + #[test] + fn treina_e_recodifica() { + let textos: Vec = ["o gato come o peixe e o cão come o osso", + "o gato mira o peixe e o cão mira o osso", + "peixe osso gato cão o e come mira"].iter().map(|s| s.to_string()).collect(); + let mut b = Bpe::treinar(&textos, 300); + let ids = b.codificar("o gato come o peixe"); + assert_eq!(ids.first(), Some(&BOS)); + assert_eq!(ids.last(), Some(&EOS)); + let texto = b.decodificar(&ids); + assert_eq!(texto, "o gato come o peixe"); + assert!(b.n_vocab() >= 260); + } +} diff --git a/src/treino.rs b/src/treino.rs new file mode 100644 index 0000000000000000000000000000000000000000..aa1cb091f5b2ade2e5f9d1068f38e2ce67af35f2 --- /dev/null +++ b/src/treino.rs @@ -0,0 +1,440 @@ +//! Loops de treino (fases A e B — n-04 §4) com otimizador AdamW MANUAL +//! (controle total para PCGrad multi-perda, clip global e LR dinâmico do +//! controlador), telemetria completa, callback Python periódico e +//! checkpoints atômicos (Teo 35.3). + +use candle_core::{Device, Result, Tensor, Var}; +use candle_nn::loss::cross_entropy; +use rand::prelude::*; +use std::collections::HashMap; + +use crate::config::ConfigKhtst; +use crate::controlador::Controlador; +use crate::gerador::GeradorConceitos; +use crate::memoria::{JepaLatente, SomConceitos}; +use crate::mascaras::interp_para; +use crate::telemetria::TelemetryHub; +use crate::tokenizador::TokenizadorConceitos; + +/// AdamW manual (estado por índice de variável; grads achatados). +pub struct AdamWManual { + pub m: HashMap>, + pub v: HashMap>, + pub t: usize, + pub lr: f64, + pub beta1: f64, + pub beta2: f64, + pub eps: f64, + pub wd: f64, + pub vars: Vec, +} + +impl AdamWManual { + pub fn novo(vars: Vec, lr: f64, wd: f64) -> Self { + AdamWManual { m: HashMap::new(), v: HashMap::new(), t: 0, lr, beta1: 0.9, beta2: 0.999, eps: 1e-8, wd, vars } + } + + pub fn set_lr(&mut self, lr: f64) { + self.lr = lr; + } + + /// Um passo. `grads`: por variável, gradiente ACHATADO (None = zero). + pub fn passo(&mut self, grads: Vec>>) { + self.t += 1; + let bc1 = 1.0 - self.beta1.powi(self.t as i32); + let bc2 = 1.0 - self.beta2.powi(self.t as i32); + for (i, var) in self.vars.iter().enumerate() { + let Some(g) = grads.get(i).cloned().flatten() else { continue }; + let n = g.len(); + let m = self.m.entry(i).or_insert(vec![0f32; n]); + let v = self.v.entry(i).or_insert(vec![0f32; n]); + let dados = var.as_tensor().flatten_all().unwrap().to_vec1::().unwrap(); + let mut novos = vec![0f32; n]; + for j in 0..n { + m[j] = self.beta1 as f32 * m[j] + (1.0 - self.beta1 as f32) * g[j]; + v[j] = self.beta2 as f32 * v[j] + (1.0 - self.beta2 as f32) * g[j] * g[j]; + let mh = m[j] / bc1 as f32; + let vh = v[j] / bc2 as f32; + // AdamW: decaimento desacoplado + novos[j] = dados[j] - (self.lr as f32) * (mh / (vh.sqrt() + self.eps as f32) + self.wd as f32 * dados[j]); + } + let forma = var.as_tensor().shape(); + let dev = var.as_tensor().device(); + let novo_t = Tensor::from_vec(novos, forma.clone(), dev).unwrap() + .reshape(forma).unwrap(); + let _ = var.set(&novo_t); + } + } + + /// Norma global de gradiente (para clip e telemetria). + pub fn norma_global(grads: &[Option>]) -> f64 { + let mut s = 0f64; + for g in grads.iter().flatten() { + for x in g { + s += (*x as f64) * (*x as f64); + } + } + s.sqrt() + } + + /// Clip global por norma (in-place nos grads achatados). + pub fn clipar(grads: &mut [Option>], teto: f64) { + let norma = Self::norma_global(grads); + if norma > teto && norma > 0.0 { + let f = (teto / norma) as f32; + for g in grads.iter_mut().flatten() { + for x in g.iter_mut() { + *x *= f; + } + } + } + } +} + +/// Extrai grads achatados do GradStore na ordem de `vars`. +pub fn grads_achatados(perda: &Tensor, vars: &[Var]) -> Result>>> { + let gs = perda.backward()?; + let mut out = Vec::with_capacity(vars.len()); + for v in vars { + match gs.get(v) { + Some(t) => out.push(Some(t.flatten_all()?.to_vec1::()?)), + None => out.push(None), + } + } + Ok(out) +} + +/// PCGrad multi-perda sobre grads achatados (Teo D.7 — projeção por pares). +pub fn pcgrad_achatado(mut grads: Vec>>>) -> Vec>> { + let n_perdas = grads.len(); + let n_vars = grads[0].len(); + let mut saida: Vec>> = vec![None; n_vars]; + for i in 0..n_perdas { + // projeta g_i contra cada g_j conflitante + for j in 0..n_perdas { + if i == j { continue; } + let mut ip = 0f64; + let mut nj = 0f64; + for v in 0..n_vars { + if let (Some(a), Some(b)) = (&grads[i][v], &grads[j][v]) { + for k in 0..a.len().min(b.len()) { + ip += a[k] as f64 * b[k] as f64; + nj += b[k] as f64 * b[k] as f64; + } + } + } + if ip < 0.0 && nj > 1e-12 { + let alfa = (ip / nj) as f32; + for v in 0..n_vars { + if let Some(bv) = grads[j][v].clone() { + if let Some(a) = &mut grads[i][v] { + for k in 0..a.len().min(bv.len()) { + a[k] -= alfa * bv[k]; + } + } + } + } + } + } + for v in 0..n_vars { + if let Some(a) = &grads[i][v] { + let media: Vec = a.iter().map(|x| x / n_perdas as f32).collect(); + saida[v] = Some(match &saida[v] { + Some(s) => s.iter().zip(media.iter()).map(|(x, y)| x + y).collect(), + None => media, + }); + } + } + } + saida +} + +pub struct DadosTreino { + pub sequencias: Vec>, // cada uma de comprimento N (= ctx) +} + +impl DadosTreino { + pub fn novo(sequencias: Vec>, n: usize) -> Self { + let seqs = sequencias + .into_iter() + .filter(|s| s.len() >= 8) + .map(|mut s| { + while s.len() < n { + s.push(crate::tokens::PAD); + } + s.truncate(n); + s + }) + .collect(); + DadosTreino { sequencias: seqs } + } + + pub fn lote(&self, b: usize, rng: &mut StdRng, dev: &Device) -> Result { + let mut escolhidas = Vec::with_capacity(b); + for _ in 0..b { + if self.sequencias.is_empty() { + break; + } + escolhidas.push(self.sequencias[rng.gen_range(0..self.sequencias.len())].clone()); + } + let b_efetivo = escolhidas.len().max(1); + let n = escolhidas[0].len(); + let plano: Vec = escolhidas.into_iter().flatten().collect(); + Tensor::from_vec(plano, (b_efetivo, n), dev) + } +} + +/// Callback Python opcional (chamado a cada `a_cada` passos com um dict). +pub type CallbackPy = Option>; + +pub fn chamar_callback(cb: &CallbackPy, dados: &serde_json::Value) { + if let Some(f) = cb { + pyo3::Python::with_gil(|py| { + if let Ok(obj) = pythonize::pythonize(py, dados) { + let _ = f.call1(py, (obj,)); + } + }); + } +} + +pub struct ResumoFase { + pub passos: usize, + pub perda_final: f64, + pub perda_inicial: f64, + pub acc_recon: f64, + pub delta_ort_max: f64, + pub perplexidade_codebook: f64, + pub monotonia_prefixo: f64, + pub escore_aprendizado: f64, +} + +/// FASE A — tokenizador (n-04 §4): nested dropout + commitment + GSQ + RCO. +pub fn treinar_fase_a( + cfg: &ConfigKhtst, + dados: &DadosTreino, + hub: &mut TelemetryHub, + callback: &CallbackPy, + caminho_checkpoint: Option<&str>, + teto_seg: Option, +) -> Result { + let dev = Device::Cpu; + let inicio = std::time::Instant::now(); + let mut tok = TokenizadorConceitos::novo(cfg, &dev)?; + let vars = tok.vars(); + let mut opt = AdamWManual::novo(vars.clone(), cfg.treino.lr, cfg.treino.peso_decaimento); + let mut ctrl = Controlador::novo(cfg.treino.lr, cfg.treino.aquecimento, cfg.treino.passos_fase_a, cfg.telemetria.paciencia_plateau, cfg.telemetria.fator_lr_plateau, cfg.ncm.lambdas.rho_ancora); + let mut rng = StdRng::seed_from_u64(31_7); // RNG dedicado (Teo 31.7) + let perda_inicial = { + let ids = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let (p, _) = tok.perda_fase_a(&ids, &mut rng)?; + p.to_scalar::()? as f64 + }; + let a_cada = cfg.treino.telemetria_a_cada.max(1); + let mut passos_feitos = 0usize; + 'laco_a: for passo in 0..cfg.treino.passos_fase_a { + hub.passo_corrente = passo; + if let Some(t) = teto_seg { + if inicio.elapsed().as_secs_f64() > t { + passos_feitos = passo; + break 'laco_a; + } + } + let ids = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let (perda_t, _m) = tok.perda_fase_a(&ids, &mut rng)?; + let perda = perda_t.to_scalar::()? as f64; + // agenda τ (Teo 30.6) + tok.agendar_tau(passo, cfg.ncm.gsq.tau0, cfg.ncm.gsq.tau_min, cfg.ncm.gsq.t_alvo); + // LR + clip do controlador (ajustes AUTOMÁTICOS — auditados) + let lr = ctrl.lr_passo(passo, perda, hub); + opt.set_lr(lr); + let mut grads = grads_achatados(&perda_t, &vars)?; + let norma = AdamWManual::norma_global(&grads); + ctrl.registrar_norma(norma); + let teto = ctrl.clip_corrente(hub); + AdamWManual::clipar(&mut grads, teto); + opt.passo(grads); + // EMA do codebook (modo ste_ema) + if cfg.ncm.modo_quantizacao == "ste_ema" { + let cod = tok.codificar_congelado(&ids)?; + tok.atualizar_ema_codebook(&cod.ids)?; + } + // telemetria + hub.registrar_multi(&[ + ("perda", perda), + ("lr", lr), + ("norma_grad", norma), + ]); + if passo % a_cada == 0 || passo == cfg.treino.passos_fase_a - 1 { + let perp: f64 = tok.quants.iter().map(|q| q.perplexidade_uso()).sum::() / tok.quants.len().max(1) as f64; + let dort: f64 = tok.quants.iter().map(|q| q.delta_ort_ultimo).fold(0f64, f64::max); + hub.registrar_multi(&[ + ("codebook_perplexidade_media", perp), + ("delta_ort_max", dort), + ("escore_aprendizado", hub.escore_aprendizado()), + ]); + if cfg.telemetria.deteccao_aprendizado { + let snap = serde_json::json!({ + "fase": "A", "passo": passo, "perda": perda, "lr": lr, + "codebook_perplexidade_media": perp, "delta_ort_max": dort, + "escore": hub.escore_aprendizado(), + }); + chamar_callback(callback, &snap); + } + } + if !perda.is_finite() { + hub.erro("fase_a", &format!("perda não finita no passo {passo}")); + break; + } + } + if passos_feitos == 0 { passos_feitos = cfg.treino.passos_fase_a; } + // avaliação final: monotonia de prefixo (V3) + perplexidade + let ids_val = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let ces_prefixo = tok.ce_por_prefixo(&ids_val)?; + let mut pares_ok = 0usize; + let mut pares = 0usize; + for w in ces_prefixo.windows(2) { + pares += 1; + if w[1] <= w[0] * 1.02 { + pares_ok += 1; + } + } + let monotonia = pares_ok as f64 / pares.max(1) as f64; + let perda_final = ces_prefixo.last().copied().unwrap_or(f64::NAN); + let perp: f64 = tok.quants.iter().map(|q| q.perplexidade_uso()).sum::() / tok.quants.len().max(1) as f64; + let dort = tok.quants.iter().map(|q| q.delta_ort_ultimo).fold(0f64, f64::max); + let acc = { let (_, m) = tok.perda_fase_a(&ids_val, &mut rng)?; m.acc_recon }; + if let Some(c) = caminho_checkpoint { + tok.salvar(c)?; + } + hub.registrar("passos_feitos", passos_feitos as f64); + Ok(ResumoFase { + passos: passos_feitos, + perda_final, + perda_inicial, + acc_recon: acc, + delta_ort_max: dort, + perplexidade_codebook: perp, + monotonia_prefixo: monotonia, + escore_aprendizado: hub.escore_aprendizado(), + }) +} + +/// FASE B — gerador (n-04 §4): MLE exato sobre hierarquias congeladas (B.1), +/// corrupção κ + dropout CFG (C.3/D.2), MTP auxiliar (D.6), JEPA latente e +/// PCGrad entre as perdas (D.7). +pub fn treinar_fase_b( + cfg: &ConfigKhtst, + tok: &TokenizadorConceitos, + dados: &DadosTreino, + hub: &mut TelemetryHub, + callback: &CallbackPy, + caminho_checkpoint: Option<&str>, + teto_seg: Option, +) -> Result { + let dev = Device::Cpu; + let inicio = std::time::Instant::now(); + let mut ger = GeradorConceitos::novo(cfg, &dev)?; + let jepa = JepaLatente::novo(cfg.ncm.d_lat, &dev)?; + let mut som = SomConceitos::novo(cfg.memoria.som_lado, cfg.ncm.d_lat, &dev)?; + let mut vars = ger.vars(); + vars.extend(jepa.vars()); + let mut opt = AdamWManual::novo(vars.clone(), cfg.treino.lr * 0.7, cfg.treino.peso_decaimento); + let mut ctrl = Controlador::novo(cfg.treino.lr * 0.7, cfg.treino.aquecimento, cfg.treino.passos_fase_b, cfg.telemetria.paciencia_plateau, cfg.telemetria.fator_lr_plateau, cfg.ncm.lambdas.rho_ancora); + let mut rng = StdRng::seed_from_u64(31_7); + let a_cada = cfg.treino.telemetria_a_cada.max(1); + let lambda_jepa = cfg.memoria.lambda_jepa; + let perda_inicial = { + let ids = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let cod = tok.codificar_congelado(&ids)?; + let s = ger.perda_treino(tok, &cod.ids, &mut rng)?; + s.ce_por_nivel.iter().sum::() / s.ce_por_nivel.len() as f64 + }; + let mut passos_feitos = 0usize; + 'laco_b: for passo in 0..cfg.treino.passos_fase_b { + hub.passo_corrente = passo; + if let Some(t) = teto_seg { + if inicio.elapsed().as_secs_f64() > t { + passos_feitos = passo; + break 'laco_b; + } + } + let ids = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let cod = tok.codificar_congelado(&ids)?; + let saida = ger.perda_treino(tok, &cod.ids, &mut rng)?; + let ce = saida.ce_por_nivel.iter().sum::() / saida.ce_por_nivel.len() as f64; + // JEPA latente (alvo com stop-grad — contrato doc 30) + let perda_jepa_t = { + let b = ids.dim(0)?; + let zhats = tok.reconstruir_de_codigos(&cod.ids, cod.ids.len(), b, &dev)?; + let mut soma = None; + for l in 1..zhats.len() { + let n_l = zhats[l].dim(1)?; + let ant = interp_para(&zhats[l - 1], n_l, &dev)?; + let alvo = (&zhats[l] - &ant)?.detach(); + let pj = jepa.perda(&ant, &alvo)?; + soma = Some(match soma { Some(s) => (&s + &pj)?, None => pj }); + } + match soma { + Some(s) => s.affine(lambda_jepa / zhats.len().max(1) as f64, 0.0)?, + None => Tensor::zeros((), candle_core::DType::F32, &dev)?, + } + }; + // perdas separadas para PCGrad: [CE (com MTP embutido), JEPA] + let mut grads_lista = Vec::new(); + grads_lista.push(grads_achatados(&saida.perda, &vars)?); + grads_lista.push(grads_achatados(&perda_jepa_t, &vars)?); + let mut combinado = pcgrad_achatado(grads_lista); + let norma = AdamWManual::norma_global(&combinado); + ctrl.registrar_norma(norma); + let lr = ctrl.lr_passo(passo, ce, hub); + opt.set_lr(lr); + let teto = ctrl.clip_corrente(hub); + AdamWManual::clipar(&mut combinado, teto); + opt.passo(combinado); + // SOM pós-geração (stop-grad — Teo 17.4): insere vetores de nível 1 + if passo % a_cada == 0 { + let b = ids.dim(0)?; + let zhats = tok.reconstruir_de_codigos(&cod.ids, 1, b, &dev)?; + let _eq = som.inserir(&zhats[0])?; + hub.registrar("som_eq_medio", som.eq_medio); + } + hub.registrar_multi(&[ + ("perda", ce), + ("ce_mtp", saida.ce_mtp), + ("acc_conceitos", saida.acuracia_media), + ("lr", lr), + ("norma_grad", norma), + ]); + if passo % a_cada == 0 || passo == cfg.treino.passos_fase_b - 1 { + hub.registrar("escore_aprendizado", hub.escore_aprendizado()); + let snap = serde_json::json!({ + "fase": "B", "passo": passo, "perda": ce, "ce_mtp": saida.ce_mtp, + "acc_conceitos": saida.acuracia_media, "lr": lr, + "escore": hub.escore_aprendizado(), + }); + chamar_callback(callback, &snap); + } + if !ce.is_finite() { + hub.erro("fase_b", &format!("CE não finita no passo {passo}")); + break; + } + } + if passos_feitos == 0 { passos_feitos = cfg.treino.passos_fase_b; } + let ids_val = dados.lote(cfg.treino.lote, &mut rng, &dev)?; + let cod = tok.codificar_congelado(&ids_val)?; + let saida = ger.perda_treino(tok, &cod.ids, &mut rng)?; + let perda_final = saida.ce_por_nivel.iter().sum::() / saida.ce_por_nivel.len() as f64; + if let Some(c) = caminho_checkpoint { + ger.salvar(c)?; + } + Ok(ResumoFase { + passos: cfg.treino.passos_fase_b, + perda_final, + perda_inicial, + acc_recon: saida.acuracia_media, + delta_ort_max: 0.0, + perplexidade_codebook: 0.0, + monotonia_prefixo: 0.0, + escore_aprendizado: hub.escore_aprendizado(), + }) +} diff --git a/src/tronco.rs b/src/tronco.rs new file mode 100644 index 0000000000000000000000000000000000000000..0654d100e38f728dbda1c0f6a3d203a443ca0077 --- /dev/null +++ b/src/tronco.rs @@ -0,0 +1,215 @@ +//! Tronco híbrido 5:1 (port do `mamba3/tronco.py`): 5 camadas ADBA (atenção +//! block-causal com melhorias) + 1 camada SSD (slot Mamba-3 causal) — Teo D.1 +//! com a restrição honesta H_D1 (bidirecionalidade intra-nível nas camadas de +//! atenção; a camada recorrente é causal). +//! +//! Sequência do gerador: s = [cond; lev_1; …; lev_L] com entradas +//! ẑ_{ℓ−1}^{(n_ℓ)} + e_ℓ (reconstrução cumulativa interpolada + embedding de +//! nível — Teo D.1). Treino: 1 passada com teacher forcing (D.1(iv)); +//! inferência: bloco a bloco com KV-cache (D.1(iii), T2). + +use candle_core::{Device, Result, Tensor, Var}; +use crate::atencao::{AncoraNivel, BlocoAdba}; +pub use crate::atencao::CacheKv; +use crate::camadas::{Embedding, Linear, RmsNorm}; +use crate::config::ConfigKhtst; +use crate::ssd::BlocoSsd; + +pub struct Tronco { + pub blocos_atencao: Vec, + pub bloco_ssd: BlocoSsd, + pub norm_final: RmsNorm, + pub ancora: Option, + /// gamma FiLM por nível (2*L+2: [escala, deslocamento] × nível) — ADBA. + pub film_gamma: Option, + pub film_beta: Option, + pub n_niveis: usize, +} + +impl Tronco { + pub fn novo(cfg: &ConfigKhtst, dev: &Device) -> Result { + let m = &cfg.modelo; + let l = cfg.l_niveis(); + let adba = &cfg.adba; + let mut blocos = Vec::with_capacity(m.n_camadas - 1); + for _ in 0..(m.n_camadas - 1) { + blocos.push(BlocoAdba::novo( + m.d_modelo, m.n_cabecas, m.d_ff, l, + adba.ativo, adba.reponderacao_nivel, adba.temperatura_nivel, dev, + )?); + } + let ancora = if adba.ativo && adba.gamma_ancora > 0.0 { + Some(AncoraNivel::nova(m.d_modelo, l, dev)?) + } else { + None + }; + let (film_gamma, film_beta) = if adba.ativo { + let g = Tensor::ones((l + 1, m.d_modelo), candle_core::DType::F32, dev)?; + let b = Tensor::zeros((l + 1, m.d_modelo), candle_core::DType::F32, dev)?; + (Some(Var::from_tensor(&g)?), Some(Var::from_tensor(&b)?)) + } else { + (None, None) + }; + Ok(Tronco { + blocos_atencao: blocos, + bloco_ssd: BlocoSsd::novo(m.d_modelo, m.d_ff, dev)?, + norm_final: RmsNorm::novo(m.d_modelo, 1e-5, dev)?, + ancora, + film_gamma, + film_beta, + n_niveis: l, + }) + } + + /// Injeção FiLM do resumo-âncora nas posições do nível `nivel` + /// (ADBA (i): o resumo depende APENAS de c_{<ℓ} — paralelismo preservado). + pub fn aplicar_film(&self, x: &Tensor, resumo: &Tensor, nivel: usize) -> Result { + match (&self.film_gamma, &self.film_beta) { + (Some(g), Some(b)) => { + let d = x.dims()[2]; + let bsz = resumo.dims()[0].max(1); + let gv = g.as_tensor().get(nivel)?.reshape((1, 1, d))?; + let bv = b.as_tensor().get(nivel)?.reshape((1, 1, d))?; + let r = resumo.reshape((bsz, 1, d))?; + // x ⊙ (1 + γ·tanh(r)) + β·r — neutro em γ=β=0 (nascimento neutro) + let gate = gv.broadcast_mul(&r.tanh()?)?.affine(1.0, 1.0)?; // 1 + γ·tanh(r) + let xg = x.broadcast_mul(&gate)?; + let desloc = bv.broadcast_mul(&r)?; + xg.broadcast_add(&desloc) + } + _ => Ok(x.clone()), + } + } + + /// Forward de treino: sequência completa s (b, T, d) com máscara aditiva + /// (T, T) e mapa de níveis por posição (query e chave). 1 passada — D.1(iv). + pub fn forward_treino( + &self, + s: &Tensor, + mascara: &Tensor, + niveis: &[usize], + resumos_por_nivel: &mut Vec, + ) -> Result { + let b = s.dim(0)?; + let mut x = s.clone(); + for (i, bloco) in self.blocos_atencao.iter().enumerate() { + let mut cache = CacheKv::default(); + x = bloco.fwd(&x, Some(mascara), &mut cache, Some(niveis), Some(niveis))?; + // após o 1º bloco: injeta o resumo-âncora por nível (ADBA) + if i == 0 { + if let Some(anc) = &self.ancora { + resumos_por_nivel.clear(); + let n_prefixo = x.dims()[1] - self.tamanhos_por_nivel(niveis).iter().sum::(); + // prefixo entra inalterado (sem FiLM — nível 0) + let mut partes = vec![x.narrow(1, 0, n_prefixo)?]; + let mut inicio = n_prefixo; + for (nivel, &n_n) in self.tamanhos_por_nivel(niveis).iter().enumerate() { + let trecho = x.narrow(1, inicio, n_n)?; + // resumo do CONTEXTO ANTERIOR (níveis < atual): usa as + // posições já processadas (função de c_{<ℓ} apenas) + if inicio == n_prefixo { + resumos_por_nivel.push(Tensor::zeros((b, s.dims()[2]), candle_core::DType::F32, s.device())?); + } else { + let ctx = x.narrow(1, 0, inicio)?; + let mut r_nivel = Vec::new(); + for bi in 0..b { + r_nivel.push(anc.resumir(&ctx.narrow(0, bi, 1)?, nivel)?); + } + resumos_por_nivel.push(Tensor::cat(&r_nivel, 0)?); + } + let r = resumos_por_nivel[nivel].clone(); + partes.push(self.aplicar_film(&trecho, &r, nivel + 1)?); + inicio += n_n; + } + x = Tensor::cat(&partes, 1)?; + } + } + } + let mut cache_ssd = None; + x = self.bloco_ssd.fwd(&x, &mut cache_ssd)?; + self.norm_final.fwd(&x) + } + + /// Forward incremental (inferência): bloco novo (b, n_novo, d) + caches. + /// `niveis_novos`/`niveis_cache` mapeiam posições para níveis. + pub fn forward_nivel( + &self, + bloco_x: &Tensor, + caches: &mut Vec, + mascara_nova: &Tensor, + niveis_novos: &[usize], + niveis_totais: &[usize], + ) -> Result { + let mut x = bloco_x.clone(); + for (i, bloco) in self.blocos_atencao.iter().enumerate() { + if caches.len() <= i { + caches.push(CacheKv::default()); + } + x = bloco.fwd(&x, Some(mascara_nova), &mut caches[i], Some(niveis_novos), Some(niveis_totais))?; + let _ = i; + } + let mut cache_ssd = None; + x = self.bloco_ssd.fwd(&x, &mut cache_ssd)?; + self.norm_final.fwd(&x) + } + + fn tamanhos_por_nivel(&self, niveis: &[usize]) -> Vec { + let max_n = niveis.iter().copied().max().unwrap_or(0); + let mut out = vec![0usize; max_n]; + for &n in niveis { + if n >= 1 && n <= max_n { + out[n - 1] += 1; + } + } + out + } + + pub fn vars(&self) -> Vec { + let mut v: Vec = self.blocos_atencao.iter().flat_map(|b| b.vars()).collect(); + v.extend(self.bloco_ssd.vars()); + v.extend(self.norm_final.vars()); + if let Some(a) = &self.ancora { + v.extend(a.vars()); + } + if let Some(g) = &self.film_gamma { + v.push(g.clone()); + } + if let Some(b) = &self.film_beta { + v.push(b.clone()); + } + v + } +} + +/// Cabeças de conceitos por nível (via A de T1): linear d → K_ℓ. +pub struct CabecaConceitos { + pub cabecas: Vec, +} + +impl CabecaConceitos { + pub fn nova(cfg: &ConfigKhtst, dev: &Device) -> Result { + let mut c = Vec::with_capacity(cfg.l_niveis()); + for _ in 0..cfg.l_niveis() { + c.push(Linear::sem_vies(cfg.modelo.d_modelo, cfg.ncm.k_por_nivel, 0.02, dev)?); + } + Ok(CabecaConceitos { cabecas: c }) + } + + pub fn vars(&self) -> Vec { + self.cabecas.iter().flat_map(|c| c.vars()).collect() + } +} + +/// Embeddings de nível e_ℓ (T1 via A). +pub struct EmbNiveis { + pub tabela: Embedding, +} + +impl EmbNiveis { + pub fn nova(cfg: &ConfigKhtst, dev: &Device) -> Result { + Ok(EmbNiveis { tabela: Embedding::novo(cfg.l_niveis() + 1, cfg.modelo.d_modelo, dev)? }) + } + pub fn vars(&self) -> Vec { + self.tabela.vars() + } +}