diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5808db668..ee10093a0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,6 +45,13 @@ jobs: sudo apt-get update -q -y sudo apt-get install -q -y clang-${{ matrix.clang-version }} lld-${{ matrix.clang-version }} libomp-${{ matrix.clang-version }}-dev libeigen3-dev libboost-dev sudo ln -sf $(which ld.lld-${{ matrix.clang-version }}) /usr/local/bin/ld.lld + # Install Rust + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 @@ -55,7 +62,7 @@ jobs: run: | mkdir build cd build - cmake .. -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DIQTREE_FLAGS=static -DCMAKE_C_COMPILER=$(which clang-${{ matrix.clang-version }}) -DCMAKE_CXX_COMPILER=$(which clang++-${{ matrix.clang-version }}) + cmake .. -DUSE_MUTSEL=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DIQTREE_FLAGS=static -DCMAKE_C_COMPILER=$(which clang-${{ matrix.clang-version }}) -DCMAKE_CXX_COMPILER=$(which clang++-${{ matrix.clang-version }}) make -j make package file iqtree3 | grep x86-64 @@ -109,11 +116,18 @@ jobs: sudo apt-get update -q -y sudo apt-get install -q -y gcc g++ libeigen3-dev libboost-dev + # Install Rust + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal - name: Build run: | mkdir build cd build - cmake .. -DIQTREE_FLAGS=static + cmake .. -DIQTREE_FLAGS=static -DUSE_MUTSEL=ON make -j make package file iqtree3 | grep aarch64 @@ -199,6 +213,13 @@ jobs: - name: Install dependencies run: brew install make eigen boost libomp + # Install Rust + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal - name: Build run: | set -x @@ -206,7 +227,7 @@ jobs: cd build export CPPFLAGS="-I/usr/local/opt/libomp/include" export CXXFLAGS="-I/usr/local/opt/libomp/include" - cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DEIGEN3_INCLUDE_DIR=$(brew --prefix eigen)/include/eigen3 + cmake .. -DUSE_MUTSEL=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DEIGEN3_INCLUDE_DIR=$(brew --prefix eigen)/include/eigen3 make -j make package file iqtree3 | grep x86_64 @@ -256,6 +277,13 @@ jobs: - name: Install dependencies run: brew install make eigen boost libomp + # Install Rust + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal - name: Build run: | set -x @@ -263,7 +291,7 @@ jobs: cd build export CPPFLAGS="-I/opt/homebrew/opt/libomp/include" export CXXFLAGS="-I/opt/homebrew/opt/libomp/include" - cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DEIGEN3_INCLUDE_DIR=$(brew --prefix eigen)/include/eigen3 + cmake .. -DUSE_MUTSEL=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DEIGEN3_INCLUDE_DIR=$(brew --prefix eigen)/include/eigen3 make -j make package file iqtree3 | grep arm64 @@ -378,6 +406,14 @@ jobs: shell: cmd run: choco install eigen + # Install Rust + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal + target: x86_64-pc-windows-gnu - name: Compile shell: cmd run: | @@ -385,14 +421,19 @@ jobs: mkdir build cd build cmake -G "MinGW Makefiles" ^ + -DUSE_MUTSEL=ON ^ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ^ - -DCMAKE_C_FLAGS=--target=x86_64-pc-windows-gnu ^ - -DCMAKE_CXX_FLAGS=--target=x86_64-pc-windows-gnu ^ + -DCMAKE_C_FLAGS="--target=x86_64-pc-windows-gnu --sysroot=C:/mingw64 -B C:/mingw64/bin" ^ + -DCMAKE_CXX_FLAGS="--target=x86_64-pc-windows-gnu --sysroot=C:/mingw64 -B C:/mingw64/bin" ^ -DCMAKE_MAKE_PROGRAM=mingw32-make ^ -DBoost_INCLUDE_DIR="C:/local/boost/include" ^ -DBoost_LIBRARY_DIRS="C:/local/boost/lib" ^ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^ - -DIQTREE_FLAGS="static cpp14" .. + -DIQTREE_FLAGS="static" .. + + type CMakeFiles\iqtree3.dir\link.txt + type CMakeFiles\iqtree3.dir\linkLibs.rsp + make -j make package env: diff --git a/.gitignore b/.gitignore index 031049267..43f47d455 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ zlib-1.2.7/ /.direnv/ /.envrc softwipe_build +mutsel_rust/target/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0db587396..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cmake.configureOnOpen": true -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c4637498..2c21c837e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,6 +284,43 @@ else() message("Integrate CMAPLE_AA: OFF") endif() +################################################################## +# Include Rust dependecies: phylo_grad, MUTSEL model +################################################################## + +if (USE_MUTSEL STREQUAL "ON") + message("Compile Rust Dependencies: ON") + if (WIN32) + set(MUTSEL_RUST_LIB_FILE "x86_64-pc-windows-gnu/release/libmutsel_rust.a") + else() + set(MUTSEL_RUST_LIB_FILE "release/libmutsel_rust.a") + endif() + set(MUTSEL_RUST_LIB_PATH "${CMAKE_SOURCE_DIR}/mutsel_rust/target/${MUTSEL_RUST_LIB_FILE}") + + if (WIN32) + set(CARGO_TARGET --target x86_64-pc-windows-gnu) + else() + set(CARGO_TARGET "") + endif() + + + include(ExternalProject) + ExternalProject_Add( + mutsel + SOURCE_DIR "${CMAKE_SOURCE_DIR}/mutsel_rust" # Where your Rust source is + CONFIGURE_COMMAND "" # No configure step for Rust + BUILD_COMMAND cargo build --release --lib ${CARGO_TARGET} + BUILD_BYPRODUCTS "${MUTSEL_RUST_LIB_PATH}" + INSTALL_COMMAND "" # No install step for Rust + BUILD_IN_SOURCE 1 # Build in source directory + LOG_BUILD ON + LOG_OUTPUT_ON_FAILURE ON + ) + add_definitions(-DUSE_MUTSEL) +else() + message("Compile Rust Dependencies: OFF") +endif() + ################################################################## # build IQTREE library ################################################################## @@ -313,16 +350,10 @@ elseif (APPLE) # set the first version of mac 11 that supports ARM set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --target=arm64-apple-macos11.0.1") else() - # to be compatible back to Mac OS X 10.7 - if (IQTREE_FLAGS MATCHES "oldmac") - add_definitions("-mmacosx-version-min=10.5") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mmacosx-version-min=10.5") - else() - # supports the first version changed from OS X to macOS - add_definitions("--target=x86_64-apple-macos10.12") - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --target=x86_64-apple-macos10.12") - endif() + # supports the first version changed from OS X to macOS + add_definitions("--target=x86_64-apple-macos11.0.1") + set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0.1) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --target=x86_64-apple-macos11.0.1") endif() SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) elseif (UNIX) @@ -1017,7 +1048,8 @@ endif() # basic linking librararies target_link_libraries(iqtree3 pll ncl nclextra utils pda lbfgsb whtest sprng vectorclass model - gsl alignment tree simulator terrace yaml-cpp phyloYAML main ${TARGET_CMAPLE} ${PLATFORM_LIB} ${STD_LIB} ${THREAD_LIB} ${ATOMIC_LIB}) + gsl alignment tree simulator terrace yaml-cpp phyloYAML main ${TARGET_CMAPLE} ${PLATFORM_LIB} ${STD_LIB} ${THREAD_LIB} ${ATOMIC_LIB} ${CMAKE_DL_LIBS}) + # Link the bundled LLVM libomp.a even for GCC builds # dl is needed by libomp on Linux for dlsym diff --git a/alignment/alignment.cpp b/alignment/alignment.cpp index 111987cf9..9a4a9526b 100644 --- a/alignment/alignment.cpp +++ b/alignment/alignment.cpp @@ -4102,6 +4102,15 @@ void Alignment::createBootstrapAlignment(Alignment *aln, IntVector* pattern_freq memcpy(state_freq, aln->ptn_state_freq[ptn], num_states*sizeof(double)); } ptn_state_freq.push_back(state_freq); + if (!aln->site_rate_matrices.empty()) { + /* Minh/Thomas: Better change 190 to num_states*(numstates-1)/2 so that if you want to + extend the model in the future, no change is needed here + Also: This is only for reversible models. For non-rev models + you need to store the full matrix, i.e., num_states*num_states entries + */ + const double *rate_matrix = aln->site_rate_matrices.data() + ptn * 190; + site_rate_matrices.insert(site_rate_matrices.end(), rate_matrix, rate_matrix + 190); + } } if (pattern_freq) { ((*pattern_freq)[ptn])++; @@ -4186,6 +4195,9 @@ void Alignment::createBootstrapAlignment(Alignment *aln, IntVector* pattern_freq out_site += site_vec[part+1]; } } + if (!aln->site_rate_matrices.empty()) { + ASSERT(aln->site_rate_matrices.size() == aln->getNPattern() * 190); + } if (aln->isSSF()) { ASSERT(ptn_state_freq.size() == getNPattern()); } diff --git a/alignment/alignment.h b/alignment/alignment.h index e011d84da..f42233a1c 100644 --- a/alignment/alignment.h +++ b/alignment/alignment.h @@ -949,6 +949,10 @@ class Alignment : public vector, public CharSet, public StateSpace { /** pattern index to state frequency vector map */ vector ptn_state_freq; + /** site to rate matrix. Stored in row-major order [num_sites, 190] used for MUTSEL */ + vector site_rate_matrices; + // Minh/Thomas: TODO rename this to ptn_rate_matrices to avoid confusions + /** * @return true if data type is SEQ_CODON and state is a stop codon */ diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 5c7916294..ab989d385 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(main terraceanalysis.h ) + if (USE_BOOSTER) target_link_libraries(main booster) endif() @@ -58,4 +59,4 @@ if (USE_CMAPLE) target_link_libraries(main-aa pda whtest vectorclass terrace maple-aa) endif() -endif() +endif() \ No newline at end of file diff --git a/main/main.cpp b/main/main.cpp index 94435557e..784f2c695 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -64,6 +64,7 @@ #include "utils/operatingsystem.h" //for getOSName() #include #include "vectorclass/instrset.h" +#include "main/outstreambuf.h" #include "alignment/alignment.h" #include "utils/MPIHelper.h" @@ -1686,30 +1687,6 @@ void processNCBITree(Params ¶ms) { } } -/* write simultaneously to cout/cerr and a file */ -class outstreambuf : public streambuf { -public: - outstreambuf* open( const char* name, ios::openmode mode = ios::out); - bool is_open(); - outstreambuf* close(); - ~outstreambuf() { close(); } - streambuf *get_fout_buf() { - return fout_buf; - } - streambuf *get_cout_buf() { - return cout_buf; - } - ofstream *get_fout() { - return &fout; - } - -protected: - ofstream fout; - streambuf *cout_buf; - streambuf *fout_buf; - virtual int overflow( int c = EOF); - virtual int sync(); -}; outstreambuf* outstreambuf::open( const char* name, ios::openmode mode) { if (!(Params::getInstance().suppress_output_flags & OUT_LOG)) { diff --git a/main/outstreambuf.h b/main/outstreambuf.h new file mode 100644 index 000000000..d94acd048 --- /dev/null +++ b/main/outstreambuf.h @@ -0,0 +1,33 @@ +#ifndef OUTSTREAMBUF_H +#define OUTSTREAMBUF_H + +#include +#include +#include + +/* write simultaneously to cout/cerr and a file */ +class outstreambuf : public std::streambuf { +public: + outstreambuf* open( const char* name, std::ios::openmode mode = std::ios::out); + bool is_open(); + outstreambuf* close(); + ~outstreambuf() { close(); } + std::streambuf *get_fout_buf() { + return fout_buf; + } + std::streambuf *get_cout_buf() { + return cout_buf; + } + std::ofstream *get_fout() { + return &fout; + } + +protected: + std::ofstream fout; + std::streambuf *cout_buf; + std::streambuf *fout_buf; + virtual int overflow( int c = EOF); + virtual int sync(); +}; + +#endif // OUTSTREAMBUF_H \ No newline at end of file diff --git a/main/phyloanalysis.cpp b/main/phyloanalysis.cpp index c2dac05a5..46918dda9 100644 --- a/main/phyloanalysis.cpp +++ b/main/phyloanalysis.cpp @@ -67,6 +67,10 @@ #include #include +#include "utils/mutsel_wrapper.h" +#include "utils/self_process.h" +#include + using namespace Eigen; using Eigen::Map; @@ -2570,7 +2574,30 @@ void runApproximateBranchLengths(Params ¶ms, IQTree &iqtree) { } +// For MUTSEL model write a different file since we here only have the actual substitution rate +void printMutselSiteRates(Alignment &alignment, const char *rate_file) { + DoubleVector site_rates = computeMutselSiteRates(alignment); + try { + ofstream out; + out.exceptions(ios::failbit | ios::badbit); + out.open(rate_file); + out.setf(ios::fixed, ios::floatfield); + out.precision(5); + out << "Site\tRate" << endl; + for (size_t i = 0; i < site_rates.size(); ++i) + out << i + 1 << "\t" << site_rates[i] << endl; + out.close(); + } catch (ios::failure) { + outError(ERR_WRITE_OUTPUT, rate_file); + } + cout << "Site rates printed to " << rate_file << endl; +} + void printSiteRates(IQTree &iqtree, const char *rate_file, bool bayes) { + if (Params::getInstance().model_name.rfind("MUTSEL") == 0) { + printMutselSiteRates(*iqtree.aln, rate_file); + return; + } try { ofstream out; out.exceptions(ios::failbit | ios::badbit); @@ -2588,7 +2615,7 @@ void printSiteRates(IQTree &iqtree, const char *rate_file, bool bayes) { << "# Site: Site ID within partition (starting from 1 for each partition)" << endl; } else out << "# Site: Alignment site ID" << endl; - + if (bayes) out << "# Rate: Posterior mean site rate weighted by posterior probability" << endl << "# Cat: Category with highest posterior (0=invariable, 1=slow, etc)" << endl @@ -5196,19 +5223,65 @@ void runPhyloAnalysis(Params ¶ms, Checkpoint *checkpoint, IQTree *&tree, Ali // Initialize site-frequency model if (params.tree_freq_file) { - if (checkpoint->getBool("finishedSiteFreqFile")) { - alignment->readSiteStateFreq(((string)params.out_prefix + ".sitefreq").c_str()); - params.print_site_state_freq = WSF_NONE; - cout << "CHECKPOINT: Site frequency model restored" << endl; + if ((std::string)params.tree_freq_file == "AUTO") { + /* Minh/Thomas comments: the design of spawning process is not great + because you need to load the alignment again causing overhead. + It's better to run inside IQ-TREE. Suggest that we do not + announce -ft AUTO option for now, and just ask users to explicitly + infer a guide tree themselves. + */ + cout << "INFO: Automatic guide tree inference using LG+F+G4" << endl; + auto guide_tree_out = (std::string)params.out_prefix + ".guide_tree"; + if (fileExists(guide_tree_out + ".treefile")) { + cout << "INFO: Guide tree already exists at " << guide_tree_out + ".treefile" << endl; + params.tree_freq_file = strdup((guide_tree_out + ".treefile").c_str()); + } else { + cout << "INFO: Guide tree does not exist, inferring..." << endl; + auto arguments = std::vector{"-s", (std::string)params.aln_file, "-m", "LG+F+G4", "-nt", std::to_string(params.num_threads), "-pre", guide_tree_out}; + auto process = selfproc::spawn_self(arguments); + auto exit_code = process.wait(); + if (exit_code != 0) { + outError("Guide tree inference failed with exit code " + std::to_string(exit_code)); + exit(1); + } + cout << "INFO: Guide tree written to " << guide_tree_out + ".treefile" << endl; + params.tree_freq_file = strdup((guide_tree_out + ".treefile").c_str()); + } + } + if (params.model_name.rfind("MUTSEL") == 0) { + if (checkpoint->getBool("finishedSiteModelFile")) { + read_site_model_file((string)params.out_prefix + ".sitemodel", *alignment); + alignment->model_name = params.model_name; + params.print_site_state_freq = WSF_NONE; + cout << "CHECKPOINT: Site model restored" << endl; + } else { + computeMutselSiteFrequencyModel(params, alignment); + alignment->model_name = params.model_name; + checkpoint->putBool("finishedSiteModelFile", true); + checkpoint->dump(); + } } else { - computeSiteFrequencyModel(params, alignment); - checkpoint->putBool("finishedSiteFreqFile", true); - checkpoint->dump(); + if (checkpoint->getBool("finishedSiteFreqFile")) { + alignment->readSiteStateFreq(((string)params.out_prefix + ".sitefreq").c_str()); + params.print_site_state_freq = WSF_NONE; + cout << "CHECKPOINT: Site frequency model restored" << endl; + } else { + computeSiteFrequencyModel(params, alignment); + checkpoint->putBool("finishedSiteFreqFile", true); + checkpoint->dump(); + } } } if (params.site_freq_file) { alignment->readSiteStateFreq(params.site_freq_file); } + if (!params.site_model_file.empty()) { + read_site_model_file(params.site_model_file, *alignment); + std::cout << "INFO: Site model read from " << params.site_model_file << std::endl; + alignment->model_name = "MUTSEL"; + params.model_name = alignment->model_name; + params.print_site_state_freq = WSF_NONE; + } } if (params.symtest) { @@ -5225,6 +5298,14 @@ void runPhyloAnalysis(Params ¶ms, Checkpoint *checkpoint, IQTree *&tree, Ali tree = newIQTree(params, alignment); tree->setCheckpoint(checkpoint); + // Increase the maximum branch length if MutSel is used because the time unit is different. + if (params.model_name.rfind("MUTSEL") == 0) { + // Minh/Thomas: Better have some option like --max-mutsel-brlen with the + // default of 200.0. So users can change. We don't like hard-coded + // constant in the code + // Also this has to be in the utils.cpp file, not here, which is hard to debug. + params.max_branch_length = 200.0; + } if (tree->isTreeMix()) { ((IQTreeMix*) tree)->setMinBranchLen(params); } else if (params.min_branch_length <= 0.0) { @@ -5243,6 +5324,7 @@ void runPhyloAnalysis(Params ¶ms, Checkpoint *checkpoint, IQTree *&tree, Ali cout << "NOTE: minimal branch length is increased to " << params.min_branch_length << " because PoMo infers number of mutations and frequency shifts" << endl; cout.precision(3); } + } // Increase the minimum branch length if PoMo is used. if (alignment->seq_type == SEQ_POMO) { diff --git a/model/modelfactory.cpp b/model/modelfactory.cpp index a45f1a842..d677312e6 100644 --- a/model/modelfactory.cpp +++ b/model/modelfactory.cpp @@ -639,39 +639,64 @@ ModelFactory::ModelFactory(Params ¶ms, string &model_name, PhyloTree *tree, // fused_mix_rate &= model->isMixture() && site_rate->getNRate() > 1; } else { // site-specific model - if (model_str == "JC" || model_str == "POISSON") - outError("JC is not suitable for site-specific model"); - model = new ModelSet(model_str.c_str(), tree); - ModelSet *models = (ModelSet*)model; // assign pointer for convenience - models->init((params.freq_type != FREQ_UNKNOWN) ? params.freq_type : FREQ_EMPIRICAL); - double *state_freq = new double[model->num_states]; - double *rates = new double[model->getNumRateEntries()]; - for (size_t i = 0; i < tree->aln->ptn_state_freq.size(); ++i) { - ModelMarkov *modeli; - if (i == 0) { - modeli = (ModelMarkov*)createModel(model_str, models_block, (params.freq_type != FREQ_UNKNOWN) ? params.freq_type : FREQ_EMPIRICAL, "", tree); - modeli->getStateFrequency(state_freq); - modeli->getRateMatrix(rates); - } else { - modeli = (ModelMarkov*)createModel(model_str, models_block, FREQ_EQUAL, "", tree); - modeli->setStateFrequency(state_freq); - modeli->setRateMatrix(rates); + + if (tree->aln->site_rate_matrices.empty()) { + // PMSF + if (model_str == "JC" || model_str == "POISSON") + outError("JC is not suitable for site-specific model"); + model = new ModelSet(model_str.c_str(), tree); + ModelSet *models = (ModelSet*)model; // assign pointer for convenience + models->init((params.freq_type != FREQ_UNKNOWN) ? params.freq_type : FREQ_EMPIRICAL); + double *state_freq = new double[model->num_states]; + double *rates = new double[model->getNumRateEntries()]; + for (size_t i = 0; i < tree->aln->ptn_state_freq.size(); ++i) { + ModelMarkov *modeli; + if (i == 0) { + modeli = (ModelMarkov*)createModel(model_str, models_block, (params.freq_type != FREQ_UNKNOWN) ? params.freq_type : FREQ_EMPIRICAL, "", tree); + modeli->getStateFrequency(state_freq); + modeli->getRateMatrix(rates); + } else { + modeli = (ModelMarkov*)createModel(model_str, models_block, FREQ_EQUAL, "", tree); + modeli->setStateFrequency(state_freq); + modeli->setRateMatrix(rates); + } + if (tree->aln->ptn_state_freq[i]) + modeli->setStateFrequency (tree->aln->ptn_state_freq[i]); + + modeli->init(FREQ_USER_DEFINED); + models->push_back(modeli); } - if (tree->aln->ptn_state_freq[i]) + delete [] rates; + delete [] state_freq; + + models->joinEigenMemory(); + models->decomposeRateMatrix(); + } else { + // MUTSEL + ModelSet *models = new ModelSet(model_str.c_str(), tree); + + models->init((params.freq_type != FREQ_UNKNOWN) ? params.freq_type : FREQ_EMPIRICAL); + models->fixParameters(true); + + for (size_t i = 0; i < tree->aln->ptn_state_freq.size(); ++i) { + ModelMarkov *modeli = new ModelMarkov(tree, true, true); // dummy model for getting num_states and num_rate_entries modeli->setStateFrequency(tree->aln->ptn_state_freq[i]); + modeli->setRateMatrix(tree->aln->site_rate_matrices.data() + i * 190); + + // Minh/Thomas: Important to note: site Q matrices are not normalised + // But make sure to normalise across all sites, i.e. + // (1/nsites) * sum_i mu_i = 1.0, where mu_i = -sum_j pi^i_j * Q^i_{jj} + modeli->normalize_matrix = false; + modeli->init(FREQ_USER_DEFINED); + modeli->fixParameters(true); + models->push_back(modeli); + } + + models->joinEigenMemory(); + models->decomposeRateMatrix(); - modeli->init(FREQ_USER_DEFINED); - models->push_back(modeli); + model = models; } - delete [] rates; - delete [] state_freq; - - models->joinEigenMemory(); - models->decomposeRateMatrix(); - - // delete information of the old alignment -// tree->aln->ordered_pattern.clear(); -// tree->deleteAllPartialLh(); } // if (model->isMixture()) diff --git a/mutsel_rust/Cargo.lock b/mutsel_rust/Cargo.lock new file mode 100644 index 000000000..efae748ad --- /dev/null +++ b/mutsel_rust/Cargo.lock @@ -0,0 +1,2419 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "accurate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f209f0bc218ee6cf50db56ec0d9fe10b3cbfb6f3900d019b36c8fdb6d3bc03e" +dependencies = [ + "cfg-if", + "ieee754", + "num-traits 0.2.19", + "rayon", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "buffer-redux" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8acf87c5b9f5897cd3ebb9a327f420e0cae9dd4e5c1d2e36f2c84c571a58f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "candle-core" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c15b675b80d994b2eadb20a4bbe434eabeb454eac3ee5e2b4cf6f147ee9be091" +dependencies = [ + "byteorder", + "float8", + "gemm 0.19.0", + "half", + "libm", + "memmap2", + "num-traits 0.2.19", + "num_cpus", + "rand 0.9.2", + "rand_distr 0.5.1", + "rayon", + "safetensors", + "thiserror 2.0.18", + "yoke", + "zip", +] + +[[package]] +name = "candle-nn" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3045fa9e7aef8567d209a27d56b692f60b96f4d0569f4c3011f8ca6715c65e03" +dependencies = [ + "candle-core", + "half", + "libc", + "num-traits 0.2.19", + "rayon", + "safetensors", + "serde 1.0.228", + "thiserror 2.0.18", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_complete" +version = "4.5.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c757a3b7e39161a4e56f9365141ada2a6c915a8622c408ab6bb4b5d047371031" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "config" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" +dependencies = [ + "lazy_static 1.5.0", + "nom", + "rust-ini", + "serde 1.0.228", + "serde-hjson", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[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.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "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.117", +] + +[[package]] +name = "equator" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" +dependencies = [ + "equator-macro 0.2.1", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro 0.4.2", +] + +[[package]] +name = "equator-macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "faer" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb922206162d9405f9fc059052b3f997bdc92745da7bfd620645f5092df20d1" +dependencies = [ + "bytemuck", + "dyn-stack", + "equator 0.4.2", + "faer-macros", + "faer-traits", + "gemm 0.18.2", + "generativity", + "libm", + "nano-gemm", + "num-complex", + "num-traits 0.2.19", + "pulp 0.21.5", + "reborrow", +] + +[[package]] +name = "faer-macros" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc4b8cd876795d3b19ddfd59b03faa303c0b8adb9af6e188e81fc647c485bb9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "faer-traits" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b69235b5f54416286c485fb047f2f499fc935a4eee2caadf4757f3c94c7b62" +dependencies = [ + "bytemuck", + "dyn-stack", + "faer-macros", + "generativity", + "libm", + "num-complex", + "num-traits 0.2.19", + "pulp 0.21.5", + "qd", + "reborrow", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float8" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719a903cc23e4a89e87962c2a80fdb45cdaad0983a89bd150bb57b4c8571a7d5" +dependencies = [ + "half", + "num-traits 0.2.19", + "rand 0.9.2", + "rand_distr 0.5.1", +] + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "gemm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" +dependencies = [ + "dyn-stack", + "gemm-c32 0.18.2", + "gemm-c64 0.18.2", + "gemm-common 0.18.2", + "gemm-f32 0.18.2", + "gemm-f64 0.18.2", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb" +dependencies = [ + "dyn-stack", + "gemm-c32 0.19.0", + "gemm-c64 0.19.0", + "gemm-common 0.19.0", + "gemm-f16", + "gemm-f32 0.19.0", + "gemm-f64 0.19.0", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" +dependencies = [ + "dyn-stack", + "gemm-common 0.18.2", + "num-complex", + "num-traits 0.2.19", + "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 0.19.0", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" +dependencies = [ + "dyn-stack", + "gemm-common 0.18.2", + "num-complex", + "num-traits 0.2.19", + "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 0.19.0", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" +dependencies = [ + "bytemuck", + "dyn-stack", + "libm", + "num-complex", + "num-traits 0.2.19", + "once_cell", + "paste", + "pulp 0.21.5", + "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 0.2.19", + "once_cell", + "paste", + "pulp 0.22.2", + "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 0.19.0", + "gemm-f32 0.19.0", + "half", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" +dependencies = [ + "dyn-stack", + "gemm-common 0.18.2", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "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 0.19.0", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" +dependencies = [ + "dyn-stack", + "gemm-common 0.18.2", + "num-complex", + "num-traits 0.2.19", + "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 0.19.0", + "num-complex", + "num-traits 0.2.19", + "paste", + "raw-cpuid", + "seq-macro", +] + +[[package]] +name = "generativity" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5881e4c3c2433fe4905bb19cfd2b5d49d4248274862b68c27c33d9ba4e13f9ec" + +[[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", + "wasip2", +] + +[[package]] +name = "glam" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da" + +[[package]] +name = "glam" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb554f8ee44336b72d522e0a7fe86a29e09f839a36022fa869a7dfe941a54b" + +[[package]] +name = "glam" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4126c0479ccf7e8664c36a2d719f5f2c140fbb4f9090008098d2c291fa5b3f16" + +[[package]] +name = "glam" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776" + +[[package]] +name = "glam" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525a3e490ba77b8e326fb67d4b44b4bd2f920f44d4cc73ccec50adc68e3bee34" + +[[package]] +name = "glam" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca" + +[[package]] +name = "glam" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f" + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "glam" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" + +[[package]] +name = "glam" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" + +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + +[[package]] +name = "glam" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[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 0.2.19", + "rand 0.9.2", + "rand_distr 0.5.1", + "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 1.0.228", + "serde_core", +] + +[[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.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "ieee754" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "libc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mutsel_rust" +version = "0.1.0" +dependencies = [ + "anyhow", + "candle-core", + "candle-nn", + "lazy_static 1.5.0", + "libc", + "phylo_grad", + "phylotree", + "rayon", + "seq_io", + "spec_math", +] + +[[package]] +name = "nalgebra" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d5b3eff5cd580f93da45e64715e8c20a3996342f1e466599cf7a267a0c2f5f" +dependencies = [ + "approx", + "glam 0.14.0", + "glam 0.15.2", + "glam 0.16.0", + "glam 0.17.3", + "glam 0.18.0", + "glam 0.19.0", + "glam 0.20.5", + "glam 0.21.3", + "glam 0.22.0", + "glam 0.23.0", + "glam 0.24.2", + "glam 0.25.0", + "glam 0.27.0", + "glam 0.28.0", + "glam 0.29.3", + "glam 0.30.10", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits 0.2.19", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "nano-gemm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb5ba2bea1c00e53de11f6ab5bd0761ba87dc0045d63b0c87ee471d2d3061376" +dependencies = [ + "equator 0.2.2", + "nano-gemm-c32", + "nano-gemm-c64", + "nano-gemm-codegen", + "nano-gemm-core", + "nano-gemm-f32", + "nano-gemm-f64", + "num-complex", +] + +[[package]] +name = "nano-gemm-c32" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a40449e57a5713464c3a1208c4c3301c8d29ee1344711822cf022bc91373a91b" +dependencies = [ + "nano-gemm-codegen", + "nano-gemm-core", + "num-complex", +] + +[[package]] +name = "nano-gemm-c64" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743a6e6211358fba85d1009616751e4107da86f4c95b24e684ce85f25c25b3bf" +dependencies = [ + "nano-gemm-codegen", + "nano-gemm-core", + "num-complex", +] + +[[package]] +name = "nano-gemm-codegen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963bf7c7110d55430169dc74c67096375491ed580cd2ef84842550ac72e781fa" + +[[package]] +name = "nano-gemm-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3fc4f83ae8861bad79dc3c016bd6b0220da5f9de302e07d3112d16efc24aa6" + +[[package]] +name = "nano-gemm-f32" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3681b7ce35658f79da94b7f62c60a005e29c373c7111ed070e3bf64546a8bb" +dependencies = [ + "nano-gemm-codegen", + "nano-gemm-core", +] + +[[package]] +name = "nano-gemm-f64" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc1e619ed04d801809e1f63e61b669d380c4119e8b0cdd6ed184c6b111f046d8" +dependencies = [ + "nano-gemm-codegen", + "nano-gemm-core", +] + +[[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 0.2.19", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "needletail" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db05a5ab397f64070d8c998fa0fbb84e484b81f95752af317dac183a82d9295d" +dependencies = [ + "buffer-redux", + "bytecount", + "bzip2", + "flate2", + "memchr", + "xz2", +] + +[[package]] +name = "nom" +version = "5.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits 0.2.19", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits 0.2.19", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.19", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.19", +] + +[[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 0.5.2", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "numeric_literals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "095aa67b0b9f2081746998f4f17106bdb51d56dc8c211afca5531b92b83bf98a" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phylo_grad" +version = "2.3.2" +source = "git+https://github.com/soedinglab/phylo_grad?rev=939dedb07605411bd6b2dbb4d3d733f842a15ff5#939dedb07605411bd6b2dbb4d3d733f842a15ff5" +dependencies = [ + "faer", + "glam 0.30.10", + "nalgebra", + "rayon", +] + +[[package]] +name = "phylotree" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90725e1c88d0e32161012534ac83013f23e365d38c02c924d2c095c0e553daa" +dependencies = [ + "accurate", + "clap", + "clap_complete", + "fixedbitset", + "indicatif", + "itertools", + "ndarray", + "needletail", + "num-traits 0.2.19", + "numeric_literals", + "ptree", + "rand 0.8.5", + "rand_distr 0.4.3", + "serde 1.0.228", + "thiserror 1.0.69", + "tinytemplate", + "trait-set", + "utf8-read", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +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.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0de80796b316aec75344095a6d2ef68ec9b8f573b9e7adc821149ba3598e270" +dependencies = [ + "ansi_term", + "atty", + "config", + "directories", + "petgraph", + "serde 1.0.228", + "serde-value", + "tint", +] + +[[package]] +name = "pulp" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e205bb30d5b916c55e584c22201771bcf2bad9aabd5d4127f38387140c38632" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e24eee682d89fb193496edf918a7f407d30175b2e785fe057e4392dfd182e0" + +[[package]] +name = "qd" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8bb755b6008c3b41bf8a0866c8dd4e1245a2f011ceaa22a13ee55c538493e2" +dependencies = [ + "bytemuck", + "libm", + "num-traits 0.2.19", + "pulp 0.21.5", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +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.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits 0.2.19", + "rand 0.8.5", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits 0.2.19", + "rand 0.9.2", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[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 = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "safetensors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5" +dependencies = [ + "hashbrown", + "serde 1.0.228", + "serde_json", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "seq_io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1303559e530ee83c1d7a8593a033792c2a29217544a5c48563e116e158d76ade" +dependencies = [ + "buffer-redux", + "crossbeam-utils", + "memchr", + "scoped_threadpool", + "serde 1.0.228", + "serde_derive", +] + +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-hjson" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" +dependencies = [ + "lazy_static 1.5.0", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde 1.0.228", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde 1.0.228", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simba" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95" +dependencies = [ + "approx", + "num-complex", + "num-traits 0.2.19", + "paste", + "wide", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "spec_math" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02ef091d4e8b981dbaa4cc17789d00b53d5d2c001ae689f14e6093f30c529036" + +[[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.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.11.0", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[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.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tint" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af24570664a3074673dbbf69a65bdae0ae0b72f2949b1adfbacb736ee4d6896" +dependencies = [ + "lazy_static 0.2.11", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde 1.0.228", + "serde_json", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde 1.0.228", +] + +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "utf8-read" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb566ac06e11c3f13872ebcb0e72ea5f97f0f65a16f45048d0adea21edc28018" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[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.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[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 = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zip" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", + "typed-path", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/mutsel_rust/Cargo.toml b/mutsel_rust/Cargo.toml new file mode 100644 index 000000000..c5e058a86 --- /dev/null +++ b/mutsel_rust/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "mutsel_rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1.0.100" +candle-core = "0.9.2" +candle-nn = "0.9.2" +lazy_static = "1.5.0" +phylo_grad = { git = "https://github.com/soedinglab/phylo_grad", rev="939dedb07605411bd6b2dbb4d3d733f842a15ff5"} +rayon = "1.11.0" +phylotree = "0.1.3" +seq_io = "0.3.4" +libc = "0.2.182" +spec_math = "0.1.6" + +[lib] +name = "mutsel_rust" +crate-type = ["staticlib", "rlib"] + +[profile.release] +lto = false # There seems to be an issue with LLVM which makes the code slower when using lto +panic = 'abort' + +[profile.dev] +panic = 'abort' + diff --git a/mutsel_rust/src/data.rs b/mutsel_rust/src/data.rs new file mode 100644 index 000000000..7287d87c6 --- /dev/null +++ b/mutsel_rust/src/data.rs @@ -0,0 +1,7854 @@ +use candle_core::Tensor; + +pub const LG_TXT : &'static str = " +0.425093 +0.276818 0.751878 +0.395144 0.123954 5.076149 +2.489084 0.534551 0.528768 0.062556 +0.969894 2.807908 1.695752 0.523386 0.084808 +1.038545 0.363970 0.541712 5.243870 0.003499 4.128591 +2.066040 0.390192 1.437645 0.844926 0.569265 0.267959 0.348847 +0.358858 2.426601 4.509238 0.927114 0.640543 4.813505 0.423881 0.311484 +0.149830 0.126991 0.191503 0.010690 0.320627 0.072854 0.044265 0.008705 0.108882 +0.395337 0.301848 0.068427 0.015076 0.594007 0.582457 0.069673 0.044261 0.366317 4.145067 +0.536518 6.326067 2.145078 0.282959 0.013266 3.234294 1.807177 0.296636 0.697264 0.159069 0.137500 +1.124035 0.484133 0.371004 0.025548 0.893680 1.672569 0.173735 0.139538 0.442472 4.273607 6.312358 0.656604 +0.253701 0.052722 0.089525 0.017416 1.105251 0.035855 0.018811 0.089586 0.682139 1.112727 2.592692 0.023918 1.798853 +1.177651 0.332533 0.161787 0.394456 0.075382 0.624294 0.419409 0.196961 0.508851 0.078281 0.249060 0.390322 0.099849 0.094464 +4.727182 0.858151 4.008358 1.240275 2.784478 1.223828 0.611973 1.739990 0.990012 0.064105 0.182287 0.748683 0.346960 0.361819 1.338132 +2.139501 0.578987 2.000679 0.425860 1.143480 1.080136 0.604545 0.129836 0.584262 1.033739 0.302936 1.136863 2.020366 0.165001 0.571468 6.472279 +0.180717 0.593607 0.045376 0.029890 0.670128 0.236199 0.077852 0.268491 0.597054 0.111660 0.619632 0.049906 0.696175 2.457121 0.095131 0.248862 0.140825 +0.218959 0.314440 0.612025 0.135107 1.165532 0.257336 0.120037 0.054679 5.306834 0.232523 0.299648 0.131932 0.481306 7.803902 0.089613 0.400547 0.245841 3.151815 +2.547870 0.170887 0.083688 0.037967 1.959291 0.210332 0.245034 0.076701 0.119013 10.649107 1.702745 0.185202 1.898718 0.654683 0.296501 0.098369 2.188158 0.189510 0.249313 +"; + +pub const CODON_TXT: &'static str = " +0.013119 +0.013119 0.013119 +1.652941 0.013119 6.572407 +0.013119 2.199548 0.013119 0.013119 +0.013119 2.199548 0.013119 0.013119 0.013119 +1.652941 0.013119 0.013119 6.572407 0.013119 3.292763 +1.652941 2.199548 0.013119 3.292763 1.652941 0.013119 3.292763 +0.013119 2.199548 3.292763 3.292763 0.013119 6.572407 0.013119 0.013119 +0.013119 0.377524 2.199548 0.013119 0.013119 0.013119 0.013119 0.013119 0.013119 +0.013119 0.741928 0.013119 0.013119 0.013119 1.106333 0.013119 0.013119 1.106333 1.470738 +0.013119 2.199548 6.572407 0.013119 0.013119 3.292763 6.572407 0.013119 0.013119 1.106333 0.013119 +0.013119 1.106333 0.013119 0.013119 0.013119 0.013119 0.013119 0.013119 0.013119 8.758837 2.199548 3.292763 +0.013119 0.013119 0.013119 0.013119 3.292763 0.013119 0.013119 0.013119 0.013119 2.199548 4.385978 0.013119 0.013119 +1.652941 1.106333 0.013119 0.013119 0.013119 1.652941 0.013119 0.013119 1.652941 0.013119 2.199548 0.013119 0.013119 0.013119 +1.106333 1.106333 2.199548 0.013119 2.199548 0.013119 0.013119 1.106333 0.013119 0.741928 0.741928 0.013119 0.013119 2.199548 2.199548 +3.292763 0.559726 1.652941 0.013119 0.013119 0.013119 0.013119 0.013119 0.013119 3.292763 0.013119 1.652941 3.292763 0.013119 1.652941 1.652941 +0.013119 3.292763 0.013119 0.013119 6.572407 0.013119 0.013119 1.652941 0.013119 0.013119 1.106333 0.013119 0.013119 0.013119 0.013119 1.106333 0.013119 +0.013119 0.013119 3.292763 3.292763 6.572407 0.013119 0.013119 0.013119 6.572407 0.013119 0.013119 0.013119 0.013119 3.292763 0.013119 1.106333 0.013119 0.013119 +3.292763 0.013119 0.013119 1.652941 0.013119 0.013119 1.652941 1.652941 0.013119 3.292763 1.652941 0.013119 3.292763 1.652941 0.013119 0.013119 0.013119 0.013119 0.013119"; + +pub const CODON2_TXT: &'static str = " +0.000023 +0.000023 0.000023 +1.747002 0.000023 6.987938 +0.000023 2.329328 0.000023 0.000023 +0.000023 2.329328 0.000023 0.000023 0.000023 +1.747002 0.000023 0.000023 6.987938 0.000023 3.493980 +1.747002 2.329328 0.000023 3.493980 1.747002 0.000023 3.493980 +0.000023 2.329328 3.493980 3.493980 0.000023 6.987938 0.000023 0.000023 +0.000023 0.388240 2.329328 0.000023 0.000023 0.000023 0.000023 0.000023 0.000023 +0.000023 0.776458 0.000023 0.000023 0.000023 1.164675 0.000023 0.000023 1.164675 1.552893 +0.000023 2.329328 6.987938 0.000023 0.000023 3.493980 6.987938 0.000023 0.000023 1.164675 0.000023 +0.000023 1.164675 0.000023 0.000023 0.000023 0.000023 0.000023 0.000023 0.000023 9.317243 2.329328 3.493980 +0.000023 0.000023 0.000023 0.000023 3.493980 0.000023 0.000023 0.000023 0.000023 2.329328 4.658633 0.000023 0.000023 +1.747002 1.164675 0.000023 0.000023 0.000023 1.747002 0.000023 0.000023 1.747002 0.000023 2.329328 0.000023 0.000023 0.000023 +1.164675 1.164675 2.329328 0.000023 2.329328 0.000023 0.000023 1.164675 0.000023 0.776458 0.776458 0.000023 0.000023 2.329328 2.329328 +3.493980 0.582349 1.747002 0.000023 0.000023 0.000023 0.000023 0.000023 0.000023 3.493980 0.000023 1.747002 3.493980 0.000023 1.747002 1.747002 +0.000023 3.493980 0.000023 0.000023 6.987938 0.000023 0.000023 1.747002 0.000023 0.000023 1.164675 0.000023 0.000023 0.000023 0.000023 1.164675 0.000023 +0.000023 0.000023 3.493980 3.493980 6.987938 0.000023 0.000023 0.000023 6.987938 0.000023 0.000023 0.000023 0.000023 3.493980 0.000023 1.164675 0.000023 0.000023 +3.493980 0.000023 0.000023 1.747002 0.000023 0.000023 1.747002 1.747002 0.000023 3.493980 1.747002 0.000023 3.493980 1.747002 0.000023 0.000023 0.000023 0.000023 0.000023 + +0.065574 0.098361 0.032787 0.032787 0.032787 0.032787 0.032787 0.065574 0.032787 0.049180 0.098361 0.032787 0.016393 0.032787 0.065574 0.098361 0.065574 0.016393 0.032787 0.065574"; + +/// Load a lower-triangular rate matrix from a whitespace-separated string +/// It will load the first 190 values into a 20x20 matrix +/// Diagonal and upper-triangular values are set to zero +pub fn load_lower_R(matrix: &str) -> Tensor { + let vals = matrix + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect::>(); + + let mut data = vec![0.0; 20 * 20]; + let mut index = 0; + for i in 1..20 { + for j in 0..i { + data[i * 20 + j] = vals[index]; + index += 1; + } + } + Tensor::from_vec(data, &[20, 20], &candle_core::Device::Cpu).unwrap() +} + +pub fn load_lower_R_with_equi(matrix: &str) -> Tensor { + let vals = matrix + .split_whitespace() + .map(|s| s.parse::().unwrap()) + .collect::>(); + + let mut data = vec![0.0; 20 * 20]; + let mut index = 0; + for i in 1..20 { + for j in 0..i { + data[i * 20 + j] = vals[index]; + index += 1; + } + } + for i in 0..20 { + data[i * 20 + i] = vals[index]; + index += 1; + } + Tensor::from_vec(data, &[20, 20], &candle_core::Device::Cpu).unwrap() +} + +pub const C20: &'static [[f64; 20]] = &[ + [ + 0.0862412505, + 0.0171943793, + 0.0791293376, + 0.0329908619, + 0.0130504558, + 0.0169046938, + 0.0184526503, + 0.0366905299, + 0.0108013340, + 0.0097907148, + 0.0112826424, + 0.0220195221, + 0.0087821483, + 0.0044155335, + 0.0189273201, + 0.3178152357, + 0.2711700523, + 0.0015317305, + 0.0048342853, + 0.0179753220, + ], + [ + 0.2035582865, + 0.0050980810, + 0.0077052407, + 0.0031656079, + 0.0348667285, + 0.0064044073, + 0.0070859400, + 0.0195235515, + 0.0024392035, + 0.1152573291, + 0.0789777393, + 0.0042380850, + 0.0309187017, + 0.0112429356, + 0.0164189221, + 0.0496777139, + 0.1118946615, + 0.0017762569, + 0.0048448213, + 0.2849057867, + ], + [ + 0.0211547413, + 0.0014946177, + 0.0012755030, + 0.0005492865, + 0.0048188557, + 0.0012328812, + 0.0014539632, + 0.0011430874, + 0.0011346394, + 0.3928460626, + 0.1250644210, + 0.0013579946, + 0.0209788805, + 0.0128251737, + 0.0020247248, + 0.0026240726, + 0.0171914121, + 0.0011591071, + 0.0036027969, + 0.3860677787, + ], + [ + 0.0376903543, + 0.2885196153, + 0.0365411474, + 0.0109469400, + 0.0064073829, + 0.0893564381, + 0.0358365464, + 0.0191106776, + 0.0329513951, + 0.0101711878, + 0.0237495504, + 0.2897626974, + 0.0096528870, + 0.0036349802, + 0.0105337370, + 0.0356313768, + 0.0355926500, + 0.0027925238, + 0.0066557222, + 0.0144621902, + ], + [ + 0.0084597802, + 0.0053589922, + 0.0072525884, + 0.0024487852, + 0.0084909000, + 0.0042781483, + 0.0025055486, + 0.0024277107, + 0.0433214027, + 0.0097713028, + 0.0380507037, + 0.0026741007, + 0.0080724771, + 0.3420463838, + 0.0021418673, + 0.0080418935, + 0.0055322116, + 0.0494840193, + 0.4375001561, + 0.0121410277, + ], + [ + 0.1759898886, + 0.0290429175, + 0.0332845569, + 0.1301263816, + 0.0017558693, + 0.0707183953, + 0.2182166681, + 0.0409535143, + 0.0130708195, + 0.0085622087, + 0.0159530702, + 0.0542946169, + 0.0054045759, + 0.0025276980, + 0.0371020404, + 0.0793480500, + 0.0540083424, + 0.0010592104, + 0.0036259116, + 0.0249552645, + ], + [ + 0.1634397322, + 0.0195541184, + 0.0438701833, + 0.0374272612, + 0.0088659891, + 0.0137554758, + 0.0220611924, + 0.5296717726, + 0.0090006141, + 0.0017569353, + 0.0061156267, + 0.0167117975, + 0.0029390787, + 0.0030641349, + 0.0126457766, + 0.0829342776, + 0.0142835614, + 0.0028640685, + 0.0032398299, + 0.0057985736, + ], + [ + 0.0917468761, + 0.0265853306, + 0.0290699087, + 0.0133818895, + 0.0284015012, + 0.0255084506, + 0.0196875685, + 0.0249898794, + 0.0449766405, + 0.0583555688, + 0.1155009222, + 0.0164915955, + 0.0395994595, + 0.0998479096, + 0.0209916159, + 0.0736482742, + 0.0661518462, + 0.0246463919, + 0.0972327226, + 0.0831856483, + ], + [ + 0.0646700714, + 0.0988015996, + 0.0228907308, + 0.0168733856, + 0.0077117603, + 0.0996414875, + 0.0544977962, + 0.0148893975, + 0.0313851988, + 0.0505983315, + 0.1844282999, + 0.0907931290, + 0.0774839960, + 0.0219148172, + 0.0105004469, + 0.0321196170, + 0.0411766062, + 0.0084303030, + 0.0206106035, + 0.0505824221, + ], + [ + 0.0135993865, + 0.0043408375, + 0.0018469375, + 0.0007951703, + 0.0100090240, + 0.0046420778, + 0.0018011758, + 0.0026794645, + 0.0072401918, + 0.0814026713, + 0.3661422246, + 0.0025158135, + 0.0734965132, + 0.2640965246, + 0.0038994134, + 0.0043668760, + 0.0075248451, + 0.0261564898, + 0.0660970801, + 0.0573472826, + ], + [ + 0.1478036236, + 0.0842845089, + 0.0726630217, + 0.0534743238, + 0.0048825808, + 0.0757166156, + 0.0727246460, + 0.0907725939, + 0.0262288856, + 0.0035781075, + 0.0126777221, + 0.1051660098, + 0.0059621792, + 0.0029903868, + 0.0156558198, + 0.1459903343, + 0.0634877444, + 0.0015928454, + 0.0050760739, + 0.0092719768, + ], + [ + 0.0186377412, + 0.0042055165, + 0.0019865236, + 0.0008329696, + 0.0054968852, + 0.0065890091, + 0.0020248504, + 0.0021713483, + 0.0023665991, + 0.2020809776, + 0.4370381920, + 0.0029120653, + 0.1241860384, + 0.0385383157, + 0.0040672279, + 0.0046177381, + 0.0149904396, + 0.0026871667, + 0.0056324117, + 0.1189379840, + ], + [ + 0.0477624336, + 0.0505742667, + 0.0209574273, + 0.0141349161, + 0.0075791708, + 0.0429296799, + 0.0462688073, + 0.0052327914, + 0.0165351815, + 0.1741496627, + 0.1121253570, + 0.0577575020, + 0.0330288046, + 0.0130691347, + 0.0124374733, + 0.0264988925, + 0.0951754678, + 0.0031660482, + 0.0112465746, + 0.2093704079, + ], + [ + 0.4164189845, + 0.0056100821, + 0.0091701381, + 0.0045131748, + 0.0406937949, + 0.0061320495, + 0.0063229801, + 0.0946185184, + 0.0031057404, + 0.0076443223, + 0.0099885414, + 0.0038941773, + 0.0069323155, + 0.0048438356, + 0.0187840756, + 0.2360774301, + 0.0746274607, + 0.0012172579, + 0.0034825786, + 0.0459225422, + ], + [ + 0.0402295888, + 0.0735203003, + 0.1036647193, + 0.0365523994, + 0.0124782975, + 0.0826558132, + 0.0372197283, + 0.0233618081, + 0.2108307125, + 0.0093478727, + 0.0360561493, + 0.0482410586, + 0.0100289536, + 0.0459094917, + 0.0098503973, + 0.0533383445, + 0.0310209005, + 0.0140076639, + 0.1064377821, + 0.0152480184, + ], + [ + 0.0323453034, + 0.0236282995, + 0.2520448083, + 0.2431495959, + 0.0035976296, + 0.0330831153, + 0.0710274499, + 0.1016074562, + 0.0366225082, + 0.0031410809, + 0.0051980542, + 0.0470129351, + 0.0024028744, + 0.0024429276, + 0.0094837826, + 0.0848355278, + 0.0359083275, + 0.0008730928, + 0.0067247672, + 0.0048704638, + ], + [ + 0.1476256642, + 0.0334506604, + 0.0211972524, + 0.0403051550, + 0.0032327194, + 0.0371554480, + 0.0576893391, + 0.0330850942, + 0.0146392559, + 0.0108267008, + 0.0256200793, + 0.0451350877, + 0.0058651400, + 0.0047177179, + 0.3473710507, + 0.0892065279, + 0.0485899446, + 0.0016358749, + 0.0044177191, + 0.0282335685, + ], + [ + 0.1031448143, + 0.0717747663, + 0.0435172139, + 0.0386401502, + 0.0061762467, + 0.0786603123, + 0.0923369140, + 0.0202338419, + 0.0246761899, + 0.0376904275, + 0.0376283678, + 0.0921698920, + 0.0161883318, + 0.0067666433, + 0.0128302120, + 0.0951450188, + 0.1378566702, + 0.0022144738, + 0.0083041573, + 0.0740453560, + ], + [ + 0.0837542823, + 0.0899383244, + 0.0518811417, + 0.0804870571, + 0.0020735078, + 0.1456497470, + 0.1947759184, + 0.0229030361, + 0.0268458796, + 0.0074079756, + 0.0190249576, + 0.1459287407, + 0.0067395241, + 0.0023063393, + 0.0085616014, + 0.0455739585, + 0.0451080843, + 0.0010771349, + 0.0049325333, + 0.0150302559, + ], + [ + 0.0578735570, + 0.0138313604, + 0.0491421636, + 0.2946738942, + 0.0011130839, + 0.0598250358, + 0.3402102668, + 0.0293911435, + 0.0139817004, + 0.0030525663, + 0.0062611922, + 0.0363365043, + 0.0027295976, + 0.0017034884, + 0.0156106390, + 0.0358044639, + 0.0249941878, + 0.0008664342, + 0.0038312977, + 0.0087674229, + ], +]; + +pub const C20_WEIGHTS: &'static [f64] = &[ + 0.0559910600, + 0.0514824870, + 0.0812922124, + 0.0721976867, + 0.0556718858, + 0.0331003080, + 0.0589501763, + 0.0263756889, + 0.0307584220, + 0.0376701125, + 0.0303058290, + 0.0808775576, + 0.0263349134, + 0.0579101455, + 0.0371248064, + 0.0586867766, + 0.0561479138, + 0.0349810886, + 0.0544937394, + 0.0596471901, +]; + +pub const C60: &'static [[f64; 20]] = &[ + [ + 0.1534363248, + 0.0444389067, + 0.0796726990, + 0.0546757288, + 0.0047306596, + 0.0514333025, + 0.0529324359, + 0.1103775749, + 0.0174480218, + 0.0050343887, + 0.0130294160, + 0.0603928711, + 0.0075550589, + 0.0035554315, + 0.0249523704, + 0.2029625968, + 0.0957668473, + 0.0014444483, + 0.0059800307, + 0.0101808864, + ], + [ + 0.0281984692, + 0.3031055487, + 0.0312954609, + 0.0091549350, + 0.0019503463, + 0.0939884393, + 0.0388530140, + 0.0084028325, + 0.0155384715, + 0.0107872879, + 0.0217786594, + 0.3476042929, + 0.0109904917, + 0.0015919288, + 0.0071539896, + 0.0197479052, + 0.0328352333, + 0.0009209994, + 0.0025714024, + 0.0135302919, + ], + [ + 0.0083680740, + 0.0007319768, + 0.0006123446, + 0.0002228366, + 0.0020433870, + 0.0009498685, + 0.0004731544, + 0.0004825748, + 0.0005189995, + 0.3768453098, + 0.2608334606, + 0.0006296168, + 0.0315700586, + 0.0123984358, + 0.0009595916, + 0.0009746383, + 0.0049990761, + 0.0008657759, + 0.0017132332, + 0.2938075872, + ], + [ + 0.2227229348, + 0.0064846074, + 0.0061206496, + 0.0007997588, + 0.1640285908, + 0.0051051888, + 0.0027280806, + 0.0202702520, + 0.0037183875, + 0.0455406072, + 0.0883350071, + 0.0022832871, + 0.0348094559, + 0.0228667054, + 0.0035471579, + 0.0850040072, + 0.1012848285, + 0.0048424833, + 0.0096500033, + 0.1698580069, + ], + [ + 0.0412139519, + 0.0067627055, + 0.0051067690, + 0.0017434391, + 0.0204715649, + 0.0057538477, + 0.0037263409, + 0.0069107492, + 0.0180293946, + 0.1154281623, + 0.1693562458, + 0.0042900270, + 0.0414066566, + 0.2239001858, + 0.0058416410, + 0.0149106129, + 0.0239548406, + 0.0332237129, + 0.1379349474, + 0.1200342049, + ], + [ + 0.0480550249, + 0.0308438053, + 0.0940628721, + 0.2084606133, + 0.0037801787, + 0.0747676701, + 0.1855184661, + 0.0191402239, + 0.0872162350, + 0.0094685435, + 0.0277340828, + 0.0375741243, + 0.0088308358, + 0.0196000958, + 0.0081267777, + 0.0439680761, + 0.0324588883, + 0.0034665720, + 0.0387499964, + 0.0181769181, + ], + [ + 0.0062848745, + 0.0026246919, + 0.0030342510, + 0.0005324147, + 0.0073027627, + 0.0034409089, + 0.0009741492, + 0.0019578159, + 0.0102225186, + 0.0180592309, + 0.1179064681, + 0.0016205916, + 0.0234721825, + 0.3974552519, + 0.0020165583, + 0.0056903327, + 0.0037091821, + 0.0598639097, + 0.3185565304, + 0.0152753744, + ], + [ + 0.1815005560, + 0.0026845411, + 0.0148484537, + 0.0025145485, + 0.4205633920, + 0.0014097001, + 0.0007088144, + 0.0461854175, + 0.0014374605, + 0.0041745536, + 0.0098310464, + 0.0006474254, + 0.0041611385, + 0.0068976432, + 0.0038767247, + 0.1864537050, + 0.0687189855, + 0.0027083549, + 0.0061033012, + 0.0345742379, + ], + [ + 0.0600740822, + 0.0367642654, + 0.0134869242, + 0.0170572285, + 0.0070719770, + 0.0142469806, + 0.0127486975, + 0.0343564471, + 0.0305859029, + 0.0204571345, + 0.0994551128, + 0.0212367087, + 0.0318165939, + 0.1140907926, + 0.0297628218, + 0.0505792699, + 0.0339368402, + 0.2312808862, + 0.1192491702, + 0.0217421638, + ], + [ + 0.0708394513, + 0.0474098489, + 0.0416822304, + 0.0324482918, + 0.0131641265, + 0.0494874703, + 0.0508264389, + 0.0183309196, + 0.0567272697, + 0.0650369079, + 0.1282255556, + 0.0343618389, + 0.0390362930, + 0.0594359563, + 0.0135608209, + 0.0551343199, + 0.0642260358, + 0.0137118382, + 0.0673934289, + 0.0789609573, + ], + [ + 0.0617689371, + 0.0076332888, + 0.0303081645, + 0.3430234188, + 0.0007199837, + 0.0307856241, + 0.3792509407, + 0.0284658686, + 0.0079592120, + 0.0016999627, + 0.0039945339, + 0.0216076877, + 0.0019734329, + 0.0009814186, + 0.0174791407, + 0.0337831940, + 0.0203426591, + 0.0006130268, + 0.0017102752, + 0.0058992300, + ], + [ + 0.0421559537, + 0.1042068314, + 0.0286980872, + 0.0164385240, + 0.0044450330, + 0.1393690851, + 0.0531949072, + 0.0134711207, + 0.0177764997, + 0.0267727728, + 0.1967237776, + 0.1323735242, + 0.1182827521, + 0.0086728324, + 0.0051837880, + 0.0255852718, + 0.0333292020, + 0.0045852327, + 0.0070281498, + 0.0217066546, + ], + [ + 0.2814809927, + 0.0100367066, + 0.0172867775, + 0.0064385734, + 0.0258337508, + 0.0133101925, + 0.0115046410, + 0.0270054934, + 0.0054629657, + 0.0188216093, + 0.0190993462, + 0.0098712843, + 0.0158719589, + 0.0050481705, + 0.0129510033, + 0.1886808600, + 0.2427104979, + 0.0012274627, + 0.0036052922, + 0.0837524211, + ], + [ + 0.2769188320, + 0.0017226995, + 0.0021315271, + 0.0011672545, + 0.0318292645, + 0.0018216251, + 0.0024752467, + 0.0199646887, + 0.0005170863, + 0.0983109006, + 0.0489264326, + 0.0016232163, + 0.0173414948, + 0.0070843906, + 0.0070179705, + 0.0336348952, + 0.0814141404, + 0.0007118144, + 0.0032942319, + 0.3620922883, + ], + [ + 0.1577797792, + 0.1112140270, + 0.0570403237, + 0.0648290471, + 0.0053318076, + 0.1065373681, + 0.0913586945, + 0.0906209718, + 0.0533809635, + 0.0029171632, + 0.0156225571, + 0.0782148712, + 0.0045758969, + 0.0025047816, + 0.0067077844, + 0.0929310045, + 0.0393122597, + 0.0028575821, + 0.0077590269, + 0.0085040899, + ], + [ + 0.0593735135, + 0.0354740772, + 0.1151175314, + 0.2189482708, + 0.0015332173, + 0.0688752402, + 0.1819422913, + 0.0813707101, + 0.0220478285, + 0.0020993577, + 0.0056191259, + 0.0750172075, + 0.0021871739, + 0.0010838321, + 0.0109737422, + 0.0726449461, + 0.0380238271, + 0.0007346460, + 0.0026664883, + 0.0042669729, + ], + [ + 0.0978066326, + 0.0265576438, + 0.0101843505, + 0.0120781428, + 0.0064138404, + 0.0307876446, + 0.0291282947, + 0.0128912798, + 0.0128036716, + 0.0723904209, + 0.1279438950, + 0.0245630658, + 0.0303267312, + 0.0198963719, + 0.2723524069, + 0.0350549441, + 0.0484557340, + 0.0046842467, + 0.0104773833, + 0.1152032995, + ], + [ + 0.0124023388, + 0.0030680354, + 0.0009239105, + 0.0006037316, + 0.0041885695, + 0.0032957441, + 0.0012524000, + 0.0011306791, + 0.0013542104, + 0.2344167852, + 0.4550557697, + 0.0016718177, + 0.0667307666, + 0.0610615367, + 0.0037076169, + 0.0019420934, + 0.0067612939, + 0.0038937184, + 0.0074911765, + 0.1290478057, + ], + [ + 0.0794230623, + 0.1294739355, + 0.0662792725, + 0.0587236242, + 0.0019919499, + 0.1143880588, + 0.1246900644, + 0.0325432311, + 0.0238605372, + 0.0036277150, + 0.0097987961, + 0.2147597316, + 0.0041846209, + 0.0012869951, + 0.0142410239, + 0.0615807386, + 0.0477333594, + 0.0006525371, + 0.0029420233, + 0.0078187231, + ], + [ + 0.0248148778, + 0.0083552910, + 0.1888915388, + 0.4278832998, + 0.0027839717, + 0.0210777725, + 0.1432386297, + 0.0643968435, + 0.0185736870, + 0.0022506941, + 0.0034558626, + 0.0179274104, + 0.0015714503, + 0.0014680353, + 0.0073768035, + 0.0377003132, + 0.0187767966, + 0.0005891859, + 0.0042602708, + 0.0046072655, + ], + [ + 0.0017003427, + 0.0060674330, + 0.0004222900, + 0.0010711490, + 0.0029059420, + 0.0016424179, + 0.0011731741, + 0.0035579609, + 0.0027630465, + 0.0012291190, + 0.0127420810, + 0.0004273804, + 0.0025671348, + 0.0513377024, + 0.0013536738, + 0.0011871674, + 0.0014033068, + 0.8640436936, + 0.0390912582, + 0.0033137266, + ], + [ + 0.0468360682, + 0.0639796924, + 0.0205603686, + 0.0185615516, + 0.0059954138, + 0.0557030821, + 0.0705436036, + 0.0045435329, + 0.0152062773, + 0.1550613356, + 0.0824253382, + 0.0866248354, + 0.0245854443, + 0.0080177192, + 0.0081485616, + 0.0237025617, + 0.0962054496, + 0.0018368673, + 0.0067131723, + 0.2047491243, + ], + [ + 0.0258764792, + 0.0201097124, + 0.0298384107, + 0.0107037437, + 0.0142503909, + 0.0158529432, + 0.0105649532, + 0.0073064999, + 0.1411078834, + 0.0114777629, + 0.0407992414, + 0.0119179202, + 0.0098798997, + 0.1876429961, + 0.0051228805, + 0.0275699644, + 0.0170764901, + 0.0405124999, + 0.3536390834, + 0.0187502449, + ], + [ + 0.0296285022, + 0.0046400334, + 0.0034944393, + 0.0008851024, + 0.0090046468, + 0.0055481111, + 0.0033046518, + 0.0027969482, + 0.0050701500, + 0.2583397750, + 0.2668085481, + 0.0046690936, + 0.0770825277, + 0.0408798247, + 0.0026918193, + 0.0068538089, + 0.0322265673, + 0.0035506055, + 0.0153353414, + 0.2271895033, + ], + [ + 0.0555725806, + 0.0098447861, + 0.0409064430, + 0.0140389597, + 0.0097418602, + 0.0068727710, + 0.0069443190, + 0.0157956555, + 0.0041631258, + 0.0069826497, + 0.0075271247, + 0.0139224817, + 0.0058762687, + 0.0034496730, + 0.0119733364, + 0.3482466393, + 0.4213655981, + 0.0010061491, + 0.0026576772, + 0.0131119012, + ], + [ + 0.0682671212, + 0.0615207091, + 0.0530661192, + 0.0360278709, + 0.0141433148, + 0.0612274332, + 0.0497415394, + 0.0268696520, + 0.1127674983, + 0.0132646615, + 0.0544493838, + 0.0482609047, + 0.0170033964, + 0.0803375967, + 0.0191949850, + 0.0671839752, + 0.0443995774, + 0.0199957919, + 0.1255070748, + 0.0267713947, + ], + [ + 0.0792618808, + 0.0638377192, + 0.0635289371, + 0.0436646174, + 0.0049503302, + 0.0666365188, + 0.0829639117, + 0.0183428565, + 0.0233169239, + 0.0249427251, + 0.0221483402, + 0.0932577596, + 0.0120893380, + 0.0049131149, + 0.0126360122, + 0.1334848656, + 0.1916745928, + 0.0018040086, + 0.0062353115, + 0.0503102360, + ], + [ + 0.0731759112, + 0.2105335985, + 0.0324200854, + 0.0110007149, + 0.0123458504, + 0.0858951989, + 0.0349942684, + 0.0224509173, + 0.0386903280, + 0.0246226304, + 0.0508307349, + 0.1783344831, + 0.0185740720, + 0.0093148787, + 0.0148722772, + 0.0603181436, + 0.0649574934, + 0.0051046395, + 0.0130597421, + 0.0385040321, + ], + [ + 0.0878402710, + 0.0110331750, + 0.0060801213, + 0.0032803903, + 0.0171147088, + 0.0109831614, + 0.0101465790, + 0.0087090941, + 0.0054902234, + 0.1987761871, + 0.1756460821, + 0.0082096925, + 0.0417232903, + 0.0191954435, + 0.0111283542, + 0.0209862621, + 0.0697718709, + 0.0031744014, + 0.0081905473, + 0.2825201446, + ], + [ + 0.0990215820, + 0.0349351987, + 0.0211149501, + 0.0118797946, + 0.0108995677, + 0.0557710676, + 0.0278999992, + 0.0240250097, + 0.0123445071, + 0.0776564721, + 0.2354511299, + 0.0322817789, + 0.1207665429, + 0.0214442058, + 0.0075655541, + 0.0524170141, + 0.0649785115, + 0.0047075806, + 0.0077328724, + 0.0771066610, + ], + [ + 0.0601641168, + 0.0161995226, + 0.2783522747, + 0.0337188808, + 0.0315066987, + 0.0210645987, + 0.0059839451, + 0.0543080710, + 0.0531523512, + 0.0070650825, + 0.0070698142, + 0.0139598368, + 0.0088298653, + 0.0069525877, + 0.0075834331, + 0.2829802556, + 0.0860317092, + 0.0014966551, + 0.0134849454, + 0.0100953553, + ], + [ + 0.0049781737, + 0.0018412331, + 0.0007012207, + 0.0005315368, + 0.0052978737, + 0.0024089907, + 0.0007630546, + 0.0015051317, + 0.0041575221, + 0.0443828633, + 0.4417417476, + 0.0011615060, + 0.0602807417, + 0.3351117140, + 0.0027847686, + 0.0025795769, + 0.0030288544, + 0.0171302592, + 0.0458455751, + 0.0237676560, + ], + [ + 0.0251996593, + 0.1114468110, + 0.0142031925, + 0.0041012288, + 0.0097099500, + 0.0620070749, + 0.0262571641, + 0.0038067269, + 0.0431938935, + 0.0974043253, + 0.2447197423, + 0.0824312856, + 0.0539323021, + 0.0429091639, + 0.0052658505, + 0.0096093107, + 0.0251183002, + 0.0146571900, + 0.0456965140, + 0.0783303143, + ], + [ + 0.0230361648, + 0.0014748749, + 0.0013534390, + 0.0006264439, + 0.0048580122, + 0.0009870046, + 0.0015762583, + 0.0011565336, + 0.0008899238, + 0.3952895890, + 0.0576537208, + 0.0014663528, + 0.0140986541, + 0.0072127040, + 0.0020177885, + 0.0028770237, + 0.0205580852, + 0.0005477695, + 0.0019539080, + 0.4603657493, + ], + [ + 0.1408776963, + 0.0297808449, + 0.0171297613, + 0.0285076933, + 0.0032213718, + 0.0320632225, + 0.0423838922, + 0.0299558472, + 0.0131321477, + 0.0066914481, + 0.0195120028, + 0.0383781635, + 0.0036276863, + 0.0041231064, + 0.4383466229, + 0.0851400095, + 0.0422765692, + 0.0013236871, + 0.0037087638, + 0.0198194632, + ], + [ + 0.4442491220, + 0.0050216551, + 0.0102305117, + 0.0057193038, + 0.0235405374, + 0.0055997640, + 0.0064889886, + 0.0822687710, + 0.0025505743, + 0.0033615104, + 0.0040990063, + 0.0038097073, + 0.0028683069, + 0.0024413211, + 0.0162890960, + 0.2999969708, + 0.0559664935, + 0.0007735426, + 0.0020639824, + 0.0226608347, + ], + [ + 0.0898717958, + 0.0070958305, + 0.0130067619, + 0.0129166888, + 0.0044131479, + 0.0023806547, + 0.0058957027, + 0.8087563021, + 0.0016517855, + 0.0004339282, + 0.0015564455, + 0.0033939025, + 0.0004253422, + 0.0008073572, + 0.0034128140, + 0.0362876891, + 0.0032887534, + 0.0015223902, + 0.0008537454, + 0.0020289624, + ], + [ + 0.0550840246, + 0.0472254260, + 0.1877829604, + 0.1273796123, + 0.0035824944, + 0.0527969268, + 0.0655884730, + 0.0637607521, + 0.0404883483, + 0.0075574152, + 0.0136304510, + 0.0867682792, + 0.0081684229, + 0.0040375032, + 0.0110681809, + 0.1263380956, + 0.0752544318, + 0.0013563681, + 0.0118590434, + 0.0102727908, + ], + [ + 0.0117681394, + 0.0442558806, + 0.0844144627, + 0.0144712108, + 0.0070388254, + 0.1038342049, + 0.0110901161, + 0.0049626578, + 0.4337194047, + 0.0061337038, + 0.0298794939, + 0.0137928558, + 0.0076237551, + 0.0338266335, + 0.0081346096, + 0.0140571089, + 0.0108276801, + 0.0080683065, + 0.1437251732, + 0.0083757773, + ], + [ + 0.0159285638, + 0.0048098656, + 0.0032692643, + 0.0010966937, + 0.0080519916, + 0.0134552459, + 0.0021324215, + 0.0025086365, + 0.0049192147, + 0.0501543893, + 0.5307634291, + 0.0035599431, + 0.2160085187, + 0.0743650717, + 0.0045247350, + 0.0066922196, + 0.0119092283, + 0.0070928134, + 0.0106565111, + 0.0281012433, + ], + [ + 0.0195973253, + 0.0105142992, + 0.3289103336, + 0.3099848991, + 0.0034539049, + 0.0116196758, + 0.0250777800, + 0.0627528956, + 0.0295961112, + 0.0032650434, + 0.0028246884, + 0.0240963907, + 0.0008425062, + 0.0019706550, + 0.0049062781, + 0.1064984500, + 0.0438053705, + 0.0006333959, + 0.0056197958, + 0.0040302013, + ], + [ + 0.0833804360, + 0.0125871438, + 0.0969824220, + 0.0686820704, + 0.0081981143, + 0.0121520930, + 0.0227415415, + 0.0982291876, + 0.0073954898, + 0.0017471177, + 0.0039653113, + 0.0129342146, + 0.0019557975, + 0.0024132583, + 0.0355924232, + 0.3115606483, + 0.2113368612, + 0.0016329034, + 0.0017991083, + 0.0047138579, + ], + [ + 0.0181409133, + 0.4129662563, + 0.0233205154, + 0.0033333547, + 0.0085143598, + 0.0526694251, + 0.0096531879, + 0.0224552642, + 0.0375238929, + 0.0035090482, + 0.0149146621, + 0.3208065790, + 0.0046098856, + 0.0035426859, + 0.0087197469, + 0.0262309419, + 0.0131791136, + 0.0034766995, + 0.0079588201, + 0.0044746474, + ], + [ + 0.2494227404, + 0.0185481724, + 0.0164119567, + 0.0169234299, + 0.0122862654, + 0.0228501981, + 0.0370491083, + 0.0347467705, + 0.0087069587, + 0.0595718359, + 0.0451065029, + 0.0177064733, + 0.0204556127, + 0.0077360919, + 0.0686403544, + 0.0889295672, + 0.0986017356, + 0.0028603862, + 0.0061938477, + 0.1672519917, + ], + [ + 0.1419737638, + 0.0373945961, + 0.0576296888, + 0.0537452477, + 0.0068856658, + 0.0286239972, + 0.0407540287, + 0.3988107872, + 0.0152895617, + 0.0016627616, + 0.0092348297, + 0.0314273807, + 0.0055425500, + 0.0040286132, + 0.0180328866, + 0.1123731997, + 0.0242478202, + 0.0025909098, + 0.0049054208, + 0.0048462908, + ], + [ + 0.0178903305, + 0.1958843646, + 0.0155853897, + 0.0031054277, + 0.0290304227, + 0.1051819261, + 0.0040503389, + 0.0100480293, + 0.1252696215, + 0.0016708003, + 0.0722356645, + 0.0233340169, + 0.0116142354, + 0.0238913260, + 0.0009938415, + 0.0181675536, + 0.0186260222, + 0.2260554691, + 0.0859787232, + 0.0113864962, + ], + [ + 0.1454758367, + 0.0420979067, + 0.0400419720, + 0.1294249748, + 0.0014186329, + 0.0906469055, + 0.2471353458, + 0.0319650773, + 0.0130426183, + 0.0058525371, + 0.0123593139, + 0.0818154090, + 0.0044178939, + 0.0017552077, + 0.0151135525, + 0.0656688174, + 0.0511289472, + 0.0007731441, + 0.0029258438, + 0.0169400635, + ], + [ + 0.0169799462, + 0.0242346701, + 0.1318047919, + 0.1043655101, + 0.0022087215, + 0.0269349684, + 0.0376379591, + 0.5404470183, + 0.0181137053, + 0.0007459679, + 0.0021146994, + 0.0508617611, + 0.0009473769, + 0.0006780593, + 0.0038754401, + 0.0297030159, + 0.0045836180, + 0.0006031889, + 0.0015704090, + 0.0015891728, + ], + [ + 0.0402646249, + 0.1152022601, + 0.0323829165, + 0.0293968352, + 0.0039388655, + 0.2497008043, + 0.1603524245, + 0.0129260411, + 0.0617967839, + 0.0098491259, + 0.0354918823, + 0.1448804422, + 0.0124818865, + 0.0041153375, + 0.0043374229, + 0.0243246958, + 0.0305645368, + 0.0026676598, + 0.0097227847, + 0.0156026694, + ], + [ + 0.2256914610, + 0.0523417493, + 0.0244308734, + 0.0637125217, + 0.0043390149, + 0.0578159236, + 0.1154830640, + 0.0867335173, + 0.0131066949, + 0.0085086217, + 0.0193314218, + 0.0660468804, + 0.0064877206, + 0.0027440054, + 0.0611149102, + 0.1070877179, + 0.0507677144, + 0.0013695913, + 0.0028982948, + 0.0299883012, + ], + [ + 0.0033164209, + 0.0015310773, + 0.0030830171, + 0.0008266472, + 0.0051890730, + 0.0011024889, + 0.0005134130, + 0.0010432830, + 0.0278451262, + 0.0041895268, + 0.0111212494, + 0.0007149922, + 0.0023621780, + 0.3801761447, + 0.0008365077, + 0.0035876698, + 0.0023608948, + 0.0333346985, + 0.5107889643, + 0.0060766272, + ], + [ + 0.1995014012, + 0.0236078675, + 0.0392254543, + 0.0094955104, + 0.0584590451, + 0.0254265363, + 0.0125535371, + 0.0939787338, + 0.0341857201, + 0.0140209879, + 0.0449387571, + 0.0118723304, + 0.0246990633, + 0.0634433944, + 0.0145385320, + 0.1663920640, + 0.0533159207, + 0.0129802666, + 0.0606346163, + 0.0367302614, + ], + [ + 0.0319448994, + 0.1011667268, + 0.2084709220, + 0.0378074649, + 0.0066040348, + 0.0766372935, + 0.0279488190, + 0.0365541130, + 0.2088643258, + 0.0047542347, + 0.0156545731, + 0.0868664783, + 0.0043253317, + 0.0108915768, + 0.0060899575, + 0.0577656939, + 0.0302051160, + 0.0026001883, + 0.0387897304, + 0.0060585202, + ], + [ + 0.0776799515, + 0.0142518583, + 0.0403216692, + 0.0080651725, + 0.0140092962, + 0.0179995517, + 0.0112622427, + 0.0136868237, + 0.0133729897, + 0.1239635380, + 0.0724670993, + 0.0129144967, + 0.0420745442, + 0.0173584908, + 0.0117084432, + 0.0922723571, + 0.2316899445, + 0.0028153633, + 0.0141726542, + 0.1679135132, + ], + [ + 0.1183662657, + 0.0805192606, + 0.0259524932, + 0.0495595439, + 0.0035624835, + 0.1204924917, + 0.1537589210, + 0.0194993426, + 0.0229373171, + 0.0302661211, + 0.0571250629, + 0.0982304112, + 0.0171727472, + 0.0068665705, + 0.0175153030, + 0.0486588400, + 0.0635796210, + 0.0023008307, + 0.0083027431, + 0.0553336300, + ], + [ + 0.0528559899, + 0.0193569043, + 0.0264743774, + 0.2092761515, + 0.0008625883, + 0.1212409715, + 0.4024189781, + 0.0155838458, + 0.0124148798, + 0.0054864832, + 0.0090256472, + 0.0497017031, + 0.0042357114, + 0.0012650715, + 0.0063185636, + 0.0197262901, + 0.0235463735, + 0.0008381610, + 0.0033948741, + 0.0159764347, + ], + [ + 0.0344366215, + 0.0426221820, + 0.1636716191, + 0.1139007491, + 0.0020985982, + 0.0605413987, + 0.0541780220, + 0.3361639671, + 0.0461776737, + 0.0003463416, + 0.0048355678, + 0.0667552967, + 0.0019704509, + 0.0031557619, + 0.0040369775, + 0.0481173332, + 0.0089148085, + 0.0006510101, + 0.0054145649, + 0.0020110555, + ], + [ + 0.1153088951, + 0.0151278638, + 0.0458476603, + 0.1755516676, + 0.0014962362, + 0.0366731222, + 0.1749410045, + 0.0394181311, + 0.0132401530, + 0.0056912974, + 0.0101409559, + 0.0433118387, + 0.0030332064, + 0.0015700232, + 0.1665802563, + 0.0871536033, + 0.0468260603, + 0.0007515702, + 0.0031432715, + 0.0141931831, + ], + [ + 0.3865149348, + 0.0037579334, + 0.0030420497, + 0.0022366810, + 0.0218928357, + 0.0021464743, + 0.0031387843, + 0.3694353983, + 0.0014672902, + 0.0085376076, + 0.0127257242, + 0.0018840458, + 0.0080581695, + 0.0039281367, + 0.0158688291, + 0.0808877279, + 0.0305195935, + 0.0009922880, + 0.0019020345, + 0.0410634615, + ], + [ + 0.0146570745, + 0.0028841333, + 0.0012998335, + 0.0005210575, + 0.0024317913, + 0.0049362750, + 0.0014874369, + 0.0020953252, + 0.0010181940, + 0.1913901476, + 0.4432797758, + 0.0022898369, + 0.2217427062, + 0.0091637503, + 0.0007685153, + 0.0027251487, + 0.0170997497, + 0.0008779380, + 0.0014756028, + 0.0778557075, + ], +]; + +pub const C60_WEIGHTS: &'static [f64] = &[ + 0.0169698865, + 0.0211683374, + 0.0276589079, + 0.0065675964, + 0.0141221416, + 0.0068774834, + 0.0146909701, + 0.0067225777, + 0.0018396660, + 0.0102547197, + 0.0230896163, + 0.0057941033, + 0.0125394534, + 0.0204526478, + 0.0070629602, + 0.0117982741, + 0.0068334668, + 0.0433775839, + 0.0318278731, + 0.0222546108, + 0.0102264969, + 0.0150545891, + 0.0134159878, + 0.0148552065, + 0.0239111516, + 0.0128776278, + 0.0222318842, + 0.0247444742, + 0.0214274810, + 0.0115001882, + 0.0076017389, + 0.0130258568, + 0.0093701965, + 0.0467194264, + 0.0441940314, + 0.0322263154, + 0.0402999891, + 0.0150234227, + 0.0104589903, + 0.0214742395, + 0.0154957836, + 0.0101789953, + 0.0227980379, + 0.0123204539, + 0.0066777583, + 0.0004150083, + 0.0344385130, + 0.0113663379, + 0.0127143049, + 0.0124323741, + 0.0262124415, + 0.0064994957, + 0.0103203293, + 0.0142463512, + 0.0215600067, + 0.0199150700, + 0.0038964200, + 0.0113448855, + 0.0128595846, + 0.0117656776, +]; + +pub const UDM256: &'static [[f64; 20]] = &[ + [ + 0.0688549572, + 0.0605280252, + 0.0519105389, + 0.0568524289, + 0.0179942803, + 0.0511728262, + 0.0658138717, + 0.0600029876, + 0.0268497187, + 0.0604142440, + 0.0836442548, + 0.0615695503, + 0.0211388645, + 0.0434461283, + 0.0336523401, + 0.0674385272, + 0.0599848094, + 0.0100780344, + 0.0321211264, + 0.0665324858, + ], + [ + 0.0685883410, + 0.0564612276, + 0.0579724100, + 0.0589588467, + 0.0049634517, + 0.0520377286, + 0.0610470807, + 0.0629374349, + 0.0219954724, + 0.0553418912, + 0.0752534655, + 0.0602870546, + 0.0187252694, + 0.0461336563, + 0.0406348213, + 0.0661970974, + 0.0625965074, + 0.0157536981, + 0.0496627633, + 0.0644517819, + ], + [ + 0.0708934510, + 0.0550727429, + 0.0328216828, + 0.0452519149, + 0.0110356391, + 0.0479888222, + 0.0561397354, + 0.0522772330, + 0.0218666396, + 0.0670372737, + 0.1635707641, + 0.0526801158, + 0.0254959777, + 0.0500481615, + 0.0246598831, + 0.0580524554, + 0.0547437711, + 0.0092108952, + 0.0300737966, + 0.0710790450, + ], + [ + 0.1451294666, + 0.0607528498, + 0.0415699288, + 0.0562841368, + 0.0107150695, + 0.0536019344, + 0.0642001739, + 0.0632952380, + 0.0222271210, + 0.0498107323, + 0.0786148687, + 0.0516857964, + 0.0175619515, + 0.0257073910, + 0.0305997557, + 0.0714727315, + 0.0607610975, + 0.0087103704, + 0.0224887433, + 0.0648106430, + ], + [ + 0.0764076115, + 0.0570897984, + 0.0478245773, + 0.0728070552, + 0.0076652285, + 0.0606986267, + 0.1559860156, + 0.0502441425, + 0.0208387421, + 0.0474075818, + 0.0691069716, + 0.0703170610, + 0.0162169681, + 0.0209063460, + 0.0236375318, + 0.0616871407, + 0.0576490625, + 0.0058736284, + 0.0204305715, + 0.0572053389, + ], + [ + 0.0778825403, + 0.0536629900, + 0.0540623977, + 0.0605374118, + 0.0086576713, + 0.0423324409, + 0.0567371107, + 0.1688078518, + 0.0207784101, + 0.0496236658, + 0.0710674985, + 0.0542699207, + 0.0166720416, + 0.0263842723, + 0.0277160875, + 0.0664600111, + 0.0537731894, + 0.0085066825, + 0.0239509531, + 0.0581168530, + ], + [ + 0.0852326898, + 0.0530472345, + 0.0638550979, + 0.0541358563, + 0.0118137257, + 0.0508622214, + 0.0569893969, + 0.0621563786, + 0.0227013217, + 0.0381978782, + 0.0633874597, + 0.0555457222, + 0.0164021745, + 0.0218127459, + 0.0259020761, + 0.1566772936, + 0.0785229434, + 0.0065053595, + 0.0218239971, + 0.0544284270, + ], + [ + 0.0812294559, + 0.0524145867, + 0.0296834708, + 0.0442272346, + 0.0108407450, + 0.0381126562, + 0.0546607148, + 0.0518297867, + 0.0199090830, + 0.0778124273, + 0.0865766981, + 0.0516412266, + 0.0208324777, + 0.0332835264, + 0.0251127599, + 0.0580122011, + 0.0660765407, + 0.0086067972, + 0.0259016764, + 0.1632359349, + ], + [ + 0.0695341703, + 0.0704509985, + 0.0570255062, + 0.0543701642, + 0.0072581759, + 0.0617017280, + 0.0721340096, + 0.0501406316, + 0.0217333405, + 0.0500644745, + 0.0684328046, + 0.1482371427, + 0.0169956734, + 0.0212651915, + 0.0210331580, + 0.0645445704, + 0.0609951706, + 0.0055179400, + 0.0221228836, + 0.0564422658, + ], + [ + 0.0802600904, + 0.1551614284, + 0.0437069808, + 0.0455750297, + 0.0090845344, + 0.0670680421, + 0.0635415202, + 0.0496003969, + 0.0398983751, + 0.0377116648, + 0.0711609122, + 0.0789071567, + 0.0160131376, + 0.0189416393, + 0.0190198164, + 0.0624606638, + 0.0598552722, + 0.0072250517, + 0.0193671790, + 0.0554411082, + ], + [ + 0.0675977435, + 0.0360659724, + 0.0186143820, + 0.0186042975, + 0.0101037228, + 0.0231954844, + 0.0277784176, + 0.0279494467, + 0.0150825562, + 0.1404190636, + 0.1852042048, + 0.0266742762, + 0.0491661528, + 0.0546650191, + 0.0160861006, + 0.0446907069, + 0.0549665236, + 0.0071085651, + 0.0256461017, + 0.1503812624, + ], + [ + 0.0628794938, + 0.0486145538, + 0.0232133958, + 0.0254697443, + 0.0085820307, + 0.0423824997, + 0.0441765969, + 0.0428880528, + 0.0174220067, + 0.0728234511, + 0.2559336703, + 0.0405507455, + 0.0499531233, + 0.0495419184, + 0.0166893140, + 0.0471810582, + 0.0479827057, + 0.0074597416, + 0.0253289752, + 0.0709269222, + ], + [ + 0.2308791155, + 0.0523222188, + 0.0290220311, + 0.0457437624, + 0.0098150511, + 0.0427394316, + 0.0508581488, + 0.0651797747, + 0.0181948157, + 0.0475386837, + 0.0681444051, + 0.0487005728, + 0.0166663599, + 0.0234542292, + 0.0231113417, + 0.0723034371, + 0.0610007086, + 0.0073221231, + 0.0202485425, + 0.0667552468, + ], + [ + 0.0829939350, + 0.0527752660, + 0.0382497354, + 0.0530745719, + 0.0079155737, + 0.0449048440, + 0.0611312249, + 0.0557605998, + 0.0198851844, + 0.0486477692, + 0.0726094546, + 0.0540290548, + 0.0159502616, + 0.0247673211, + 0.1534801239, + 0.0660682329, + 0.0565784048, + 0.0079017295, + 0.0215220067, + 0.0617547060, + ], + [ + 0.0735953896, + 0.0503375261, + 0.0642835982, + 0.1542924263, + 0.0073999165, + 0.0461513491, + 0.0718718234, + 0.0623312653, + 0.0214136209, + 0.0465682879, + 0.0673215902, + 0.0577022604, + 0.0156861168, + 0.0245566289, + 0.0281758396, + 0.0642877417, + 0.0562904430, + 0.0083112947, + 0.0235940746, + 0.0558288068, + ], + [ + 0.0744964382, + 0.0533687497, + 0.0515379512, + 0.0500243695, + 0.0075995047, + 0.0485135871, + 0.0580470540, + 0.0510573995, + 0.0185219897, + 0.0545472353, + 0.0674706835, + 0.0582141722, + 0.0172823688, + 0.0222817317, + 0.0210518568, + 0.0804366625, + 0.1697086517, + 0.0071239696, + 0.0205775867, + 0.0681380375, + ], + [ + 0.0639628248, + 0.0489681223, + 0.0410246908, + 0.0453447956, + 0.0090712235, + 0.0300833845, + 0.0534342121, + 0.0524929105, + 0.0184101754, + 0.1626878461, + 0.0914143304, + 0.0549179235, + 0.0224629148, + 0.0436294286, + 0.0213903084, + 0.0524463444, + 0.0550426265, + 0.0077528541, + 0.0292674575, + 0.0961956262, + ], + [ + 0.0810027389, + 0.0612515429, + 0.0814948990, + 0.1046299285, + 0.0050265398, + 0.0731600458, + 0.1114489355, + 0.0642707545, + 0.0262472442, + 0.0157870925, + 0.0373340487, + 0.0832332234, + 0.0094543772, + 0.0093448990, + 0.0288673755, + 0.0997070517, + 0.0691914775, + 0.0026862674, + 0.0116684629, + 0.0241930949, + ], + [ + 0.0718509694, + 0.0427353727, + 0.0290363667, + 0.0280421247, + 0.0109845999, + 0.0274916234, + 0.0392581581, + 0.0514240081, + 0.0256898756, + 0.0615115837, + 0.0948757589, + 0.0309599513, + 0.0242336924, + 0.1668109687, + 0.0200464555, + 0.0588050063, + 0.0529030566, + 0.0155657342, + 0.0802193267, + 0.0675553672, + ], + [ + 0.0656867156, + 0.0449609156, + 0.0418060369, + 0.0266560992, + 0.0087666227, + 0.0286691648, + 0.0402344175, + 0.0421018855, + 0.0540801374, + 0.0481681587, + 0.0756622877, + 0.0427778811, + 0.0174134005, + 0.0926680057, + 0.0151386435, + 0.0559037072, + 0.0494712197, + 0.0146535689, + 0.1775792353, + 0.0576018963, + ], + [ + 0.1018860333, + 0.0508148666, + 0.0373719248, + 0.0538481750, + 0.0051647196, + 0.0488159579, + 0.0654295998, + 0.0479979716, + 0.0161760912, + 0.0231124589, + 0.0515791330, + 0.0579673849, + 0.0107501277, + 0.0122639635, + 0.2191719323, + 0.0782753207, + 0.0572138531, + 0.0039031635, + 0.0110579080, + 0.0471994147, + ], + [ + 0.0591730028, + 0.1434849234, + 0.0530387018, + 0.0346164023, + 0.0058863964, + 0.0727598717, + 0.0625314842, + 0.0358274064, + 0.0366705399, + 0.0247432403, + 0.0481325307, + 0.2120784271, + 0.0147951572, + 0.0100393615, + 0.0136454946, + 0.0593546229, + 0.0561732503, + 0.0033305413, + 0.0116116983, + 0.0421069469, + ], + [ + 0.0740826742, + 0.0446966901, + 0.0617921456, + 0.1651959423, + 0.0045432863, + 0.0635864613, + 0.1981357680, + 0.0502351797, + 0.0209003131, + 0.0133770764, + 0.0349495395, + 0.0631079386, + 0.0088261515, + 0.0082687966, + 0.0319865102, + 0.0676534437, + 0.0511448578, + 0.0026210612, + 0.0098423633, + 0.0250538004, + ], + [ + 0.0756669768, + 0.0816648953, + 0.0567693316, + 0.0713876530, + 0.0032235616, + 0.0877370486, + 0.1537498715, + 0.0371779535, + 0.0216287805, + 0.0183159574, + 0.0430590379, + 0.1466179515, + 0.0102501498, + 0.0078292141, + 0.0120185503, + 0.0629686263, + 0.0601974014, + 0.0020798593, + 0.0100934064, + 0.0375637734, + ], + [ + 0.1737281253, + 0.0695186466, + 0.0412008103, + 0.0872965560, + 0.0037241952, + 0.0708148313, + 0.1270060035, + 0.0540894985, + 0.0172361296, + 0.0159266478, + 0.0481477371, + 0.0642762641, + 0.0086962264, + 0.0095269229, + 0.0310286559, + 0.0677852813, + 0.0569601531, + 0.0035991951, + 0.0086709563, + 0.0407671636, + ], + [ + 0.1877809181, + 0.0389741067, + 0.0509204596, + 0.0426495859, + 0.0103791004, + 0.0454388628, + 0.0484418421, + 0.0674099285, + 0.0161587130, + 0.0201761686, + 0.0441533959, + 0.0423563268, + 0.0130508585, + 0.0117198188, + 0.0369352019, + 0.1768464500, + 0.0823508741, + 0.0033239510, + 0.0114619898, + 0.0494714476, + ], + [ + 0.0621766825, + 0.0502190068, + 0.1944583000, + 0.0771212389, + 0.0067246761, + 0.0513092226, + 0.0549985121, + 0.0598472485, + 0.0445411062, + 0.0291366605, + 0.0511711514, + 0.0637955781, + 0.0129970938, + 0.0183875411, + 0.0153848002, + 0.0767716225, + 0.0589395685, + 0.0055718907, + 0.0238235878, + 0.0426245116, + ], + [ + 0.0653026095, + 0.0477607702, + 0.0523104385, + 0.0518667463, + 0.0070159893, + 0.0369735721, + 0.0460185002, + 0.2918552116, + 0.0172751127, + 0.0433261619, + 0.0604872173, + 0.0490338951, + 0.0136291709, + 0.0203719137, + 0.0194594159, + 0.0588942590, + 0.0446065869, + 0.0061965938, + 0.0170061368, + 0.0506096984, + ], + [ + 0.0524905804, + 0.0205046123, + 0.0128038053, + 0.0108419551, + 0.0080713790, + 0.0170754765, + 0.0159678607, + 0.0156588742, + 0.0106777585, + 0.1688954849, + 0.2869908280, + 0.0174952506, + 0.0640641311, + 0.0625314492, + 0.0100723072, + 0.0318668381, + 0.0434084357, + 0.0058114009, + 0.0262901538, + 0.1184814185, + ], + [ + 0.0895133456, + 0.0414310702, + 0.0658416729, + 0.0456155539, + 0.0081240281, + 0.0440720286, + 0.0472544839, + 0.0480160232, + 0.0168765394, + 0.0250440473, + 0.0417455525, + 0.0490062485, + 0.0131419613, + 0.0111187610, + 0.0211071306, + 0.1934076561, + 0.1766106552, + 0.0032378903, + 0.0113603737, + 0.0474749778, + ], + [ + 0.0652348379, + 0.0441276809, + 0.0219111975, + 0.0255849180, + 0.0085129917, + 0.0316358648, + 0.0482401559, + 0.0414837643, + 0.0148278230, + 0.1163958084, + 0.0797806143, + 0.0463063024, + 0.0168959957, + 0.0265319288, + 0.0171172854, + 0.0444018080, + 0.0555793225, + 0.0057358610, + 0.0205967030, + 0.2690991366, + ], + [ + 0.0456604534, + 0.2651675885, + 0.0448250861, + 0.0141362787, + 0.0059345535, + 0.0693279589, + 0.0427002480, + 0.0236472568, + 0.0378869462, + 0.0141871442, + 0.0364116963, + 0.2371460437, + 0.0121118617, + 0.0064078909, + 0.0088017217, + 0.0528772233, + 0.0458619019, + 0.0027301780, + 0.0083037162, + 0.0258742519, + ], + [ + 0.0511584800, + 0.0204583790, + 0.0198524374, + 0.0130510006, + 0.0099747093, + 0.0183273430, + 0.0150762169, + 0.0185599130, + 0.0507535264, + 0.0430011409, + 0.0818387483, + 0.0162683465, + 0.0182373763, + 0.2279158594, + 0.0103803712, + 0.0454047440, + 0.0370815099, + 0.0442242682, + 0.2085477664, + 0.0498878633, + ], + [ + 0.0678203601, + 0.0186965450, + 0.0114868635, + 0.0093099099, + 0.0081222462, + 0.0154375750, + 0.0147427103, + 0.0181068446, + 0.0094005515, + 0.1645628735, + 0.2110799162, + 0.0142253374, + 0.0509301380, + 0.0453887734, + 0.0110642613, + 0.0354177197, + 0.0530268611, + 0.0047019370, + 0.0146453500, + 0.2218332263, + ], + [ + 0.0724877669, + 0.0685327850, + 0.0514655506, + 0.0427645757, + 0.0060365920, + 0.2044792367, + 0.0850048038, + 0.0319408234, + 0.0477996715, + 0.0251372677, + 0.0667546640, + 0.0720936924, + 0.0198491097, + 0.0115745589, + 0.0125444641, + 0.0617887856, + 0.0581237094, + 0.0033435542, + 0.0128520366, + 0.0454263519, + ], + [ + 0.0437562945, + 0.0108007705, + 0.0070909550, + 0.0047893582, + 0.0064014480, + 0.0104768635, + 0.0081681947, + 0.0080724992, + 0.0064795011, + 0.1800180808, + 0.3605056486, + 0.0091123606, + 0.0713277957, + 0.0581391474, + 0.0063664834, + 0.0175785616, + 0.0334777071, + 0.0040543755, + 0.0143283806, + 0.1390555740, + ], + [ + 0.0614132234, + 0.0397988095, + 0.1068242480, + 0.2487825133, + 0.0046040339, + 0.0445618237, + 0.0858194831, + 0.0576559650, + 0.0345771909, + 0.0145431269, + 0.0348570734, + 0.0529975984, + 0.0083754190, + 0.0104915630, + 0.0183474258, + 0.0767110594, + 0.0555282253, + 0.0036426308, + 0.0130447800, + 0.0274238072, + ], + [ + 0.0591032755, + 0.0336567820, + 0.0478680781, + 0.1898021997, + 0.0028422803, + 0.0753113048, + 0.3284700309, + 0.0346380543, + 0.0178254076, + 0.0077633239, + 0.0141782617, + 0.0573191841, + 0.0061626245, + 0.0039344737, + 0.0102934944, + 0.0493369703, + 0.0371628859, + 0.0011718864, + 0.0055059002, + 0.0176535819, + ], + [ + 0.0561240674, + 0.0194942735, + 0.0152242293, + 0.0111917357, + 0.0102274512, + 0.0168801604, + 0.0145846049, + 0.0188672002, + 0.0188695232, + 0.0882312699, + 0.2111199134, + 0.0151805593, + 0.0554163138, + 0.1692988247, + 0.0108909263, + 0.0409763586, + 0.0406988869, + 0.0147163195, + 0.0881443913, + 0.0838629906, + ], + [ + 0.0839226244, + 0.0607611040, + 0.0783756363, + 0.1258228774, + 0.0019000450, + 0.0914605656, + 0.1702496434, + 0.0452049971, + 0.0282981953, + 0.0075787967, + 0.0153770528, + 0.1143080454, + 0.0056205751, + 0.0032932574, + 0.0108127368, + 0.0793317290, + 0.0578830481, + 0.0007816284, + 0.0052443668, + 0.0137730751, + ], + [ + 0.0358201316, + 0.2976917737, + 0.0380177895, + 0.0093316227, + 0.0038870737, + 0.0692798121, + 0.0352620920, + 0.0181218239, + 0.0299607958, + 0.0094448040, + 0.0268879784, + 0.3118898858, + 0.0088337322, + 0.0036979393, + 0.0051513230, + 0.0417687779, + 0.0349774192, + 0.0016022571, + 0.0048088244, + 0.0135641436, + ], + [ + 0.0471565593, + 0.0109483972, + 0.0082416228, + 0.0055973900, + 0.0063931242, + 0.0103194251, + 0.0092708767, + 0.0082384393, + 0.0064020519, + 0.2575252409, + 0.2039772936, + 0.0109673000, + 0.0558669090, + 0.0392874133, + 0.0066606773, + 0.0239611666, + 0.0453104543, + 0.0029046758, + 0.0107091122, + 0.2302618708, + ], + [ + 0.0586705744, + 0.0649889623, + 0.0761003906, + 0.0436848180, + 0.0092829386, + 0.0697749993, + 0.0458015222, + 0.0255023233, + 0.1932541906, + 0.0195603489, + 0.0541650088, + 0.0523255164, + 0.0133847681, + 0.0386269177, + 0.0124193433, + 0.0631254710, + 0.0490145213, + 0.0064512952, + 0.0648595693, + 0.0390065208, + ], + [ + 0.0598669083, + 0.2717019578, + 0.0442825903, + 0.0190452758, + 0.0085334335, + 0.0721972160, + 0.0462561831, + 0.0372211682, + 0.0577411256, + 0.0194755020, + 0.0527395748, + 0.1080856921, + 0.0128937871, + 0.0120084320, + 0.0123465220, + 0.0568906500, + 0.0491187295, + 0.0053142540, + 0.0151541539, + 0.0391268441, + ], + [ + 0.0841000147, + 0.0427648555, + 0.0214718391, + 0.0361599931, + 0.0049458326, + 0.0400163728, + 0.0451073892, + 0.0366009329, + 0.0132869651, + 0.0307326011, + 0.0500202398, + 0.0457568386, + 0.0097643817, + 0.0102607766, + 0.3584928501, + 0.0641872126, + 0.0482192376, + 0.0033294822, + 0.0090639526, + 0.0457182322, + ], + [ + 0.0565611214, + 0.0301536286, + 0.0853191755, + 0.2802081047, + 0.0033794296, + 0.0500934949, + 0.1998268077, + 0.0506829658, + 0.0262244732, + 0.0074789442, + 0.0129088959, + 0.0481354563, + 0.0056032116, + 0.0048186322, + 0.0135564334, + 0.0631187092, + 0.0408195685, + 0.0015144015, + 0.0065000902, + 0.0130964555, + ], + [ + 0.3695286607, + 0.0360072219, + 0.0192214840, + 0.0279701482, + 0.0136904059, + 0.0239221705, + 0.0371749116, + 0.0703977586, + 0.0135478906, + 0.0408698439, + 0.0585153356, + 0.0315792694, + 0.0148921230, + 0.0170548887, + 0.0119972697, + 0.0788879161, + 0.0535813591, + 0.0044408303, + 0.0142808931, + 0.0624396190, + ], + [ + 0.2072340652, + 0.0393247315, + 0.0392905846, + 0.0412707010, + 0.0095084800, + 0.0316444387, + 0.0410081912, + 0.2254384091, + 0.0140846679, + 0.0204524816, + 0.0481339074, + 0.0362033194, + 0.0119191644, + 0.0148160986, + 0.0219183660, + 0.0841771469, + 0.0507271048, + 0.0048678425, + 0.0122094063, + 0.0457708931, + ], + [ + 0.2137907554, + 0.0239569004, + 0.0164569774, + 0.0147216567, + 0.0161245132, + 0.0187108807, + 0.0263729932, + 0.0431375773, + 0.0118096114, + 0.0851776227, + 0.0772422105, + 0.0200086198, + 0.0234451927, + 0.0194615181, + 0.0174086215, + 0.0650103084, + 0.0768511190, + 0.0041996906, + 0.0129009280, + 0.2132123028, + ], + [ + 0.0634402427, + 0.0230470852, + 0.0131270052, + 0.0100527513, + 0.0080868123, + 0.0148265809, + 0.0251131161, + 0.0135386636, + 0.0084325769, + 0.2158943631, + 0.0916064383, + 0.0276861484, + 0.0367343270, + 0.0201991218, + 0.0109152733, + 0.0377833841, + 0.0643834840, + 0.0027489679, + 0.0105214447, + 0.3018622134, + ], + [ + 0.0769465085, + 0.0477466317, + 0.0374317321, + 0.0829003802, + 0.0038545665, + 0.0811586202, + 0.2896672502, + 0.0340935856, + 0.0158071940, + 0.0267270513, + 0.0428021767, + 0.0683571195, + 0.0100872169, + 0.0080502316, + 0.0115511354, + 0.0518369056, + 0.0513713330, + 0.0024927188, + 0.0090237168, + 0.0480939253, + ], + [ + 0.0606453473, + 0.0382991984, + 0.0493674180, + 0.0518821790, + 0.0059721040, + 0.0300965527, + 0.0411326270, + 0.4541954197, + 0.0127967644, + 0.0165652479, + 0.0376388650, + 0.0395718593, + 0.0092328775, + 0.0108731138, + 0.0131308996, + 0.0521429721, + 0.0312877847, + 0.0036981456, + 0.0100783496, + 0.0313922744, + ], + [ + 0.0858447030, + 0.0981119210, + 0.0809137748, + 0.0489100951, + 0.0043467679, + 0.0783960075, + 0.0646142814, + 0.0515146978, + 0.0347751020, + 0.0126547346, + 0.0302180076, + 0.1234448279, + 0.0094706966, + 0.0060687580, + 0.0106086251, + 0.1409092709, + 0.0856988882, + 0.0016074201, + 0.0076694918, + 0.0242219285, + ], + [ + 0.0507869227, + 0.0336012132, + 0.0149221400, + 0.0120479272, + 0.0069891388, + 0.0306832465, + 0.0174039370, + 0.0167974368, + 0.0126865264, + 0.0749937116, + 0.4154863159, + 0.0190952984, + 0.0590167098, + 0.0531584710, + 0.0106726024, + 0.0358218355, + 0.0375755499, + 0.0058950244, + 0.0224143911, + 0.0699516018, + ], + [ + 0.0429941518, + 0.0180621445, + 0.0473613288, + 0.2999353898, + 0.0018021028, + 0.0520041463, + 0.3502505668, + 0.0299480765, + 0.0124352627, + 0.0045976823, + 0.0084301288, + 0.0354889219, + 0.0037811240, + 0.0023643326, + 0.0081134297, + 0.0404654702, + 0.0276635259, + 0.0007242375, + 0.0035808661, + 0.0099971109, + ], + [ + 0.3316024020, + 0.0186772493, + 0.0326706038, + 0.0174453726, + 0.0165581671, + 0.0274907103, + 0.0318665125, + 0.0697023649, + 0.0097984918, + 0.0162140544, + 0.0319268272, + 0.0252807890, + 0.0099954626, + 0.0085786410, + 0.0162147793, + 0.2038094218, + 0.0725883832, + 0.0023145899, + 0.0075011699, + 0.0497640077, + ], + [ + 0.0512725728, + 0.0342244630, + 0.0207762249, + 0.0185834163, + 0.0068978026, + 0.0170960895, + 0.0333328815, + 0.0400589539, + 0.0123763867, + 0.2841599401, + 0.1019193154, + 0.0376636494, + 0.0356116290, + 0.0420342403, + 0.0118812207, + 0.0374924544, + 0.0485743142, + 0.0045207507, + 0.0224256661, + 0.1390980286, + ], + [ + 0.0799911585, + 0.0279932820, + 0.0628267650, + 0.0322246106, + 0.0089559477, + 0.0274678592, + 0.0266874591, + 0.0395244506, + 0.0108218166, + 0.0141286304, + 0.0238415256, + 0.0327278844, + 0.0092979352, + 0.0067228159, + 0.0122197434, + 0.2872360782, + 0.2561953657, + 0.0019307143, + 0.0063837201, + 0.0328222376, + ], + [ + 0.0561890064, + 0.1752323562, + 0.0496663138, + 0.0353666425, + 0.0035354793, + 0.1576853050, + 0.0822172453, + 0.0179575718, + 0.0457033169, + 0.0107151565, + 0.0373881834, + 0.1834019402, + 0.0096975347, + 0.0042116463, + 0.0059302430, + 0.0526243177, + 0.0464955604, + 0.0016761782, + 0.0063930791, + 0.0179129234, + ], + [ + 0.0727567046, + 0.0479787513, + 0.0340440708, + 0.0142605866, + 0.0070185595, + 0.0439101412, + 0.0479078234, + 0.0144843356, + 0.0122197498, + 0.1100772232, + 0.0779382121, + 0.0510656920, + 0.0379229045, + 0.0133622294, + 0.0094395863, + 0.0664268425, + 0.1627620095, + 0.0027982306, + 0.0109014797, + 0.1627248670, + ], + [ + 0.0997278378, + 0.0286347528, + 0.0152673661, + 0.0259444990, + 0.0038062885, + 0.0314278757, + 0.0344033574, + 0.0275154987, + 0.0096950326, + 0.0123092582, + 0.0341234157, + 0.0326870324, + 0.0060297776, + 0.0058031626, + 0.4788185742, + 0.0715108283, + 0.0423079646, + 0.0017806256, + 0.0049838067, + 0.0332230454, + ], + [ + 0.0350539990, + 0.0062313518, + 0.0042248802, + 0.0024790438, + 0.0046712081, + 0.0064104425, + 0.0045658297, + 0.0045017211, + 0.0037588692, + 0.2500475814, + 0.3035617023, + 0.0056215473, + 0.0634211376, + 0.0474174094, + 0.0038128391, + 0.0102425163, + 0.0296069829, + 0.0024779392, + 0.0090646421, + 0.2028283570, + ], + [ + 0.0261735241, + 0.0051629364, + 0.0037165690, + 0.0019997153, + 0.0049889792, + 0.0062526401, + 0.0037239252, + 0.0035495120, + 0.0036109748, + 0.1786339830, + 0.4489064696, + 0.0044406362, + 0.0888441468, + 0.0553355072, + 0.0034406037, + 0.0088013853, + 0.0216955858, + 0.0026313713, + 0.0086370617, + 0.1194544731, + ], + [ + 0.0662418583, + 0.0393903557, + 0.2256381195, + 0.0663988542, + 0.0075184935, + 0.0475498263, + 0.0403531036, + 0.0558709548, + 0.0442312820, + 0.0128211107, + 0.0191724710, + 0.0496596411, + 0.0086604674, + 0.0077005474, + 0.0101018735, + 0.1751789768, + 0.0901322677, + 0.0021207807, + 0.0111102302, + 0.0201487857, + ], + [ + 0.0325570869, + 0.0032750397, + 0.0029140776, + 0.0014713954, + 0.0045620805, + 0.0037280227, + 0.0026643414, + 0.0031176794, + 0.0022913325, + 0.3054260549, + 0.2276395050, + 0.0029764424, + 0.0565122806, + 0.0313411311, + 0.0027009178, + 0.0077683768, + 0.0268612089, + 0.0013735424, + 0.0044866074, + 0.2763328765, + ], + [ + 0.0309166230, + 0.0119005416, + 0.0132800984, + 0.0070305609, + 0.0077162620, + 0.0117198609, + 0.0085377005, + 0.0082245528, + 0.0510455894, + 0.0292358114, + 0.0641375277, + 0.0093210587, + 0.0128267009, + 0.2934433233, + 0.0056955655, + 0.0298118813, + 0.0176326347, + 0.0453568963, + 0.3085802555, + 0.0335865551, + ], + [ + 0.1889426550, + 0.0407101365, + 0.0158330752, + 0.0150203217, + 0.0115106457, + 0.0308936033, + 0.0243267716, + 0.0525743430, + 0.0114379838, + 0.0680979726, + 0.2004902436, + 0.0196631150, + 0.0487167531, + 0.0381095970, + 0.0114404222, + 0.0538104485, + 0.0574786507, + 0.0054164578, + 0.0146992174, + 0.0908275862, + ], + [ + 0.0789275877, + 0.0463147751, + 0.0902703923, + 0.1369566983, + 0.0044285594, + 0.0505404492, + 0.0891069640, + 0.1897574259, + 0.0216437672, + 0.0105295989, + 0.0188993853, + 0.0593021998, + 0.0069606219, + 0.0073597795, + 0.0212352688, + 0.0896304141, + 0.0502830913, + 0.0028786228, + 0.0086645327, + 0.0163098658, + ], + [ + 0.2219743145, + 0.0142882516, + 0.0315603686, + 0.0110385424, + 0.0180360232, + 0.0172904020, + 0.0184313553, + 0.0440956700, + 0.0084278088, + 0.0543543905, + 0.0521726266, + 0.0150897039, + 0.0303107689, + 0.0113774436, + 0.0143996483, + 0.1409461262, + 0.1821196253, + 0.0024131244, + 0.0078470451, + 0.1038267610, + ], + [ + 0.0242825151, + 0.0035056244, + 0.0025168328, + 0.0013306839, + 0.0042945017, + 0.0040903568, + 0.0024900949, + 0.0026128264, + 0.0023315107, + 0.2437868925, + 0.3949245358, + 0.0028001646, + 0.0730372701, + 0.0409960756, + 0.0023589481, + 0.0061710900, + 0.0189960310, + 0.0015621686, + 0.0052415779, + 0.1626702992, + ], + [ + 0.0540981791, + 0.0055549015, + 0.0042534080, + 0.0025201877, + 0.0067130196, + 0.0056559764, + 0.0046837031, + 0.0056806767, + 0.0035692639, + 0.2479078581, + 0.1867835011, + 0.0047538486, + 0.0478624504, + 0.0312746712, + 0.0046608896, + 0.0183653625, + 0.0396766417, + 0.0019446564, + 0.0054996575, + 0.3185411472, + ], + [ + 0.0564223335, + 0.0087498376, + 0.0075603094, + 0.0048832202, + 0.0079773058, + 0.0081353131, + 0.0089175407, + 0.0076159110, + 0.0049022006, + 0.2747409624, + 0.0885428984, + 0.0096407281, + 0.0331622116, + 0.0226879478, + 0.0063848350, + 0.0261073000, + 0.0502550173, + 0.0018183198, + 0.0071151462, + 0.3643806614, + ], + [ + 0.2212044382, + 0.0604129609, + 0.0354205997, + 0.0965146340, + 0.0019159151, + 0.0760417266, + 0.1829371463, + 0.0439160934, + 0.0122669798, + 0.0095983482, + 0.0304599083, + 0.0639110156, + 0.0049548047, + 0.0042326878, + 0.0110559394, + 0.0625160762, + 0.0476234000, + 0.0015078929, + 0.0039882877, + 0.0295211452, + ], + [ + 0.0378777368, + 0.0041853223, + 0.0039752567, + 0.0023769746, + 0.0056557056, + 0.0043826893, + 0.0042345812, + 0.0037206897, + 0.0027610368, + 0.3350374943, + 0.0964254858, + 0.0044108302, + 0.0294347710, + 0.0188143495, + 0.0033089045, + 0.0145026438, + 0.0345937339, + 0.0012385887, + 0.0044537132, + 0.3886094921, + ], + [ + 0.0252712404, + 0.0027544053, + 0.0026293973, + 0.0014354393, + 0.0036832731, + 0.0028038155, + 0.0023723780, + 0.0024835607, + 0.0018977324, + 0.3950526398, + 0.1393450150, + 0.0028972033, + 0.0329365864, + 0.0198394973, + 0.0022486782, + 0.0059373896, + 0.0229153803, + 0.0008420915, + 0.0033233638, + 0.3293309130, + ], + [ + 0.0632253390, + 0.0445887490, + 0.0508624708, + 0.0406676135, + 0.0068430562, + 0.0380635705, + 0.0446055122, + 0.0354948611, + 0.0138366992, + 0.0432486353, + 0.0503986335, + 0.0448090875, + 0.0158333347, + 0.0122415808, + 0.0115488422, + 0.1096672793, + 0.3044867580, + 0.0038047668, + 0.0114321559, + 0.0543410543, + ], + [ + 0.1920297231, + 0.0223085101, + 0.0551547285, + 0.0228215507, + 0.0143138758, + 0.0326314220, + 0.0276198131, + 0.0636222176, + 0.0097414098, + 0.0113516513, + 0.0206364142, + 0.0270887760, + 0.0088323631, + 0.0064944327, + 0.0145441414, + 0.3121345157, + 0.1162866663, + 0.0015203607, + 0.0057363187, + 0.0351311089, + ], + [ + 0.0916669594, + 0.0363394924, + 0.0618601171, + 0.0372939273, + 0.0273554358, + 0.0302265558, + 0.0292433341, + 0.0571577753, + 0.0171134911, + 0.0194838606, + 0.0478892687, + 0.0355143154, + 0.0121136815, + 0.0164168308, + 0.0176080813, + 0.3186475359, + 0.0868564409, + 0.0040622179, + 0.0145498474, + 0.0386008314, + ], + [ + 0.0468322451, + 0.0311952453, + 0.2355337574, + 0.2160697428, + 0.0030801578, + 0.0398357055, + 0.0731511446, + 0.0634401269, + 0.0377481353, + 0.0072765228, + 0.0107093967, + 0.0551510703, + 0.0046033977, + 0.0050901167, + 0.0081779813, + 0.0922165131, + 0.0491356666, + 0.0017888337, + 0.0087307754, + 0.0102334653, + ], + [ + 0.0706640870, + 0.0993071318, + 0.0492975018, + 0.0621909037, + 0.0017565417, + 0.1052683538, + 0.1897330673, + 0.0264142884, + 0.0209000784, + 0.0087597109, + 0.0233923881, + 0.1997764205, + 0.0063814714, + 0.0029932242, + 0.0052068742, + 0.0514829743, + 0.0481495800, + 0.0008616365, + 0.0044863931, + 0.0229773729, + ], + [ + 0.3801364129, + 0.0083840096, + 0.0245284138, + 0.0087518086, + 0.0270967828, + 0.0119174073, + 0.0117576185, + 0.0646623735, + 0.0053359397, + 0.0090483110, + 0.0175283873, + 0.0093035631, + 0.0065860111, + 0.0052517931, + 0.0113461649, + 0.2908855158, + 0.0672883443, + 0.0012830520, + 0.0043381924, + 0.0345698982, + ], + [ + 0.0170776804, + 0.0027354228, + 0.0021394884, + 0.0010590963, + 0.0032679478, + 0.0037384208, + 0.0018830169, + 0.0019701227, + 0.0019853035, + 0.1567127574, + 0.5359301410, + 0.0021885362, + 0.1002601392, + 0.0473765077, + 0.0017686232, + 0.0053040868, + 0.0149141779, + 0.0013106254, + 0.0048624863, + 0.0935154193, + ], + [ + 0.0187778250, + 0.0078157408, + 0.0100486347, + 0.0040776246, + 0.0060101763, + 0.0072634375, + 0.0050640128, + 0.0049031777, + 0.0504422082, + 0.0180399882, + 0.0408556050, + 0.0057994374, + 0.0080657411, + 0.2674518377, + 0.0031574034, + 0.0198345017, + 0.0099935967, + 0.0322678644, + 0.4589866471, + 0.0211445399, + ], + [ + 0.0274270578, + 0.0101505017, + 0.0066045276, + 0.0040939606, + 0.0058602946, + 0.0142166037, + 0.0066067478, + 0.0057591129, + 0.0064993731, + 0.0970144629, + 0.5522631146, + 0.0085340717, + 0.0743309752, + 0.0498027183, + 0.0056047404, + 0.0189652083, + 0.0234463410, + 0.0031430368, + 0.0100668905, + 0.0696102605, + ], + [ + 0.0193750390, + 0.0060446257, + 0.0070531350, + 0.0034023346, + 0.0062696060, + 0.0061770216, + 0.0043104692, + 0.0044431760, + 0.0281865271, + 0.0322382863, + 0.0839323315, + 0.0047661341, + 0.0234278191, + 0.4048368432, + 0.0031720008, + 0.0181779061, + 0.0100065122, + 0.0290837742, + 0.2738736443, + 0.0312228140, + ], + [ + 0.0447950215, + 0.1431239801, + 0.0493706800, + 0.0213350668, + 0.0032091235, + 0.0668905815, + 0.0518541096, + 0.0212149196, + 0.0163287374, + 0.0147299464, + 0.0320826996, + 0.3841704762, + 0.0114843898, + 0.0044777895, + 0.0075459588, + 0.0473540090, + 0.0448648725, + 0.0016501620, + 0.0051115393, + 0.0284059369, + ], + [ + 0.0612734334, + 0.0245491833, + 0.0369193204, + 0.0380953176, + 0.0047016136, + 0.0165459494, + 0.0291350561, + 0.6341302893, + 0.0080650949, + 0.0062162135, + 0.0109811141, + 0.0235963355, + 0.0045368519, + 0.0045448724, + 0.0070689773, + 0.0493156477, + 0.0209907341, + 0.0019255160, + 0.0044209435, + 0.0129875360, + ], + [ + 0.0293852754, + 0.0025289380, + 0.0025851584, + 0.0014393654, + 0.0044912700, + 0.0026744189, + 0.0024882129, + 0.0024354543, + 0.0016612085, + 0.3515554986, + 0.0616029491, + 0.0028231024, + 0.0199261315, + 0.0126554521, + 0.0021051045, + 0.0089798568, + 0.0258662615, + 0.0006721245, + 0.0024725332, + 0.4616516840, + ], + [ + 0.1451442051, + 0.0247250455, + 0.0381888213, + 0.0341889032, + 0.0070444470, + 0.0194086177, + 0.0291943401, + 0.4648159447, + 0.0091782785, + 0.0084498770, + 0.0152716293, + 0.0253523783, + 0.0062742465, + 0.0062948718, + 0.0121761556, + 0.0896838612, + 0.0332075914, + 0.0023779208, + 0.0057531617, + 0.0232697033, + ], + [ + 0.0245600103, + 0.4178028589, + 0.0277572424, + 0.0051069316, + 0.0031279139, + 0.0515886747, + 0.0203387900, + 0.0103195872, + 0.0263862421, + 0.0069104306, + 0.0209747502, + 0.3037821894, + 0.0063546763, + 0.0027354410, + 0.0035599346, + 0.0298350388, + 0.0248585772, + 0.0013976017, + 0.0038460473, + 0.0087570619, + ], + [ + 0.0501590069, + 0.0144758078, + 0.0240687789, + 0.0225100656, + 0.0029692955, + 0.0078533450, + 0.0165199298, + 0.7611286220, + 0.0044166225, + 0.0038083310, + 0.0056892177, + 0.0143536819, + 0.0028764665, + 0.0027107967, + 0.0042413632, + 0.0370462841, + 0.0138602635, + 0.0011546552, + 0.0024844047, + 0.0076730615, + ], + [ + 0.0121071330, + 0.0038362429, + 0.0049764166, + 0.0022188856, + 0.0040266262, + 0.0041987100, + 0.0028720033, + 0.0029800882, + 0.0283173801, + 0.0164728702, + 0.0431921818, + 0.0031893435, + 0.0088207462, + 0.3894583445, + 0.0018335948, + 0.0125780729, + 0.0064820771, + 0.0250240085, + 0.4098289710, + 0.0175863037, + ], + [ + 0.0208497658, + 0.0022056411, + 0.0017909593, + 0.0009630858, + 0.0033716079, + 0.0024721556, + 0.0015937538, + 0.0019157869, + 0.0015570503, + 0.3304565016, + 0.2905966974, + 0.0018162603, + 0.0465070018, + 0.0293635795, + 0.0015321735, + 0.0044066156, + 0.0166751990, + 0.0009069570, + 0.0035446075, + 0.2374746002, + ], + [ + 0.1192221784, + 0.0363616049, + 0.0953881343, + 0.1251293615, + 0.0020084365, + 0.0612332580, + 0.1012065861, + 0.0665750699, + 0.0114669733, + 0.0063651585, + 0.0102024877, + 0.0580452494, + 0.0045893585, + 0.0032105857, + 0.0141506564, + 0.1772551947, + 0.0896456643, + 0.0009418114, + 0.0040215880, + 0.0129806423, + ], + [ + 0.1810856902, + 0.1725341353, + 0.0336209621, + 0.0545158014, + 0.0030767946, + 0.0853242865, + 0.0914315409, + 0.0458896068, + 0.0283381106, + 0.0088909295, + 0.0403894382, + 0.0829411364, + 0.0068110295, + 0.0045087041, + 0.0069742756, + 0.0643725495, + 0.0536701752, + 0.0019371217, + 0.0043252996, + 0.0293624122, + ], + [ + 0.0338617271, + 0.0093393707, + 0.0091837472, + 0.0050452427, + 0.0084400871, + 0.0101771565, + 0.0066224406, + 0.0074446747, + 0.0289595154, + 0.0620682470, + 0.1663034593, + 0.0078471960, + 0.0451700232, + 0.2825001358, + 0.0051113581, + 0.0256338203, + 0.0189292128, + 0.0322548872, + 0.1788373826, + 0.0562703158, + ], + [ + 0.3575063016, + 0.0079044439, + 0.0081380966, + 0.0052750017, + 0.0435395553, + 0.0079506897, + 0.0085795185, + 0.0428494998, + 0.0050534047, + 0.0609172219, + 0.0500051822, + 0.0075479382, + 0.0238010311, + 0.0094599851, + 0.0084174932, + 0.0746832281, + 0.0782057174, + 0.0017942585, + 0.0054526833, + 0.1929187490, + ], + [ + 0.0367046819, + 0.4885940662, + 0.0290018592, + 0.0080929153, + 0.0060536444, + 0.0587050283, + 0.0247956337, + 0.0185970217, + 0.0425516759, + 0.0104086379, + 0.0335740035, + 0.1263027335, + 0.0085889273, + 0.0055209632, + 0.0057163541, + 0.0378851991, + 0.0302368592, + 0.0027836137, + 0.0073082812, + 0.0185779007, + ], + [ + 0.0768488204, + 0.0180148990, + 0.0085272777, + 0.0142693788, + 0.0028241442, + 0.0204609973, + 0.0226090813, + 0.0177186604, + 0.0063858324, + 0.0094534040, + 0.0241125845, + 0.0212107716, + 0.0043654756, + 0.0039370734, + 0.6326276011, + 0.0570869831, + 0.0312140316, + 0.0011414327, + 0.0033435422, + 0.0238480086, + ], + [ + 0.0439113702, + 0.0169230381, + 0.0089637878, + 0.0050338119, + 0.0072190271, + 0.0313945668, + 0.0094007197, + 0.0075743088, + 0.0078235711, + 0.0955929813, + 0.3645368340, + 0.0140684473, + 0.1781914979, + 0.0473337278, + 0.0050077086, + 0.0303449786, + 0.0410762184, + 0.0034498073, + 0.0117861633, + 0.0703674340, + ], + [ + 0.1388900854, + 0.0326439192, + 0.0597597524, + 0.0411935882, + 0.0089463432, + 0.0307949514, + 0.0365566745, + 0.2375018297, + 0.0110572874, + 0.0093850983, + 0.0158320687, + 0.0329236120, + 0.0074871726, + 0.0067467193, + 0.0125376342, + 0.2178457863, + 0.0657277080, + 0.0021617583, + 0.0061003776, + 0.0259076334, + ], + [ + 0.0612084015, + 0.1390792731, + 0.0170536337, + 0.0101928517, + 0.0046266786, + 0.0739025181, + 0.0480823909, + 0.0101955005, + 0.0149457246, + 0.0680515561, + 0.1813651726, + 0.1328365238, + 0.0543489260, + 0.0113838359, + 0.0050054142, + 0.0366999842, + 0.0495477160, + 0.0027206540, + 0.0105257329, + 0.0682275116, + ], + [ + 0.0406958783, + 0.0184161998, + 0.0314335441, + 0.0116379276, + 0.0078536936, + 0.0167781197, + 0.0131816451, + 0.0144077561, + 0.0656320383, + 0.0290572116, + 0.0563167680, + 0.0151090701, + 0.0111768968, + 0.1422354089, + 0.0071679168, + 0.0409423168, + 0.0304090205, + 0.0210832080, + 0.3879175697, + 0.0385478103, + ], + [ + 0.0663124097, + 0.0384497176, + 0.0324781798, + 0.0122386740, + 0.0078329015, + 0.0581882846, + 0.0234171641, + 0.0192165083, + 0.0137196717, + 0.0730353547, + 0.1552486846, + 0.0420286080, + 0.2105960052, + 0.0393942331, + 0.0082938090, + 0.0524553256, + 0.0626139153, + 0.0044970133, + 0.0146210139, + 0.0653625261, + ], + [ + 0.0399087100, + 0.0094498815, + 0.0077812713, + 0.0048663057, + 0.0088924791, + 0.0102067608, + 0.0067251606, + 0.0088032503, + 0.0106929532, + 0.0783775193, + 0.3303413448, + 0.0074411299, + 0.0758961579, + 0.1979424701, + 0.0054510435, + 0.0274234465, + 0.0277992394, + 0.0122972537, + 0.0657037101, + 0.0639999123, + ], + [ + 0.0416771398, + 0.0221169089, + 0.1169495654, + 0.4454606095, + 0.0036007417, + 0.0299634452, + 0.0884746233, + 0.0405374096, + 0.0308520097, + 0.0072242430, + 0.0119112806, + 0.0302540864, + 0.0050594731, + 0.0048427847, + 0.0083166826, + 0.0573194729, + 0.0355017818, + 0.0015358747, + 0.0066579203, + 0.0117439467, + ], + [ + 0.0172099804, + 0.0043071518, + 0.0028186497, + 0.0015204809, + 0.0040847071, + 0.0059552181, + 0.0026945586, + 0.0027086250, + 0.0033305753, + 0.0963035365, + 0.6293618376, + 0.0035119483, + 0.0782115537, + 0.0508047038, + 0.0026960404, + 0.0075406401, + 0.0142398388, + 0.0020917035, + 0.0072253971, + 0.0633828534, + ], + [ + 0.0256344906, + 0.2391748318, + 0.0325462658, + 0.0058407604, + 0.0023635926, + 0.0477450413, + 0.0260489167, + 0.0086327173, + 0.0166386076, + 0.0067366978, + 0.0178988286, + 0.4887871802, + 0.0068356436, + 0.0022946982, + 0.0039506409, + 0.0281626721, + 0.0273892020, + 0.0009564097, + 0.0026419434, + 0.0097208594, + ], + [ + 0.5244664877, + 0.0125254948, + 0.0126934000, + 0.0120263649, + 0.0231732194, + 0.0112264636, + 0.0231644717, + 0.0607505057, + 0.0064964872, + 0.0244657005, + 0.0296935115, + 0.0173867172, + 0.0081235352, + 0.0071609812, + 0.0100735231, + 0.1052988164, + 0.0525350989, + 0.0019282222, + 0.0057504367, + 0.0510605620, + ], + [ + 0.0684729714, + 0.0112127701, + 0.0403335323, + 0.0191649891, + 0.0080579914, + 0.0106467677, + 0.0122717083, + 0.0298851793, + 0.0059333163, + 0.0090162984, + 0.0122256684, + 0.0202533560, + 0.0067383478, + 0.0042926012, + 0.0093768645, + 0.3579911171, + 0.3454716445, + 0.0012520155, + 0.0039047077, + 0.0234981530, + ], + [ + 0.0431160797, + 0.0215832692, + 0.1192887705, + 0.3539316598, + 0.0016000541, + 0.0399706275, + 0.1859723986, + 0.0460698092, + 0.0202436900, + 0.0034321356, + 0.0059874011, + 0.0454100232, + 0.0026805546, + 0.0021938566, + 0.0065396690, + 0.0587782875, + 0.0325783252, + 0.0006656556, + 0.0033322972, + 0.0066254358, + ], + [ + 0.3573125519, + 0.0107739792, + 0.0185904600, + 0.0101529526, + 0.0238277042, + 0.0102983115, + 0.0130640673, + 0.2739505968, + 0.0062329007, + 0.0134629908, + 0.0279626556, + 0.0100403518, + 0.0080660083, + 0.0080613837, + 0.0115909925, + 0.1055494364, + 0.0430638712, + 0.0022044279, + 0.0055644947, + 0.0402298632, + ], + [ + 0.0159306780, + 0.0019861711, + 0.0016155205, + 0.0008388731, + 0.0030122267, + 0.0025620004, + 0.0014581158, + 0.0015316121, + 0.0013862241, + 0.2455696281, + 0.4616985539, + 0.0017000369, + 0.0640011160, + 0.0324706573, + 0.0013486013, + 0.0037612371, + 0.0130101963, + 0.0008845745, + 0.0034279115, + 0.1418060652, + ], + [ + 0.0256595252, + 0.0051398507, + 0.0041933206, + 0.0020618461, + 0.0056962061, + 0.0062435114, + 0.0033932371, + 0.0043865309, + 0.0047455138, + 0.1093546126, + 0.4337122399, + 0.0040112984, + 0.0884835342, + 0.1534126558, + 0.0032694406, + 0.0111090694, + 0.0203935806, + 0.0060339205, + 0.0346075560, + 0.0740925502, + ], + [ + 0.2603930332, + 0.0073475515, + 0.0274139717, + 0.0063098597, + 0.0295274636, + 0.0099778448, + 0.0086635315, + 0.0437217348, + 0.0047244367, + 0.0308693282, + 0.0303231536, + 0.0079919138, + 0.0133086321, + 0.0064295443, + 0.0114932213, + 0.2125431297, + 0.2162313199, + 0.0014309431, + 0.0044162709, + 0.0668831157, + ], + [ + 0.2398682211, + 0.0296580554, + 0.0166720679, + 0.0285695513, + 0.0051008878, + 0.0326600515, + 0.0396739293, + 0.0457650224, + 0.0090374608, + 0.0252362338, + 0.0366299593, + 0.0337300875, + 0.0080670322, + 0.0068145111, + 0.2374469983, + 0.0835294135, + 0.0566637697, + 0.0023132951, + 0.0056482253, + 0.0569152265, + ], + [ + 0.1630002622, + 0.0047427947, + 0.0060825443, + 0.0026244608, + 0.0330792286, + 0.0058581001, + 0.0041018685, + 0.0366585736, + 0.0031771350, + 0.1231031772, + 0.1752249322, + 0.0040937805, + 0.0579611401, + 0.0450813699, + 0.0049957490, + 0.0602233144, + 0.0783535053, + 0.0027457816, + 0.0067466555, + 0.1821456266, + ], + [ + 0.1016540377, + 0.0269983186, + 0.0434475087, + 0.0157791031, + 0.2255662492, + 0.0201773403, + 0.0177276432, + 0.0501564700, + 0.0167602619, + 0.0470784959, + 0.0669713543, + 0.0202809553, + 0.0191603246, + 0.0387562907, + 0.0130253479, + 0.1022913849, + 0.0692395733, + 0.0064607064, + 0.0242671334, + 0.0742015005, + ], + [ + 0.0840356664, + 0.0571048468, + 0.0579222868, + 0.1299077821, + 0.0009595075, + 0.1013868108, + 0.2631117692, + 0.0261692541, + 0.0127718810, + 0.0042570552, + 0.0086291181, + 0.1383236799, + 0.0033381598, + 0.0015465733, + 0.0039395105, + 0.0536522004, + 0.0408899328, + 0.0004150112, + 0.0025946131, + 0.0090443411, + ], + [ + 0.1569088377, + 0.0097025375, + 0.0080413058, + 0.0058447175, + 0.0310553392, + 0.0092046516, + 0.0099620808, + 0.0214224363, + 0.0055044481, + 0.1220282549, + 0.0662330171, + 0.0092184141, + 0.0301390123, + 0.0124363753, + 0.0099185964, + 0.0440087571, + 0.0706768938, + 0.0019549709, + 0.0063306227, + 0.3694087308, + ], + [ + 0.0554711926, + 0.0432670496, + 0.0197873228, + 0.0148911765, + 0.0096853088, + 0.0207046866, + 0.0163475389, + 0.0441003076, + 0.0239690167, + 0.0387588514, + 0.0775793825, + 0.0199204450, + 0.0193160539, + 0.0975446941, + 0.0127355884, + 0.0514471187, + 0.0428135357, + 0.2489692795, + 0.0952315577, + 0.0474598930, + ], + [ + 0.0154144169, + 0.0018029434, + 0.0018295289, + 0.0009270643, + 0.0029420411, + 0.0018144150, + 0.0016746718, + 0.0014452484, + 0.0012157445, + 0.4915617620, + 0.0763199676, + 0.0018126135, + 0.0206526786, + 0.0125909364, + 0.0013234994, + 0.0038766808, + 0.0162106278, + 0.0004477827, + 0.0021447539, + 0.3439926231, + ], + [ + 0.0361614834, + 0.0015770339, + 0.0014916703, + 0.0007620196, + 0.0036696287, + 0.0016065289, + 0.0013301230, + 0.0023677117, + 0.0009436472, + 0.3099681186, + 0.1344318070, + 0.0013240267, + 0.0301553040, + 0.0162498924, + 0.0014245857, + 0.0070774984, + 0.0223113392, + 0.0005729634, + 0.0019741286, + 0.4246004892, + ], + [ + 0.1419139588, + 0.0323567410, + 0.0433971790, + 0.2073084309, + 0.0012982533, + 0.0605466740, + 0.2432306451, + 0.0476288636, + 0.0111308641, + 0.0045680138, + 0.0087051065, + 0.0455779715, + 0.0030759365, + 0.0020850039, + 0.0263747551, + 0.0640052206, + 0.0424443743, + 0.0007857691, + 0.0021651939, + 0.0114010450, + ], + [ + 0.1232251773, + 0.0341185244, + 0.0337681810, + 0.1108597839, + 0.0016729117, + 0.0460427254, + 0.1587798968, + 0.0342301772, + 0.0089446665, + 0.0060780622, + 0.0136182030, + 0.0669929252, + 0.0037516248, + 0.0032545825, + 0.2257526028, + 0.0659554662, + 0.0394411930, + 0.0010617818, + 0.0035000894, + 0.0189514249, + ], + [ + 0.0248476071, + 0.0013965561, + 0.0014102314, + 0.0008032552, + 0.0032553333, + 0.0013832379, + 0.0013503669, + 0.0013654791, + 0.0009085661, + 0.3090266922, + 0.0514966055, + 0.0014019089, + 0.0135431838, + 0.0072655298, + 0.0011575475, + 0.0052280363, + 0.0167135485, + 0.0003431951, + 0.0012532734, + 0.5558498458, + ], + [ + 0.1117415302, + 0.0283211746, + 0.0382199731, + 0.0339934842, + 0.0049172405, + 0.0378428852, + 0.0334628248, + 0.0427518322, + 0.0116841962, + 0.0103184897, + 0.0308795077, + 0.0322858518, + 0.0061412028, + 0.0059002202, + 0.2472566507, + 0.2023832117, + 0.0867730230, + 0.0015334113, + 0.0051735604, + 0.0284197298, + ], + [ + 0.0466012599, + 0.0057373489, + 0.0054053599, + 0.0029520950, + 0.0068563504, + 0.0058327969, + 0.0040687198, + 0.0078295145, + 0.0055590747, + 0.1822282514, + 0.1957274091, + 0.0048231043, + 0.0496467749, + 0.1793605312, + 0.0035814947, + 0.0199290398, + 0.0313011488, + 0.0104893286, + 0.0695146794, + 0.1625557177, + ], + [ + 0.0507281677, + 0.0544220123, + 0.1579229755, + 0.0788685052, + 0.0039334840, + 0.0509870265, + 0.0477651794, + 0.2796151713, + 0.0369814312, + 0.0069052509, + 0.0134891426, + 0.0755513460, + 0.0058960655, + 0.0058160482, + 0.0068744278, + 0.0735036409, + 0.0318932622, + 0.0017794508, + 0.0069120028, + 0.0101554090, + ], + [ + 0.1012940500, + 0.0113951687, + 0.0270180518, + 0.0067000485, + 0.0151910484, + 0.0137337382, + 0.0121074384, + 0.0118400404, + 0.0062930085, + 0.1082273194, + 0.0608746996, + 0.0132648593, + 0.0396202280, + 0.0099430674, + 0.0069925894, + 0.0809279777, + 0.2501215831, + 0.0018086135, + 0.0063891997, + 0.2162572700, + ], + [ + 0.5581212015, + 0.0043882915, + 0.0068458308, + 0.0034872233, + 0.0267847969, + 0.0050347326, + 0.0051624085, + 0.0563359963, + 0.0028702437, + 0.0077985525, + 0.0114614720, + 0.0043400933, + 0.0046487500, + 0.0032677011, + 0.0059278308, + 0.2110346692, + 0.0473702791, + 0.0007957395, + 0.0025993594, + 0.0317248279, + ], + [ + 0.0366990737, + 0.0088117491, + 0.0141346745, + 0.0122504205, + 0.0022559042, + 0.0040513968, + 0.0088534120, + 0.8516617601, + 0.0025327277, + 0.0020967353, + 0.0032320110, + 0.0082818663, + 0.0018263858, + 0.0014858731, + 0.0021668343, + 0.0257254026, + 0.0078861749, + 0.0006687786, + 0.0014068010, + 0.0039720184, + ], + [ + 0.0325299830, + 0.0079189064, + 0.0271972378, + 0.2883675789, + 0.0010501979, + 0.0455936755, + 0.4794970513, + 0.0195892563, + 0.0061816679, + 0.0029808524, + 0.0048190814, + 0.0246099198, + 0.0023859173, + 0.0013294113, + 0.0035627749, + 0.0252280258, + 0.0173068390, + 0.0003793154, + 0.0019088405, + 0.0075634672, + ], + [ + 0.0183732285, + 0.0012004157, + 0.0011031805, + 0.0005721476, + 0.0021570953, + 0.0013421811, + 0.0009486039, + 0.0013249492, + 0.0008401634, + 0.3906659522, + 0.2004459805, + 0.0009801049, + 0.0330335241, + 0.0189466361, + 0.0010542030, + 0.0031220981, + 0.0137436252, + 0.0005314587, + 0.0019602900, + 0.3076541622, + ], + [ + 0.0407340423, + 0.0211409025, + 0.0266761496, + 0.1272152395, + 0.0018565070, + 0.0709735920, + 0.5264962988, + 0.0241160442, + 0.0090603820, + 0.0062481884, + 0.0112139165, + 0.0439684494, + 0.0047511429, + 0.0028543997, + 0.0046843579, + 0.0286679920, + 0.0248255063, + 0.0008512382, + 0.0034817020, + 0.0201839486, + ], + [ + 0.2064432652, + 0.0631796718, + 0.0414341876, + 0.0448132393, + 0.0017213239, + 0.0719449284, + 0.0751642055, + 0.0423921203, + 0.0089416046, + 0.0109439288, + 0.0315518825, + 0.2156827117, + 0.0067323312, + 0.0047622166, + 0.0101575250, + 0.0707013927, + 0.0525431355, + 0.0014911792, + 0.0047301771, + 0.0346689730, + ], + [ + 0.0237681211, + 0.0052813563, + 0.0040396130, + 0.0022500341, + 0.0042881466, + 0.0145192252, + 0.0038691448, + 0.0036190611, + 0.0034915761, + 0.0796673512, + 0.4975479977, + 0.0048131459, + 0.2105932417, + 0.0456849269, + 0.0026378886, + 0.0140003123, + 0.0201164398, + 0.0021368986, + 0.0071145642, + 0.0505609550, + ], + [ + 0.0243518811, + 0.0040453089, + 0.0039673777, + 0.0018963614, + 0.0074155690, + 0.0043571396, + 0.0025748495, + 0.0044153590, + 0.0058270463, + 0.0715399798, + 0.2707053561, + 0.0033240401, + 0.0531313762, + 0.3591545885, + 0.0026903081, + 0.0148383637, + 0.0156987104, + 0.0181706113, + 0.0749741700, + 0.0569216032, + ], + [ + 0.0433329269, + 0.1009380779, + 0.1873040738, + 0.0631651864, + 0.0027814797, + 0.0696650526, + 0.0580977164, + 0.0483670585, + 0.0500391499, + 0.0066393730, + 0.0117581524, + 0.2022931194, + 0.0053505118, + 0.0040672815, + 0.0052878433, + 0.0765378573, + 0.0470262674, + 0.0013274905, + 0.0066763517, + 0.0093450297, + ], + [ + 0.0297173770, + 0.0166678718, + 0.3185935332, + 0.3152613973, + 0.0021776566, + 0.0221225463, + 0.0465347670, + 0.0476685033, + 0.0276217975, + 0.0042962482, + 0.0057826241, + 0.0341429787, + 0.0027987823, + 0.0030020326, + 0.0038774624, + 0.0747142374, + 0.0329766936, + 0.0009408652, + 0.0049505427, + 0.0061520829, + ], + [ + 0.0435961869, + 0.0489705550, + 0.0593695259, + 0.0127982200, + 0.0086750351, + 0.0485607080, + 0.0153215904, + 0.0110379960, + 0.2247125644, + 0.0130520756, + 0.0505778854, + 0.0314163028, + 0.0101591892, + 0.0892864898, + 0.0055962679, + 0.0482172152, + 0.0333850688, + 0.0079147272, + 0.2179605623, + 0.0193918341, + ], + [ + 0.0824735220, + 0.0040958054, + 0.0039677446, + 0.0022712989, + 0.0197004881, + 0.0040064710, + 0.0041538153, + 0.0049882771, + 0.0024606567, + 0.1837411531, + 0.0568753435, + 0.0040190403, + 0.0234199543, + 0.0126628160, + 0.0036039853, + 0.0202628922, + 0.0468671387, + 0.0009447109, + 0.0034831012, + 0.5160017855, + ], + [ + 0.5129227575, + 0.0043436058, + 0.0061350111, + 0.0039633346, + 0.0254540613, + 0.0046120550, + 0.0053407516, + 0.1741790288, + 0.0027556873, + 0.0124951071, + 0.0159544665, + 0.0039321709, + 0.0055723404, + 0.0043524438, + 0.0063199428, + 0.1330749440, + 0.0405632858, + 0.0010461359, + 0.0027808992, + 0.0342019707, + ], + [ + 0.0319787428, + 0.0018530342, + 0.0018903132, + 0.0009205515, + 0.0061215764, + 0.0021868192, + 0.0012811505, + 0.0045229366, + 0.0017307744, + 0.1869550755, + 0.3224846157, + 0.0015618036, + 0.0581232500, + 0.1819571990, + 0.0017767069, + 0.0121114355, + 0.0197066826, + 0.0055984245, + 0.0263049619, + 0.1309339459, + ], + [ + 0.0229407460, + 0.0083268960, + 0.1200651405, + 0.5986176572, + 0.0019087421, + 0.0181106672, + 0.0824798937, + 0.0277226541, + 0.0188325448, + 0.0033526907, + 0.0048267391, + 0.0187365995, + 0.0023966692, + 0.0022140878, + 0.0037816638, + 0.0372394540, + 0.0191621512, + 0.0006801203, + 0.0031799713, + 0.0054249115, + ], + [ + 0.0288193737, + 0.0058320855, + 0.0054875987, + 0.0031354364, + 0.0044802217, + 0.0055736690, + 0.0049034711, + 0.0046910521, + 0.0037819241, + 0.4497801308, + 0.1238264351, + 0.0067122439, + 0.0503198925, + 0.0262480651, + 0.0033388375, + 0.0157684226, + 0.0380496373, + 0.0016963933, + 0.0063321057, + 0.2112230040, + ], + [ + 0.1674975235, + 0.0083965755, + 0.0215955479, + 0.0166162052, + 0.0061924889, + 0.0070185641, + 0.0098852711, + 0.5995467253, + 0.0045393028, + 0.0052274023, + 0.0085651777, + 0.0082485649, + 0.0042282742, + 0.0039182158, + 0.0056596367, + 0.0782752832, + 0.0232701641, + 0.0013292174, + 0.0032582684, + 0.0167315911, + ], + [ + 0.0104733805, + 0.0015266224, + 0.0012310281, + 0.0006966232, + 0.0018396261, + 0.0020946794, + 0.0010714003, + 0.0011556333, + 0.0009981674, + 0.1519011093, + 0.6373750805, + 0.0012883946, + 0.0670406121, + 0.0296741320, + 0.0010270413, + 0.0028076255, + 0.0084311142, + 0.0007034328, + 0.0023699883, + 0.0762943089, + ], + [ + 0.0400128851, + 0.0057753456, + 0.0054229606, + 0.0025133046, + 0.0054261932, + 0.0076974835, + 0.0043339309, + 0.0048839117, + 0.0036544240, + 0.2221867122, + 0.2276752294, + 0.0053630998, + 0.1830542296, + 0.0346660059, + 0.0032703596, + 0.0226117451, + 0.0436706611, + 0.0018377870, + 0.0058162009, + 0.1701275303, + ], + [ + 0.0172238436, + 0.0009271221, + 0.0009040352, + 0.0005248004, + 0.0023813040, + 0.0009887214, + 0.0007843647, + 0.0010294429, + 0.0005956594, + 0.3905439927, + 0.1017098506, + 0.0007968299, + 0.0182926329, + 0.0109498026, + 0.0007053655, + 0.0022169283, + 0.0106372203, + 0.0002854911, + 0.0010776386, + 0.4374249536, + ], + [ + 0.1082611148, + 0.0016064238, + 0.0019671682, + 0.0008149601, + 0.0197069467, + 0.0019553228, + 0.0011419805, + 0.0301012546, + 0.0011916617, + 0.1625640600, + 0.2493818799, + 0.0012749462, + 0.0507818345, + 0.0841228821, + 0.0028740093, + 0.0322249032, + 0.0463396354, + 0.0038079898, + 0.0059428338, + 0.1939381924, + ], + [ + 0.1015896009, + 0.0015870461, + 0.0020716765, + 0.0009408561, + 0.0194283943, + 0.0018782624, + 0.0015093911, + 0.0130140829, + 0.0011954681, + 0.2262097444, + 0.1305769486, + 0.0013626986, + 0.0372967527, + 0.0246714750, + 0.0021225791, + 0.0225761978, + 0.0496703217, + 0.0008951164, + 0.0024487203, + 0.3589546670, + ], + [ + 0.5223534714, + 0.0044523401, + 0.0053511676, + 0.0031533978, + 0.0333126223, + 0.0042832779, + 0.0051434695, + 0.0433548832, + 0.0028633951, + 0.0281888692, + 0.0239425768, + 0.0039228976, + 0.0088328715, + 0.0046064897, + 0.0059137504, + 0.1125553425, + 0.0889452607, + 0.0009857551, + 0.0029086157, + 0.0949295461, + ], + [ + 0.0173178545, + 0.0009605177, + 0.0010122939, + 0.0004675494, + 0.0023778830, + 0.0013013531, + 0.0008002002, + 0.0012062195, + 0.0008311825, + 0.3171292054, + 0.3577193425, + 0.0008311915, + 0.0541728521, + 0.0294133019, + 0.0008919974, + 0.0027963250, + 0.0116704446, + 0.0006297227, + 0.0022923220, + 0.1961782411, + ], + [ + 0.0587477727, + 0.0636231847, + 0.0445207271, + 0.0340848518, + 0.0015737719, + 0.0638737266, + 0.0824819658, + 0.0121043724, + 0.0105302296, + 0.0303900282, + 0.0265219926, + 0.1766831363, + 0.0064985641, + 0.0037652243, + 0.0069035383, + 0.0886810371, + 0.2269194499, + 0.0016075964, + 0.0048336849, + 0.0556551454, + ], + [ + 0.2349695604, + 0.0030445622, + 0.0035546894, + 0.0019121034, + 0.0369090548, + 0.0031831435, + 0.0027418050, + 0.0206439218, + 0.0021779588, + 0.1275931605, + 0.0680783569, + 0.0027173348, + 0.0268878181, + 0.0147657171, + 0.0034553334, + 0.0378247547, + 0.0653822820, + 0.0008978361, + 0.0028574963, + 0.3404031109, + ], + [ + 0.0981748595, + 0.0116733401, + 0.0395107422, + 0.0205119908, + 0.0333058934, + 0.0090940086, + 0.0088629331, + 0.0457854103, + 0.0065313888, + 0.0078602156, + 0.0186324112, + 0.0113250986, + 0.0052649374, + 0.0063541537, + 0.0104165169, + 0.5430144411, + 0.0967886205, + 0.0015701916, + 0.0053590076, + 0.0199638391, + ], + [ + 0.0628326161, + 0.1747466039, + 0.0389896126, + 0.0304345888, + 0.0011897208, + 0.1550652634, + 0.0926077060, + 0.0164988172, + 0.0259452978, + 0.0048820931, + 0.0180791313, + 0.2800516191, + 0.0042591418, + 0.0017268704, + 0.0024051597, + 0.0407469939, + 0.0377294992, + 0.0006065331, + 0.0021203673, + 0.0090823644, + ], + [ + 0.0181771412, + 0.4177245448, + 0.0187734897, + 0.0029230219, + 0.0017326540, + 0.0390103787, + 0.0144002503, + 0.0058920628, + 0.0157110588, + 0.0040328620, + 0.0132516210, + 0.3941448717, + 0.0039605944, + 0.0016411114, + 0.0020018671, + 0.0212464876, + 0.0171890346, + 0.0007206656, + 0.0020957561, + 0.0053705264, + ], + [ + 0.0118862523, + 0.0019615182, + 0.0016436816, + 0.0009176722, + 0.0027778155, + 0.0038952147, + 0.0014639227, + 0.0016195284, + 0.0015321415, + 0.0702755047, + 0.6558678882, + 0.0020542894, + 0.1480520957, + 0.0395439204, + 0.0011659649, + 0.0042819614, + 0.0105036667, + 0.0009126113, + 0.0039244781, + 0.0357198722, + ], + [ + 0.0308391290, + 0.0063188584, + 0.0551084437, + 0.4735191982, + 0.0012568003, + 0.0300798713, + 0.2720395142, + 0.0252118862, + 0.0081666484, + 0.0030055378, + 0.0046283082, + 0.0221108896, + 0.0022537447, + 0.0017385431, + 0.0043656352, + 0.0325278147, + 0.0186810942, + 0.0005470496, + 0.0023244921, + 0.0052765409, + ], + [ + 0.0632455755, + 0.0238468809, + 0.2372867005, + 0.0523244090, + 0.0061521887, + 0.0276274247, + 0.0228522191, + 0.0612571235, + 0.0240082751, + 0.0062158582, + 0.0086231939, + 0.0333500288, + 0.0045101518, + 0.0039674226, + 0.0057373912, + 0.3142230635, + 0.0893183739, + 0.0011177546, + 0.0043460398, + 0.0099899250, + ], + [ + 0.0332341054, + 0.0250370076, + 0.5153463068, + 0.0658533474, + 0.0051307016, + 0.0263346900, + 0.0230515356, + 0.0323359278, + 0.0385402601, + 0.0083916546, + 0.0111960364, + 0.0391028453, + 0.0058330737, + 0.0056408948, + 0.0050252289, + 0.0945243297, + 0.0443995026, + 0.0014869058, + 0.0085301661, + 0.0110054797, + ], + [ + 0.0085234069, + 0.0022030842, + 0.0013906519, + 0.0008850918, + 0.0022714390, + 0.0025542280, + 0.0012242237, + 0.0012841401, + 0.0019502916, + 0.0736067963, + 0.7321192224, + 0.0015659167, + 0.0494458496, + 0.0563233068, + 0.0018289796, + 0.0059315095, + 0.0068045757, + 0.0013629883, + 0.0038569560, + 0.0448673422, + ], + [ + 0.0589774964, + 0.0007696692, + 0.0009802650, + 0.0004023925, + 0.0114970860, + 0.0009728181, + 0.0005542774, + 0.0134381060, + 0.0006160130, + 0.2353154655, + 0.2758434212, + 0.0006292788, + 0.0432372654, + 0.0840551018, + 0.0018378532, + 0.0144064714, + 0.0258396961, + 0.0022691315, + 0.0038183116, + 0.2245398799, + ], + [ + 0.0623479058, + 0.0197717479, + 0.0345282381, + 0.0096614369, + 0.0082682586, + 0.0117337465, + 0.0135895655, + 0.0181166697, + 0.0066456545, + 0.0411656062, + 0.0329704241, + 0.0250316077, + 0.0235278514, + 0.0066012981, + 0.0068729063, + 0.1255910690, + 0.4931968706, + 0.0017920619, + 0.0052183870, + 0.0533686941, + ], + [ + 0.0097140245, + 0.0037109093, + 0.0064403048, + 0.0021061279, + 0.0050159241, + 0.0039133369, + 0.0025305084, + 0.0025410607, + 0.0434529671, + 0.0078285006, + 0.0221621909, + 0.0026792539, + 0.0038569631, + 0.2063468466, + 0.0014930624, + 0.0109623832, + 0.0052876004, + 0.0190429185, + 0.6294535432, + 0.0114615736, + ], + [ + 0.0155640741, + 0.0032141043, + 0.0037127373, + 0.0018531541, + 0.0048464577, + 0.0033751458, + 0.0022727586, + 0.0033126673, + 0.0068807221, + 0.0347417192, + 0.1080619263, + 0.0027118335, + 0.0256141271, + 0.5487904795, + 0.0019149343, + 0.0133782634, + 0.0076417140, + 0.0194321062, + 0.1630924737, + 0.0295886016, + ], + [ + 0.0175442271, + 0.0016635077, + 0.0018057268, + 0.0008346654, + 0.0028422278, + 0.0018727641, + 0.0013981397, + 0.0015909255, + 0.0012717491, + 0.4667254931, + 0.1576311248, + 0.0016147650, + 0.0622696796, + 0.0231093573, + 0.0013056266, + 0.0045460638, + 0.0182460173, + 0.0006944080, + 0.0027191720, + 0.2303143595, + ], + [ + 0.0748416558, + 0.0056167556, + 0.0044775741, + 0.0051995102, + 0.0018697329, + 0.0098584282, + 0.0103391826, + 0.0131696775, + 0.0034241001, + 0.0054957730, + 0.0141039975, + 0.0082520829, + 0.0026609976, + 0.0024570272, + 0.7582828462, + 0.0411231721, + 0.0206361267, + 0.0007047921, + 0.0019902105, + 0.0154963571, + ], + [ + 0.1088181933, + 0.0227923562, + 0.0342154348, + 0.2056978989, + 0.0006252550, + 0.0732144876, + 0.3727850118, + 0.0243343384, + 0.0055765519, + 0.0022363026, + 0.0046209834, + 0.0549159775, + 0.0020044096, + 0.0010274542, + 0.0076879663, + 0.0419215590, + 0.0291043890, + 0.0003645891, + 0.0011806041, + 0.0068762371, + ], + [ + 0.0416168551, + 0.0053285627, + 0.0274542126, + 0.0077477655, + 0.0060913388, + 0.0049299865, + 0.0048859123, + 0.0151689522, + 0.0034110454, + 0.0112932331, + 0.0115263520, + 0.0068283918, + 0.0047692374, + 0.0028848275, + 0.0036907338, + 0.2663999554, + 0.5539560980, + 0.0007661092, + 0.0024548618, + 0.0187955690, + ], + [ + 0.0333834642, + 0.0085445510, + 0.0095604980, + 0.0055788098, + 0.0100633352, + 0.0080181825, + 0.0068934532, + 0.0095784395, + 0.0108965046, + 0.0469538980, + 0.1110750366, + 0.0079049071, + 0.0321655950, + 0.4831129783, + 0.0052058955, + 0.0347893841, + 0.0271050255, + 0.0133179296, + 0.0934609167, + 0.0423911956, + ], + [ + 0.0549753816, + 0.0432154129, + 0.0290546592, + 0.0552307103, + 0.0024559418, + 0.2312819553, + 0.3190879559, + 0.0226565799, + 0.0257461957, + 0.0082965310, + 0.0267987607, + 0.0599544903, + 0.0078397214, + 0.0036028252, + 0.0045614669, + 0.0374966468, + 0.0361330527, + 0.0013252169, + 0.0044319273, + 0.0258545683, + ], + [ + 0.0251707278, + 0.0049532447, + 0.0084097142, + 0.0065760228, + 0.0014762303, + 0.0020965462, + 0.0041720201, + 0.9103062758, + 0.0014464445, + 0.0013291554, + 0.0019519439, + 0.0038401683, + 0.0011459373, + 0.0009934370, + 0.0009914049, + 0.0167186841, + 0.0047199529, + 0.0003816612, + 0.0008660266, + 0.0024544021, + ], + [ + 0.0334006795, + 0.0345838372, + 0.1230246369, + 0.0809422565, + 0.0021653444, + 0.0334905519, + 0.0394149456, + 0.4874305855, + 0.0251129408, + 0.0035532000, + 0.0060062429, + 0.0542507857, + 0.0030441508, + 0.0028249506, + 0.0037803889, + 0.0472909702, + 0.0104622205, + 0.0008769260, + 0.0031367472, + 0.0052076389, + ], + [ + 0.2595873679, + 0.0027029449, + 0.0051250262, + 0.0018345012, + 0.0419926427, + 0.0036840367, + 0.0029900256, + 0.0320713333, + 0.0020479814, + 0.0738359401, + 0.0468836273, + 0.0026556975, + 0.0297092208, + 0.0085734862, + 0.0036912928, + 0.1194546333, + 0.1645069538, + 0.0010061991, + 0.0028808484, + 0.1947662408, + ], + [ + 0.0113265002, + 0.0011079882, + 0.0010634094, + 0.0006597824, + 0.0022429558, + 0.0011310547, + 0.0010315874, + 0.0008719119, + 0.0007515979, + 0.4989112958, + 0.0410628257, + 0.0010933277, + 0.0106936165, + 0.0068655925, + 0.0007752513, + 0.0025702542, + 0.0104352366, + 0.0002722855, + 0.0011300246, + 0.4060035014, + ], + [ + 0.0459959043, + 0.0250309444, + 0.1388577345, + 0.2147779624, + 0.0026214127, + 0.0333007342, + 0.0812911308, + 0.2670451965, + 0.0219938898, + 0.0038314074, + 0.0065237404, + 0.0417531166, + 0.0034154602, + 0.0028567496, + 0.0054706257, + 0.0660683920, + 0.0276191950, + 0.0011476688, + 0.0037789695, + 0.0066197652, + ], + [ + 0.0076723728, + 0.0022629009, + 0.0029569882, + 0.0014237107, + 0.0026022464, + 0.0025589525, + 0.0017930514, + 0.0018081694, + 0.0159544494, + 0.0131782791, + 0.0432058359, + 0.0019136311, + 0.0110159733, + 0.5431624483, + 0.0011216001, + 0.0074164093, + 0.0037934829, + 0.0182669799, + 0.3043804937, + 0.0135120248, + ], + [ + 0.3617052725, + 0.0036971352, + 0.0058922379, + 0.0033990525, + 0.0169801697, + 0.0038933391, + 0.0041623133, + 0.4233540249, + 0.0024413676, + 0.0060895247, + 0.0126312370, + 0.0031951035, + 0.0045054340, + 0.0034293990, + 0.0042974225, + 0.0918985928, + 0.0241777193, + 0.0009112845, + 0.0022715429, + 0.0210678271, + ], + [ + 0.0163926803, + 0.0023973533, + 0.0022964381, + 0.0012549906, + 0.0043565047, + 0.0035062134, + 0.0017595169, + 0.0025415692, + 0.0026061822, + 0.0687357087, + 0.5327945542, + 0.0019796309, + 0.0953903950, + 0.1763661912, + 0.0018563184, + 0.0061566236, + 0.0123667851, + 0.0036350243, + 0.0247889380, + 0.0388183818, + ], + [ + 0.2625606689, + 0.0039087191, + 0.0201733524, + 0.0035830144, + 0.0334149334, + 0.0052092305, + 0.0039216959, + 0.0470818491, + 0.0028840442, + 0.0098099028, + 0.0143502604, + 0.0035551251, + 0.0060509238, + 0.0040888068, + 0.0058025655, + 0.3854632223, + 0.1527998515, + 0.0008240041, + 0.0027022147, + 0.0318156151, + ], + [ + 0.0073411098, + 0.0021064323, + 0.0026324749, + 0.0011391062, + 0.0023458663, + 0.0019832089, + 0.0014087467, + 0.0015687276, + 0.0239508413, + 0.0075780091, + 0.0200728582, + 0.0016782970, + 0.0030210812, + 0.3281154863, + 0.0009474067, + 0.0061124137, + 0.0034406872, + 0.0175159503, + 0.5579376568, + 0.0091036397, + ], + [ + 0.2723513621, + 0.0536765156, + 0.0335044526, + 0.0709221665, + 0.0008774791, + 0.0779839697, + 0.1957794827, + 0.0342243290, + 0.0060329995, + 0.0038507683, + 0.0087640698, + 0.1009527761, + 0.0027860434, + 0.0014147301, + 0.0041739235, + 0.0698767109, + 0.0425194843, + 0.0004557040, + 0.0014374671, + 0.0184155657, + ], + [ + 0.3743567807, + 0.0033602239, + 0.0128640468, + 0.0029242518, + 0.0246823045, + 0.0049019752, + 0.0034946017, + 0.0426805366, + 0.0024969388, + 0.0041917253, + 0.0059438634, + 0.0031688952, + 0.0033398405, + 0.0028536235, + 0.0045356463, + 0.4362816353, + 0.0470435617, + 0.0007051793, + 0.0021142711, + 0.0180600984, + ], + [ + 0.6460473131, + 0.0020351924, + 0.0030888359, + 0.0016127216, + 0.0182576368, + 0.0025746322, + 0.0021624890, + 0.0387291763, + 0.0013496802, + 0.0036169193, + 0.0048831004, + 0.0020599836, + 0.0025437266, + 0.0016743774, + 0.0029348397, + 0.2129255383, + 0.0316977617, + 0.0004062822, + 0.0012601659, + 0.0201396272, + ], + [ + 0.0399445191, + 0.0763186291, + 0.0623126344, + 0.0236700976, + 0.0061815744, + 0.2388305600, + 0.0503409604, + 0.0139274123, + 0.2227453452, + 0.0102967142, + 0.0460248977, + 0.0553564212, + 0.0113160672, + 0.0088584024, + 0.0076894254, + 0.0453874589, + 0.0320442077, + 0.0028258622, + 0.0317758953, + 0.0141529152, + ], + [ + 0.0755624516, + 0.0015148377, + 0.0017383441, + 0.0010005167, + 0.0164041798, + 0.0014725224, + 0.0013736659, + 0.0025008413, + 0.0010567651, + 0.1846158014, + 0.0459840814, + 0.0013676865, + 0.0155265169, + 0.0086288017, + 0.0015184807, + 0.0114811384, + 0.0314632382, + 0.0004410905, + 0.0014027570, + 0.5949462828, + ], + [ + 0.0646033158, + 0.0060502366, + 0.0094576255, + 0.0029521284, + 0.0088699007, + 0.0065888305, + 0.0056879144, + 0.0062079750, + 0.0031825148, + 0.2317935588, + 0.0738085283, + 0.0063050553, + 0.0423309460, + 0.0094953556, + 0.0034437641, + 0.0473386866, + 0.2003185277, + 0.0012310916, + 0.0039480431, + 0.2663860009, + ], + [ + 0.2629535280, + 0.0078723784, + 0.0081929251, + 0.0067900766, + 0.0036109040, + 0.0106522404, + 0.0180257580, + 0.0355627861, + 0.0046198518, + 0.0088793132, + 0.0184295017, + 0.0096668605, + 0.0040905671, + 0.0033433552, + 0.4187988260, + 0.1005322723, + 0.0414816701, + 0.0010250884, + 0.0030039834, + 0.0324681139, + ], + [ + 0.1304596322, + 0.0040196070, + 0.0099078164, + 0.0039888274, + 0.0075762621, + 0.0028435104, + 0.0036513469, + 0.7425249628, + 0.0018762306, + 0.0026700692, + 0.0044724894, + 0.0028438070, + 0.0023356625, + 0.0021055089, + 0.0020848008, + 0.0532007331, + 0.0120336222, + 0.0006096938, + 0.0015758768, + 0.0092195408, + ], + [ + 0.2174112906, + 0.0067725382, + 0.0308088713, + 0.0106480509, + 0.0212599093, + 0.0091098210, + 0.0084609967, + 0.2567497109, + 0.0038389030, + 0.0053618508, + 0.0075426146, + 0.0059503311, + 0.0045360277, + 0.0038043203, + 0.0050933517, + 0.3225062895, + 0.0566124655, + 0.0010759922, + 0.0029676441, + 0.0194890207, + ], + [ + 0.0085358787, + 0.0009157021, + 0.0009776624, + 0.0005427311, + 0.0015135900, + 0.0011044685, + 0.0008080293, + 0.0008463519, + 0.0006955216, + 0.5987918953, + 0.0981552685, + 0.0008721951, + 0.0210109917, + 0.0109797913, + 0.0006574764, + 0.0021522371, + 0.0091076458, + 0.0003056524, + 0.0013669253, + 0.2406599856, + ], + [ + 0.2255037987, + 0.0050043256, + 0.0186336845, + 0.0038400854, + 0.2611431363, + 0.0055268832, + 0.0046632706, + 0.0383918832, + 0.0042109747, + 0.0242576911, + 0.0273189693, + 0.0048611595, + 0.0097125321, + 0.0075459295, + 0.0041886858, + 0.2007649684, + 0.0866551606, + 0.0015497511, + 0.0045771746, + 0.0616499358, + ], + [ + 0.0211538925, + 0.0006732528, + 0.0009059645, + 0.0004159533, + 0.0025502183, + 0.0012921827, + 0.0006053390, + 0.0022636694, + 0.0005999807, + 0.1728461112, + 0.4837044919, + 0.0005587445, + 0.0773344560, + 0.1035030407, + 0.0009055845, + 0.0047249186, + 0.0129859150, + 0.0016525767, + 0.0084928843, + 0.1028308235, + ], + [ + 0.0299370300, + 0.0241900206, + 0.0099355598, + 0.0064715727, + 0.0079742842, + 0.0095688866, + 0.0078856067, + 0.0216808142, + 0.0110040631, + 0.0239470465, + 0.0533224970, + 0.0093563400, + 0.0114274868, + 0.0772597705, + 0.0069164280, + 0.0288505449, + 0.0203577891, + 0.5477592933, + 0.0653512594, + 0.0268037066, + ], + [ + 0.5061694034, + 0.0013700844, + 0.0038904753, + 0.0013561749, + 0.0193293569, + 0.0019840812, + 0.0017215621, + 0.1603198970, + 0.0010185238, + 0.0079429042, + 0.0081661965, + 0.0012718474, + 0.0041870893, + 0.0028087417, + 0.0027700024, + 0.2146039512, + 0.0383830401, + 0.0004990543, + 0.0013513328, + 0.0208562811, + ], + [ + 0.0291394175, + 0.0463173948, + 0.0628604044, + 0.0253963966, + 0.0056080298, + 0.0611061435, + 0.0200732169, + 0.0093711590, + 0.4900751396, + 0.0088563043, + 0.0298885629, + 0.0286393927, + 0.0064344949, + 0.0279414462, + 0.0053456488, + 0.0357825888, + 0.0230486032, + 0.0026612584, + 0.0700671342, + 0.0113872635, + ], + [ + 0.0201939544, + 0.0022774107, + 0.0023201915, + 0.0011355526, + 0.0026569867, + 0.0031962133, + 0.0018746875, + 0.0022682540, + 0.0015219746, + 0.2789228260, + 0.2645645158, + 0.0021831930, + 0.2353573782, + 0.0260244948, + 0.0012370699, + 0.0083103863, + 0.0198635819, + 0.0009612898, + 0.0030065395, + 0.1221234995, + ], + [ + 0.0092655180, + 0.0022738701, + 0.0027908468, + 0.0024439593, + 0.0006205465, + 0.0007423269, + 0.0010951272, + 0.9646815778, + 0.0008444293, + 0.0005955009, + 0.0011391363, + 0.0008473948, + 0.0004367266, + 0.0005867195, + 0.0007096502, + 0.0070534997, + 0.0020279221, + 0.0002112232, + 0.0003769453, + 0.0012570794, + ], + [ + 0.0215832759, + 0.0189420203, + 0.0314462815, + 0.0054871515, + 0.0063155226, + 0.0199961639, + 0.0063704227, + 0.0051331529, + 0.1929473716, + 0.0072751515, + 0.0331842849, + 0.0073086127, + 0.0050514149, + 0.1257669656, + 0.0031371536, + 0.0245736582, + 0.0102968166, + 0.0103308533, + 0.4531162415, + 0.0117374843, + ], + [ + 0.7147537999, + 0.0021224820, + 0.0025691705, + 0.0017985650, + 0.0192905954, + 0.0022071036, + 0.0023316533, + 0.0496293040, + 0.0013244349, + 0.0123782270, + 0.0105955142, + 0.0019187384, + 0.0035782954, + 0.0019728199, + 0.0034310601, + 0.0814690711, + 0.0371992555, + 0.0005303817, + 0.0013772386, + 0.0495222894, + ], + [ + 0.0123113867, + 0.0005662604, + 0.0006323206, + 0.0003431800, + 0.0014002059, + 0.0006068538, + 0.0005141319, + 0.0008309888, + 0.0003936455, + 0.4248750404, + 0.2409846308, + 0.0004924365, + 0.0300840203, + 0.0165262491, + 0.0005396285, + 0.0016461929, + 0.0082184637, + 0.0002672411, + 0.0009548785, + 0.2578122446, + ], + [ + 0.0064324498, + 0.0010084348, + 0.0007661057, + 0.0004671562, + 0.0012001276, + 0.0015204017, + 0.0007274350, + 0.0007487976, + 0.0007030962, + 0.0586300396, + 0.7767512997, + 0.0008669570, + 0.0802982468, + 0.0291003027, + 0.0006176585, + 0.0023112824, + 0.0053726742, + 0.0004477307, + 0.0016577432, + 0.0303720606, + ], + [ + 0.0346139539, + 0.0381329188, + 0.3072123296, + 0.0434178870, + 0.0047014591, + 0.0453922134, + 0.0268513824, + 0.0244329716, + 0.2496970425, + 0.0077114470, + 0.0152954698, + 0.0362362493, + 0.0059010957, + 0.0110651548, + 0.0047790008, + 0.0560669253, + 0.0331806303, + 0.0019738021, + 0.0434223878, + 0.0099156789, + ], + [ + 0.0355313938, + 0.0534772414, + 0.0283389492, + 0.0094407438, + 0.0033396268, + 0.4956667860, + 0.0645961269, + 0.0113451065, + 0.0629740168, + 0.0089405697, + 0.0458547499, + 0.0523689876, + 0.0268055545, + 0.0051229887, + 0.0060526092, + 0.0363807821, + 0.0301761206, + 0.0021069955, + 0.0068550642, + 0.0146255869, + ], + [ + 0.0162974842, + 0.0007780292, + 0.0007611541, + 0.0004879309, + 0.0039262425, + 0.0007598956, + 0.0006903278, + 0.0007121460, + 0.0005016175, + 0.2806840980, + 0.0306913890, + 0.0008054080, + 0.0067783943, + 0.0039539947, + 0.0004850268, + 0.0022329476, + 0.0099102939, + 0.0001678201, + 0.0006564900, + 0.6387193098, + ], + [ + 0.0506131403, + 0.0049661940, + 0.0270594025, + 0.0132589097, + 0.0077095776, + 0.0045515572, + 0.0049880243, + 0.0234832102, + 0.0031256562, + 0.0047437633, + 0.0060548777, + 0.0054748846, + 0.0032249929, + 0.0027019788, + 0.0047621925, + 0.5586518662, + 0.2598699286, + 0.0007293967, + 0.0023912110, + 0.0116392358, + ], + [ + 0.0157508449, + 0.0019556244, + 0.0021377304, + 0.0011462685, + 0.0031902236, + 0.0021845681, + 0.0014684979, + 0.0024007612, + 0.0021615081, + 0.0534703931, + 0.3603626270, + 0.0016079954, + 0.0518594971, + 0.4083089947, + 0.0014771780, + 0.0083582851, + 0.0110805130, + 0.0034236491, + 0.0306724153, + 0.0369824250, + ], + [ + 0.0147993759, + 0.7347421122, + 0.0122736936, + 0.0027520064, + 0.0029171383, + 0.0254962623, + 0.0059030899, + 0.0089095381, + 0.0198290591, + 0.0048628353, + 0.0137625359, + 0.1087093741, + 0.0034749333, + 0.0025667529, + 0.0020588798, + 0.0150110879, + 0.0123641383, + 0.0011637197, + 0.0028772382, + 0.0055262287, + ], + [ + 0.0063696376, + 0.0005382008, + 0.0005695543, + 0.0003816620, + 0.0009435955, + 0.0006251450, + 0.0005259444, + 0.0005456299, + 0.0003625883, + 0.5771915901, + 0.0493592407, + 0.0005515524, + 0.0101419924, + 0.0048996090, + 0.0003364938, + 0.0012638121, + 0.0064310235, + 0.0001637363, + 0.0005844768, + 0.3382145149, + ], + [ + 0.0225573152, + 0.0022833779, + 0.0209591413, + 0.3787374361, + 0.0006767566, + 0.0226109481, + 0.4833621349, + 0.0145599631, + 0.0024692160, + 0.0013898127, + 0.0022108098, + 0.0134251858, + 0.0012158802, + 0.0008080377, + 0.0016304825, + 0.0160635246, + 0.0104394903, + 0.0001977833, + 0.0008863840, + 0.0035163197, + ], + [ + 0.2946910552, + 0.0014831220, + 0.0023674910, + 0.0009929173, + 0.0282405716, + 0.0020416408, + 0.0015748805, + 0.1341097611, + 0.0010934612, + 0.0736568120, + 0.1086444406, + 0.0012396871, + 0.0357735247, + 0.0461020394, + 0.0030816120, + 0.0706129646, + 0.0602269592, + 0.0021926334, + 0.0032426653, + 0.1286317611, + ], + [ + 0.0078170568, + 0.0007099246, + 0.0007048683, + 0.0004395536, + 0.0011345779, + 0.0009739593, + 0.0006479529, + 0.0007323081, + 0.0004900872, + 0.2237293042, + 0.5946216406, + 0.0006063232, + 0.0477269772, + 0.0247560234, + 0.0004950143, + 0.0016098527, + 0.0054323677, + 0.0003427476, + 0.0011957573, + 0.0858337031, + ], + [ + 0.4575609837, + 0.0014988653, + 0.0030065898, + 0.0010836846, + 0.0427979655, + 0.0019329985, + 0.0017066423, + 0.0379967963, + 0.0011372310, + 0.0183795551, + 0.0138782957, + 0.0014129485, + 0.0096758640, + 0.0026580351, + 0.0021671398, + 0.2003947844, + 0.1355534534, + 0.0004801566, + 0.0015604414, + 0.0651175691, + ], + [ + 0.0326193137, + 0.0111074785, + 0.1916495826, + 0.0913437069, + 0.0029322066, + 0.0193735473, + 0.0261936228, + 0.0283590174, + 0.0080456078, + 0.0054556616, + 0.0074517469, + 0.0236424829, + 0.0034970285, + 0.0028362357, + 0.0043779621, + 0.2284382934, + 0.2996742263, + 0.0009506527, + 0.0030507952, + 0.0090008311, + ], + [ + 0.0468012330, + 0.0243905390, + 0.0215012034, + 0.0114776849, + 0.5383734213, + 0.0101931574, + 0.0121616085, + 0.0323230638, + 0.0102258130, + 0.0290608086, + 0.0360190979, + 0.0113349458, + 0.0104404689, + 0.0251180182, + 0.0100593723, + 0.0699660853, + 0.0403438102, + 0.0042353006, + 0.0122917953, + 0.0436825724, + ], + [ + 0.7469095963, + 0.0007566451, + 0.0014977382, + 0.0005948493, + 0.0100532196, + 0.0008938489, + 0.0008347512, + 0.0498829528, + 0.0005806353, + 0.0023454538, + 0.0022654495, + 0.0007143290, + 0.0016447929, + 0.0008544401, + 0.0012431543, + 0.1458365599, + 0.0195592258, + 0.0002642055, + 0.0006928724, + 0.0125752803, + ], + [ + 0.0124533816, + 0.0030191061, + 0.0669612623, + 0.7813083980, + 0.0010074047, + 0.0085521494, + 0.0561929561, + 0.0124161108, + 0.0088953739, + 0.0016678990, + 0.0024372146, + 0.0071018096, + 0.0012682917, + 0.0011855055, + 0.0017595337, + 0.0187977946, + 0.0101104824, + 0.0003681407, + 0.0017279515, + 0.0027692336, + ], + [ + 0.1943783915, + 0.0004377626, + 0.0007503528, + 0.0003406997, + 0.0160398126, + 0.0006076684, + 0.0004470602, + 0.0647831099, + 0.0003538859, + 0.1456751869, + 0.1988959237, + 0.0004318751, + 0.0327192259, + 0.0517541819, + 0.0010533605, + 0.0411267086, + 0.0529569745, + 0.0011023414, + 0.0014500094, + 0.1946954687, + ], + [ + 0.0785961394, + 0.0002113724, + 0.0003736186, + 0.0001632614, + 0.0103011704, + 0.0003680586, + 0.0002270831, + 0.0192606411, + 0.0001869455, + 0.2451449593, + 0.2949969808, + 0.0002012155, + 0.0283248845, + 0.0663560114, + 0.0006938299, + 0.0112455953, + 0.0212421019, + 0.0009836611, + 0.0014441051, + 0.2196783647, + ], + [ + 0.0195872828, + 0.0133741988, + 0.0943266401, + 0.0983815199, + 0.0008938753, + 0.0164098670, + 0.0316244056, + 0.6398988680, + 0.0122020875, + 0.0016906526, + 0.0027188832, + 0.0294389820, + 0.0013778651, + 0.0012598733, + 0.0016864186, + 0.0246880621, + 0.0061095981, + 0.0004099955, + 0.0013164304, + 0.0026044940, + ], + [ + 0.0202339521, + 0.0061097664, + 0.0054915660, + 0.0031922449, + 0.0031282310, + 0.0055328831, + 0.0041878129, + 0.0055330789, + 0.0239880063, + 0.0191417076, + 0.0402207648, + 0.0048878217, + 0.0092147245, + 0.2439114577, + 0.0028255303, + 0.0111957028, + 0.0098843592, + 0.3241580263, + 0.2366041431, + 0.0205582202, + ], + [ + 0.6207365231, + 0.0019314726, + 0.0022174504, + 0.0013176486, + 0.0121994415, + 0.0018012322, + 0.0018453095, + 0.2413575833, + 0.0012585234, + 0.0037336741, + 0.0065242405, + 0.0015181965, + 0.0027431558, + 0.0020128180, + 0.0022058204, + 0.0650569883, + 0.0146789060, + 0.0004871899, + 0.0010950047, + 0.0152788213, + ], + [ + 0.0582724554, + 0.0008829756, + 0.0040964051, + 0.0012424760, + 0.0014603386, + 0.0009657897, + 0.0008842681, + 0.8886516961, + 0.0006199452, + 0.0012884937, + 0.0016750502, + 0.0007290214, + 0.0009460275, + 0.0008795758, + 0.0006198301, + 0.0278391551, + 0.0045772405, + 0.0003000167, + 0.0006042714, + 0.0034649679, + ], + [ + 0.0269748529, + 0.0107102344, + 0.0118557067, + 0.0805035933, + 0.0009985963, + 0.0634295629, + 0.7113339776, + 0.0129887242, + 0.0037886484, + 0.0030403687, + 0.0043773666, + 0.0233416650, + 0.0024890317, + 0.0013526476, + 0.0016764589, + 0.0149428566, + 0.0140438879, + 0.0004877021, + 0.0014970550, + 0.0101670632, + ], + [ + 0.0110791924, + 0.2440673634, + 0.0154482018, + 0.0018915744, + 0.0011257042, + 0.0217016716, + 0.0105761405, + 0.0036378350, + 0.0072624279, + 0.0030869301, + 0.0076720762, + 0.6363164483, + 0.0038276098, + 0.0010895549, + 0.0011696497, + 0.0128784818, + 0.0118948922, + 0.0004365818, + 0.0011742969, + 0.0036633671, + ], + [ + 0.2545086287, + 0.0032342584, + 0.0062530531, + 0.0026876724, + 0.0352077221, + 0.0036867504, + 0.0031187520, + 0.0213847435, + 0.0022021754, + 0.0227617362, + 0.0209838201, + 0.0031975802, + 0.0138623937, + 0.0037832236, + 0.0039716061, + 0.1368463629, + 0.3846575150, + 0.0008675824, + 0.0022649386, + 0.0745194852, + ], + [ + 0.3056445256, + 0.0013231209, + 0.0025872697, + 0.0010328731, + 0.0087093996, + 0.0014406875, + 0.0014442301, + 0.5558720263, + 0.0009734511, + 0.0029382131, + 0.0046905770, + 0.0010234611, + 0.0023472682, + 0.0017606222, + 0.0017892513, + 0.0816273808, + 0.0141533366, + 0.0004109046, + 0.0010792642, + 0.0091521370, + ], + [ + 0.0080047319, + 0.0016329195, + 0.0016173051, + 0.0009947064, + 0.0029178421, + 0.0016189886, + 0.0013472405, + 0.0015724663, + 0.0027664062, + 0.0192394598, + 0.0813370451, + 0.0015123725, + 0.0153837295, + 0.7402163859, + 0.0010952180, + 0.0073156746, + 0.0037138741, + 0.0079638834, + 0.0827109028, + 0.0170388476, + ], + [ + 0.4593911564, + 0.0026669351, + 0.0028523824, + 0.0018822443, + 0.0297064996, + 0.0027483930, + 0.0029480823, + 0.0203448938, + 0.0018171351, + 0.0412458900, + 0.0261264454, + 0.0027155722, + 0.0124585016, + 0.0034391821, + 0.0026084922, + 0.0396470304, + 0.0608974600, + 0.0006472392, + 0.0018392159, + 0.2840172489, + ], + [ + 0.0107216345, + 0.0088739073, + 0.0042944084, + 0.0025873909, + 0.0044878863, + 0.0042605776, + 0.0034439575, + 0.0061267910, + 0.0043881023, + 0.0061519345, + 0.0243188885, + 0.0040010068, + 0.0045366561, + 0.0430634081, + 0.0022893831, + 0.0144788293, + 0.0096728690, + 0.7955698818, + 0.0358942639, + 0.0108382231, + ], + [ + 0.0137932293, + 0.0058655418, + 0.3264486606, + 0.5058427950, + 0.0010465982, + 0.0104872319, + 0.0265312530, + 0.0179769294, + 0.0128560915, + 0.0025175514, + 0.0035368792, + 0.0141778650, + 0.0015805449, + 0.0014572906, + 0.0019429291, + 0.0322682996, + 0.0156422199, + 0.0005702515, + 0.0020936892, + 0.0033641489, + ], + [ + 0.0253239356, + 0.0029330677, + 0.0137231189, + 0.0035232726, + 0.0030435637, + 0.0025205111, + 0.0024280130, + 0.0090864145, + 0.0016674261, + 0.0037718200, + 0.0035664431, + 0.0028855884, + 0.0022748969, + 0.0015331028, + 0.0017705852, + 0.4010904723, + 0.5089782391, + 0.0004927194, + 0.0012760206, + 0.0081107890, + ], + [ + 0.0364329744, + 0.0080723728, + 0.0074282539, + 0.0041357150, + 0.0045083327, + 0.0257814533, + 0.0062026969, + 0.0069294613, + 0.0047847724, + 0.0827256395, + 0.1499278146, + 0.0111216884, + 0.4926481721, + 0.0337099568, + 0.0036117256, + 0.0241437239, + 0.0392729873, + 0.0021996661, + 0.0082382540, + 0.0481243389, + ], + [ + 0.0167679278, + 0.0082930849, + 0.0050613427, + 0.0051370636, + 0.8260488254, + 0.0064247490, + 0.0145749062, + 0.0112412658, + 0.0047731129, + 0.0096303226, + 0.0121436791, + 0.0113047968, + 0.0033511528, + 0.0048754565, + 0.0047309065, + 0.0240650574, + 0.0131885324, + 0.0018791728, + 0.0044753721, + 0.0120332726, + ], + [ + 0.5011544300, + 0.0010758530, + 0.0022308203, + 0.0009762201, + 0.0126546922, + 0.0014725460, + 0.0011855724, + 0.0286895114, + 0.0007599106, + 0.0019416172, + 0.0020619747, + 0.0009771507, + 0.0015812359, + 0.0010173837, + 0.0012629056, + 0.4004606225, + 0.0289722554, + 0.0002865541, + 0.0008717265, + 0.0103670179, + ], + [ + 0.0082401651, + 0.0011708108, + 0.0011791136, + 0.0007535322, + 0.0012424202, + 0.0013875564, + 0.0010108643, + 0.0010217986, + 0.0008394394, + 0.5331838459, + 0.2667424951, + 0.0013404626, + 0.0502078871, + 0.0134465029, + 0.0008784259, + 0.0022839322, + 0.0080615478, + 0.0004342254, + 0.0017238925, + 0.1048510819, + ], + [ + 0.0158110713, + 0.0022503470, + 0.0022367878, + 0.0011765119, + 0.0020109546, + 0.0069716036, + 0.0018829595, + 0.0020921309, + 0.0014822791, + 0.0610472988, + 0.3729592210, + 0.0022106991, + 0.4423438886, + 0.0264536543, + 0.0012525276, + 0.0073465480, + 0.0135739179, + 0.0007800995, + 0.0026769972, + 0.0334405022, + ], + [ + 0.0924352779, + 0.0027566182, + 0.0044662804, + 0.0018696416, + 0.0247022335, + 0.0034218220, + 0.0029268141, + 0.0045285851, + 0.0018776386, + 0.1002279241, + 0.0335659404, + 0.0030385428, + 0.0174134724, + 0.0035000514, + 0.0026502254, + 0.0426352535, + 0.2474907791, + 0.0006779015, + 0.0018371304, + 0.4079778674, + ], + [ + 0.0408156787, + 0.0019107197, + 0.0021528845, + 0.0015666080, + 0.0012159573, + 0.0025631646, + 0.0020649495, + 0.0051805139, + 0.0016474400, + 0.0025710528, + 0.0064578237, + 0.0019925272, + 0.0013560686, + 0.0011349162, + 0.8847896423, + 0.0201303641, + 0.0118296820, + 0.0003226926, + 0.0009469980, + 0.0093503163, + ], + [ + 0.1157586321, + 0.0023716443, + 0.0112488383, + 0.0023029338, + 0.0214280272, + 0.0025675945, + 0.0021199538, + 0.0289268010, + 0.0018946978, + 0.0025330204, + 0.0064891243, + 0.0020307030, + 0.0022061951, + 0.0021433385, + 0.0023598892, + 0.7357380458, + 0.0478363752, + 0.0005586098, + 0.0015499228, + 0.0079356531, + ], + [ + 0.0349906143, + 0.0356080196, + 0.0408097762, + 0.0254757204, + 0.0008842806, + 0.0511039973, + 0.1643207358, + 0.0219445704, + 0.0038765073, + 0.0068971381, + 0.0076642607, + 0.5029371070, + 0.0025167998, + 0.0026575153, + 0.0032796174, + 0.0243197828, + 0.0502295432, + 0.0009776491, + 0.0026886851, + 0.0168176796, + ], + [ + 0.0041364298, + 0.0016269670, + 0.0014528256, + 0.0010446558, + 0.9594298690, + 0.0011497890, + 0.0012814363, + 0.0024187614, + 0.0011095944, + 0.0021494695, + 0.0035929840, + 0.0014281970, + 0.0009839080, + 0.0014107050, + 0.0008977366, + 0.0067809464, + 0.0035670450, + 0.0004489576, + 0.0017018361, + 0.0033878865, + ], + [ + 0.0113674874, + 0.0005811409, + 0.0015300667, + 0.0016392583, + 0.0003004493, + 0.0004056006, + 0.0011648055, + 0.9740978959, + 0.0003272178, + 0.0003373238, + 0.0005062548, + 0.0004139458, + 0.0002847896, + 0.0002311786, + 0.0002465138, + 0.0048714108, + 0.0010201338, + 0.0000646212, + 0.0001868573, + 0.0004230482, + ], + [ + 0.0105115962, + 0.0039179025, + 0.8481729277, + 0.0219909682, + 0.0023250409, + 0.0078855196, + 0.0032942022, + 0.0096057230, + 0.0179422022, + 0.0027572428, + 0.0034394540, + 0.0105505296, + 0.0021348281, + 0.0017144742, + 0.0012277814, + 0.0300811551, + 0.0153898155, + 0.0005389121, + 0.0027886278, + 0.0037310968, + ], + [ + 0.0025467281, + 0.0011093608, + 0.0020292716, + 0.0008704391, + 0.0014814879, + 0.0012697132, + 0.0010799089, + 0.0010171417, + 0.0185818664, + 0.0023336860, + 0.0065445550, + 0.0009625246, + 0.0015133713, + 0.1219302869, + 0.0005246140, + 0.0023750971, + 0.0021929386, + 0.0109595547, + 0.8176793358, + 0.0029981182, + ], + [ + 0.0053463120, + 0.0009509803, + 0.0013962723, + 0.0006563455, + 0.0011000771, + 0.0010846615, + 0.0009204072, + 0.0009580447, + 0.0058156117, + 0.0049568468, + 0.0181859952, + 0.0010380012, + 0.0047316621, + 0.6669446035, + 0.0005373062, + 0.0041734593, + 0.0020339017, + 0.0068238890, + 0.2672901433, + 0.0050554795, + ], + [ + 0.0090906821, + 0.0083891088, + 0.0268772067, + 0.0028942681, + 0.0018495551, + 0.0276441596, + 0.0033195709, + 0.0027637786, + 0.8477445332, + 0.0035946234, + 0.0098165405, + 0.0031403564, + 0.0029324886, + 0.0084603197, + 0.0016721287, + 0.0106976471, + 0.0090486674, + 0.0009511879, + 0.0143804222, + 0.0047327550, + ], + [ + 0.0149451132, + 0.0018735398, + 0.0088071718, + 0.0019735801, + 0.0057629865, + 0.0017260572, + 0.0013698343, + 0.0037408219, + 0.0012288701, + 0.0046842343, + 0.0049796913, + 0.0076200061, + 0.0051778323, + 0.0011713586, + 0.0018949880, + 0.0808031232, + 0.8424393924, + 0.0003502773, + 0.0011664607, + 0.0082846609, + ], + [ + 0.0040518988, + 0.9362062008, + 0.0035497378, + 0.0009039109, + 0.0011937131, + 0.0053010850, + 0.0012781108, + 0.0019757996, + 0.0049499985, + 0.0012879297, + 0.0037915593, + 0.0193284213, + 0.0012819075, + 0.0008969649, + 0.0006577212, + 0.0053342455, + 0.0049861730, + 0.0003837759, + 0.0008622330, + 0.0017786134, + ], + [ + 0.0032144162, + 0.0006886313, + 0.0132532373, + 0.9452545555, + 0.0003822369, + 0.0025362867, + 0.0165697248, + 0.0022918808, + 0.0022640542, + 0.0005651621, + 0.0009349163, + 0.0008945372, + 0.0005155701, + 0.0003969504, + 0.0004426615, + 0.0053234500, + 0.0030288409, + 0.0001360466, + 0.0004642849, + 0.0008425563, + ], + [ + 0.0040153469, + 0.0014812403, + 0.0012978828, + 0.0009085945, + 0.0015236063, + 0.0015518352, + 0.0012113905, + 0.0018771734, + 0.0011386515, + 0.0014521824, + 0.0063163517, + 0.0010967489, + 0.0015912681, + 0.0146119399, + 0.0007342342, + 0.0044180974, + 0.0025329750, + 0.9362725549, + 0.0141257395, + 0.0018421867, + ], + [ + 0.0106642685, + 0.0093245549, + 0.0079063737, + 0.0034749195, + 0.0015221501, + 0.8257471230, + 0.0279456584, + 0.0061751225, + 0.0230313789, + 0.0031976776, + 0.0153997545, + 0.0186618224, + 0.0128243564, + 0.0017570364, + 0.0023360342, + 0.0124292387, + 0.0102632162, + 0.0007356825, + 0.0018198961, + 0.0047837355, + ], + [ + 0.0047970679, + 0.0032841520, + 0.0015733529, + 0.0105186354, + 0.0003555544, + 0.0148087895, + 0.9438427420, + 0.0009855191, + 0.0008123537, + 0.0007379429, + 0.0012059557, + 0.0074570243, + 0.0008019033, + 0.0004051340, + 0.0004904064, + 0.0037152586, + 0.0013594786, + 0.0001602349, + 0.0006169570, + 0.0020715372, + ], +]; + +pub const UDM256_WEIGHTS: &'static [f64] = &[ + 0.0762326617, + 0.0331562190, + 0.0324804617, + 0.0257352390, + 0.0185489214, + 0.0179772624, + 0.0175405785, + 0.0175052909, + 0.0167889529, + 0.0140859235, + 0.0131534490, + 0.0131269833, + 0.0131261011, + 0.0129390769, + 0.0129293728, + 0.0127988087, + 0.0126479542, + 0.0126241351, + 0.0095664655, + 0.0094967725, + 0.0094411946, + 0.0092753429, + 0.0092479950, + 0.0091438966, + 0.0090609708, + 0.0089974531, + 0.0085942924, + 0.0084390270, + 0.0080349841, + 0.0071713204, + 0.0069631236, + 0.0069128388, + 0.0066552394, + 0.0065132068, + 0.0061268077, + 0.0060474106, + 0.0058586220, + 0.0058462714, + 0.0058392139, + 0.0057448196, + 0.0056751266, + 0.0056283705, + 0.0056054336, + 0.0055666172, + 0.0055286831, + 0.0053213685, + 0.0052163879, + 0.0052040373, + 0.0051793359, + 0.0051696319, + 0.0051211114, + 0.0050161308, + 0.0050073089, + 0.0049437913, + 0.0046720768, + 0.0046226742, + 0.0044232993, + 0.0043721323, + 0.0043650748, + 0.0043244941, + 0.0042892065, + 0.0042706805, + 0.0042195135, + 0.0042186313, + 0.0041965766, + 0.0041745218, + 0.0041595246, + 0.0040951248, + 0.0039725004, + 0.0039380950, + 0.0038922211, + 0.0038833992, + 0.0037987090, + 0.0037863583, + 0.0037290160, + 0.0036999038, + 0.0036954928, + 0.0036919640, + 0.0036646162, + 0.0035561068, + 0.0035349343, + 0.0035049398, + 0.0033443813, + 0.0033346772, + 0.0031291270, + 0.0030973682, + 0.0030841353, + 0.0030744312, + 0.0030576696, + 0.0030303217, + 0.0029544534, + 0.0029421028, + 0.0029412206, + 0.0029182836, + 0.0028671166, + 0.0027771333, + 0.0027427279, + 0.0027400813, + 0.0027136156, + 0.0027021472, + 0.0027021472, + 0.0026571555, + 0.0026492158, + 0.0026456870, + 0.0026086350, + 0.0025945200, + 0.0025786406, + 0.0025724653, + 0.0025583502, + 0.0025477640, + 0.0025327667, + 0.0025265914, + 0.0025239448, + 0.0025160051, + 0.0025089476, + 0.0025010079, + 0.0024948326, + 0.0024648381, + 0.0024586628, + 0.0024577806, + 0.0024348437, + 0.0024074958, + 0.0023836767, + 0.0023219234, + 0.0023192768, + 0.0022381154, + 0.0021816552, + 0.0021446032, + 0.0021234307, + 0.0021234307, + 0.0021181376, + 0.0021128444, + 0.0020934362, + 0.0020828500, + 0.0020343295, + 0.0020290364, + 0.0019743406, + 0.0019602256, + 0.0019125873, + 0.0019002367, + 0.0018764176, + 0.0018305437, + 0.0018146643, + 0.0018102533, + 0.0018067246, + 0.0018058424, + 0.0017952561, + 0.0017661439, + 0.0017582041, + 0.0017529110, + 0.0017220344, + 0.0017211522, + 0.0017061549, + 0.0017017440, + 0.0016858646, + 0.0016426373, + 0.0016382263, + 0.0016338154, + 0.0016188182, + 0.0015923525, + 0.0015702977, + 0.0015667690, + 0.0015632402, + 0.0015579471, + 0.0015500074, + 0.0015447142, + 0.0015244239, + 0.0014953116, + 0.0014944294, + 0.0014909007, + 0.0014794322, + 0.0014741390, + 0.0014723747, + 0.0014706103, + 0.0014635528, + 0.0014538487, + 0.0014062104, + 0.0013770982, + 0.0013391640, + 0.0013382818, + 0.0013162271, + 0.0013003477, + 0.0012968189, + 0.0012941723, + 0.0012721176, + 0.0012527094, + 0.0012315369, + 0.0012315369, + 0.0012059534, + 0.0012015424, + 0.0012006602, + 0.0011988959, + 0.0011803699, + 0.0011627261, + 0.0011106769, + 0.0011106769, + 0.0010798002, + 0.0010736249, + 0.0010736249, + 0.0010498058, + 0.0010462770, + 0.0010233401, + 0.0009942278, + 0.0009854059, + 0.0009845237, + 0.0009836416, + 0.0009783484, + 0.0009642334, + 0.0009404143, + 0.0009386499, + 0.0008601350, + 0.0008451378, + 0.0008380802, + 0.0008151433, + 0.0008001461, + 0.0007930886, + 0.0007763270, + 0.0007675051, + 0.0007586832, + 0.0007454503, + 0.0007286887, + 0.0007269243, + 0.0007260422, + 0.0007066340, + 0.0007022230, + 0.0006828149, + 0.0006713464, + 0.0006686998, + 0.0006678176, + 0.0006660533, + 0.0006492916, + 0.0006484095, + 0.0006175328, + 0.0006060643, + 0.0005813630, + 0.0005451933, + 0.0005363714, + 0.0005187276, + 0.0005178454, + 0.0005143166, + 0.0005002016, + 0.0004975550, + 0.0004243333, + 0.0003758128, + 0.0003458184, + 0.0003369965, + 0.0003070020, + 0.0002778898, + 0.0002637747, + 0.0002514241, + 0.0002408378, + 0.0002099612, + 0.0001517366, + 0.0001455613, + 0.0001402682, + 0.0000961587, +]; diff --git a/mutsel_rust/src/felsenstein.rs b/mutsel_rust/src/felsenstein.rs new file mode 100644 index 000000000..261321bb2 --- /dev/null +++ b/mutsel_rust/src/felsenstein.rs @@ -0,0 +1,377 @@ +use std::sync::{Arc, Mutex}; + +use candle_core::CpuStorage; + +pub struct FelsensteinOp { + felsenstein : Arc>>, + result_storage: Mutex>>, +} +pub struct FelsensteinWithEdgeOp { + felsenstein : Arc>>, + result_storage: Mutex>>, +} + +#[derive(Clone, Debug)] +pub struct FelsensteinWithEdgeFwdOp { + felsenstein : Arc>>, +} + +#[derive(Clone, Debug)] +pub struct FelsensteinFwdOp { + felsenstein: Arc>>, +} + +impl Clone for FelsensteinOp { + fn clone(&self) -> Self { + Self { + felsenstein: Arc::clone(&self.felsenstein), + result_storage: Mutex::new(None), + } + } +} + +impl Clone for FelsensteinWithEdgeOp { + fn clone(&self) -> Self { + Self { + felsenstein: Arc::clone(&self.felsenstein), + result_storage: Mutex::new(None), + } + } +} + +fn tensor2nalgebra2d(s: &candle_core::CpuStorage, l: &candle_core::Layout) -> Vec> { + let dims = l.shape().dims(); + let stride = l.stride(); + assert!(dims.len() == 3); + let batch_size = dims[0]; + let mut result = Vec::with_capacity(batch_size); + match s { + CpuStorage::F64(data) => { + let mut offset = l.start_offset(); + for _ in 0..batch_size { + let mut mat = phylo_grad::nalgebra::SMatrix::::zeros(); + for i in 0..20 { + for j in 0..20 { + mat[(i, j)] = data[offset + i * stride[1] + j * stride[2]]; + } + } + result.push(mat); + offset += stride[0]; + } + } + _ => panic!("Expected f64 storage."), + } + result +} + +fn tensor2nalgebra1d(s: &candle_core::CpuStorage, l: &candle_core::Layout) -> Vec> { + let dims = l.shape().dims(); + let stride = l.stride(); + assert!(dims.len() == 2); + let batch_size = dims[0]; + let mut result = Vec::with_capacity(batch_size); + match s { + CpuStorage::F64(data) => { + let mut offset = l.start_offset(); + for _ in 0..batch_size { + let mut vec = phylo_grad::nalgebra::SVector::::zeros(); + for i in 0..20 { + vec[i] = data[offset + i * stride[1]]; + } + result.push(vec); + offset += stride[0]; + } + } + _ => panic!("Expected f64 storage."), + } + result +} + +fn tensor2vec(s: &candle_core::CpuStorage, l: &candle_core::Layout) -> Vec { + let dims = l.shape().dims(); + let stride = l.stride(); + assert!(dims.len() == 1); + let batch_size = dims[0]; + let mut result = Vec::with_capacity(batch_size); + match s { + CpuStorage::F64(data) => { + let mut offset = l.start_offset(); + for _ in 0..batch_size { + result.push(data[offset]); + offset += stride[0]; + } + } + _ => panic!("Expected f64 storage."), + } + result +} + +fn nalgebra2tensor1d(vec: &Vec>) -> candle_core::Tensor { + let batch_size = vec.len(); + let mut data = vec![0f64; batch_size * 20]; + for (b, v) in vec.iter().enumerate() { + for i in 0..20 { + data[b * 20 + i] = v[i]; + } + } + candle_core::Tensor::from_vec(data, &candle_core::Shape::from(&[batch_size, 20]), &candle_core::Device::Cpu).unwrap() +} + +fn nalgebra2tensor2d(mats: &Vec>) -> candle_core::Tensor { + let batch_size = mats.len(); + let mut data = vec![0f64; batch_size * 20 * 20]; + for (b, m) in mats.iter().enumerate() { + for i in 0..20 { + for j in 0..20 { + data[b * 20 * 20 + i * 20 + j] = m[(i, j)]; + } + } + } + candle_core::Tensor::from_vec(data, &candle_core::Shape::from(&[batch_size, 20, 20]), &candle_core::Device::Cpu).unwrap() +} + +impl FelsensteinFwdOp { + pub fn new(felsenstein: Arc>>) -> Self { + Self { + felsenstein, + } + } +} + +impl FelsensteinWithEdgeOp { + pub fn new(felsenstein: Arc>>) -> Self { + Self { + felsenstein, + result_storage: Mutex::new(None), + } + } + pub fn into_fwd_op(&self) -> FelsensteinWithEdgeFwdOp { + FelsensteinWithEdgeFwdOp { + felsenstein: Arc::clone(&self.felsenstein), + } + } +} + +impl candle_core::CustomOp2 for FelsensteinFwdOp { + + fn name(&self) -> &'static str { + "FelsensteinFwdOp" + } + + /// S, sqrt + fn cpu_fwd( + &self, + s1: &candle_core::CpuStorage, + l1: &candle_core::Layout, + s2: &candle_core::CpuStorage, + l2: &candle_core::Layout, + ) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + + let s = tensor2nalgebra2d(s1, l1); + let sqrt_pi = tensor2nalgebra1d(s2, l2); + + let mut felsenstein = self.felsenstein.lock().unwrap(); + let result = felsenstein.calculate_likelihoods(&s, &sqrt_pi); + + let shape = candle_core::Shape::from(&[result.len()]); + let cpu_storage = candle_core::CpuStorage::F64(result); + return Ok((cpu_storage, shape)) + } +} + +impl FelsensteinOp { + pub fn new(felsenstein: Arc>>) -> Self { + Self { + felsenstein, + result_storage: Mutex::new(None), + } + } + + pub fn into_fwd_op(&self) -> FelsensteinFwdOp { + FelsensteinFwdOp { + felsenstein: Arc::clone(&self.felsenstein), + } + } + + pub fn into_with_edge_op(&self) -> FelsensteinWithEdgeOp { + FelsensteinWithEdgeOp { + felsenstein: Arc::clone(&self.felsenstein), + result_storage: Mutex::new(None), + } + } + + pub fn into_with_edge_fwd_op(&self) -> FelsensteinWithEdgeFwdOp { + FelsensteinWithEdgeFwdOp { + felsenstein: Arc::clone(&self.felsenstein), + } + } +} + +impl candle_core::CustomOp2 for FelsensteinOp { + + fn name(&self) -> &'static str { + "FelsensteinOp" + } + + /// S, sqrt + fn cpu_fwd( + &self, + s1: &candle_core::CpuStorage, + l1: &candle_core::Layout, + s2: &candle_core::CpuStorage, + l2: &candle_core::Layout, + ) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + + let s = tensor2nalgebra2d(s1, l1); + let sqrt_pi = tensor2nalgebra1d(s2, l2); + + let mut felsenstein = self.felsenstein.lock().unwrap(); + let mut result = felsenstein.calculate_gradients(&s, &sqrt_pi); + + let likelihood = std::mem::take(&mut result.log_likelihood); + + let mut storage = self.result_storage.lock().unwrap(); + *storage = Some(result); + + let shape = candle_core::Shape::from(&[likelihood.len()]); + let cpu_storage = candle_core::CpuStorage::F64(likelihood); + return Ok((cpu_storage, shape)) + } + + fn bwd( + &self, + _arg1: &candle_core::Tensor, + _arg2: &candle_core::Tensor, + _res: &candle_core::Tensor, + _grad_res: &candle_core::Tensor, + ) -> candle_core::Result<(Option, Option)> { + let mut result = self.result_storage.lock().unwrap(); + + + let grad_s = std::mem::take(&mut result.as_mut().unwrap().grad_s); + let grad_s_tensor = nalgebra2tensor2d(&grad_s); + let grad_sqrt_pi = std::mem::take(&mut result.as_mut().unwrap().grad_sqrt_pi); + let grad_sqrt_pi_tensor = nalgebra2tensor1d(&grad_sqrt_pi); + + let grad_2 = _grad_res.unsqueeze(1).unwrap().unsqueeze(2).unwrap(); + let grad_1 = _grad_res.unsqueeze(1).unwrap(); + + Ok(( + Some(grad_2.broadcast_mul(&grad_s_tensor).unwrap()), + Some(grad_1.broadcast_mul(&grad_sqrt_pi_tensor).unwrap()), + )) + + } +} + + +impl candle_core::CustomOp3 for FelsensteinWithEdgeOp { + + fn name(&self) -> &'static str { + "FelsensteinWithEdgeOp" + } + + /// S, sqrt + fn cpu_fwd( + &self, + s1: &candle_core::CpuStorage, + l1: &candle_core::Layout, + s2: &candle_core::CpuStorage, + l2: &candle_core::Layout, + s3: &candle_core::CpuStorage, + l3: &candle_core::Layout, + ) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + + let s = tensor2nalgebra2d(s1, l1); + let sqrt_pi = tensor2nalgebra1d(s2, l2); + let branch_lengths = tensor2vec(s3, l3); + + let mut felsenstein = self.felsenstein.lock().unwrap(); + let mut result = felsenstein.calculate_gradients_with_branch_lengths(&s, &sqrt_pi, &branch_lengths); + + let likelihood = std::mem::take(&mut result.log_likelihood); + + let mut storage = self.result_storage.lock().unwrap(); + *storage = Some(result); + + let shape = candle_core::Shape::from(&[likelihood.len()]); + let cpu_storage = candle_core::CpuStorage::F64(likelihood); + return Ok((cpu_storage, shape)) + } + + fn bwd( + &self, + _arg1: &candle_core::Tensor, + _arg2: &candle_core::Tensor, + _arg3: &candle_core::Tensor, + _res: &candle_core::Tensor, + grad_res: &candle_core::Tensor, + ) -> candle_core::Result<(Option, Option, Option)> { + let mut result = self.result_storage.lock().unwrap(); + + + let grad_s = std::mem::take(&mut result.as_mut().unwrap().grad_s); + let grad_s_tensor = nalgebra2tensor2d(&grad_s); + let grad_sqrt_pi = std::mem::take(&mut result.as_mut().unwrap().grad_sqrt_pi); + let grad_sqrt_pi_tensor = nalgebra2tensor1d(&grad_sqrt_pi); + let grad_branch_lengths = std::mem::take(&mut result.as_mut().unwrap().grad_tree); + let L = grad_branch_lengths.len(); + let num_branch = grad_branch_lengths[0].len(); + let grad_branch_lengths_flat: Vec = grad_branch_lengths.into_iter().flatten().collect(); + + let grad_branch_lengths_tensor = candle_core::Tensor::from_vec(grad_branch_lengths_flat, &candle_core::Shape::from(&[L, num_branch]), &candle_core::Device::Cpu).unwrap(); + + + let grad_2 = grad_res.unsqueeze(1).unwrap().unsqueeze(2).unwrap(); + let grad_1 = grad_res.unsqueeze(1).unwrap(); + + + Ok(( + Some(grad_2.broadcast_mul(&grad_s_tensor).unwrap()), + Some(grad_1.broadcast_mul(&grad_sqrt_pi_tensor).unwrap()), + Some(grad_1.broadcast_mul(&grad_branch_lengths_tensor).unwrap().sum(0).unwrap()), + )) + + } +} + +impl candle_core::CustomOp3 for FelsensteinWithEdgeFwdOp { + + fn name(&self) -> &'static str { + "FelsensteinWithEdgeFwdOp" + } + + /// S, sqrt + fn cpu_fwd( + &self, + s1: &candle_core::CpuStorage, + l1: &candle_core::Layout, + s2: &candle_core::CpuStorage, + l2: &candle_core::Layout, + s3: &candle_core::CpuStorage, + l3: &candle_core::Layout, + ) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + + let s = tensor2nalgebra2d(s1, l1); + let sqrt_pi = tensor2nalgebra1d(s2, l2); + let branch_lengths = tensor2vec(s3, l3); + + let mut felsenstein = self.felsenstein.lock().unwrap(); + let likelihood = felsenstein.calculate_likelihoods_with_branch_lengths(&s, &sqrt_pi, &branch_lengths); + + let shape = candle_core::Shape::from(&[likelihood.len()]); + let cpu_storage = candle_core::CpuStorage::F64(likelihood); + return Ok((cpu_storage, shape)) + } + + fn bwd( + &self, + _arg1: &candle_core::Tensor, + _arg2: &candle_core::Tensor, + _arg3: &candle_core::Tensor, + _res: &candle_core::Tensor, + _grad_res: &candle_core::Tensor, + ) -> candle_core::Result<(Option, Option, Option)> { + panic!("FelsensteinWithEdgeFwdOp does not support backward pass"); + } +} \ No newline at end of file diff --git a/mutsel_rust/src/gamma.rs b/mutsel_rust/src/gamma.rs new file mode 100644 index 000000000..ea97bd9d5 --- /dev/null +++ b/mutsel_rust/src/gamma.rs @@ -0,0 +1,136 @@ +use std::ops::Deref; + +use candle_core::{CpuStorage, CustomOp1, Storage, Tensor}; + + +pub fn log_gamma_pdf(x: &Tensor, alpha: &Tensor) -> Tensor { + let lgamma_alpha = alpha.apply_op1(LgammaOp).unwrap(); + + let lgamma_alpha_b = lgamma_alpha.broadcast_as(x.shape()).unwrap(); + let alpha_b = alpha.broadcast_as(x.shape()).unwrap(); + + let log_pdf = ((&alpha_b * &alpha_b.log().unwrap() - lgamma_alpha_b).unwrap() + (&alpha_b - 1.0) * x.log().unwrap()).unwrap() - &alpha_b * x; + log_pdf.unwrap() +} + +/// Custom op that computes lgamma(x) elementwise. +/// Backward uses the digamma function (derivative of lgamma). +#[derive(Debug, Clone)] +pub struct LgammaOp; + +impl CustomOp1 for LgammaOp { + fn name(&self) -> &'static str { + "LgammaOp" + } + + fn cpu_fwd( + &self, + storage: &CpuStorage, + layout: &candle_core::Layout, + ) -> candle_core::Result<(CpuStorage, candle_core::Shape)> { + let data = match storage { + CpuStorage::F64(data) => data, + _ => panic!("LgammaOp: expected f64 storage"), + }; + + let output = candle_core::cpu_backend::unary_map(data, layout, spec_math::cephes64::lgam); + Ok((CpuStorage::F64(output), layout.shape().clone())) + } + + fn bwd( + &self, + arg: &Tensor, + _res: &candle_core::Tensor, + grad_res: &Tensor, + ) -> candle_core::Result> { + let (storage, layout) = arg.storage_and_layout(); + + let data = match storage.deref() { + Storage::Cpu(CpuStorage::F64(data)) => data, + _ => panic!("LgammaOp: expected cpu f64 storage in bwd"), + }; + + let grads = candle_core::cpu_backend::unary_map(data, &layout, spec_math::cephes64::psi); + let grad_tensor = Tensor::from_vec(grads, arg.shape(), &candle_core::Device::Cpu)?; + + Ok(Some(grad_tensor.mul(grad_res)?)) + } +} + +#[derive(Debug, Clone)] +pub struct GammaOp { + categories: usize, +} + +impl GammaOp { + pub fn new(categories: usize) -> Self { + Self { categories } + } +} + +impl candle_core::CustomOp1 for GammaOp { + fn name(&self) -> &'static str { + "GammaOp" + } + + fn cpu_fwd(&self, storage: &candle_core::CpuStorage, layout: &candle_core::Layout) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + let alpha = match storage { + candle_core::CpuStorage::F64(v) => v[layout.start_offset()], + _ => panic!("Expected f64 storage for GammaOp"), + }; + + let bounds = (0..=self.categories).map(|k| { + //gamma.inverse_cdf(k as f64 / self.categories as f64) + spec_math::cephes64::gdtri(alpha, alpha, k as f64 / self.categories as f64) + }).collect::>(); + + let categories = bounds.iter().zip(bounds.iter().skip(1)).map(|(a, b)| { + //let mean = gamma_alpha1.cdf(*b) - gamma_alpha1.cdf(*a); + // a and b seems to be swapped here. + let mean = spec_math::cephes64::gdtr(alpha, alpha + 1.0, *b) - spec_math::cephes64::gdtr(alpha, alpha + 1.0, *a); + mean * self.categories as f64 + }).collect::>(); + + let output = CpuStorage::F64(categories); + let shape = candle_core::Shape::from(&[self.categories]); + + Ok((output, shape)) + } + + fn bwd(&self, _arg: &candle_core::Tensor, _res: &candle_core::Tensor, _grad_res: &candle_core::Tensor) -> candle_core::Result> { + + let h = 1e-5; + + let h_plus = _arg + candle_core::Tensor::full(h, &[], _arg.device())?; + let h_minus = _arg - candle_core::Tensor::full(h, &[], _arg.device())?; + + let derivative = (h_plus?.apply_op1(self.clone())? - h_minus?.apply_op1(self.clone())?)? / (2.0 * h); + + let grad = (_grad_res * derivative?)?.sum_all()?; + Ok(Some(grad)) + } +} + + +#[cfg(test)] +mod test { + use candle_core::{Tensor, Var}; + + use super::*; + #[test] + fn test_gamma_op() { + let op = GammaOp::new(4); + let alpha = 0.08; + + let alpha = Tensor::from_vec(vec![alpha], &[], &candle_core::Device::Cpu).unwrap(); + let alpha = Var::from_tensor(&alpha).unwrap(); + + let categories = alpha.apply_op1(op).unwrap(); + + println!("{:?}", categories); + + + + println!("{:?}", categories.get(0).unwrap().backward().unwrap()); + } +} \ No newline at end of file diff --git a/mutsel_rust/src/io.rs b/mutsel_rust/src/io.rs new file mode 100644 index 000000000..5daa94582 --- /dev/null +++ b/mutsel_rust/src/io.rs @@ -0,0 +1,411 @@ +use candle_core::Tensor; +use lazy_static::lazy_static; +use seq_io::fasta::Record; +use std::{collections::HashMap, io::Read, path::Path, vec}; + +use anyhow::{Context, Result}; + +lazy_static! { + static ref AMINO_MAPPING: HashMap = { + let mut m = HashMap::new(); + m.insert(b'A', 0); + m.insert(b'R', 1); + m.insert(b'N', 2); + m.insert(b'D', 3); + m.insert(b'C', 4); + m.insert(b'Q', 5); + m.insert(b'E', 6); + m.insert(b'G', 7); + m.insert(b'H', 8); + m.insert(b'I', 9); + m.insert(b'L', 10); + m.insert(b'K', 11); + m.insert(b'M', 12); + m.insert(b'F', 13); + m.insert(b'P', 14); + m.insert(b'S', 15); + m.insert(b'T', 16); + m.insert(b'W', 17); + m.insert(b'Y', 18); + m.insert(b'V', 19); + m.insert(b'-', 20); + m.insert(b'X', 20); + m.insert(b'?', 20); + m.insert(b'.', 20); + m + }; +} + +fn normalize_residue(residue: u8) -> u8 { + residue.to_ascii_uppercase() +} + +fn seq2pll( + seq: impl Iterator, +) -> Vec> { + seq.map(|c| *AMINO_MAPPING.get(&normalize_residue(c)).unwrap_or(&20)) + .map(|idx| { + let mut v = phylo_grad::nalgebra::SVector::::zeros(); + + if idx < 20 { + v[idx as usize] = 1.0; + } else { + for i in 0..20 { + v[i] = 1.0; + } + } + v + }) + .collect() +} + +pub fn read_alignment(fasta_file: &Path) -> HashMap> { + let mut alignment = seq_io::fasta::Reader::new( + std::fs::File::open(fasta_file).expect("Could not open fasta file"), + ); + let mut sequences = HashMap::new(); + while let Some(result) = alignment.next() { + let record = result.expect("Error reading fasta record"); + let seq: Vec = record.seq().iter().copied().collect(); + sequences.insert(record.id().unwrap().to_string(), seq); + } + sequences +} + +pub fn get_site_specific_aa_distribution(sequences: &HashMap>) -> Tensor { + let num_sites = sequences.values().next().unwrap().len(); + + let mut data = vec![0f64; num_sites * 20]; + + for seq in sequences.values() { + for (site_idx, &residue) in seq.iter().enumerate() { + let aa_idx = *AMINO_MAPPING.get(&normalize_residue(residue)).unwrap_or(&20); + if aa_idx == 20 { + continue; + } + data[site_idx * 20 + aa_idx as usize] += 1.0; + } + } + + Tensor::from_vec(data, &[num_sites, 20], &candle_core::Device::Cpu).unwrap() +} + +pub fn get_site_specific_aa_distribution_iqtree(alignment: &[u8], L: usize, N: usize) -> Tensor { + let mut data = vec![0f64; L * 20]; + + for site_idx in 0..L { + for seq_idx in 0..N { + let residue = alignment[site_idx * N + seq_idx]; + if residue == 20 { + continue; + } + data[site_idx * 20 + residue as usize] += 1.0; + } + } + + Tensor::from_vec(data, &[L, 20], &candle_core::Device::Cpu).unwrap() +} + +pub fn create_felsenstein_tree( + parents: &[i32], + distances: &[f64], + alignment: &[u8], + L : usize, + N : usize, +) -> phylo_grad::FelsensteinTree<20> { + let mut felsenstein = phylo_grad::FelsensteinTree::<20>::new(parents, distances); + + let mut sites = vec![]; + sites.resize(L, vec![]); + for site_idx in 0..L { + sites[site_idx].resize(N, phylo_grad::nalgebra::SVector::::zeros()); + for seq_idx in 0..N { + let residue = alignment[site_idx * N + seq_idx]; + if residue < 20 { + sites[site_idx][seq_idx][residue as usize] = 1.0; + } else { + for i in 0..20 { + sites[site_idx][seq_idx][i] = 1.0; + } + } + } + } + felsenstein.bind_leaf_pl(sites); + felsenstein +} + +pub fn process_newick_alignment( + newick: &str, + sequences: &HashMap>, +) -> (phylo_grad::FelsensteinTree<20>, Vec) { + let tree = phylotree::tree::Tree::from_newick(newick).unwrap(); + + let num_sides = sequences.values().next().unwrap().len(); + let level_order = tree.levelorder(&tree.get_root().unwrap()).unwrap(); + + let mut parents = vec![i32::MAX; level_order.len()]; + let mut distances = vec![f64::NAN; level_order.len()]; + + let num_leaves = tree.n_leaves(); + + // idx_mapping[tree_idx] = new_idx + let mut idx_mapping = vec![i32::MAX; level_order.len()]; + + let mut leaf_idx = 0usize; + let mut internal_idx = level_order.len() - 1; + + for node_idx in &level_order { + let node = tree.get(node_idx).unwrap(); + if node.is_tip() { + idx_mapping[*node_idx] = leaf_idx as i32; + parents[leaf_idx] = idx_mapping[node.parent.unwrap()]; + distances[leaf_idx] = node.parent_edge.unwrap(); + leaf_idx += 1; + } else { + idx_mapping[*node_idx] = internal_idx as i32; + if let Some(parent_idx) = node.parent { + parents[internal_idx] = idx_mapping[parent_idx]; + distances[internal_idx] = node.parent_edge.unwrap(); + } else { + parents[internal_idx] = -1; + } + internal_idx -= 1; + } + } + + let mut leaf_pll = vec![]; + + for i in 0..num_sides { + let mut column_seq = vec![b'x'; num_leaves]; + + for node_idx in level_order.iter() { + let node = tree.get(&node_idx).unwrap(); + if node.is_tip() { + let new_idx = idx_mapping[*node_idx]; + assert!(new_idx < num_leaves as i32); + let seq = sequences.get(node.name.as_ref().unwrap()).unwrap(); + column_seq[new_idx as usize] = seq[i]; + } + } + leaf_pll.push(seq2pll(column_seq.into_iter())); + } + + let mut felsenstein = phylo_grad::FelsensteinTree::<20>::new(&parents, &distances); + felsenstein.bind_leaf_pl(leaf_pll); + (felsenstein, distances) +} + +pub fn write_sitefreq_file(pi: &Tensor, path: &Path) { + use std::io::Write; + let pi_data: Vec> = pi.to_vec2().unwrap(); + let mut file = std::fs::File::create(path).expect("Could not create sitefreq file"); + for (idx, chunk) in pi_data.iter().enumerate() { + let line = chunk + .iter() + .map(|v| v.to_string()) + .collect::>() + .join("\t"); + writeln!(file, "{}\t{}", idx + 1, line).expect("Could not write to sitefreq file"); + } +} + +pub fn write_pam_file(R: &Tensor, path: &Path) { + use std::io::Write; + let R_data: Vec> = R.to_vec2().unwrap(); + let mut file = std::fs::File::create(path).expect("Could not create pam file"); + for i in 1..20 { + for j in 0..i { + write!(file, "{}\t", R_data[i][j]).expect("Could not write to pam file"); + } + write!(file, "\n").expect("Could not write to pam file"); + } + let equi: Vec<&str> = vec!["0.05"; 20]; + writeln!(file, "{}", equi.join("\t")).expect("Could not write to pam file"); +} + +/// Ignores the first column (site index) +pub fn read_sitefreq_file(path: &Path) -> Tensor { + use std::io::BufRead; + let file = std::fs::File::open(path).expect("Could not open sitefreq file"); + let reader = std::io::BufReader::new(file); + let mut data = vec![]; + for line in reader.lines() { + let line = line.expect("Could not read line from sitefreq file"); + line.split_whitespace().skip(1).for_each(|v| { + data.push( + v.parse::() + .expect("Could not parse float from sitefreq file"), + ) + }); + } + let L = data.len() / 20; + return Tensor::from_vec(data, &[L, 20], &candle_core::Device::Cpu).unwrap(); +} + +pub fn read_pam_file(path: &Path) -> Tensor { + let file_content = std::fs::read_to_string(path).expect("Could not read pam file"); + return crate::data::load_lower_R(&file_content); +} + +pub fn write_nexus_file(S: &Tensor, sqrt_pi: &Tensor, alpha : &Tensor, path: &Path) { + use std::io::Write; + let mut file = std::fs::File::create(path).expect("Could not create nexus file"); + + file.write(b"#nexus\n") + .expect("Could not write to nexus file"); + file.write(b"begin sets;\n") + .expect("Could not write to nexus file"); + + let (R, pi) = crate::model::phylograd2iqtree_parametrization(S, sqrt_pi).unwrap(); + + let L = R.dims()[0]; + + for i in 0..L { + file.write(format!(" charset p{} = AA, {}-{};\n", i + 1, i + 1, i + 1).as_bytes()) + .expect("Could not write to nexus file"); + } + + file.write(b"charpartition mine = ").expect("Could not write to nexus file"); + + let mut charpart_elems = vec![]; + + let alpha : f64 = alpha.to_scalar().unwrap(); + + for i in 0..L { + let freq_str = pi + .get(i) + .unwrap() + .to_vec1::() + .unwrap() + .iter() + .map(|v| format!("{:.6}", v)) + .collect::>() + .join("/"); + + let R_data: Vec> = R.get(i).unwrap().to_vec2().unwrap(); + + let mut rate_elems = vec![]; + for a in 1..20 { + for b in 0..a { + rate_elems.push(format!("{:.6}", R_data[a][b])); + } + } + + let rate_str = rate_elems.join("/"); + + charpart_elems.push(format!( + "GTR{{{}}}+F{{{}}}+G4{{{}}} : p{}", + rate_str, + freq_str, + format!("{:.6}", alpha), + i + 1 + )); + } + + file.write(charpart_elems.join(", ").as_bytes()) + .expect("Could not write to nexus file"); + file.write(b";\nend;\n").expect("Could not write to nexus file"); +} + +pub struct BinarySiteModelData { + pub rate_model_string: String, + pub site_freq: Tensor, + pub rate_matrices: Tensor, +} + +fn read_u64_le(reader: &mut impl Read, field_name: &str) -> Result { + let mut buf = [0u8; 8]; + reader + .read_exact(&mut buf) + .with_context(|| format!("Failed to read {} from binary site model file", field_name))?; + Ok(u64::from_le_bytes(buf)) +} + +fn read_f64_vec_le(reader: &mut impl Read, len: usize, field_name: &str) -> Result> { + let byte_len = len + .checked_mul(8) + .context("Binary site model file field is too large")?; + let mut bytes = vec![0u8; byte_len]; + reader + .read_exact(&mut bytes) + .with_context(|| format!("Failed to read {} from binary site model file", field_name))?; + + let mut out = Vec::with_capacity(len); + for chunk in bytes.chunks_exact(8) { + out.push(f64::from_le_bytes(chunk.try_into().unwrap())); + } + Ok(out) +} + +/// Read IQ-TREE binary site model format. +/// +/// Format: +/// - uint64 little-endian: byte length of rate-model string +/// - [len] bytes: rate-model string +/// - uint64 little-endian: number of sites +/// - num_sites * 20 little-endian f64: per-site frequencies +/// - num_sites * 190 little-endian f64: per-site upper-triangular rates +pub fn read_binary_site_model_file(path: &Path) -> Result { + if cfg!(target_endian = "big") { + anyhow::bail!("Only little-endian machine is supported for reading binary site model file"); + } + + let file = std::fs::File::open(path) + .with_context(|| format!("Failed to open binary site model file: {}", path.display()))?; + let mut reader = std::io::BufReader::new(file); + + let rate_model_string_len = usize::try_from(read_u64_le(&mut reader, "rate model string length")?) + .context("Rate model string length does not fit in usize")?; + let mut rate_model_string_buf = vec![0u8; rate_model_string_len]; + if rate_model_string_len > 0 { + reader + .read_exact(&mut rate_model_string_buf) + .context("Failed to read rate model string from binary site model file")?; + } + let rate_model_string = String::from_utf8(rate_model_string_buf) + .context("Rate model string is not valid UTF-8")?; + + let num_sites = usize::try_from(read_u64_le(&mut reader, "number of sites")?) + .context("Number of sites does not fit in usize")?; + + let freq_len = num_sites + .checked_mul(20) + .context("Number of frequency values overflows usize")?; + let site_freq_data = read_f64_vec_le(&mut reader, freq_len, "site frequencies")?; + + let rate_len = num_sites + .checked_mul(190) + .context("Number of rate values overflows usize")?; + let rate_matrices_data = read_f64_vec_le(&mut reader, rate_len, "rate matrices")?; + + let site_freq = Tensor::from_vec(site_freq_data, &[num_sites, 20], &candle_core::Device::Cpu) + .context("Failed to create site frequency tensor")?; + + let mut rate_matrices = Vec::with_capacity(num_sites * 20 * 20); + + for i in 0..num_sites { + let mut full_matrix = vec![0f64; 20 * 20]; + let mut idx = 0; + for a in 0..20 { + for b in (a+1)..20 { + let rate = rate_matrices_data[i * 190 + idx]; + full_matrix[a * 20 + b] = rate; + full_matrix[b * 20 + a] = rate; + idx += 1; + } + } + rate_matrices.extend(full_matrix); + } + + let rate_matrices = Tensor::from_vec(rate_matrices, &[num_sites, 20, 20], &candle_core::Device::Cpu) + .context("Failed to create rate matrices tensor")?; + + // Convert the upper diagonal rate matrices to full R matrices + + + Ok(BinarySiteModelData { + rate_model_string, + site_freq, + rate_matrices, + }) +} \ No newline at end of file diff --git a/mutsel_rust/src/lib.rs b/mutsel_rust/src/lib.rs new file mode 100644 index 000000000..fcc500355 --- /dev/null +++ b/mutsel_rust/src/lib.rs @@ -0,0 +1,593 @@ +#![allow(non_snake_case)] + +pub mod data; +pub mod felsenstein; +pub mod gamma; +pub mod io; +pub mod model; +mod optimization; +mod utils; + +use std::{ + io::Write, + mem::MaybeUninit, + path::Path, +}; + +use candle_core::{IndexOp, Tensor}; +use candle_nn::ops::sigmoid; + +use crate::{gamma::log_gamma_pdf, utils::tensor_full}; + +#[unsafe(no_mangle)] +pub extern "C" fn rust_set_rayon_threads(num_threads: u32) { + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads as usize) + .build_global() + .unwrap_or_else(|_| println!("Rust Threadnumber has already been set. Ignoring.")); +} + +const STDOUT_FD: libc::c_int = 1; +const STDERR_FD: libc::c_int = 2; + +unsafe fn os_dup(fd: libc::c_int) -> libc::c_int { + unsafe { libc::dup(fd) } +} + +unsafe fn os_dup2(src: libc::c_int, dst: libc::c_int) -> libc::c_int { + unsafe { libc::dup2(src, dst) } +} + + +unsafe fn os_close(fd: libc::c_int) -> libc::c_int { + unsafe { libc::close(fd) } +} + +#[cfg(unix)] +unsafe fn os_read(fd: libc::c_int, buf: &mut [u8]) -> isize { + unsafe { libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) as isize } +} + +#[cfg(windows)] +unsafe fn os_read(fd: libc::c_int, buf: &mut [u8]) -> isize { + unsafe { libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len() as libc::c_uint) as isize } +} + +#[cfg(unix)] +unsafe fn os_write(fd: libc::c_int, buf: &[u8]) -> isize { + unsafe { libc::write(fd, buf.as_ptr() as *const libc::c_void, buf.len()) as isize } +} + +#[cfg(windows)] +unsafe fn os_write(fd: libc::c_int, buf: &[u8]) -> isize { + unsafe { libc::write(fd, buf.as_ptr() as *const libc::c_void, buf.len() as libc::c_uint) as isize } +} + +#[cfg(unix)] +fn create_pipe() -> std::io::Result<[libc::c_int; 2]> { + let mut fds = [0; 2]; + let ret = unsafe { libc::pipe(fds.as_mut_ptr()) }; + if ret != 0 { + Err(std::io::Error::last_os_error()) + } else { + Ok(fds) + } +} + +#[cfg(windows)] +fn create_pipe() -> std::io::Result<[libc::c_int; 2]> { + let mut fds = [0; 2]; + // libc::pipe on Windows maps to the CRT signature (fds, psize, textmode). + let ret = unsafe { libc::pipe(fds.as_mut_ptr(), 4096, 0) }; + if ret != 0 { + Err(std::io::Error::last_os_error()) + } else { + Ok(fds) + } +} + +fn write_all_fd(fd: libc::c_int, mut buf: &[u8]) -> std::io::Result<()> { + while !buf.is_empty() { + let n = unsafe { os_write(fd, buf) }; + if n < 0 { + let err = std::io::Error::last_os_error(); + if err.kind() == std::io::ErrorKind::Interrupted { + continue; + } + return Err(err); + } + let n = n as usize; + if n == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::WriteZero, + "write to redirected stdout returned 0", + )); + } + buf = &buf[n..]; + } + Ok(()) +} + +fn tee_to_file(path: &str) -> (i32, i32, std::thread::JoinHandle<()>) { + let fds = create_pipe().unwrap_or_else(|e| panic!("tee_to_file: pipe() failed: {}", e)); + + // Save original stdout + let saved_stdout = unsafe { os_dup(STDOUT_FD) }; + if saved_stdout < 0 { + panic!( + "tee_to_file: dup(STDOUT_FILENO) failed: {}", + std::io::Error::last_os_error() + ); + } + let saved_stderr = unsafe { os_dup(STDERR_FD) }; + if saved_stderr < 0 { + panic!( + "tee_to_file: dup(STDERR_FILENO) failed: {}", + std::io::Error::last_os_error() + ); + } + + // Dedicated copy for tee thread so saved_stdout can be restored/closed independently. + let tee_stdout = unsafe { os_dup(saved_stdout) }; + if tee_stdout < 0 { + panic!( + "tee_to_file: dup(saved_stdout) failed: {}", + std::io::Error::last_os_error() + ); + } + + // Redirect stdout to pipe write end + let ret = unsafe { os_dup2(fds[1], STDOUT_FD) }; + if ret < 0 { + panic!( + "tee_to_file: dup2(STDOUT_FILENO) failed: {}", + std::io::Error::last_os_error() + ); + } + let ret = unsafe { os_dup2(fds[1], STDERR_FD) }; + if ret < 0 { + panic!( + "tee_to_file: dup2(STDERR_FILENO) failed: {}", + std::io::Error::last_os_error() + ); + } + + // Close the original write end — stdout/stderr now hold the only references + let ret = unsafe { os_close(fds[1]) }; + if ret != 0 { + panic!( + "tee_to_file: close(pipe write end) failed: {}", + std::io::Error::last_os_error() + ); + } + + // Open log file + let mut file = std::fs::OpenOptions::new() + .append(true) + .open(path) + .unwrap_or_else(|e| panic!("tee_to_file: failed to open '{}': {}", path, e)); + + // Spawn thread to read from pipe and write to both + let handle = std::thread::spawn(move || { + let mut buffer = [0u8; 1024]; + + loop { + let n = unsafe { os_read(fds[0], &mut buffer) }; + if n == 0 { + break; // EOF + } + if n < 0 { + let err = std::io::Error::last_os_error(); + if err.kind() == std::io::ErrorKind::Interrupted { + continue; + } + panic!("tee_to_file: read from pipe failed: {}", err); + } + + let n = n as usize; + // Write to original stdout + write_all_fd(tee_stdout, &buffer[..n]) + .unwrap_or_else(|e| panic!("tee_to_file: write to stdout failed: {}", e)); + // Write to file + file.write_all(&buffer[..n]) + .unwrap_or_else(|e| panic!("tee_to_file: write to log file failed: {}", e)); + } + + let ret = unsafe { os_close(fds[0]) }; + if ret != 0 { + panic!( + "tee_to_file: close(pipe read end) failed: {}", + std::io::Error::last_os_error() + ); + } + let ret = unsafe { os_close(tee_stdout) }; + if ret != 0 { + panic!( + "tee_to_file: close(tee stdout) failed: {}", + std::io::Error::last_os_error() + ); + } + + file.flush() + .unwrap_or_else(|e| panic!("tee_to_file: flush log file failed: {}", e)); + }); + + (saved_stdout, saved_stderr, handle) +} + +fn restore_stdout_stderr( + saved_stdout: i32, + saved_stderr: i32, + handle: std::thread::JoinHandle<()>, +) { + unsafe { + // Restoring stdout/stderr drops the last write-end references to the pipe, + // causing EOF on the read end so the tee thread can exit cleanly. + os_dup2(saved_stdout, STDOUT_FD); + os_dup2(saved_stderr, STDERR_FD); + } + // Wait for the tee thread to drain and flush all remaining output. + handle + .join() + .unwrap_or_else(|_| panic!("restore_stdout_stderr: tee thread panicked")); + unsafe { + os_close(saved_stdout); + os_close(saved_stderr); + } +} + +pub struct MutselParams { + pi_reg: f64, + Mu_reg: f64, + branch_reg: f64, +} + +fn parse_mustel_str(model_str: &str) -> MutselParams { + let model_str = model_str.trim(); + let model_upper = model_str.to_ascii_uppercase(); + + let (pi_reg, Mu_reg, branch_reg) = if model_upper == "MUTSEL" { + (0.65, 1.05, 1.86) + } else if model_upper.starts_with("MUTSEL{") && model_str.ends_with('}') { + let params_str = &model_str[7..model_str.len() - 1]; + let values = params_str + .split('/') + .map(|value| value.trim().parse::().unwrap()) + .collect::>(); + assert!( + values.len() == 3, + "Invalid MUTSEL format: expected MUTSEL{{pi_reg/Mu_reg/branch_reg}}, got {}", + model_str + ); + (values[0], values[1], values[2]) + } else { + panic!( + "Invalid MUTSEL format: expected MUTSEL or MUTSEL{{pi_reg/Mu_reg/branch_reg}}, got {}", + model_str + ); + }; + + MutselParams { + pi_reg, + Mu_reg, + branch_reg, + } +} + +/// parents: [num_nodes] +/// branch_lengths: [num_nodes] +/// alignment: [num_sites * num_leaves] (row-major) +/// out_site_freq: [num_sites * 20] (row-major) +/// out_rate_matrix: [num_sites * 190] (row-major) +/// out_rate_para: [num_para] from the rate model 1 for gamma, 2 * num_cat for free rate +/// out variables do not need to be initialized +/// prior_R_file and prior_pi_file can be null pointers +#[unsafe(no_mangle)] +pub unsafe extern "C" fn rust_mutsel( + parents: *const i32, + branch_lengths: *const f64, + alignment: *const u8, + num_sites: u32, + num_leaves: u32, + num_nodes: u32, + model_str: *const std::os::raw::c_char, + prior_R_file: *const std::os::raw::c_char, + prior_pi_file: *const std::os::raw::c_char, + verbose: u8, + out_site_freq: *mut f64, + out_rate_matrix: *mut f64, + output_prefix: *const std::os::raw::c_char, +) { + let out_prefix = unsafe { std::ffi::CStr::from_ptr(output_prefix) } + .to_str() + .unwrap(); + let (saved_stdout, saved_stderr, tee_handle) = tee_to_file(&format!("{}.log", out_prefix)); + + let parents = unsafe { std::slice::from_raw_parts(parents, num_nodes as usize) }; + let branch_lengths = unsafe { std::slice::from_raw_parts(branch_lengths, num_nodes as usize) }; + let alignment = + unsafe { std::slice::from_raw_parts(alignment, (num_sites * num_leaves) as usize) }; + + let out_site_freq = unsafe { + std::slice::from_raw_parts_mut( + out_site_freq as *mut MaybeUninit, + (num_sites * 20) as usize, + ) + }; + + let out_rate_matrix = unsafe { + std::slice::from_raw_parts_mut( + out_rate_matrix as *mut MaybeUninit, + (num_sites * 190) as usize, + ) + }; + + let model_cstr = unsafe { std::ffi::CStr::from_ptr(model_str) }; + let model_str = model_cstr.to_str().unwrap(); + + println!("Starting mutsel optimization with {}", model_str); + + let mutsel_params = parse_mustel_str(model_str); + + let felsenstein = io::create_felsenstein_tree( + parents, + branch_lengths, + alignment, + num_sites as usize, + num_leaves as usize, + ); + + let prior_R_file = if prior_R_file.is_null() { + None + } else { + let cstr = unsafe { std::ffi::CStr::from_ptr(prior_R_file) }; + Some(Path::new(cstr.to_str().unwrap())) + }; + + let prior_pi_file = if prior_pi_file.is_null() { + None + } else { + let cstr = unsafe { std::ffi::CStr::from_ptr(prior_pi_file) }; + Some(Path::new(cstr.to_str().unwrap())) + }; + + let substitution_model = SubstitutionModel::MutSel; + + let aa_dist = io::get_site_specific_aa_distribution_iqtree( + alignment, + num_sites as usize, + num_leaves as usize, + ); + + let (S, sqrt_pi, _rate_para, _substitution_rates) = optimization::optimize_internal( + felsenstein, + branch_lengths, + aa_dist, + mutsel_params, + RateModel::R(1), + prior_R_file, + prior_pi_file, + substitution_model, + crate::Verbosity::from_u8(verbose), + out_prefix, + ) + .unwrap(); + + let (R, pi) = model::phylograd2iqtree_parametrization(&S, &sqrt_pi).unwrap(); + let site_freq = pi.to_vec2().unwrap(); + + for site_index in 0..num_sites as usize { + for aa_index in 0..20 { + let value = site_freq[site_index][aa_index]; + out_site_freq[site_index * 20 + aa_index].write(value); + } + } + + for site_index in 0..num_sites as usize { + let mut idx = 0; + // Upper diagonal + for i in 0..20 { + for j in (i + 1)..20 { + out_rate_matrix[site_index * 190 + idx] + .write(R.i((site_index, i, j)).unwrap().to_scalar().unwrap()); + idx += 1; + } + } + } + std::io::stdout().flush().unwrap(); + restore_stdout_stderr(saved_stdout, saved_stderr, tee_handle); +} + +#[derive(Debug, Clone, Copy)] +enum RateModel { + G(usize), + R(usize), + X(f64, SiteSpecificRateModel), // this is the strength of the prior +} + +#[derive(Debug, Clone, Copy)] +enum SiteSpecificRateModel { + Triangle, + Uniform, + Gamma(f64), // alpha parameter + LogNormal(f64), // Mean +} + +impl SiteSpecificRateModel { + fn from_str(s: &str) -> SiteSpecificRateModel { + let s = s.trim().to_ascii_lowercase(); + if s == "triangle" { + SiteSpecificRateModel::Triangle + } else if s == "uniform" { + SiteSpecificRateModel::Uniform + } else if let Some(alpha_str) = s.strip_prefix("gamma{").and_then(|s| s.strip_suffix('}')) { + let alpha: f64 = alpha_str.parse().unwrap(); + SiteSpecificRateModel::Gamma(alpha) + } else if let Some(mean_str) = s + .strip_prefix("lognormal{") + .and_then(|s| s.strip_suffix('}')) + { + let mean: f64 = mean_str.parse().unwrap(); + SiteSpecificRateModel::LogNormal(mean) + } else { + panic!("Unknown site-specific rate model: {}", s); + } + } + + fn penalty(&self, rate_para: &Tensor) -> Tensor { + match self { + SiteSpecificRateModel::Triangle => (1.0 - rate_para).unwrap().sum_all().unwrap(), + SiteSpecificRateModel::Uniform => { + return tensor_full(1.0, &[]); + } + SiteSpecificRateModel::Gamma(alpha) => { + return log_gamma_pdf(rate_para, &tensor_full(*alpha, &[])) + .neg() + .unwrap(); + } + SiteSpecificRateModel::LogNormal(mean) => { + return (rate_para.log().unwrap() - mean.ln()) + .unwrap() + .powf(2.0) + .unwrap(); + } + } + } + + fn rates_from_parameters(&self, rate_para: &Tensor) -> Tensor { + match self { + SiteSpecificRateModel::Triangle | SiteSpecificRateModel::Uniform => { + sigmoid(rate_para).unwrap() + } + SiteSpecificRateModel::Gamma(_) => { + rate_para.exp().unwrap() // this will be transformed to rates in the penalty function + } + SiteSpecificRateModel::LogNormal(_) => { + rate_para.exp().unwrap() // this will be transformed to rates in the penalty function + } + } + } + + fn init(&self, num_sites: usize) -> Tensor { + match self { + SiteSpecificRateModel::Triangle | SiteSpecificRateModel::Uniform => { + tensor_full(0.0, &[num_sites]) + } + SiteSpecificRateModel::Gamma(_) => tensor_full(0.0, &[num_sites]), + SiteSpecificRateModel::LogNormal(mean) => tensor_full(mean.ln(), &[num_sites]), + } + } +} + +fn parse_rate_model(rate_model: &str) -> RateModel { + let mut chars = rate_model.chars(); + let model_type = chars.next().unwrap(); + match model_type { + 'G' => { + let num_categories: usize = chars.collect::().parse().unwrap(); + RateModel::G(num_categories) + } + 'R' => { + let num_categories: usize = chars.collect::().parse().unwrap(); + RateModel::R(num_categories) + } + 'X' => { + // X{strength, site_specific_model} + let params_str = chars.collect::(); + let params_str = params_str.trim(); + assert!( + params_str.starts_with('{') && params_str.ends_with('}'), + "Invalid X model format: {}", + params_str + ); + let params_str = ¶ms_str[1..params_str.len() - 1]; // remove { and } + let mut params = params_str.splitn(2, '/'); + let strength: f64 = params.next().unwrap().trim().parse().unwrap(); + let site_specific_model_str = params.next().unwrap().trim(); + let site_specific_model = SiteSpecificRateModel::from_str(site_specific_model_str); + RateModel::X(strength, site_specific_model) + } + _ => panic!("Unknown rate model"), + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SubstitutionModel { + MutSel, + MutSelApprox, + RelaxPMSF, +} + +#[derive(Debug, Clone, Copy)] +enum Verbosity { + Quiet, + Min, + Med, + Max, + Debug, +} + +impl Verbosity { + fn from_u8(value: u8) -> Verbosity { + match value { + 0 => Verbosity::Quiet, + 1 => Verbosity::Min, + 2 => Verbosity::Med, + 3 => Verbosity::Max, + 4 => Verbosity::Debug, + _ => panic!("Invalid verbosity level"), + } + } + + fn should_print(&self, level: Verbosity) -> bool { + match (self, level) { + (Verbosity::Quiet, _) => false, + ( + Verbosity::Min, + Verbosity::Min | Verbosity::Med | Verbosity::Max | Verbosity::Debug, + ) => true, + (Verbosity::Med, Verbosity::Med | Verbosity::Max | Verbosity::Debug) => true, + (Verbosity::Max, Verbosity::Max | Verbosity::Debug) => true, + (Verbosity::Debug, _) => true, + _ => false, + } + } +} + +// optimize function called from the rust binary +pub fn optimize_rust_binary( + newick: &Path, + fasta: &Path, + pi_reg: f64, + R_reg: f64, + rate_mode: &str, + prior_R_file: Option<&Path>, + prior_pi_file: Option<&Path>, + substitution_model: SubstitutionModel, +) -> Result<(Tensor, Tensor, Tensor, Vec), candle_core::Error> { + let sequences = io::read_alignment(fasta); + + let (felsenstein, distances) = + io::process_newick_alignment(&std::fs::read_to_string(&newick).unwrap(), &sequences); + + let aa_dist = io::get_site_specific_aa_distribution(&sequences); + + let rate_model = parse_rate_model(rate_mode); + + optimization::optimize_internal( + felsenstein, + &distances, + aa_dist, + MutselParams { + pi_reg, + Mu_reg: R_reg, + branch_reg: 10.0, // default value + }, + rate_model, + prior_R_file, + prior_pi_file, + substitution_model, + Verbosity::Debug, + "./mutsel" + ) +} diff --git a/mutsel_rust/src/main.rs b/mutsel_rust/src/main.rs new file mode 100644 index 000000000..b5415c720 --- /dev/null +++ b/mutsel_rust/src/main.rs @@ -0,0 +1,229 @@ +#![allow(non_snake_case)] + +use candle_core::Tensor; +use mutsel_rust::gamma::GammaOp; + +fn run(args : &[String]) { + let newick = args[0].clone(); + let fasta = args[1].clone(); + let pi_reg = args[2].parse::().unwrap(); + let R_reg = args[3].parse::().unwrap(); + let rate_model = args[4].clone(); + let mutsel = args[5].clone(); + + + let substitution_model = match mutsel.as_str() { + "mutselapprox" => mutsel_rust::SubstitutionModel::MutSelApprox, + "relaxpmsf" => mutsel_rust::SubstitutionModel::RelaxPMSF, + "mutsel" => mutsel_rust::SubstitutionModel::MutSel, + _ => panic!("Unknown substitution model"), + }; + + let (S, sqrt_pi, rate_para, _substitution_rates) = mutsel_rust::optimize_rust_binary( + &std::path::Path::new(&newick), + &std::path::Path::new(&fasta), + pi_reg, + R_reg, + &rate_model, + None, + None, + substitution_model + ) + .unwrap(); + + if substitution_model == mutsel_rust::SubstitutionModel::RelaxPMSF { + let (R, pi) = mutsel_rust::model::phylograd2iqtree_parametrization(&S, &sqrt_pi).unwrap(); + mutsel_rust::io::write_sitefreq_file(&pi, &std::path::Path::new(args[6].as_str())); + // R should be the same for all sites + mutsel_rust::io::write_pam_file(&R.get(0).unwrap(), &std::path::Path::new(args[7].as_str())); + } else { + mutsel_rust::io::write_nexus_file(&S, &sqrt_pi, &rate_para, &std::path::Path::new(args[6].as_str())); + } +} + +fn phylo_grad_param(args : &[String]) { + let model_file = args[0].clone(); + let parsed = mutsel_rust::io::read_binary_site_model_file(std::path::Path::new(&model_file)) + .unwrap_or_else(|e| panic!("Error reading site model file '{}': {e}", model_file)); + + let rate_model = parse_rate_model(&parsed.rate_model_string).unwrap(); + + println!("Parsed rate model: {:?}\n", rate_model); + + let (weights, rates) = if let ParsedRateModel::Gamma { categories, alpha } = rate_model { + (Tensor::full(1.0 / categories as f64, &[categories], &candle_core::Device::Cpu).unwrap(), Tensor::full(alpha.unwrap(), &[categories], &candle_core::Device::Cpu).unwrap().apply_op1(GammaOp::new(categories)).unwrap()) + } else if let ParsedRateModel::FreeRate { categories, weights, rates } = rate_model { + (Tensor::from_vec(weights.unwrap(), &[categories], &candle_core::Device::Cpu).unwrap(), Tensor::from_vec(rates.unwrap(), &[categories], &candle_core::Device::Cpu).unwrap()) + } else if let ParsedRateModel::X = rate_model { + (Tensor::full(1.0, &[1], &candle_core::Device::Cpu).unwrap(), Tensor::full(1.0, &[1], &candle_core::Device::Cpu).unwrap()) + } else { + panic!("Unexpected rate model variant"); + }; + + println!("Weights: {:?}", weights); + println!("Rates: {:?}", rates); + + + let (S, sqrt_pi) = mutsel_rust::model::iqtree2phylograd_parametrization(&parsed.rate_matrices, &parsed.site_freq).unwrap(); + + Tensor::write_npz(&[("weights", weights), ("rates", rates), ("S", S), ("sqrt_pi", sqrt_pi)], args[1].as_str()).unwrap(); +} + +#[derive(Debug, Clone, PartialEq)] +enum ParsedRateModel { + Gamma { + categories: usize, + alpha: Option, + }, + FreeRate { + categories: usize, + weights: Option>, + rates: Option>, + }, + X +} + +fn parse_rate_model(rate_model: &str) -> Result { + let model = rate_model.trim(); + if model.is_empty() { + return Err("Rate model string is empty".to_string()); + } + + if model.starts_with("R1") { + return Ok(ParsedRateModel::X); + } + + let first_brace = model.find('{'); + let (head, body) = match first_brace { + Some(pos) => { + if !model.ends_with('}') { + return Err(format!("Missing closing '}}' in rate model '{model}'")); + } + (&model[..pos], Some(&model[pos + 1..model.len() - 1])) + } + None => (model, None), + }; + + let mut chars = head.chars(); + let model_type = chars + .next() + .ok_or_else(|| "Missing rate model type".to_string())? + .to_ascii_uppercase(); + let categories_str = chars.as_str().trim(); + let categories = categories_str + .parse::() + .map_err(|_| format!("Invalid category count '{categories_str}' in '{model}'"))?; + if categories == 0 { + return Err("Category count must be greater than 0".to_string()); + } + + let params = if let Some(inner) = body { + let values = inner + .split(',') + .map(|v| { + let token = v.trim(); + token + .parse::() + .map_err(|_| format!("Invalid numeric value '{token}' in '{model}'")) + }) + .collect::, _>>()?; + Some(values) + } else { + None + }; + + match model_type { + 'G' => { + if let Some(values) = params { + if values.len() != 1 { + return Err(format!( + "Gamma model expects exactly 1 parameter (alpha), got {}", + values.len() + )); + } + Ok(ParsedRateModel::Gamma { + categories, + alpha: Some(values[0]), + }) + } else { + Ok(ParsedRateModel::Gamma { + categories, + alpha: None, + }) + } + } + 'R' => { + if let Some(values) = params { + if values.len() != 2 * categories { + return Err(format!( + "FreeRate model expects {} parameters ({} weights + {} rates), got {}", + 2 * categories, + categories, + categories, + values.len() + )); + } + let weights = values[..categories].to_vec(); + let rates = values[categories..].to_vec(); + Ok(ParsedRateModel::FreeRate { + categories, + weights: Some(weights), + rates: Some(rates), + }) + } else { + Ok(ParsedRateModel::FreeRate { + categories, + weights: None, + rates: None, + }) + } + }, + 'X' => Ok(ParsedRateModel::X), + _ => Err(format!( + "Unknown rate model type '{}', expected 'G' or 'R'", + model_type + )), + } +} + +fn main() { + let args: Vec = std::env::args().collect(); + if args[1] == "run" { + run(&args[2..].to_vec()); + } else if args[1] == "phylograd-param" { + phylo_grad_param(&args[2..].to_vec()); + } + else { + panic!("Unknown command"); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_gamma_with_alpha() { + let parsed = parse_rate_model("G4{0.456}").unwrap(); + assert_eq!( + parsed, + ParsedRateModel::Gamma { + categories: 4, + alpha: Some(0.456), + } + ); + } + + #[test] + fn parses_freerate_with_weights_and_rates() { + let parsed = parse_rate_model("R2{0.5,1.0, 0.5, 3.5}").unwrap(); + assert_eq!( + parsed, + ParsedRateModel::FreeRate { + categories: 2, + weights: Some(vec![0.5, 1.0]), + rates: Some(vec![0.5, 3.5]), + } + ); + } +} diff --git a/mutsel_rust/src/model.rs b/mutsel_rust/src/model.rs new file mode 100644 index 000000000..fde3959ef --- /dev/null +++ b/mutsel_rust/src/model.rs @@ -0,0 +1,268 @@ +use std::ops::Deref; + +use candle_core::{CpuStorage, CustomOp1, Storage, Tensor}; + +use crate::SubstitutionModel; + +fn g_scalar(x: f64) -> f64 { + if x.abs() < 1e-6 { + return 1.0 + x / 2.0 + x * x / 12.0; + } else { + return x / (1.0 - (-x).exp()); + } +} + +fn dx_g_scalar(x: f64) -> f64 { + if x.abs() < 1e-6 { + return 0.5 + x / 6.0 - x * x * x / 180.0; + } else { + let exp_x = x.exp(); + return exp_x * (-1.0 + exp_x - x) / (exp_x - 1.0).powi(2); + } +} + +#[derive(Debug, Clone)] +pub struct GOp {} + +impl CustomOp1 for GOp { + fn name(&self) -> &'static str { + "g_op" + } + + fn cpu_fwd( + &self, + storage: &candle_core::CpuStorage, + layout: &candle_core::Layout, + ) -> candle_core::Result<(candle_core::CpuStorage, candle_core::Shape)> { + let data = match storage { + CpuStorage::F64(data) => data, + _ => panic!("Expected f64 storage."), + }; + + let output = candle_core::cpu_backend::unary_map(&data, layout, g_scalar); + + Ok((CpuStorage::F64(output), layout.shape().clone())) + } + + fn bwd( + &self, + _arg: &Tensor, + _res: &Tensor, + _grad_res: &Tensor, + ) -> candle_core::Result> { + let (storage, layout) = _arg.storage_and_layout(); + + let data = match storage.deref() { + Storage::Cpu(CpuStorage::F64(data)) => data, + _ => panic!("Expected f64 storage."), + }; + + let grads = candle_core::cpu_backend::unary_map(&data, &layout, dx_g_scalar); + + let grad_tensor = Tensor::from_vec(grads, _arg.shape(), &candle_core::Device::Cpu)?; + + Ok(Some(grad_tensor.mul(_grad_res)?)) + } +} + +pub fn calc_rate_matrix( + R: &Tensor, + log_pi: &Tensor, + global_scaling: &Tensor, + substitution_model: SubstitutionModel, +) -> (Tensor, Tensor) { + match substitution_model { + SubstitutionModel::MutSelApprox => { + calc_rate_matrix_mutselapprox(R, log_pi, global_scaling).unwrap() + } + SubstitutionModel::RelaxPMSF => calc_rate_matrix_relaxpmsf(R, log_pi, global_scaling), + SubstitutionModel::MutSel => calc_rate_matrix_mutsel(R, log_pi, global_scaling), + } +} + +/// RelaxPMSF rate matrix. We do normalize to 1 PAM per column here. +pub fn calc_rate_matrix_relaxpmsf(R: &Tensor, log_pi: &Tensor, rate: &Tensor) -> (Tensor, Tensor) { + let pi = candle_nn::ops::softmax(log_pi, 1).unwrap(); + let pi_sqrt = pi.sqrt().unwrap(); + + let R = R.unsqueeze(0).unwrap(); + + let Q = R.broadcast_mul(&pi.unsqueeze(1).unwrap()).unwrap(); + + let eye = Tensor::eye(20, candle_core::DType::F64, &candle_core::Device::Cpu).unwrap(); + + // Make sure diagonal of Q is correct, i.e. Q_ii = -sum_{j!=i} Q_ij + let Q = (Q.broadcast_sub( + &(&Q.sum_keepdim(2).unwrap().broadcast_as(Q.dims()).unwrap() * &eye.unsqueeze(0).unwrap()) + .unwrap(), + )) + .unwrap(); + + // normalize to 1 PAM per column, i.e. -sum_i pi_i Q_ii = 1 + let q_diag = Q + .broadcast_mul(&eye.unsqueeze(0).unwrap()) + .unwrap() + .sum(2) + .unwrap(); + let normalization = pi.mul(&q_diag).unwrap().sum(1).unwrap().neg().unwrap(); + + let Q = Q + .broadcast_div(&normalization.unsqueeze(1).unwrap().unsqueeze(2).unwrap()) + .unwrap(); + + // Diagonal of S and therefore Q does not get used + + let sqrt_pi_Q = pi_sqrt.unsqueeze(2).unwrap().broadcast_mul(&Q).unwrap(); + let S = (sqrt_pi_Q.broadcast_div(&pi_sqrt.unsqueeze(1).unwrap())).unwrap(); + + let S = S.broadcast_mul(&rate).unwrap(); + (S, pi_sqrt) +} + +pub fn calc_rate_matrix_mutselapprox( + R: &Tensor, + log_pi: &Tensor, + rate: &Tensor, +) -> Result<(Tensor, Tensor), candle_core::Error> { + let L = log_pi.dims()[0]; + let pi = candle_nn::ops::softmax(log_pi, 1)?; + let pi_sqrt = pi.sqrt()?; + + let S = R + .broadcast_mul(rate)? + .unsqueeze(0)? + .broadcast_as(&[L, 20, 20])?; + + Ok((S, pi_sqrt)) +} + +/// We assume a mutation process Mu is the rate matrix of the mutation process with its equlibirium in the diagonal. +/// It should be the output of the Mu function. +pub fn calc_rate_matrix_mutsel( + Mu: &Tensor, + log_pi: &Tensor, + rate: &Tensor, +) -> (Tensor, Tensor) { + let L = log_pi.dims()[0]; + + let equi_mutation = (Mu * Tensor::eye(20, candle_core::DType::F64, &candle_core::Device::Cpu).unwrap()).unwrap(); + let equi_mutation = equi_mutation.sum(1).unwrap(); + let log_equi_mutation = equi_mutation.log().unwrap(); + + // This is a correction because of the equilibirum of the mutation process. + let fitness = log_pi.broadcast_sub(&log_equi_mutation.unsqueeze(0).unwrap()).unwrap(); + + let log_pi_diff = fitness.unsqueeze(1).unwrap().broadcast_sub(&fitness.unsqueeze(2).unwrap()).unwrap(); + + let fixation = log_pi_diff.apply_op1(GOp {}).unwrap(); + + let R = Mu.unsqueeze(0).unwrap().broadcast_as(&[L, 20, 20]).unwrap(); + + let Q = R.mul(&fixation).unwrap(); + + let pi = candle_nn::ops::softmax(&log_pi, 1).unwrap(); + let pi_sqrt = pi.sqrt().unwrap(); + + let sqrt_pi_Q = pi_sqrt.unsqueeze(2).unwrap().broadcast_mul(&Q).unwrap(); + let S = sqrt_pi_Q.broadcast_div(&pi_sqrt.unsqueeze(1).unwrap()).unwrap(); + + let S = S.broadcast_mul(&rate).unwrap(); + (S, pi_sqrt) +} + +// From S, sqrt_pi to R, pi +pub fn phylograd2iqtree_parametrization( + S: &Tensor, + sqrt_pi: &Tensor, +) -> Result<(Tensor, Tensor), candle_core::Error> { + let S_sqrt_pi_inv = S.broadcast_div(&sqrt_pi.unsqueeze(1)?)?; + let R = S_sqrt_pi_inv.broadcast_div(&sqrt_pi.unsqueeze(2)?)?; + + let pi = sqrt_pi.mul(sqrt_pi)?; + + Ok((R, pi)) +} + +// From R, pi to S, sqrt_pi +pub fn iqtree2phylograd_parametrization( + R: &Tensor, + pi: &Tensor, +) -> Result<(Tensor, Tensor), candle_core::Error> { + let pi_sqrt = pi.sqrt()?; + + let sqrt_pi_R = R.broadcast_mul(&pi_sqrt.unsqueeze(2)?)?; + let S = sqrt_pi_R.broadcast_mul(&pi_sqrt.unsqueeze(1)?)?; + + Ok((S, pi_sqrt)) +} + +pub fn substitution_rates(S: &Tensor, sqrt_pi: &Tensor) -> Vec { + // Q_ij = S_ij * sqrt_pi_j / sqrt_pi_i + + let S = S.to_vec3::().unwrap(); + let sqrt_pi = sqrt_pi.to_vec2::().unwrap(); + + assert_eq!(S.len(), sqrt_pi.len(), "Batch dimensions do not match."); + + let mut rates = Vec::with_capacity(S.len()); + for site in 0..S.len() { + let mut total_rate = 0.0; + for i in 0..20 { + for j in 0..20 { + if i != j { + total_rate += S[site][i][j] * sqrt_pi[site][j] * sqrt_pi[site][i]; + } + } + } + rates.push(total_rate); + } + rates +} + +pub fn average_substitution_rate(S: &Tensor, sqrt_pi: &Tensor) -> f64 { + // Q_ij = S_ij * sqrt_pi_j / sqrt_pi_i + + let S = S.to_vec3::().unwrap(); + let sqrt_pi = sqrt_pi.to_vec2::().unwrap(); + + assert_eq!(S.len(), sqrt_pi.len(), "Batch dimensions do not match."); + + let mut total_rate = 0.0; + for site in 0..S.len() { + for i in 0..20 { + for j in 0..20 { + if i != j { + total_rate += S[site][i][j] * sqrt_pi[site][j] * sqrt_pi[site][i]; + } + } + } + } + + total_rate / S.len() as f64 +} + +// Tests +#[cfg(test)] +mod tests { + use crate::{optimization::Mu, utils::tensor_full}; + +use super::*; + #[test] + fn test_mutsel() { + let L = 2; + let log_pi = Tensor::rand(-1.0, 1.0, &[L, 20], &candle_core::Device::Cpu).unwrap(); + + let R = Tensor::rand(0.1, 2.0, &[20, 20], &candle_core::Device::Cpu).unwrap(); + + let R = Mu(&R); + + let (S, sqrt_pi) = calc_rate_matrix_mutsel(&R, &log_pi, &tensor_full(1.0, &[])); + + println!("S: {}", S); + println!("sqrt_pi: {}", (&sqrt_pi * &sqrt_pi).unwrap()); + + println!("S - S.T: {}", (&S - &S.transpose(1, 2).unwrap()).unwrap()); + + assert!((&S - &S.transpose(1, 2).unwrap()).unwrap().abs().unwrap().max_all().unwrap().to_scalar::().unwrap() < 1e-12); + } +} \ No newline at end of file diff --git a/mutsel_rust/src/optimization.rs b/mutsel_rust/src/optimization.rs new file mode 100644 index 000000000..d0793e3d1 --- /dev/null +++ b/mutsel_rust/src/optimization.rs @@ -0,0 +1,837 @@ +use std::{ + iter, + path::Path, + sync::{Arc, Mutex}, +}; + +use candle_core::{Tensor, Var}; +use candle_nn::{Optimizer, ops::softmax}; +use phylo_grad::FelsensteinTree; + +use crate::{ + RateModel, SiteSpecificRateModel, SubstitutionModel, Verbosity, + felsenstein::{self, FelsensteinOp, FelsensteinWithEdgeOp}, + gamma::GammaOp, + model, + utils::{histogram, tensor_full}, +}; + +trait Optimizable { + fn variables(&self) -> Vec; + fn likelihood(&self) -> Tensor; + fn penalty(&self) -> Tensor; + fn print_state(&self) {} +} + +pub enum RateParameters { + G(usize, Var), // alpha for gamma distribution + R(Var, Var), // log_rate_cat and log_rate_weights for free rate model + X(Var, f64, SiteSpecificRateModel), // site-specific rates paramter, strength of penalty, and the type of penalty +} + +impl RateParameters { + fn gamma(n: usize, alpha: f64) -> RateParameters { + // Alpha is unconstrained, but there is a very strong barrier approaching 0. So this is not a problem. + RateParameters::G(n, Var::from_tensor(&tensor_full(alpha, &[])).unwrap()) + } + + fn init(num_sites: usize, rate_model: RateModel, alpha: f64) -> RateParameters { + match rate_model { + RateModel::G(num_cat) => RateParameters::gamma(num_cat, alpha), + RateModel::R(num_cat) => { + let gamma_op = GammaOp::new(num_cat); + let alpha = Var::from_tensor(&tensor_full(alpha, &[])).unwrap(); + let log_rate_cat = + Var::from_tensor(&alpha.apply_op1(gamma_op).unwrap().log().unwrap()).unwrap(); + let log_rate_weights = Var::from_tensor(&tensor_full(0.0, &[num_cat])).unwrap(); + RateParameters::R(log_rate_cat, log_rate_weights) + } + RateModel::X(strength, site_specific_rate_model) => RateParameters::X( + Var::from_tensor(&site_specific_rate_model.init(num_sites)).unwrap(), + strength, + site_specific_rate_model, + ), + } + } + + fn parameters_for_iqtree(&self) -> Tensor { + match self { + RateParameters::G(_, alpha) => alpha.as_detached_tensor().unsqueeze(0).unwrap(), + RateParameters::R(log_rate_cat, log_rate_weights) => { + let (categories, log_weights) = normalize_rate_cat( + &log_rate_cat.as_detached_tensor(), + &log_rate_weights.as_detached_tensor(), + ); + Tensor::cat(&[log_weights.exp().unwrap(), categories], 0).unwrap() + } + RateParameters::X(_, _, _) => { + // Dummy value, want to make sure this allocates, so there is a valid pointer to return + tensor_full(0.0, &[1]) + } + } + } + + fn variables(&self) -> Vec { + match self { + RateParameters::G(_, alpha) => vec![alpha.clone()], + RateParameters::R(log_rate_cat, log_rate_weights) => { + vec![log_rate_cat.clone(), log_rate_weights.clone()] + } + RateParameters::X(site_rate_var, _, _) => vec![site_rate_var.clone()], + } + } + + fn rates(&self) -> (Tensor, Tensor) { + match self { + RateParameters::G(num_cat, alpha) => { + let gamma_op = GammaOp::new(*num_cat); + let categories = alpha.apply_op1(gamma_op.clone()).unwrap(); + let log_weights = tensor_full(f64::ln(1.0 / *num_cat as f64), &[*num_cat]); + (categories, log_weights) + } + RateParameters::R(log_rate_cat, log_rate_weights) => { + normalize_rate_cat(log_rate_cat, log_rate_weights) + } + RateParameters::X(_, _, _) => { + panic!( + "Rates for site-specific model should be calculated separately using the site-specific model and parameters." + ) + } + } + } + + fn site_specific_rates(&self) -> Tensor { + match self { + RateParameters::X(site_rate_var, _, site_model) => { + site_model.rates_from_parameters(site_rate_var) + } + _ => { + panic!("Site-specific rates should only be calculated for the site-specific model.") + } + } + } + + fn penalty(&self) -> Tensor { + match self { + RateParameters::X(_, strength, site_model) => { + (site_model.penalty(&self.site_specific_rates()) * *strength).unwrap() + } + _ => tensor_full(0.0, &[]), + } + } + + fn calc_rate_matrix( + &self, + R: &Tensor, + log_pi: &Tensor, + global_scaling: &Tensor, + substitution_model: SubstitutionModel, + ) -> (Tensor, Tensor) { + let (S, sqrt_pi) = model::calc_rate_matrix(R, log_pi, global_scaling, substitution_model); + let S = if let RateParameters::X(_, _, _) = self { + S.broadcast_mul( + &self + .site_specific_rates() + .unsqueeze(1) + .unwrap() + .unsqueeze(2) + .unwrap(), + ) + .unwrap() + } else { + S + }; + (S, sqrt_pi) + } + + fn likelihood( + &self, + felsenstein_op: FelsensteinWithEdgeOp, + R: &Tensor, + log_pi: &Tensor, + substitution_model: SubstitutionModel, + calc_gradients: bool, + log_branch_lengths: &Tensor, + ) -> Tensor { + self.likelihood_per_site( + felsenstein_op, + R, + log_pi, + substitution_model, + calc_gradients, + log_branch_lengths, + ) + .sum_all() + .unwrap() + } + + fn likelihood_per_site( + &self, + felsenstein_op: FelsensteinWithEdgeOp, + R: &Tensor, + log_pi: &Tensor, + substitution_model: SubstitutionModel, + calc_gradients: bool, + log_branch_lengths: &Tensor, + ) -> Tensor { + let (S, sqrt_pi) = + self.calc_rate_matrix(R, log_pi, &tensor_full(1.0, &[]), substitution_model); + let branch_lengths = log_branch_lengths.exp().unwrap(); + let likelihood = match self { + RateParameters::G(_, _) | RateParameters::R(_, _) => { + let mut all_likelihoods = vec![]; + let (rate_categories, log_weights) = self.rates(); + for r_cat_index in 0..rate_categories.dims()[0] { + let rate_tensor = rate_categories.get(r_cat_index).unwrap(); + let S = S + .broadcast_mul(&rate_tensor.reshape(&[1, 1, 1]).unwrap()) + .unwrap(); + let likelihoods = if calc_gradients { + S.apply_op3(&sqrt_pi, &branch_lengths, felsenstein_op.clone()) + .unwrap() + } else { + S.apply_op3(&sqrt_pi, &branch_lengths, felsenstein_op.into_fwd_op()) + .unwrap() + }; + let weighted_likelihoods = likelihoods + .broadcast_add(&log_weights.get(r_cat_index).unwrap()) + .unwrap(); + all_likelihoods.push(weighted_likelihoods); + } + let all_likelihoods = Tensor::stack(&all_likelihoods, 0).unwrap(); + let final_likelihoods = all_likelihoods.log_sum_exp(0).unwrap(); + final_likelihoods + } + RateParameters::X(_, _, _) => { + if calc_gradients { + S.apply_op3(&sqrt_pi, &branch_lengths, felsenstein_op.clone()) + .unwrap() + } else { + S.apply_op3(&sqrt_pi, &branch_lengths, felsenstein_op.into_fwd_op()) + .unwrap() + } + } + }; + + likelihood + } +} + +pub struct AlphaAndScalingParameters { + pub felsenstein_op: FelsensteinWithEdgeOp, + pub log_global_scaling: Var, + pub log_branch_length_scaling: Var, + pub init_log_branch_lengths: Tensor, + pub R: Tensor, + pub log_pi: Tensor, + pub rate_model: RateParameters, + pub branch_length_penalty: f64, +} + +impl Optimizable for AlphaAndScalingParameters { + fn variables(&self) -> Vec { + let mut vars = vec![ + self.log_global_scaling.clone(), + self.log_branch_length_scaling.clone(), + ]; + vars.extend(self.rate_model.variables()); + vars + } + + fn likelihood(&self) -> Tensor { + let log_branch_length_scaling = self + .log_branch_length_scaling + .broadcast_sub(&self.log_branch_length_scaling.mean(0).unwrap()) + .unwrap(); + + let log_branch_lengths = (&self.init_log_branch_lengths + log_branch_length_scaling) + .unwrap() + .broadcast_add(&self.log_global_scaling) + .unwrap(); + + self.rate_model.likelihood( + self.felsenstein_op.clone(), + &self.R, + &self.log_pi, + SubstitutionModel::MutSel, + true, + &log_branch_lengths, + ) + } + + fn penalty(&self) -> Tensor { + let branch_penalty = self + .log_branch_length_scaling + .powf(2.0) + .unwrap() + .sum_all() + .unwrap() + * self.branch_length_penalty; + (self.rate_model.penalty() + branch_penalty.unwrap()).unwrap() + } + + fn print_state(&self) { + println!( + "global_scaling: {}", + self.log_global_scaling + .exp() + .unwrap() + .to_scalar::() + .unwrap() + ); + match &self.rate_model { + RateParameters::G(num_cat, alpha) if *num_cat > 1 => { + println!("alpha: {}", alpha.to_scalar::().unwrap()) + } + _ => {} + } + } +} + +pub struct ModelParameters { + pub felsenstein_op: FelsensteinWithEdgeOp, + pub log_R: Var, + pub log_pi: Var, + pub log_global_scaling: Var, + pub log_branch_length_scaling: Var, + pub init_log_branch_lengths: Tensor, + pub rate_parameters: RateParameters, + pub pi_reg: f64, + pub R_reg: f64, + pub branch_length_penalty: f64, + pub init_log_R: Tensor, + pub init_log_pi: Tensor, + pub substitution_model: SubstitutionModel, +} + +impl ModelParameters { + pub fn calc_rate_matrix(&self) -> (Tensor, Tensor) { + self.rate_parameters.calc_rate_matrix( + &Mu(&self.log_R.as_detached_tensor()), + &self.log_pi.as_detached_tensor(), + &self.log_global_scaling.as_detached_tensor().exp().unwrap(), + self.substitution_model, + ) + } + + pub fn save_npz(&self, path: &Path) { + let Mu = Mu(&self.log_R.as_detached_tensor()); + let pi = softmax(&self.log_pi.as_detached_tensor(), 1).unwrap(); + + Tensor::write_npz( + &[ + ("Mu", &Mu), + ("pi", &pi), + ( + "global_scaling", + &self.log_global_scaling.as_detached_tensor(), + ), + ("init_log_pi", &self.init_log_pi), + ("init_log_R", &self.init_log_R), + ( + "log_branch_length_scaling", + &self.log_branch_length_scaling.as_detached_tensor(), + ), + ], + path, + ) + .unwrap(); + } +} + +impl Optimizable for ModelParameters { + fn variables(&self) -> Vec { + let mut vars = vec![ + self.log_R.clone(), + self.log_pi.clone(), + self.log_global_scaling.clone(), + self.log_branch_length_scaling.clone(), + ]; + vars.extend(self.rate_parameters.variables()); + vars + } + + fn likelihood(&self) -> Tensor { + let Mu = Mu(&self.log_R); + + let log_branch_length_scaling = self + .log_branch_length_scaling + .broadcast_sub(&self.log_branch_length_scaling.mean(0).unwrap()) + .unwrap(); + + let log_branch_lengths = (&self.init_log_branch_lengths + log_branch_length_scaling) + .unwrap() + .broadcast_add(&self.log_global_scaling) + .unwrap(); + + self.rate_parameters.likelihood( + self.felsenstein_op.clone(), + &Mu, + &self.log_pi, + self.substitution_model, + true, + &log_branch_lengths, + ) + } + + fn penalty(&self) -> Tensor { + let pi_penalty = self + .init_log_pi + .sub(&self.log_pi) + .unwrap() + .powf(2.0) + .unwrap() + .sum_all() + .unwrap(); + let pi_penalty = (pi_penalty * self.pi_reg).unwrap(); + + fn log_Mu(log_R: &Tensor) -> Tensor { + let Mu = Mu(log_R); + + // One out the diagonal, since we only want to penalize the off-diagonal elements + let Mu = (&Mu + - (&Mu - 1.0).unwrap() + * Tensor::eye(20, candle_core::DType::F64, &candle_core::Device::Cpu).unwrap()) + .unwrap(); + + return Mu.log().unwrap(); + } + + let Mu = log_Mu(&self.log_R) + .sub(&log_Mu(&self.init_log_R)) + .unwrap() + .powf(2.0) + .unwrap() + .sum_all() + .unwrap(); + let R_penalty = (Mu * self.R_reg).unwrap(); + + let branch_penalty = self + .log_branch_length_scaling + .powf(2.0) + .unwrap() + .sum_all() + .unwrap() + * self.branch_length_penalty; + + (pi_penalty + R_penalty + branch_penalty.unwrap() + self.rate_parameters.penalty()).unwrap() + } + + fn print_state(&self) { + println!( + "global_scaling: {}", + self.log_global_scaling + .exp() + .unwrap() + .to_scalar::() + .unwrap() + ); + match &self.rate_parameters { + RateParameters::G(num_cat, alpha) if *num_cat > 1 => { + println!("alpha: {}", alpha.to_scalar::().unwrap()) + } + RateParameters::G(_, _) => {} + RateParameters::R(log_rate_cat, log_rate_weights) => { + let (categories, log_weights) = normalize_rate_cat( + &log_rate_cat.as_detached_tensor(), + &log_rate_weights.as_detached_tensor(), + ); + let weights = log_weights.exp().unwrap(); + println!("Rate categories: {}", categories); + println!("Rate category weights: {}", weights); + } + RateParameters::X(site_rate_var, _, site_model) => { + let rates = site_model.rates_from_parameters(site_rate_var); + let histogram = histogram(&rates, 10); + println!("Site rate bounds: {}", histogram.0); + println!("Site rate counts: {}", histogram.1); + } + } + } +} + +fn optimize( + model: &impl Optimizable, + min_iterations: usize, + max_iterations: usize, + min_rel_improvement: f64, + no_improve_patience: usize, + verbosity: Verbosity, +) { + let variables = model.variables(); + let mut opt = candle_nn::optim::AdamW::new_lr(variables, 0.05).unwrap(); + let parameter = candle_nn::optim::ParamsAdamW { + lr: 0.05, + weight_decay: 0.0, + ..Default::default() + }; + opt.set_params(parameter); + + let mut prev_opt = f64::INFINITY; + let mut no_improve_count = 0; + + for iteration in 0.. { + let neg_likelihood = model.likelihood().neg().unwrap(); + let penalty = model.penalty(); + let opt_fn = (&neg_likelihood + &penalty).unwrap(); + + let current_opt = opt_fn.to_scalar::().unwrap(); + if verbosity.should_print(Verbosity::Med) { + println!( + "Iteration {}: neg Loglikelihood {:.3}, Optfn {:.3}", + iteration, + neg_likelihood.to_scalar::().unwrap(), + current_opt + ); + } + + model.print_state(); + let grads = opt_fn.backward().unwrap(); + opt.step(&grads).unwrap(); + + if iteration > min_iterations { + let rel_improvement = (prev_opt - current_opt) / prev_opt.abs().max(1e-12); + if rel_improvement > min_rel_improvement { + no_improve_count = 0; + } else { + no_improve_count += 1; + } + if no_improve_count >= no_improve_patience { + println!( + "Stopping at iteration {} (relative loss improvement {:.2e} <= {:.2e} for {} consecutive iterations)", + iteration, rel_improvement, min_rel_improvement, no_improve_patience + ); + break; + } + } + + if iteration > max_iterations { + println!("Reached maximum iterations ({})", max_iterations); + break; + } + + prev_opt = current_opt; + } +} + +pub fn optimize_global_scaling_alpha( + felsenstein_op: FelsensteinWithEdgeOp, + log_pi: &Tensor, + R: &Tensor, + log_branch_lengths: &Tensor, + branch_length_penalty: f64, + verbosity: Verbosity, +) -> (Tensor, Tensor, Tensor) { + let var_log_global_scaling = Var::from_tensor(&tensor_full(0.0, &[])).unwrap(); + let var_alpha = Var::from_tensor(&tensor_full(1.0, &[])).unwrap(); + let var_log_branch_length_scaling = + Var::from_tensor(&tensor_full(0.0, log_branch_lengths.dims())).unwrap(); + + let model = AlphaAndScalingParameters { + felsenstein_op, + log_global_scaling: var_log_global_scaling, + R: R.detach(), + log_pi: log_pi.detach(), + init_log_branch_lengths: log_branch_lengths.detach(), + log_branch_length_scaling: var_log_branch_length_scaling, + rate_model: RateParameters::G(1, var_alpha), + branch_length_penalty, + }; + + optimize(&model, 10, 100, 1e-5, 5, verbosity); + + let alpha = if let RateParameters::G(_, alpha) = model.rate_model { + alpha + } else { + panic!("Expected gamma rate model."); + }; + + return ( + model.log_global_scaling.as_detached_tensor(), + alpha.as_detached_tensor(), + model.log_branch_length_scaling.as_detached_tensor(), + ); +} + +pub fn two_step_light_pmsf( + felsenstein_op: FelsensteinOp, + categories: &[[f64; 20]], + weights: &[f64], + f_class: &[f64; 20], + log_branch_lengths: &Tensor, + mutsel_params: &super::MutselParams, + verbosity: Verbosity, +) -> (Tensor, f64, f64, Tensor) { + let step1_site_freq = light_pmsf( + felsenstein_op.into_with_edge_op(), + categories, + weights, + 1.0, + log_branch_lengths, + f_class, + ); + + let Mu = loadMu(); + + let log_pi = step1_site_freq.log().unwrap(); + + let (step2_log_global_scaling, step2_alpha, step2_log_branch_length_scaling) = + optimize_global_scaling_alpha( + felsenstein_op.into_with_edge_op(), + &log_pi, + &Mu, + log_branch_lengths, + mutsel_params.branch_reg, + verbosity, + ); + + let final_site_freq = light_pmsf( + felsenstein_op.into_with_edge_op(), + categories, + weights, + step2_alpha.to_scalar::().unwrap(), + &(log_branch_lengths + &step2_log_branch_length_scaling) + .unwrap() + .broadcast_add(&step2_log_global_scaling) + .unwrap(), + f_class, + ); + + ( + final_site_freq, + step2_log_global_scaling.to_scalar::().unwrap(), + step2_alpha.to_scalar::().unwrap(), + step2_log_branch_length_scaling, + ) +} + +pub fn light_pmsf( + felsenstein_op: FelsensteinWithEdgeOp, + categories: &[[f64; 20]], + weights: &[f64], + alpha: f64, + log_branch_lengths: &Tensor, + f_class: &[f64; 20], +) -> Tensor { + let mut likelihoods = vec![]; + + let Mu = loadMu(); + + let rate_model = RateParameters::gamma(1, alpha); + + for category in iter::once(f_class).chain(categories.iter()) { + let category_tensor = + Tensor::from_vec(category.to_vec(), &[20], &candle_core::Device::Cpu).unwrap(); + let log_pi = category_tensor.log().unwrap().unsqueeze(0).unwrap(); + + likelihoods.push(rate_model.likelihood_per_site( + felsenstein_op.clone(), + &Mu, + &log_pi, + SubstitutionModel::MutSel, + false, + log_branch_lengths, + )); + } + + let likelihoods = Tensor::stack(&likelihoods, 0).unwrap(); + let weights_tensor = + Tensor::from_slice(&weights, &[weights.len()], &candle_core::Device::Cpu).unwrap(); + let log_weights_tensor = weights_tensor.log().unwrap().unsqueeze(1).unwrap(); + + let weighted_likelihoods = (likelihoods.broadcast_add(&log_weights_tensor)).unwrap(); + + let posteriors = candle_nn::ops::softmax(&weighted_likelihoods, 0).unwrap(); + + let category_tensor = Tensor::from_vec( + iter::once(f_class) + .chain(categories.iter()) + .flatten() + .copied() + .collect(), + &[categories.len() + 1, 20], + &candle_core::Device::Cpu, + ) + .unwrap(); + + let site_freq = posteriors.t().unwrap().matmul(&category_tensor).unwrap(); + + site_freq +} + +/// Calculates the mutation rate matrix from the log_R variable. This is a lower triangular matrix with the exchanabilities and the equilibirum in the diagonal. Both as in log space. +/// Returns Mut and the equilibrium frequencies in the diagonal. (not log space) +pub fn Mu(log_parameter: &Tensor) -> Tensor { + let parameter = log_parameter.exp().unwrap(); + let diagonal = (¶meter + * Tensor::eye(20, candle_core::DType::F64, &candle_core::Device::Cpu).unwrap()) + .unwrap(); + let off_diagonal = (parameter - &diagonal).unwrap(); + + let pi = diagonal + .broadcast_div(&diagonal.sum_all().unwrap()) + .unwrap(); + + let R = (&off_diagonal + off_diagonal.t().unwrap()).unwrap(); + + let Q = R.matmul(&pi).unwrap(); + + let Q = (&Q + - &Q * Tensor::eye(20, candle_core::DType::F64, &candle_core::Device::Cpu).unwrap()) + .unwrap(); + + let row_sum = Q.sum(1).unwrap(); + let pi_vec = pi.sum(1).unwrap(); + let sum = row_sum.dot(&pi_vec).unwrap(); + let Q = Q.broadcast_div(&sum).unwrap(); + + // This has one expected mutation per unit time. The guide tree will be more in the regime of 1 substitution. + // So we mutlpiphy with 20. Exact factor is fitted later. We also divide with 8 which is emprically close to the optimum. + // (This does depend on the protein and how many columns are under strong selection) + + let Q = (Q * (20.0 / 12.0)).unwrap(); + + // diagonal is zero here, but they are not used anyway + (Q + pi).unwrap() +} + +// Used with the MutSel model. +fn loadMu() -> Tensor { + let R_lower = crate::data::load_lower_R_with_equi(crate::data::CODON2_TXT); + let log_R = R_lower.log().unwrap(); + Mu(&log_R) +} + +/// Returns the optimal S, sqrt_pi and rate parameters. +/// S: [L, 20, 20], sqrt_pi: [L, 20] +/// rate parameters is either alpha shape: [1] or [2 * num_cat] for free rate model (first num_cat weights, second num_cat are rates) +pub fn optimize_internal( + felsenstein: FelsensteinTree<20>, + distances: &[f64], + aa_dist: Tensor, + mutsel_params: super::MutselParams, + rate_model: RateModel, + prior_R_file: Option<&Path>, + prior_pi_file: Option<&Path>, + substitution_model: SubstitutionModel, + verbosity: Verbosity, + out_prefix: &str, +) -> Result<(Tensor, Tensor, Tensor, Vec), candle_core::Error> { + let op = felsenstein::FelsensteinOp::new(Arc::new(Mutex::new(felsenstein))); + + // 0.5 psuedo counts + let aa_dist = (aa_dist + 0.5).unwrap(); + + // Lower triangular matrix with zeros everywhere else + let init_R = if let Some(prior_R_file) = prior_R_file { + let file_content = std::fs::read_to_string(prior_R_file)?; + crate::data::load_lower_R_with_equi(&file_content) + } else { + crate::data::load_lower_R_with_equi(crate::data::CODON2_TXT) + }; + + let log_branch_lengths = + Tensor::from_slice(distances, &[distances.len()], &candle_core::Device::Cpu)?.log()?; + + let mut var_log_global_scaling = 0.0; + let mut var_alpha = 1.0; + let var_log_branch_length_scaling = + Var::from_tensor(&tensor_full(0.0, log_branch_lengths.dims())).unwrap(); + + let site_freq = if let Some(prior_pi_file) = prior_pi_file { + println!( + "Using prior site frequencies from file: {:?}", + prior_pi_file + ); + crate::io::read_sitefreq_file(prior_pi_file) + } else { + // Do our lightweight PMSF procedure for the site_freq prior: + let f_class_weight = 0.1; + + let weights = iter::once(f_class_weight) + .chain( + crate::data::UDM256_WEIGHTS + .iter() + .map(|w| w * (1.0 - f_class_weight)), + ) + .collect::>(); + + let f_class = aa_dist + .sum(0)? + .broadcast_div(&aa_dist.sum_all()?.unsqueeze(0)?)?; + let f_class: [f64; 20] = f_class.to_vec1()?.try_into().unwrap(); + + let (site_freq, global_scaling, alpha, log_branch_length_scaling) = two_step_light_pmsf( + op.clone(), + crate::data::UDM256, + &weights, + &f_class, + &log_branch_lengths, + &mutsel_params, + verbosity + ); + var_log_global_scaling = global_scaling; + var_alpha = alpha; + var_log_branch_length_scaling + .set(&log_branch_length_scaling) + .unwrap(); + + site_freq + }; + + // Variable which gets optimized + let log_R = Var::from_tensor(&init_R.log()?)?; + let init_log_pi = site_freq.log()?; + let log_pi = Var::from_tensor(&init_log_pi)?; + let num_sites = site_freq.dims()[0]; + + let init_log_R = log_R.detach().copy().unwrap(); + let init_log_pi = log_pi.detach().copy().unwrap(); + + let model = ModelParameters { + felsenstein_op: op.into_with_edge_op(), + log_R, + log_pi, + log_global_scaling: Var::from_tensor(&tensor_full(var_log_global_scaling, &[]))?, + log_branch_length_scaling: var_log_branch_length_scaling, + init_log_branch_lengths: log_branch_lengths.detach(), + rate_parameters: RateParameters::init(num_sites, rate_model, var_alpha), + pi_reg: mutsel_params.pi_reg, + R_reg: mutsel_params.Mu_reg, + branch_length_penalty: mutsel_params.branch_reg, + init_log_R, + init_log_pi, + substitution_model, + }; + + optimize(&model, 100, 500, 1e-5, 5, verbosity); + + let (S, sqrt_pi) = model.calc_rate_matrix(); + let rate_para = model.rate_parameters.parameters_for_iqtree(); + + let substitution_rates = model::substitution_rates(&S, &sqrt_pi); + + let average_rate = substitution_rates.iter().sum::() / substitution_rates.len() as f64; + if verbosity.should_print(Verbosity::Min) { + println!("Average substitution rate: {:.3}", average_rate); + model.save_npz(Path::new(&format!("{}.mutsel.npz", out_prefix))); + } + + let S = S.broadcast_div(&tensor_full(average_rate, &[])).unwrap(); + + Ok((S, sqrt_pi, rate_para, substitution_rates)) +} + +// Outputs categories and log_weights +fn normalize_rate_cat(log_rate_cat: &Tensor, log_rate_weights: &Tensor) -> (Tensor, Tensor) { + let log_weights = candle_nn::ops::log_softmax(&log_rate_weights, 0).unwrap(); + let log_sum = (log_weights.add(&log_rate_cat)) + .unwrap() + .log_sum_exp(0) + .unwrap(); + let categories = (log_rate_cat.broadcast_sub(&log_sum)) + .unwrap() + .exp() + .unwrap(); + (categories, log_weights) +} diff --git a/mutsel_rust/src/utils.rs b/mutsel_rust/src/utils.rs new file mode 100644 index 000000000..1339b4515 --- /dev/null +++ b/mutsel_rust/src/utils.rs @@ -0,0 +1,138 @@ +use candle_core::Tensor; + +pub fn tensor_full(value: f64, dims: &[usize]) -> Tensor { + Tensor::full(value, dims, &candle_core::Device::Cpu).unwrap() +} + +fn histogram_with_edges(values: &[f64], bin_edges: Vec) -> (Tensor, Tensor) { + let num_bins = bin_edges.len() - 1; + let device = &candle_core::Device::Cpu; + let mut counts = vec![0i64; num_bins]; + + for &value in values { + // Binary search for the bin: right-inclusive on the last bin + let idx = bin_edges.partition_point(|&e| e <= value).saturating_sub(1); + let idx = idx.min(num_bins - 1); + counts[idx] += 1; + } + + let bin_edges = Tensor::from_vec(bin_edges, &[num_bins + 1], device).unwrap(); + let counts = Tensor::from_vec(counts, &[num_bins], device).unwrap(); + (bin_edges, counts) +} + +/// Linear-spaced histogram. +pub fn histogram(data: &Tensor, num_bins: usize) -> (Tensor, Tensor) { + assert!(num_bins > 0, "histogram requires at least one bin"); + + let values = data.flatten_all().unwrap().to_vec1::().unwrap(); + assert!(!values.is_empty(), "histogram requires at least one value"); + + let min = values.iter().copied().fold(f64::INFINITY, f64::min); + let max = values.iter().copied().fold(f64::NEG_INFINITY, f64::max); + + if min == max { + let device = &candle_core::Device::Cpu; + let mut counts = vec![0i64; num_bins]; + counts[0] = values.len() as i64; + let edges = Tensor::from_vec(vec![min; num_bins + 1], &[num_bins + 1], device).unwrap(); + let counts = Tensor::from_vec(counts, &[num_bins], device).unwrap(); + return (edges, counts); + } + + let width = (max - min) / num_bins as f64; + let bin_edges = (0..=num_bins) + .map(|i| min + i as f64 * width) + .collect::>(); + + histogram_with_edges(&values, bin_edges) +} + +/// Log-spaced histogram. All values must be positive. +pub fn _histogram_log(data: &Tensor, num_bins: usize) -> (Tensor, Tensor) { + assert!(num_bins > 0, "histogram_log requires at least one bin"); + + let values = data.flatten_all().unwrap().to_vec1::().unwrap(); + assert!( + !values.is_empty(), + "histogram_log requires at least one value" + ); + assert!( + values.iter().all(|&v| v > 0.0), + "histogram_log requires all values to be positive" + ); + + let log_min = values + .iter() + .copied() + .map(f64::ln) + .fold(f64::INFINITY, f64::min); + let log_max = values + .iter() + .copied() + .map(f64::ln) + .fold(f64::NEG_INFINITY, f64::max); + + if log_min == log_max { + let device = &candle_core::Device::Cpu; + let mut counts = vec![0i64; num_bins]; + counts[0] = values.len() as i64; + let v = log_min.exp(); + let edges = Tensor::from_vec(vec![v; num_bins + 1], &[num_bins + 1], device).unwrap(); + let counts = Tensor::from_vec(counts, &[num_bins], device).unwrap(); + return (edges, counts); + } + + let log_width = (log_max - log_min) / num_bins as f64; + let bin_edges = (0..=num_bins) + .map(|i| (log_min + i as f64 * log_width).exp()) + .collect::>(); + + histogram_with_edges(&values, bin_edges) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn histogram_counts_values_in_expected_bins() { + let data = + Tensor::from_vec(vec![0.0, 0.2, 0.8, 1.0], &[4], &candle_core::Device::Cpu).unwrap(); + + let (edges, counts) = histogram(&data, 2); + + assert_eq!(edges.to_vec1::().unwrap(), vec![0.0, 0.5, 1.0]); + assert_eq!(counts.to_vec1::().unwrap(), vec![2, 2]); + } + + #[test] + fn histogram_handles_constant_input() { + let data = Tensor::from_vec(vec![3.0, 3.0, 3.0], &[3], &candle_core::Device::Cpu).unwrap(); + + let (edges, counts) = histogram(&data, 3); + + assert_eq!(edges.to_vec1::().unwrap(), vec![3.0, 3.0, 3.0, 3.0]); + assert_eq!(counts.to_vec1::().unwrap(), vec![3, 0, 0]); + } + + #[test] + fn histogram_log_spans_decades() { + // Values spanning 3 decades: 0.1, 1, 10, 100 + let data = + Tensor::from_vec(vec![0.1, 1.0, 10.0, 100.0], &[4], &candle_core::Device::Cpu).unwrap(); + + let (edges, counts) = _histogram_log(&data, 3); + + let edges_v = edges.to_vec1::().unwrap(); + let counts_v = counts.to_vec1::().unwrap(); + + // 4 edges spanning [0.1, 100] in 3 log-equal steps + assert_eq!(edges_v.len(), 4); + assert!((edges_v[0] - 0.1).abs() < 1e-10); + assert!((edges_v[3] - 100.0).abs() < 1e-10); + + // All 4 values should be counted + assert_eq!(counts_v.iter().sum::(), 4); + } +} diff --git a/pll/pllInternal.h b/pll/pllInternal.h index a32d5c832..811f70734 100644 --- a/pll/pllInternal.h +++ b/pll/pllInternal.h @@ -147,7 +147,6 @@ extern void initRateMatrix(pllInstance *tr, partitionList *pr); extern void bitVectorInitravSpecial(unsigned int **bitVectors, nodeptr p, int numsp, unsigned int vectorLength, pllHashTable *h, int treeNumber, int function, branchInfo *bInf, int *countBranches, int treeVectorLength, pllBoolean traverseOnly, pllBoolean computeWRF, int processID); extern unsigned int bitcount_32_bit(unsigned int i); -extern __inline unsigned int bitcount_64_bit(uint64_t i); extern void perSiteLogLikelihoods(pllInstance *tr, partitionList *pr, double *logLikelihoods); extern void updatePerSiteRates(pllInstance *tr, partitionList *pr, pllBoolean scaleRates); extern void restart(pllInstance *tr, partitionList *pr); diff --git a/test_scripts/test_data/expect_ans.txt b/test_scripts/test_data/expect_ans.txt index 0a3c8d70a..9a88ea0bb 100644 --- a/test_scripts/test_data/expect_ans.txt +++ b/test_scripts/test_data/expect_ans.txt @@ -19,4 +19,5 @@ turtle_aa.nex.constr2.iqtree Log-likelihood of the tree -5029.4460 1 turtle_aa.nex.iqtree Log-likelihood of the tree -5027.9688 1 turtle_aa.test.iqtree Log-likelihood of the tree -5039.6498 1 turtle_aa.wpl.iqtree Log-likelihood of the tree -5030.7986 1 -turtle_aa.mix.iqtree Log-likelihood of the tree -5212.5728 1 \ No newline at end of file +turtle_aa.mix.iqtree Log-likelihood of the tree -5212.5728 1 +turtle_aa.mutsel.iqtree Log-likelihood of the tree -3547.550 1 \ No newline at end of file diff --git a/test_scripts/test_data/turtle_aa.newick b/test_scripts/test_data/turtle_aa.newick new file mode 100644 index 000000000..9bbc881bc --- /dev/null +++ b/test_scripts/test_data/turtle_aa.newick @@ -0,0 +1 @@ +(Anolis:0.0543205734,(((((Gallus:0.0014359175,Taeniopygia:0.0133014847):0.0142834569,(((caretta:0.0161674188,chelonoidis_nigra:0.0052946560):0.0022096696,emys_orbicularis:0.0034233568):0.0083672035,phrynops:0.0209840768):0.0154702718):0.0043509501,(alligator:0.0000010000,caiman:0.0000010000):0.0161212459):0.0071034575,(((Homo:0.0322675822,Monodelphis:0.0143707730):0.0161409179,Ornithorhynchus:0.0739073357):0.0290482411,(Xenopus:0.1314721565,protopterus:0.1210330699):0.0354509879):0.0125965752):0.0171189889,python:0.0329330642):0.0052979455,podarcis:0.0112010029); diff --git a/test_scripts/test_iqtree.ps1 b/test_scripts/test_iqtree.ps1 index 78f58e0fb..6e7f2fa70 100755 --- a/test_scripts/test_iqtree.ps1 +++ b/test_scripts/test_iqtree.ps1 @@ -122,3 +122,5 @@ Measure-IQTree "$IQTreeBin -s $WD/turtle_aa.fasta -m `"MIX{LG+F,WAG+F}`" --prefi Measure-IQTree "$IQTreeBin -s $WD/turtle_aa.fasta -p $WD/turtle_aa.nex -g $WD/turtle.constr.tree --prefix $OutDir/turtle_aa.nex.constr -T 1 -seed $SEED" Measure-IQTree "$IQTreeBin -s $WD/turtle_aa.fasta -p $WD/turtle_aa.nex -g $WD/turtle.constr.tree2 -B 1000 -alrt 1000 --prefix $OutDir/turtle_aa.nex.constr2 -T 1 -seed $SEED" + +Measure-IQTree "$IQTreeBin -s $WD/turtle_aa.fasta -m MUTSEL -ft AUTO --prefix $OutDir/turtle_aa.mutsel -T 1 -seed $SEED" diff --git a/test_scripts/test_iqtree.sh b/test_scripts/test_iqtree.sh index d87057d71..1d9a11d09 100755 --- a/test_scripts/test_iqtree.sh +++ b/test_scripts/test_iqtree.sh @@ -118,3 +118,5 @@ run_timed ${IQTREE_BIN} -s $AA_FASTA -m "MIX{LG+F,WAG+F}" --prefix ${OUT_DIR}/tu run_timed ${IQTREE_BIN} -s $AA_FASTA -p $AA_NEX -g ${WD}/turtle.constr.tree --prefix ${OUT_DIR}/turtle_aa.nex.constr -T 1 -seed $SEED run_timed ${IQTREE_BIN} -s $AA_FASTA -p $AA_NEX -g ${WD}/turtle.constr.tree2 -B 1000 -alrt 1000 --prefix ${OUT_DIR}/turtle_aa.nex.constr2 -T 1 -seed $SEED + +run_timed ${IQTREE_BIN} -s $AA_FASTA -m "MUTSEL" -ft AUTO --prefix ${OUT_DIR}/turtle_aa.mutsel -T 1 -seed $SEED \ No newline at end of file diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 46d922b9c..75888b3ae 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -13,8 +13,18 @@ progress.cpp progress.h timeutil.h hammingdistance.h operatingsystem.cpp operatingsystem.h heapsort.h +mutsel_wrapper.cpp mutsel_wrapper.h +self_process.h ) +if (USE_MUTSEL STREQUAL "ON") + add_dependencies(utils mutsel) + target_link_libraries(utils "${MUTSEL_RUST_LIB_PATH}") + if (WIN32) + target_link_libraries(utils ntdll userenv bcrypt ws2_32) + endif() +endif() + if(ZLIB_FOUND) target_link_libraries(utils ${ZLIB_LIBRARIES}) else(ZLIB_FOUND) diff --git a/utils/mutsel_wrapper.cpp b/utils/mutsel_wrapper.cpp new file mode 100644 index 000000000..29aa07bf9 --- /dev/null +++ b/utils/mutsel_wrapper.cpp @@ -0,0 +1,487 @@ +// C++ wrapper for the mutsel rust library + +#include "mutsel_wrapper.h" + +#if !defined(USE_MUTSEL) +void rust_mutsel(int32_t *parents, + double *branch_lengths, + uint8_t *alignment, + uint32_t site_num, + uint32_t leave_num, + uint32_t node_num, + const char *model_string, + const char *priorMuFile, + const char *priorPiFile, + uint8_t verbose, + double *out_site_freq, + double *out_R_matrices, + const char *output_prefix) +{ + std::cout << "Mutsel support not compiled in!" << std::endl; + exit(1); +} +void rust_set_rayon_threads(int32_t num_threads) +{ + return; +} +#endif + +std::pair, std::vector> prepare_mutsel_tree(MTree *orig_tree) +{ + // Copy tree + + MTree *tree = new MTree(*orig_tree); + + if (tree->rooted) + { + tree->convertToUnrooted(); + } + + std::vector branch_lengths; + std::vector parent_indices; + + auto num_nodes = tree->nodeNum; + + branch_lengths.resize(num_nodes); + parent_indices.resize(num_nodes); + + auto orig_root = tree->root; + ASSERT(orig_root->isLeaf()); + + auto root = orig_root->neighbors[0]->node; + + std::vector> stack; + stack.push_back({root, nullptr}); + + branch_lengths.at(root->id) = 0.0; // root branch length + parent_indices.at(root->id) = -1; // root has no parent + + while (!stack.empty()) + { + Node *node = stack.back().first; + Node *dad = stack.back().second; + stack.pop_back(); + + for (auto nei : node->neighbors) + { + if (dad != nullptr && nei->node->id == dad->id) + { + continue; + } + Node *child = nei->node; + + if (nei->length < 0.0) + { + throw std::runtime_error("The guide Tree for MUTSEL needs to have branchlengths. Please provide a tree with branch lengths."); + } + + branch_lengths.at(child->id) = nei->length; + parent_indices.at(child->id) = node->id; + + stack.push_back({child, node}); + } + } + + delete tree; + + return {std::move(branch_lengths), std::move(parent_indices)}; +} + +// Returns the alignment in the format required by mutsel library as dense [L, N] matrix and returns L the sequence length +std::tuple, int32_t, int32_t> prepare_mutsel_alignment(Alignment *alignment) +{ + // [L, N] matrix where L is sequence length and N is number of sequences + std::vector sequences; + size_t L = alignment->getNSite(); + size_t N = alignment->getNSeq(); + + std::cout << "Preparing alignment for mutsel inference: " << N << " sequences, " << L << " sites" << std::endl; + + sequences.resize(L * N); + + for (size_t site = 0; site < L; ++site) + { + Pattern &pat = alignment->at(alignment->getPatternID(site)); + for (size_t seq_idx = 0; seq_idx < N; ++seq_idx) + { + auto state = static_cast(pat.at(seq_idx)); + if (!(state < 20)) + { + // map unknown states to gaps (state 20) + state = 20; + } + sequences[site * N + seq_idx] = state; + } + } + + return std::make_tuple(std::move(sequences), static_cast(L), static_cast(N)); +} + +std::string read_binary_site_model_file_internal(std::string &filename, std::vector &site_freq, std::vector &rate_matrices, std::vector &site_model) +{ + cout << endl + << "Reading site-specific model file " << filename << " ..." << endl; + + site_freq.clear(); + site_model.clear(); + rate_matrices.clear(); + + std::ifstream in; + std::string rate_model_string; + + // assert little-endian + uint16_t num = 1; + if (*((uint8_t *)&num) != 1) + { + throw std::runtime_error("Only little-endian machine is supported for reading binary site model file"); + } + + try + { + in.open(filename, std::ios::binary); + if (!in.is_open()) + { + throw std::runtime_error("Failed to open binary site model file"); + } + + auto read_exact = [&](char *buffer, std::streamsize size, const char *field_name) + { + in.read(buffer, size); + if (!in || in.gcount() != size) + { + throw std::runtime_error(std::string("Failed to read ") + field_name + " from binary site model file"); + } + }; + + // Read in the model string. First 8 bytes little endian length of the string, followed by the string itself. + uint64_t rate_model_string_length; + read_exact(reinterpret_cast(&rate_model_string_length), sizeof(uint64_t), "rate model string length"); + + std::vector rate_model_string_buf(rate_model_string_length); + if (rate_model_string_length > 0) + { + read_exact(rate_model_string_buf.data(), static_cast(rate_model_string_length), "rate model string"); + } + rate_model_string = std::string(rate_model_string_buf.data(), rate_model_string_length); + + // Read number of sites. 8 bytes + + uint64_t num_sites; + read_exact(reinterpret_cast(&num_sites), sizeof(uint64_t), "number of sites"); + + // num_sites * 20 doubles for site frequencies + site_freq.resize(num_sites * 20); + read_exact(reinterpret_cast(site_freq.data()), + static_cast(num_sites * 20 * sizeof(double)), + "site frequencies"); + + // num_sites * 190 doubles for rate matrices + rate_matrices.resize(num_sites * 190); + read_exact(reinterpret_cast(rate_matrices.data()), + static_cast(num_sites * 190 * sizeof(double)), + "rate matrices"); + + for (size_t i = 0; i < num_sites; ++i) + { + site_model.push_back(i); + for (int j = 0; j < 20; ++j) + { + if (site_freq[i * 20 + j] <= 1e-10) + throw std::runtime_error("Frequencies must be strictly bigger than 1e-10"); + } + double sum = 0; + for (int j = 0; j < 20; ++j) + { + sum += site_freq[i * 20 + j]; + } + if (std::abs(sum - 1.0) > 1e-4) + { + std::cout << "Warning: frequencies for site " << i + 1 << " do not sum to 1, normalizing..." << std::endl; + for (int j = 0; j < 20; ++j) + { + site_freq[i * 20 + j] /= sum; + } + } + for (int j = 0; j < 190; ++j) + { + if (rate_matrices[i * 190 + j] <= 0.0) + throw "Rate parameters must be positive"; + } + } + } + catch (const std::exception &e) + { + throw std::runtime_error("Error reading site model file: " + std::string(e.what())); + } + + return rate_model_string; +} + +void write_site_models_to_alignment(Alignment &alignment, const double *site_freq, const double *rate_matrices, int len) +{ + alignment.ptn_state_freq.clear(); + alignment.site_rate_matrices.clear(); + + size_t nsite = alignment.getNSite(); + if (len != static_cast(nsite)) + { + throw std::runtime_error("Site model file site count does not match alignment length"); + } + + IntVector site_model(nsite, -1); // map each site to a model + IntVector pattern_first_site(alignment.getNPattern(), -1); + for (size_t site = 0; site < nsite; ++site) + { + if (pattern_first_site[alignment.getPatternID(site)] == -1) + { + pattern_first_site[alignment.getPatternID(site)] = static_cast(site); + } + } + + bool aln_changed = false; + ASSERT(alignment.num_states == 20); // currently we only support 20 states for mutsel model, so this function should only be called for protein alignments + + vector models_freq; + vector models_rate; + for (size_t site = 0; site < nsite; ++site) + { + site_model[site] = models_freq.size(); + + const double *freq = site_freq + site * 20; + const double *rate_para = rate_matrices + site * 190; + + bool add = true; + int first_site = pattern_first_site[alignment.getPatternID(site)]; + if (first_site < static_cast(site) && site_model[first_site] != -1) + { + int first_model = site_model[first_site]; + bool matched_freq_and_rate = true; + for (int i = 0; i < 20; ++i) + { + if (freq[i] != models_freq[first_model][i]) + { + matched_freq_and_rate = false; + break; + } + } + if (matched_freq_and_rate) + { + for (int i = 0; i < 190; ++i) + { + if (rate_para[i] != models_rate[first_model][i]) + { + matched_freq_and_rate = false; + break; + } + } + } + + if (matched_freq_and_rate) + { + site_model[site] = first_model; + add = false; + } + else + { + aln_changed = true; + } + } + + if (add) + { + double *site_freq_entry = new double[20]; + memcpy(site_freq_entry, freq, sizeof(double) * 20); + models_freq.push_back(site_freq_entry); + models_rate.emplace_back(rate_para, rate_para + 190); + } + } + + if (aln_changed) + { + cout << "Regrouping alignment sites..." << endl; + alignment.regroupSitePattern(site_model); + pattern_first_site = IntVector(alignment.getNPattern(), -1); + for (size_t site = 0; site < nsite; ++site) + { + if (pattern_first_site[alignment.getPatternID(site)] == -1) + { + pattern_first_site[alignment.getPatternID(site)] = static_cast(site); + } + } + } + + vector used_model(models_freq.size(), false); + for (size_t ptn = 0; ptn < alignment.getNPattern(); ++ptn) + { + int first_site = pattern_first_site[ptn]; + int model_id = site_model[first_site]; + used_model[model_id] = true; + alignment.ptn_state_freq.push_back(models_freq[model_id]); + alignment.site_rate_matrices.insert( + alignment.site_rate_matrices.end(), + models_rate[model_id].begin(), + models_rate[model_id].end()); + } + + for (size_t model_id = 0; model_id < models_freq.size(); ++model_id) + { + if (!used_model[model_id]) + { + delete[] models_freq[model_id]; + } + } + + cout << models_freq.size() << " distinct per-site state frequency vectors detected" << endl; +} + +void read_site_model_file(const std::string &filename, Alignment &alignment) +{ + auto site_freq = std::vector(); + auto rate_matrices = std::vector(); + auto site_model = std::vector(); + auto _custom_str = read_binary_site_model_file_internal(const_cast(filename), site_freq, rate_matrices, site_model); + write_site_models_to_alignment(alignment, site_freq.data(), rate_matrices.data(), site_model.size()); + return; +} + +void write_binary_site_model_file(const std::string &filename, Alignment &alignment) +{ + size_t nsites = alignment.getNSite(); + size_t nstates = alignment.num_states; + ASSERT(nstates == 20); + + try + { + ofstream out; + out.exceptions(ios::failbit | ios::badbit); + out.open(filename, std::ios::binary); + IntVector pattern_index; + alignment.getSitePatternIndex(pattern_index); + + uint64_t custom_string_length = 6; // length of "UNUSED" + out.write(reinterpret_cast(&custom_string_length), sizeof(uint64_t)); + out.write("UNUSED", custom_string_length); + + uint64_t num_sites = nsites; + out.write(reinterpret_cast(&num_sites), sizeof(uint64_t)); + + for (size_t i = 0; i < nsites; ++i) + { + double *state_freq = alignment.ptn_state_freq[pattern_index[i]]; + out.write(reinterpret_cast(state_freq), 20 * sizeof(double)); + } + + for (size_t i = 0; i < nsites; ++i) + { + double *rate_para_ptr = alignment.site_rate_matrices.data() + pattern_index[i] * 190; + out.write(reinterpret_cast(rate_para_ptr), 190 * sizeof(double)); + } + + cout << "Site mutsel model printed to " << filename << endl; + } + catch (ios::failure) + { + outError(ERR_WRITE_OUTPUT, filename); + } +} + +DoubleVector computeMutselSiteRates(Alignment &alignment) +{ + ASSERT(alignment.num_states == 20); + ASSERT(alignment.ptn_state_freq.size() == alignment.getNPattern()); + ASSERT(alignment.site_rate_matrices.size() == alignment.getNPattern() * 190); + + size_t npattern = alignment.getNPattern(); + DoubleVector pattern_rates(npattern); + for (size_t ptn = 0; ptn < npattern; ++ptn) + { + double *pi = alignment.ptn_state_freq[ptn]; + double *R = alignment.site_rate_matrices.data() + ptn * 190; + double rate = 0.0; + int idx = 0; + for (int i = 0; i < 20; ++i) + { + for (int j = i + 1; j < 20; ++j) + { + rate += R[idx] * pi[i] * pi[j]; + idx++; + } + } + pattern_rates[ptn] = 2.0 * rate; + } + + size_t nsite = alignment.getNSite(); + DoubleVector site_rates(nsite); + for (size_t site = 0; site < nsite; ++site) + { + site_rates[site] = pattern_rates[alignment.getPatternID(site)]; + } + return site_rates; +} + +void computeMutselSiteFrequencyModel(Params ¶ms, Alignment *alignment) +{ + ASSERT(params.tree_freq_file); + cout << endl + << "===> COMPUTING MUTSEL MODEL BASED ON TREE FILE " << params.tree_freq_file << endl; + PhyloTree *tree = new PhyloTree(alignment); + tree->setParams(¶ms); + bool myrooted = params.is_rooted; + tree->readTree(params.tree_freq_file, myrooted); + tree->setAlignment(alignment); + tree->setRootNode(params.root); + + tree->setNumThreads(params.num_threads); + + tree->ensureNumberOfThreadsIsSet(nullptr); + + auto [branch_lengths, parent_indices] = prepare_mutsel_tree(tree); + auto [sequences, L, N] = prepare_mutsel_alignment(alignment); + + double *site_freq = new double[L * 20]; + + double *site_rate = new double[L * 190]; + + // Close log file, so we can append in the mutsel library without messing up the order of log messages from IQ-TREE and mutsel library + std::cout << std::flush; + auto outstream = dynamic_cast(std::cout.rdbuf()); + if (outstream) + { + outstream->close(); + } + else + { + throw std::runtime_error("IQTREE-Logging seems to be uninitialized"); + } + + // Calls into the Rust code + rust_set_rayon_threads(params.num_threads); + rust_mutsel(parent_indices.data(), + branch_lengths.data(), + sequences.data(), + L, + N, + parent_indices.size(), + params.model_name.c_str(), + params.mutsel_prior_rate_file.empty() ? nullptr : params.mutsel_prior_rate_file.c_str(), + params.mutsel_prior_freq_file.empty() ? nullptr : params.mutsel_prior_freq_file.c_str(), + verbose_mode, + site_freq, + site_rate, + ((string)params.out_prefix).c_str()); + + outstream->open(((string)params.out_prefix + ".log").c_str(), std::ios::app); // reopen log file + + write_site_models_to_alignment(*alignment, site_freq, site_rate, L); + + write_binary_site_model_file(((string)params.out_prefix + ".sitemodel").c_str(), *alignment); + + params.print_site_state_freq = WSF_NONE; + + delete[] site_freq; + delete[] site_rate; + delete tree; + + cout << endl + << "===> CONTINUE ANALYSIS USING THE INFERRED MUTSEL MODEL" << endl; +} \ No newline at end of file diff --git a/utils/mutsel_wrapper.h b/utils/mutsel_wrapper.h new file mode 100644 index 000000000..c94cd1864 --- /dev/null +++ b/utils/mutsel_wrapper.h @@ -0,0 +1,94 @@ +// C++ wrapper for the mutsel rust library + +#ifndef IQTREE_UTILS_MUTSEL_WRAPPER_H +#define IQTREE_UTILS_MUTSEL_WRAPPER_H + +#include +#include +#include +#include +#include +#include "tree/mtree.h" +#include "alignment/alignment.h" +#include "tree/phylotree.h" +#include "main/outstreambuf.h" + +/** + * Convert a IQ-TREE tree into the format required by the mutsel library. + */ +std::pair, std::vector> prepare_mutsel_tree(MTree *tree); + +/** + * Returns the alignment in the format required by mutsel library as dense [L, N] matrix and returns L the sequence length and N the number of sequences. + */ +std::tuple, int32_t, int32_t> prepare_mutsel_alignment(Alignment *alignment); + +// Mutsel internals, if not compiled in we provide dummy implementations here, otherwise these functions need to be linked. +#if defined(USE_MUTSEL) +extern "C" void rust_mutsel(int32_t *parents, + double *branch_lengths, + uint8_t *alignment, + uint32_t site_num, + uint32_t leave_num, + uint32_t node_num, + const char *model_string, + const char *priorMuFile, + const char *priorPiFile, + uint8_t verbose, + double *out_site_freq, + double *out_R_matrices, + const char *output_prefix); + +extern "C" void rust_set_rayon_threads(int32_t num_threads); +#else +void rust_mutsel(int32_t *parents, + double *branch_lengths, + uint8_t *alignment, + uint32_t site_num, + uint32_t leave_num, + uint32_t node_num, + const char *model_string, + const char *priorMuFile, + const char *priorPiFile, + uint8_t verbose, + double *out_site_freq, + double *out_R_matrices, + const char *output_prefix); + +void rust_set_rayon_threads(int32_t num_threads); +#endif + +/** + * Simple read function which just puts the binary file into vectors. frequences get normalized, rates are checked to be positive. It returns the rate model string of the file. + * Format is documented in the body of the function. + */ +std::string read_binary_site_model_file_internal(std::string &filename, std::vector &site_freq, std::vector &rate_matrices, std::vector &site_model); + +/** + * Takes the data from the file (or the rust_mutsel function) and updates the alignment object. + * This deals with duplicated pattern and stuff. + */ +void write_site_models_to_alignment(Alignment &alignment, const double *site_freq, const double *rate_matrices, int len); + +/** + * Read a site model file and update the alignment object. + * This is a simple wrapper function around read_binary_site_model_file_internal and write_site_models_to_alignment. + */ +void read_site_model_file(const std::string &filename, Alignment &alignment); + +/** + * Print a site model from the alignment to binary file. + */ +void write_binary_site_model_file(const std::string &filename, Alignment &alignment); + +/** + * Compute the site frequency model using the mutsel library. It writes a site model file with the inferred parameters and also updates the alignment object with the inferred site frequency and rate parameters. It returns a string representing the rate model, e.g., "G4{0.5}" or "R5{0.1/0.2/0.3/0.4/0.5/0.6/0.7/0.8/0.9/1.0}". + */ +void computeMutselSiteFrequencyModel(Params ¶ms, Alignment *alignment); + +/** + * Per-site substitution rate implied by the fitted MUTSEL model + */ +DoubleVector computeMutselSiteRates(Alignment &alignment); + +#endif // IQTREE_UTILS_MUTSEL_WRAPPER_H \ No newline at end of file diff --git a/utils/self_process.h b/utils/self_process.h new file mode 100644 index 000000000..37cb25f6d --- /dev/null +++ b/utils/self_process.h @@ -0,0 +1,197 @@ +// self_process.hpp — spawn a copy of the currently running executable, portably. +#pragma once + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include +#elif defined(__APPLE__) + #include + #include + #include + #include + extern char **environ; +#else // Linux / other POSIX + #include + #include + #include + #include + extern char **environ; + #if defined(__FreeBSD__) + #include + #include + #endif +#endif + +namespace selfproc { + +// Returns the absolute, resolved path to the currently running executable. +inline std::filesystem::path executable_path() { +#if defined(_WIN32) + std::wstring buf(MAX_PATH, L'\0'); + for (;;) { + DWORD len = GetModuleFileNameW(nullptr, buf.data(), (DWORD)buf.size()); + if (len == 0) throw std::runtime_error("GetModuleFileNameW failed"); + if (len < buf.size() - 1) { buf.resize(len); break; } + buf.resize(buf.size() * 2); + } + return std::filesystem::path(buf); + +#elif defined(__APPLE__) + std::array buffer{}; + pid_t pid = getpid(); + + int bytes = proc_pidpath(pid, buffer.data(), buffer.size()); + if (bytes > 0) { + return std::filesystem::path(buffer.data()); + } + + return {}; // Return empty path on failure +#elif defined(__linux__) + std::error_code ec; + auto p = std::filesystem::read_symlink("/proc/self/exe", ec); + if (ec) throw std::runtime_error("reading /proc/self/exe failed: " + ec.message()); + return p; + +#elif defined(__FreeBSD__) + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + char buf[PATH_MAX]; + size_t len = sizeof(buf); + if (sysctl(mib, 4, buf, &len, nullptr, 0) != 0) + throw std::runtime_error("sysctl KERN_PROC_PATHNAME failed"); + return std::filesystem::path(std::string(buf, len ? len - 1 : 0)); + +#else + #error "executable_path() not implemented for this platform" +#endif +} + +#if defined(_WIN32) + +struct Process { + PROCESS_INFORMATION pi{}; + + int wait() { + WaitForSingleObject(pi.hProcess, INFINITE); + DWORD code = 0; + GetExitCodeProcess(pi.hProcess, &code); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return static_cast(code); + } +}; + +namespace detail { +inline std::wstring to_wide(const std::string& s) { + if (s.empty()) return {}; + int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0); + std::wstring w(n, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), w.data(), n); + return w; +} + +// Correct Win32 argv-style quoting (handles embedded quotes/backslashes). +inline std::wstring quote_arg(const std::wstring& a) { + if (!a.empty() && a.find_first_of(L" \t\"") == std::wstring::npos) + return a; + std::wstring out = L"\""; + for (auto it = a.begin(); ; ++it) { + size_t backslashes = 0; + while (it != a.end() && *it == L'\\') { ++backslashes; ++it; } + if (it == a.end()) { + out.append(backslashes * 2, L'\\'); + break; + } else if (*it == L'"') { + out.append(backslashes * 2 + 1, L'\\'); + out.push_back(L'"'); + } else { + out.append(backslashes, L'\\'); + out.push_back(*it); + } + } + out.push_back(L'"'); + return out; +} +} // namespace detail + +inline Process spawn(const std::filesystem::path& exe, + const std::vector& args) { + std::wstring cmdline = detail::quote_arg(exe.wstring()); + for (auto& a : args) { + cmdline.push_back(L' '); + cmdline += detail::quote_arg(detail::to_wide(a)); + } + + STARTUPINFOW si{}; + si.cb = sizeof(si); + PROCESS_INFORMATION pi{}; + + std::vector mutable_cmd(cmdline.begin(), cmdline.end()); + mutable_cmd.push_back(L'\0'); + + BOOL ok = CreateProcessW( + exe.wstring().c_str(), // application name (avoids PATH search ambiguity) + mutable_cmd.data(), // command line, must be a mutable buffer + nullptr, nullptr, + TRUE, + 0, nullptr, nullptr, + &si, &pi); + + if (!ok) + throw std::runtime_error("CreateProcessW failed, error " + std::to_string(GetLastError())); + + Process p; + p.pi = pi; + return p; +} + +#else // POSIX (Linux, macOS, FreeBSD, ...) + +struct Process { + pid_t pid = -1; + + int wait() { + int status = 0; + if (waitpid(pid, &status, 0) < 0) + throw std::runtime_error("waitpid failed"); + if (WIFEXITED(status)) return WEXITSTATUS(status); + if (WIFSIGNALED(status)) return 128 + WTERMSIG(status); + return -1; + } +}; + +inline Process spawn(const std::filesystem::path& exe, + const std::vector& args) { + + std::vector argv_storage; + argv_storage.push_back(exe.string()); + for (auto& a : args) argv_storage.push_back(a); + + std::vector argv; + for (auto& s : argv_storage) argv.push_back(s.data()); + argv.push_back(nullptr); + + pid_t pid; + int rc = posix_spawn(&pid, exe.c_str(), nullptr, nullptr, argv.data(), environ); + if (rc != 0) + throw std::runtime_error(std::string("posix_spawn failed: ") + std::strerror(rc)); + + Process p; + p.pid = pid; + return p; +} + +#endif + +// Convenience: spawn a fresh copy of the currently running executable with the given args. +inline Process spawn_self(const std::vector& args) { + return spawn(executable_path(), args); +} + +} // namespace selfproc \ No newline at end of file diff --git a/utils/tools.cpp b/utils/tools.cpp index 5096ca343..09eaa919d 100644 --- a/utils/tools.cpp +++ b/utils/tools.cpp @@ -4623,6 +4623,29 @@ void parseArg(int argc, char *argv[], Params ¶ms) { continue; } + if (strcmp(argv[cnt], "--site-model-file") == 0 || strcmp(argv[cnt], "-site-model-file") == 0) { + cnt++; + if (cnt >= argc) + throw "Use --site-model-file "; + params.site_model_file = argv[cnt]; + continue; + } + + if (strcmp(argv[cnt], "--mutsel-prior-freq-file") == 0 || strcmp(argv[cnt], "-mutsel-prior-freq-file") == 0) { + cnt++; + if (cnt >= argc) + throw "Use --mutsel-prior-freq-file "; + params.mutsel_prior_freq_file = argv[cnt]; + continue; + } + + if (strcmp(argv[cnt], "--mutsel-prior-rate-file") == 0 || strcmp(argv[cnt], "-mutsel-prior-rate-file") == 0) { + cnt++; + if (cnt >= argc) + throw "Use --mutsel-prior-rate-file "; + params.mutsel_prior_rate_file = argv[cnt]; + continue; + } // if (strcmp(argv[cnt], "-rootstate") == 0) { // cnt++; // if (cnt >= argc) diff --git a/utils/tools.h b/utils/tools.h index 58473002e..28834f538 100644 --- a/utils/tools.h +++ b/utils/tools.h @@ -2925,6 +2925,27 @@ class Params { * input tree string (instead of a file) */ string intree_str; + + // MUTSEL parameters + + /** + * the file containing the site-specific model parameters. + * it uses a simple binary format and will be output by a MUTSEL run. + * The file is not intended to be human-readable. + */ + std::string site_model_file; + + /** + * the file containing the prior state frequencies for the mutsel model, in the format of "site_ID state1_freq state2_freq ... state20_freq" + * by default MUTSEL will calculate these priors by an approximated PMSF method. + */ + std::string mutsel_prior_freq_file; + + /** + * the prior for the shared rates in PAML format. + * by default MUTSEL will use the CODON model (A matrix derived for this purpose, for more information see the paper). + */ + std::string mutsel_prior_rate_file; }; /**