pax_global_header00006660000000000000000000000064150610401140014502gustar00rootroot0000000000000052 comment=08b3cbc5dc35ca1d3ab0a33eb5ee331b9a468df5 bbuchfink-diamond-08b3cbc/000077500000000000000000000000001506104011400155345ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/.cirrus.yml000066400000000000000000000005541506104011400176500ustar00rootroot00000000000000task: name: build arm_container: image: gcc:latest cpu: 1 memory: 4G install_script: | apt-get update && apt-get install cmake zlib1g-dev --yes --force-yes --no-install-suggests --no-install-recommends compile_script: | mkdir bin && cd bin cmake -DCMAKE_BUILD_TYPE=Release .. make test_script: | cd bin && ctest -C Releasebbuchfink-diamond-08b3cbc/.dockerignore000066400000000000000000000000141506104011400202030ustar00rootroot00000000000000.git .vs outbbuchfink-diamond-08b3cbc/.gitattributes000066400000000000000000000005721506104011400204330ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain bbuchfink-diamond-08b3cbc/.github/000077500000000000000000000000001506104011400170745ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/.github/FUNDING.yml000066400000000000000000000001011506104011400207010ustar00rootroot00000000000000# These are supported funding model platforms github: bbuchfink bbuchfink-diamond-08b3cbc/.github/workflows/000077500000000000000000000000001506104011400211315ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/.github/workflows/cmake.yml000066400000000000000000000030751506104011400227410ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: branches: [ master ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release permissions: contents: read jobs: build: # The CMake configure and build commands are platform agnostic and should work equally # well on Windows or Mac. You can convert this to a matrix build if you need # cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ${{ matrix.os }} strategy: matrix: # runner image list, https://github.com/actions/runner-images os: [ ubuntu-24.04, macos-14 ] steps: - uses: actions/checkout@v2 - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j $(nproc --all) - name: Test working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} bbuchfink-diamond-08b3cbc/.github/workflows/codeql.yml000066400000000000000000000026211506104011400231240ustar00rootroot00000000000000name: "Code Scanning - Action" on: pull_request: jobs: CodeQL-Build: # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest runs-on: ubuntu-latest permissions: # required for all workflows security-events: write steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below). - name: Autobuild uses: github/codeql-action/autobuild@v2 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # âœī¸ If the Autobuild fails above, remove it and uncomment the following # three lines and modify them (or add more) to build your code if your # project uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 bbuchfink-diamond-08b3cbc/.gitignore000066400000000000000000000014021506104011400175210ustar00rootroot00000000000000# Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msm *.msp # Windows shortcuts *.lnk # ========================= # Operating System Files # ========================= # OSX # ========================= .DS_Store .AppleDouble .LSOverride # Thumbnails ._* # Files that might appear on external disk .Spotlight-V100 .Trashes # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # CMake files CMakeCache.txt CMakeFiles cmake_install.cmake install_manifest.txt build/ .idea Makefile diamond src/extra/ .vs/ .unison /CMakeSettings.json /out/install/x64-Debug/bin/diamond.exe bbuchfink-diamond-08b3cbc/CITATION.cff000066400000000000000000000006501506104011400174270ustar00rootroot00000000000000cff-version: "1.1.0" authors: - family-names: Buchfink given-names: Benjamin - family-names: Reuter given-names: Klaus - family-names: Drost given-names: "Hajk-Georg" date-released: 2021-04-07 doi: "10.1038/s41592-021-01101-x" message: "If you use this software, please cite it using these metadata." title: "Sensitive protein alignments at tree-of-life scale using DIAMOND" version: "2.1.12" bbuchfink-diamond-08b3cbc/CMakeLists.txt000066400000000000000000000454001506104011400202770ustar00rootroot00000000000000cmake_minimum_required (VERSION 2.6...3.5) project (DIAMOND) include(CheckCXXCompilerFlag) include(CheckSymbolExists) include(CheckTypeSize) option(BUILD_STATIC "BUILD_STATIC" OFF) option(STATIC_LIBGCC "STATIC_LIBGCC" OFF) option(STATIC_LIBSTDC++ "STATIC_LIBSTDC++" OFF) option(X86 "X86" ON) option(ARM "ARM" OFF) option(AARCH64 "AARCH64" OFF) option(WITH_ZSTD "WITH_ZSTD" OFF) option(CROSS_COMPILE "CROSS_COMPILE" OFF) # experimental options not suitable for deployment purposes option(EXTRA "EXTRA" OFF) option(STRICT_BAND "STRICT_BAND" ON) option(LEFTMOST_SEED_FILTER "LEFTMOST_SEED_FILTER" ON) option(SEQ_MASK "SEQ_MASK" ON) option(DP_STAT "DP_STAT" OFF) option(SINGLE_THREADED "SINGLE_THREADED" OFF) option(HIT_KEEP_TARGET_ID "HIT_KEEP_TARGET_ID" OFF) option(LONG_SEEDS "LONG_SEEDS" OFF) option(WITH_AVX512 "WITH_AVX512" OFF) option(WITH_DNA "WITH_DNA" OFF) option(WITH_MCL "WITH_MCL" OFF) option(WITH_MIMALLOC "WITH_MIMALLOC" OFF) option(USE_TLS "USE_TLS" OFF) set(MAX_SHAPE_LEN 19) set(BLAST_INCLUDE_DIR "" CACHE STRING "BLAST_INCLUDE_DIR") set(BLAST_LIBRARY_DIR "" CACHE STRING "BLAST_LIBRARY_DIR") if(NOT CROSS_COMPILE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*|arm64.*)") set(X86 OFF) set(AARCH64 ON) elseif(NOT CROSS_COMPILE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)") set(X86 OFF) set(ARM ON) elseif(NOT CROSS_COMPILE AND CMAKE_SYSTEM_PROCESSOR MATCHES "PPC64*|ppc64*|powerpc64*") set(X86 OFF) # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec") add_definitions(-DEIGEN_DONT_VECTORIZE) elseif(NOT CROSS_COMPILE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^s390|sparc") set(X86 OFF) endif() if(STATIC_LIBSTDC++) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++") endif() if(STRICT_BAND) add_definitions(-DSTRICT_BAND) endif() if(USE_TLS) add_definitions(-DUSE_TLS) endif() if(SINGLE_THREADED) add_definitions(-DSINGLE_THREADED) endif() if(SEQ_MASK) add_definitions(-DSEQ_MASK) endif() if(LEFTMOST_SEED_FILTER) add_definitions(-DLEFTMOST_SEED_FILTER) endif() if(DP_STAT) add_definitions(-DDP_STAT) endif() if(EXTRA) add_definitions(-DEXTRA) endif() if(HIT_KEEP_TARGET_ID) add_definitions(-DHIT_KEEP_TARGET_ID) endif() if(LONG_SEEDS) add_definitions(-DLONG_SEEDS) endif() if(WITH_AVX512) add_definitions(-DWITH_AVX512) endif() if(WITH_DNA) add_definitions(-DWITH_DNA) endif() if(WITH_MCL) add_definitions(-DWITH_MCL) endif() if(WITH_FAMSA) add_definitions(-DWITH_FAMSA) endif() add_definitions(-DMAX_SHAPE_LEN=${MAX_SHAPE_LEN}) add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) IF(STATIC_LIBGCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc") endif() if(BUILD_STATIC) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(BUILD_SHARED_LIBRARIES OFF) set(CMAKE_EXE_LINKER_FLAGS "-static") endif() function(set_cxx_standard std flag) if(${CMAKE_VERSION} VERSION_LESS "3.1.0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) else() set(CMAKE_CXX_STANDARD ${std} PARENT_SCOPE) endif() endfunction(set_cxx_standard) check_type_size(ptrdiff_t SIZEOF_PTRDIFF_T) check_type_size(int SIZEOF_INT) check_cxx_compiler_flag("-std=gnu++14" HAS_GNUPP14) check_cxx_compiler_flag("-std=gnu++17" HAS_GNUPP17) check_cxx_compiler_flag("-std=gnu++20" HAS_GNUPP20) if(HAS_GNUPP20 OR ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) set_cxx_standard(20 "-std=gnu++20") elseif(HAS_GNUPP17) set_cxx_standard(17 "-std=gnu++17") elseif (HAS_GNUPP14) set_cxx_standard(14 "-std=gnu++14") else() set_cxx_standard(11 "-std=gnu++11") endif() check_symbol_exists(sysinfo "sys/sysinfo.h" HAVE_SYSINFO) if(CMAKE_BUILD_MARCH) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${CMAKE_BUILD_MARCH}") endif() find_package(ZLIB REQUIRED) find_package(Threads REQUIRED) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release) endif() if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_HAS_STD_BYTE=0) else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-implicit-fallthrough -Wreturn-type -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-uninitialized -Wno-deprecated-copy -Wno-unknown-warning-option ")#-g -fsanitize=address -fno-omit-frame-pointer ") endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pragma-clang-attribute -Wno-overloaded-virtual -Wno-missing-braces") #-g -fsanitize=thread -fno-omit-frame-pointer" ) endif() if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fabi-version=7") message("Setting -fabi-version for GCC 4.x") endif() set(DISPATCH_OBJECTS "src/dp/swipe/banded_3frame_swipe.cpp" "src/search/stage1_2.cpp" "src/tools/benchmark.cpp" "src/dp/swipe/swipe_wrapper.cpp" "src/masking/tantan.cpp" "src/dp/scan_diags.cpp" "src/dp/ungapped_simd.cpp" "src/dp/swipe/anchored_wrapper.cpp" "src/dp/score_profile.cpp" ) if(EXTRA) LIST(APPEND DISPATCH_OBJECTS "src/tools/benchmark_swipe.cpp") endif() add_library(arch_generic OBJECT ${DISPATCH_OBJECTS}) target_compile_options(arch_generic PUBLIC -DDISPATCH_ARCH=ARCH_GENERIC -DARCH_ID=0 -DEigen=Eigen_GENERIC) #target_compile_options(arch_generic PUBLIC -DDISPATCH_ARCH=ARCH_GENERIC -DARCH_ID=0) if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) target_compile_options(arch_generic PUBLIC /Zc:__cplusplus) endif() if(X86) add_library(arch_sse4_1 OBJECT ${DISPATCH_OBJECTS}) add_library(arch_avx2 OBJECT ${DISPATCH_OBJECTS}) if(WITH_AVX512) add_library(arch_avx512 OBJECT ${DISPATCH_OBJECTS}) endif() add_definitions(-DWITH_AVX2) add_definitions(-DWITH_SSE4_1) if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) target_compile_options(arch_sse4_1 PUBLIC -DDISPATCH_ARCH=ARCH_SSE4_1 -DARCH_ID=1 -D__SSSE3__ -D__SSE4_1__ -D__POPCNT__ -DEigen=Eigen_SSE4_1 /Zc:__cplusplus) target_compile_options(arch_avx2 PUBLIC -DDISPATCH_ARCH=ARCH_AVX2 -DARCH_ID=2 /arch:AVX2 -D__SSSE3__ -D__SSE4_1__ -D__POPCNT__ -DEigen=Eigen_AVX2 /Zc:__cplusplus) #target_compile_options(arch_sse4_1 PUBLIC -DDISPATCH_ARCH=ARCH_SSE4_1 -DARCH_ID=1 -D__SSSE3__ -D__SSE4_1__ -D__POPCNT__ /Zc:__cplusplus) #target_compile_options(arch_avx2 PUBLIC -DDISPATCH_ARCH=ARCH_AVX2 -DARCH_ID=2 /arch:AVX2 -D__SSSE3__ -D__SSE4_1__ -D__POPCNT__ /Zc:__cplusplus) if(WITH_AVX512) target_compile_options(arch_avx512 PUBLIC -DDISPATCH_ARCH=ARCH_AVX512 -DARCH_ID=3 /arch:AVX512 -D__SSSE3__ -D__SSE4_1__ -D__POPCNT__ -DEigen=Eigen_AVX512) endif() else() target_compile_options(arch_sse4_1 PUBLIC -DDISPATCH_ARCH=ARCH_SSE4_1 -DARCH_ID=1 -mssse3 -mpopcnt -msse4.1 -DEigen=Eigen_SSE4_1) target_compile_options(arch_avx2 PUBLIC -DDISPATCH_ARCH=ARCH_AVX2 -DARCH_ID=2 -mssse3 -mpopcnt -msse4.1 -msse4.2 -mavx -mavx2 -DEigen=Eigen_AVX2) #target_compile_options(arch_sse4_1 PUBLIC -DDISPATCH_ARCH=ARCH_SSE4_1 -DARCH_ID=1 -mssse3 -mpopcnt -msse4.1) #target_compile_options(arch_avx2 PUBLIC -DDISPATCH_ARCH=ARCH_AVX2 -DARCH_ID=2 -mssse3 -mpopcnt -msse4.1 -msse4.2 -mavx -mavx2) if(WITH_AVX512) target_compile_options(arch_avx512 PUBLIC -DDISPATCH_ARCH=ARCH_AVX512 -DARCH_ID=3 -mssse3 -mpopcnt -msse4.1 -msse4.2 -mavx -mavx2 -mavx512f -mavx512bw -DEigen=Eigen_AVX512) endif() endif() endif(X86) # NEON is mandatory on Aarch64 if(AARCH64) add_definitions(-DWITH_NEON) add_library(arch_neon OBJECT ${DISPATCH_OBJECTS}) target_compile_options(arch_neon PUBLIC -DDISPATCH_ARCH=ARCH_NEON -DARCH_ID=4 -D__ARM_NEON -D__aarch64__ -DEigen=Eigen_NEON) endif(AARCH64) # NEON is optional on Armv7, so we need to check for compiler support, # and for the header used for runtime detection. if(ARM) check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL) check_cxx_compiler_flag("-mfpu=neon" HAVE_MFPU_NEON) if(HAVE_MFPU_NEON) add_definitions(-DWITH_NEON) add_definitions(-DHAVE_MFPU_NEON) add_library(arch_neon OBJECT ${DISPATCH_OBJECTS}) target_compile_options(arch_neon PUBLIC -DDISPATCH_ARCH=ARCH_NEON -DARCH_ID=4 -D__ARM_NEON -DEigen=Eigen_NEON -mfpu=neon) endif() if(HAVE_GETAUXVAL) add_definitions(-DHAVE_GETAUXVAL) endif() endif(ARM) set(OBJECTS src/run/main.cpp src/basic/config.cpp src/stats/score_matrix.cpp src/data/queries.cpp src/data/seed_histogram.cpp src/output/daa/daa_record.cpp src/util/command_line_parser.cpp src/util/util.cpp src/basic/basic.cpp src/basic/hssp.cpp src/dp/ungapped_align.cpp src/run/tools.cpp src/chaining/greedy_align.cpp src/output/output_format.cpp src/output/join_blocks.cpp src/data/frequent_seeds.cpp src/align/legacy/query_mapper.cpp src/output/blast_tab_format.cpp src/output/blast_pairwise_format.cpp src/run/double_indexed.cpp src/output/sam_format.cpp src/align/align.cpp src/search/setup.cpp src/data/taxonomy.cpp src/masking/masking.cpp src/data/seed_set.cpp src/util/simd.cpp src/output/taxon_format.cpp src/output/daa/view.cpp src/output/output_sink.cpp src/output/target_culling.cpp src/align/legacy/banded_swipe_pipeline.cpp src/util/io/compressed_stream.cpp src/util/io/deserializer.cpp src/util/io/file_sink.cpp src/util/io/file_source.cpp src/util/io/input_file.cpp src/util/io/input_stream_buffer.cpp src/util/io/output_file.cpp src/util/io/output_stream_buffer.cpp src/util/io/serializer.cpp src/util/io/temp_file.cpp src/util/io/text_input_file.cpp src/data/taxon_list.cpp src/data/taxonomy_nodes.cpp src/lib/murmurhash/MurmurHash3.cpp src/search/stage0.cpp src/data/seed_array.cpp src/output/paf_format.cpp src/util/system/system.cpp src/util/algo/greedy_vertex_cover.cpp src/util/sequence/sequence.cpp src/tools/tools.cpp src/util/system/getRSS.cpp src/lib/tantan/LambdaCalculator.cc src/util/string/string.cpp src/align/extend.cpp src/test/test.cpp src/align/ungapped.cpp src/align/gapped_score.cpp src/align/gapped_final.cpp src/align/full_db.cpp src/align/culling.cpp src/cluster/cluster_registry.cpp src/cluster/cascaded/cascaded.cpp src/align/output.cpp #src/tools/roc.cpp src/test/data.cpp src/test/test_cases.cpp src/chaining/smith_waterman.cpp src/output/xml_format.cpp src/align/gapped_filter.cpp src/util/parallel/filestack.cpp src/util/parallel/parallelizer.cpp src/util/parallel/multiprocessing.cpp src/tools/benchmark_io.cpp src/lib/alp/njn_dynprogprob.cpp src/lib/alp/njn_dynprogproblim.cpp src/lib/alp/njn_dynprogprobproto.cpp src/lib/alp/njn_ioutil.cpp src/lib/alp/njn_localmaxstat.cpp src/lib/alp/njn_localmaxstatmatrix.cpp src/lib/alp/njn_localmaxstatutil.cpp src/lib/alp/njn_random.cpp src/lib/alp/sls_alignment_evaluer.cpp src/lib/alp/sls_alp.cpp src/lib/alp/sls_alp_data.cpp src/lib/alp/sls_alp_regression.cpp src/lib/alp/sls_alp_sim.cpp src/lib/alp/sls_basic.cpp src/lib/alp/sls_pvalues.cpp src/align/global_ranking/global_ranking.cpp src/align/global_ranking/extend.cpp #src/tools/rocid.cpp src/lib/blast/blast_seg.cpp src/lib/blast/blast_filter.cpp src/lib/blast/nlm_linear_algebra.cpp src/stats/stats.cpp src/stats/cbs.cpp src/stats/comp_based_stats.cpp src/stats/hauser_correction.cpp src/stats/matrix_adjust.cpp src/data/index.cpp src/data/dmnd/dmnd.cpp src/data/sequence_file.cpp src/tools/find_shapes.cpp src/data/block/block.cpp src/data/block/block_wrapper.cpp src/run/config.cpp src/data/sequence_set.cpp src/align/global_ranking/table.cpp src/output/daa/daa_write.cpp src/search/seed_complexity.cpp src/util/tsv/tsv.cpp src/basic/value.cpp src/masking/motifs.cpp src/align/alt_hsp.cpp src/data/fasta/fasta_file.cpp src/cluster/output.cpp src/cluster/realign.cpp src/cluster/reassign.cpp src/util/tsv/read_tsv.cpp src/tools/greedy_vertex_cover.cpp src/cluster/cascaded/recluster.cpp src/cluster/helpers.cpp src/search/kmer_ranking.cpp src/chaining/hamming_ext.cpp src/lib/blast/blast_message.cpp src/lib/blast/blast_stat.cpp src/lib/blast/blastn_score.cpp src/lib/blast/ncbi_std.cpp src/util/tsv/table.cpp src/util/tsv/file.cpp src/util/tsv/record.cpp src/cluster/cascaded/helpers.cpp src/cluster/cascaded/wrapper.cpp src/output/daa/merge.cpp src/chaining/backtrace.cpp src/util/tsv/merge.cpp src/util/tsv/join.cpp src/dp/scalar/smith_waterman.cpp src/tools/tsv.cpp src/cluster/external/external.cpp src/cluster/external/align.cpp src/cluster/external/cluster.cpp src/cluster/external/output.cpp src/util/algo/pagerank.cpp src/util/algo/mcl.cpp src/stats/blast/matrix_adjust.cpp src/stats/blast/ncbi.cpp src/search/hit_buffer.cpp ) if(WITH_DNA) list(APPEND OBJECTS src/contrib/dna/smith_watermann.cpp src/contrib/dna/dna_index.cpp src/contrib/dna/seed_set_dna.cpp src/contrib/dna/extension.cpp src/contrib/dna/chain.cpp src/contrib/dna/extension_chain.cpp src/contrib/dna/alignment.cpp src/contrib/dna/extension_seed_matches.cpp src/contrib/dna/smith_watermann.cpp src/lib/ksw2/ksw2_extz2_sse.c src/lib/ksw2/ksw2_extz.c src/lib/WFA2-lib.diamond/bindings/cpp/WFAligner.cpp src/contrib/dna/build_score.cpp ) endif() if(WITH_MCL) list(APPEND OBJECTS src/contrib/mcl/mcl.cpp src/contrib/mcl/clustering_variables.cpp src/contrib/mcl/clustering_format.cpp) endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") if(BLAST_INCLUDE_DIR) set(BLAST_OBJ "src/data/blastdb/blastdb.cpp") endif() if(WITH_ZSTD OR BLAST_INCLUDE_DIR) set(ZSTD_OBJ "src/util/io/zstd_stream.cpp") endif() if(X86) if(WITH_AVX512) add_executable(diamond $ $ $ $ ${OBJECTS} ${BLAST_OBJ} ${ZSTD_OBJ}) else() add_executable(diamond $ $ $ ${OBJECTS} ${BLAST_OBJ} ${ZSTD_OBJ}) endif() elseif(ARM OR AARCH64) add_executable(diamond $ $ ${OBJECTS} ${BLAST_OBJ} ${ZSTD_OBJ}) else() add_executable(diamond $ ${OBJECTS} ${BLAST_OBJ} ${ZSTD_OBJ}) endif() if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) target_compile_options(diamond PUBLIC /Zc:__cplusplus) endif() include_directories("${CMAKE_SOURCE_DIR}/src/" "${ZLIB_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/src/lib") if(BLAST_INCLUDE_DIR) function(find_blast_lib var library) find_library(${var} ${library} PATHS ${BLAST_LIBRARY_DIR} "/usr/lib/ncbi-blast+") if(${${var}} STREQUAL "${var}-NOTFOUND") message(FATAL_ERROR "Unable to find BLAST library: ${library}") endif() message("Found BLAST library: ${${var}}") endfunction(find_blast_lib) message("BLAST_INCLUDE_DIR: ${BLAST_INCLUDE_DIR}") message("BLAST_LIBRARY_DIR: ${BLAST_LIBRARY_DIR}") target_include_directories(diamond PRIVATE "${BLAST_INCLUDE_DIR}") find_blast_lib(SEQDB_LIBRARY seqdb) find_blast_lib(BIBLIO_LIBRARY biblio) find_blast_lib(BLASTDB_LIBRARY blastdb) find_blast_lib(BLASTDB_FORMAT_LIBRARY blastdb_format) find_blast_lib(GENERAL_LIBRARY general) find_blast_lib(GENOME_COLLECTION_LIBRARY genome_collection) find_blast_lib(MEDLINE_LIBRARY medline) find_blast_lib(PUB_LIBRARY pub) find_blast_lib(SEQ_LIBRARY seq) find_blast_lib(SEQCODE_LIBRARY seqcode) find_blast_lib(SEQSET_LIBRARY seqset) find_blast_lib(SEQUTIL_LIBRARY sequtil) find_blast_lib(SUBMIT_LIBRARY submit) find_blast_lib(XOBJMGR_LIBRARY xobjmgr) find_blast_lib(XOBJUTIL_LIBRARY xobjutil) find_blast_lib(XSER_LIBRARY xser) find_blast_lib(XNCBI_LIBRARY xncbi) find_blast_lib(XUTIL_LIBRARY xutil) find_blast_lib(LMDB_LIBRARY lmdb) target_link_libraries(diamond ${SEQDB_LIBRARY} ${BLASTDB_LIBRARY} ${BLASTDB_FORMAT_LIBRARY} ${GENERAL_LIBRARY} ${XOBJUTIL_LIBRARY} ${XOBJMGR_LIBRARY} ${GENOME_COLLECTION_LIBRARY} ${SEQ_LIBRARY} ${SEQCODE_LIBRARY} ${SEQSET_LIBRARY} ${SEQUTIL_LIBRARY} ${PUB_LIBRARY} ${MEDLINE_LIBRARY} ${BIBLIO_LIBRARY} ${SUBMIT_LIBRARY} ${XSER_LIBRARY} ${XNCBI_LIBRARY} ${XUTIL_LIBRARY} ${LMDB_LIBRARY}) add_definitions(-DWITH_BLASTDB) set_target_properties(diamond PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) find_library(DBGHELP_LIBRARY Dbghelp) target_link_libraries(diamond ${DBGHELP_LIBRARY}) else() target_link_libraries(diamond ${CMAKE_DL_LIBS}) endif() endif() if(WITH_DNA) include_directories(src/lib/WFA2-lib.diamond) add_subdirectory(src/lib/WFA2-lib.diamond) target_link_libraries(diamond wfa2) endif() if(WITH_ZSTD OR BLAST_INCLUDE_DIR) find_path(${ZSTD_INCLUDE_DIR} NAMES zstd.h PATHS ${ZSTD_INCLUDE_DIR}) find_library(ZSTD_LIBRARY NAMES libzstd.a libzstd_static) target_include_directories(diamond PRIVATE "${ZSTD_INCLUDE_DIR}") target_link_libraries(diamond ${ZSTD_LIBRARY}) add_definitions(-DWITH_ZSTD) endif() if(WITH_MIMALLOC) find_package(mimalloc 2.0 REQUIRED) add_definitions(-DWITH_MIMALLOC) target_link_libraries(diamond mimalloc) target_include_directories(diamond PRIVATE ${MIMALLOC_INCLUDE_DIR}) endif() if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) find_library(BCRYPT_LIBRARY BCrypt) find_library(WS2_32_LIBRARY Ws2_32) target_link_libraries(diamond ${BCRYPT_LIBRARY} ${WS2_32_LIBRARY}) endif() target_link_libraries(diamond ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS diamond DESTINATION bin) enable_testing() SET(TD ${CMAKE_SOURCE_DIR}/src/test) SET(SP -DTEST_DIR=${CMAKE_SOURCE_DIR}/src/test -P ${CMAKE_SOURCE_DIR}/src/test/test.cmake) add_test(NAME blastp COMMAND ${CMAKE_COMMAND} -DNAME=blastp "-DARGS=blastp -q ${TD}/1.faa -d ${TD}/2.faa -p1" ${SP}) add_test(NAME blastp-mid-sens COMMAND ${CMAKE_COMMAND} -DNAME=blastp-mid-sens "-DARGS=blastp -q ${TD}/3.faa -d ${TD}/4.faa --mid-sensitive -p1" ${SP}) add_test(NAME blastp-f0 COMMAND ${CMAKE_COMMAND} -DNAME=blastp-f0 "-DARGS=blastp -q ${TD}/1.faa -d ${TD}/2.faa -f0 -p1" ${SP}) # add_test(NAME diamond COMMAND diamond test)bbuchfink-diamond-08b3cbc/Dockerfile000066400000000000000000000037571506104011400175420ustar00rootroot00000000000000FROM ubuntu:latest as build-diamond ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Moscow RUN apt-get update && apt-get install -y g++ automake cmake zlib1g-dev git libzstd-dev libsqlite3-dev WORKDIR /opt/diamond ADD . . RUN git clone https://github.com/ncbi/ncbi-cxx-toolkit-public.git WORKDIR ncbi-cxx-toolkit-public # This is only for compatibility with older systems and can be skipped RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-darwin-clang.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-darwin-clang.cmake.in RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-clang-1600.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-clang.cmake.in RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-gcc-1220.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-gcc-1320.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-gcc-730.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-gcc.cmake.in RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-icc-210.cmake RUN sed -i 's/-msse4.2//g' ./src/build-system/cmake/toolchains/x86_64-linux-icc.cmake.in RUN ./cmake-configure --without-debug --with-projects="objtools/blast/seqdb_reader;objtools/blast/blastdb_format" --with-build-root=build WORKDIR build/build RUN make -j $(nproc --all) RUN cp /opt/diamond/ncbi-cxx-toolkit-public/build/inc/ncbiconf_unix.h /opt/diamond/ncbi-cxx-toolkit-public/include WORKDIR /opt/diamond/build RUN cmake -DCMAKE_BUILD_TYPE=Release -DBLAST_INCLUDE_DIR=/opt/diamond/ncbi-cxx-toolkit-public/include -DBLAST_LIBRARY_DIR=/opt/diamond/ncbi-cxx-toolkit-public/build/lib .. RUN make -j $(nproc --all) && make install FROM ubuntu:latest LABEL maintainer="Benjamin Buchfink " COPY --from=build-diamond /usr/local/bin/diamond /usr/local/bin/diamond ENTRYPOINT ["diamond"] CMD ["help"]bbuchfink-diamond-08b3cbc/LICENSE000066400000000000000000000773301506104011400165530ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONSbbuchfink-diamond-08b3cbc/README.md000066400000000000000000000074231506104011400170210ustar00rootroot00000000000000![DIAMOND](/../../../../bbuchfink/diamond-data/blob/main/diamond_white_95px.png) Introduction ============ DIAMOND is a sequence aligner for protein and translated DNA searches, designed for high performance analysis of big sequence data. The key features are: - Pairwise alignment of proteins and translated DNA at 100x-10,000x speed of BLAST. - [Protein clustering of up to tens of billions of proteins](https://github.com/bbuchfink/diamond/wiki/Clustering) - Frameshift alignments for long read analysis. - Low resource requirements and suitable for running on standard desktops or laptops. - Various output formats, including BLAST pairwise, tabular and XML, as well as taxonomic classification. [![Build](https://github.com/bbuchfink/diamond/actions/workflows/cmake.yml/badge.svg)](https://github.com/bbuchfink/diamond/actions/workflows/cmake.yml) [![image](https://img.shields.io/cirrus/github/bbuchfink/diamond)](https://cirrus-ci.com/github/bbuchfink/diamond/master) [![image](https://img.shields.io/github/downloads/bbuchfink/diamond/total)](https://github.com/bbuchfink/diamond/releases) [![image](https://anaconda.org/bioconda/diamond/badges/version.svg)](https://anaconda.org/bioconda/diamond) [![image](https://anaconda.org/bioconda/diamond/badges/downloads.svg)](https://anaconda.org/bioconda/diamond) [![image](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fbbuchfink%2Fdiamond-data%2Frefs%2Fheads%2Fmain%2Fcitations.json&query=%24.citations&style=flat&label=Citations&color=%23a020f0 )](https://scholar.google.com/citations?user=kjPIF1cAAAAJ) Documentation ============= The online documentation is located at the [GitHub Wiki](https://github.com/bbuchfink/diamond/wiki). Support ======= DIAMOND is actively supported and developed software. Please use the [issue tracker](https://github.com/bbuchfink/diamond/issues) for malfunctions and the [GitHub discussions](https://github.com/bbuchfink/diamond/discussions) for questions, comments, feature requests, etc. About ===== DIAMOND is developed by Benjamin Buchfink at the Max Planck Institute for Biology TÃŧbingen in collaboration with the Drost lab at the University of Dundee. From 2019-2024, it was developed by Benjamin Buchfink at the Drost lab, Max Planck Institute for Biology TÃŧbingen. From 2018-2019, its development was supported by the German Federal Ministry for Economic Affairs and Energy through an EXIST grant. From 2016-2018, it was developed by Benjamin Buchfink as an independent researcher. From 2013-2015, the initial version was developed by Benjamin Buchfink at the Huson lab, University of TÃŧbingen, Germany. \[[:email:Email](mailto:buchfink@gmail.com)\] \[[X](https://x.com/bbuchfink)\] \[[Bluesky](https://bsky.app/profile/bbuchfink.bsky.social)\] \[[LinkedIn](https://www.linkedin.com/in/benjamin-buchfink-875692105/)\] \[[Google Scholar](https://scholar.google.de/citations?user=kjPIF1cAAAAJ)\] \[[Drost lab](https://drostlab.com/)\] \[[MPI-BIO](https://www.bio.mpg.de/)\] **When using the tool in published research, please cite:** - Buchfink B, Reuter K, Drost HG, \"Sensitive protein alignments at tree-of-life scale using DIAMOND\", *Nature Methods* **18**, 366–368 (2021). [doi:10.1038/s41592-021-01101-x](https://doi.org/10.1038/s41592-021-01101-x) For sequence clustering: - Buchfink B, Ashkenazy H, Reuter K, Kennedy JA, Drost HG, \"Sensitive clustering of protein sequences at tree-of-life scale using DIAMOND DeepClust\", *bioRxiv* 2023.01.24.525373; doi: https://doi.org/10.1101/2023.01.24.525373 Original publication to cite DIAMOND until v0.9.25: - Buchfink B, Xie C, Huson DH, \"Fast and sensitive protein alignment using DIAMOND\", *Nature Methods* **12**, 59-60 (2015). [doi:10.1038/nmeth.3176](https://doi.org/10.1038/nmeth.3176) bbuchfink-diamond-08b3cbc/src/000077500000000000000000000000001506104011400163235ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/ChangeLog000066400000000000000000001301461506104011400201020ustar00rootroot00000000000000[2.1.14] - Improved the performance and sensitivity of the `cluster`, `deepclust` and `linclust` workflows. - The `getseq` workflow now supports BLAST databases. - Disabled clearing of the page cache for mmaped pages when using BLAST databases. - Reduced memory use when the `sallseqid` and `staxids` output fields are used. - Fixed a bug that could cause a crash when using the JSON output format and processing the database in multiple blocks. - Fixed a bug that could cause extra commas in the JSON output format. - Fixed a bug that could cause extra quotation marks when using the `stitle` output field for the JSON output format. - The `prepdb` workflow is deprecated, and no longer needed to use BLAST databases. - The `--anchored-swipe` option can be applied to linear mode clustering rounds and searches. - The `--anchored-swipe` option can be used without compiling with `-DEXTRA=ON` (only available on systems that support AVX2). - Improved the performace of compositional matrix adjustment. [2.1.13] - Fixed an invalid error message for the `cluster`, `deepclust` and `linclust` workflows. - Added the option `--oid-output` to output OIDs instead of accessions for the clustering workflows, reducing their memory use. - Added support for using the `--multiprocessing` feature on Windows. - Using `--multiprocessing` requires explicitly setting `--parallel-tmpdir`. - Fixed a bug that could cause a crash when the `--target-indexed` option was used. - As of now, a macOS binary is available for the GitHub release, supporting both x86 and Apple silicon CPUs. Using BLAST databases is also supported. - Added compatibility with later CMake versions (tested up to v4.0.3). - Added CMake option `-DCROSS_COMPILE` to disable auto-detection of host architecture. - Added compilation script to produce macOS fat binary. [2.1.12] - Added support for the new NCBI taxonomic ranks "cellular root", "acellular root", "domain" and "realm". - Added support for using BLAST databases to the Bioconda release. - Fixed compiler errors for Clang 20. - Enabled transitive closure computation in earlier clustering rounds and for bi-directional coverage clustering. - Fixed an issue that could cause hits to be partially lost in frameshift alignment mode when they occured in both query strands for the same target. - Fixed an error parsing FASTQ files when quality value lines started with the @ character. - Fixed a compiler error on macOS. [2.1.11] - Improved the performance and sensitivity of the `cluster`, `deepclust` and `linclust` workflows. - The `--faster` mode will by default use a minimizer sketch of fixed size per sequence instead of window-based minimizers. - Added the option `--sketch-size` to enable seeding using a minimizer sketch of the given size per sequence. - Cascaded clustering and iterated search will by default use the `--fast` mode with linearization in the second round. - The `--round-coverage` parameter is now also applied to uni-directional coverage clustering. - Cluster output files will correctly contain carriage returns on Windows. - Fixed generation of the Docker container against the latest version of the NCBI toolkit. - Fixed a bug that caused target coordinates not to be reported correctly in the tabular format in frameshift alignment mode. - Added the options `--ungapped-evalue` and `--ungapped-evalue-short` to set e-value thresholds for the ungapped hit filter. - Linearization of search or clustering rounds is limited to seeds of weight >= 10. - Fixed an issue that could cause an `array size overflow` error when using very large `.dmnd` databases with taxonomic annotation. - Fixed a bug that caused query letters to be printed as `ARND` instead of `ACGT` in the `view` workflow. - Fixed a bug that caused using paired end input files to malfunction with an error message. - Fixed a bug that could produce clustering errors when clustering at sequence identities >= 50% and processing the database in multiple super blocks. - Fixed a bug that could cause a crash in global ranking mode. - Accession parsing rules applied to database sequence accessions for the purpose of matching them to accessions in the taxonomy mapping file are now by default also applied to the accessions in the mapping file (disable using `--no-parse-seqids`). - Fixed an issue that could cause increased memory use in the hash join stage. - Added support for FASTA headers containing multiple sequence IDs separated by blank spaces (so far only the `\1` character was supported as a separator). - Fixed an issue that could cause hanging or crashes in the `Computing alignments` stage. - `--linsearch` can now be used in conjunction with `--iterate`. - Fixed a compiler error for GCC 4.8.5. - Fixed a compiler error on Solaris. - Fixed compiler errors on systems that do not support the sysinfo function. - Fixed `Bus error` occuring on Sparc systems. - Compilation on Sparc systems can be performed without setting `-DX86=OFF`. - Fixed two issues that could cause increased memory use in the computing alignments stage. - Fixed a bug that caused superfluous quote characters in the JSON output format. - Linear search modes will by default use full-matrix extension. - Fixed an issue that could cause reduced performance in the masking sequences stage. - Fixed a bug that could cause a crash when using mutual coverage thresholds in blastx mode. - Fixed a bug that could cause a crash when the `--include-lineage` option was used. - When reading protein sequences that unexpectedly only contain DNA letters, an error message is only produced if the first 10 sequences in the input file all exhibit the problem. - Fixed a bug that caused setting `--top 100` not to function correctly. - Fixed a bug that caused target coordinates not to be reported correctly in the output of the `realign` workflow. - Fixed a bug that did not permit using the `--memory-limit/-M` option for the `realign` workflow. - Fixed an issue that could cause non-deterministic output in frameshift alignment mode. - Fixed a bug that could cause a crash when using the XML output format in the `view` workflow. - Fixed an issue that could cause non-deterministic output for identically-scoring HSPs in the same target. - Disabled the default use of increased coverage and identity cutoffs in earlier clustering rounds. - Optimized the performance of the extension stage when coverage or approximate identity filters are used. - Optimized the performance of the extension stage when not using output fields that require alignment traceback. - Fixed an issue that could cause an incorrect order of cascaded clustering rounds. [2.1.10] - Fixed a bug that could cause a crash when using a bi-directional coverage cutoff in query-indexed mode. - Fixed a bug that caused the `--include-lineage` option to malfunction for targets with no taxonomic assignment available. [2.1.9] - Corrected the prefix of the query length field for the SAM format. - Added the size modifiers 'T', 'M' and 'K' for the `--memory-limit`/`-M` option. - Added the option `--mutual-cover` to cluster sequences by mutual coverage percentage of the cluster representative and member sequence. - Added the option `--symmetric` for computing greedy vertex cover with symmetric edges. - Fixed an issue that caused the `--approx-id` option and the `approx_pident` output field not to work correctly when using the `--anchored-swipe` option. - Added the option `--no-reassign` to prevent reassignment to closest representative for the greedy vertex cover and clustering workflows. - Added the option `--connected-component-depth` to activate clustering of connected components at a given maximum depth for the greedy vertex cover and the clustering workflows. - Fixed a compiler error for Clang v17. - Improved search performance when searching with mutual coverage threshold by filtering for sequence length ratio. - Added the sensitivity mode `--shapes-30x10` with sensitivity approximately equivalent to `--mid-sensitive`. - Added the options `--round-coverage` and `--round-approx-id` to set per round cutoffs for cascaded clustering. - The CMake switch `-DKEEP_TARGET_ID` is now obsolete and the corresponding function is always available. - Added the option `--include-lineage` to the taxonomic classification format to include taxonomic lineage in the output. - Added native support for the ARM NEON instruction set (contributed by Martin Larralde). [2.1.8] - Fixed an issue that could cause reduced performance when running in query-indexed mode. - Added support for the JSON output format (option `-f json-flat`). - Added the option `--sam-query-len` to output query length in SAM format. [2.1.7] - Fixed a bug that caused taxonomy names not to be loaded correctly for the `makedb` workflow. - Fixed a bug that caused a crash when using the `--target-indexed` option. - Fixed an error when using the `--tmpdir` option for the makedb workflow. - Added a warning message when sequence accessions are shortened due to parsing rules for the `makedb` workflow. - Added the option `--no-parse-seqids` to disable parsing of sequence accessions. - Changed the command line help to print options separated by command. - Fixed an issue that the `--ignore-warnings` option could not be used for the `makedb` workflow. [2.1.6] - Fixed compatibility issues on older systems without support for AVX2. - Fixed linker errors when compiled with `-DX86=OFF`. - Fixed a compiler error on macOS systems. - Fixed a bug that could cause missing tags in the XML output format and unaligned queries not to be reported correctly. - Fixed a bug that caused the PAF output format not to work correctly. [2.1.5] - Disabled the use of frequency based seed masking when using the linear-time search feature with respect to the targets. - Fixed a bug that caused a `Database file is not a BLAST database` error message for the `prepdb` workflow. - Fixed a bug that caused a segmentation fault when using BLAST databases. - Added line numbers for error messages when reading taxonomy mapping files. - Fixed a bug that could cause a crash when using the `greedy-vertex-cover` workflow without the `--out` and `--centroid-out` options. - Fixed a bug that caused the `greedy-vertex-cover` workflow to only produce a trivial clustering. - Fixed a bug that caused the last codon of the -2 reading frame to be translated incorrectly. - Reduced the memory use of the clustering workflow. - Updated the bundled NCBI toolkit to the latest version. [2.1.4] - Leading spaces are now trimmed and tabulator characters escaped as `\t` in sequence titles, and a warning message is produced. - Blank sequence titles are now replaced by `N/A`, and a warning message is produced. - Fixed a bug that could cause a `Traceback error` in certain cases. - Fixed a bug that caused the `qlen` and `score` output fields not to be reported correctly for the `realign` workflow. - Added an error message when using unsupported output fields for the `realign` workflow. - Fixed an issue that could cause a `Missing fields in input line` error when clustering. - Optimized the performance of the `linclust` workflow. - Reduced the memory use of the clustering workflow. - Fixed a bug that caused using standard input as the query not to work. [2.1.3] - Fixed compiler errors for GCC 4.8. - Fixed a GCC compiler error. - Fixed a segfault issue occuring when compiled using GCC 12 on ARM64 systems. - Fixed an issue that caused missing support for AVX2. [2.1.2] - The iterated search mode (option `--iterate`) now uses a linear-time feature as the first search round. - Added the `linclust` command to cluster using only a single linear-time search round. - Fixed compiler errors on macOS. - Fixed a bug that caused invalid alignment traceback output for the DAA `view` workflow. - Added the `merge-daa` workflow to merge DAA files. - Fixed an error when using the `--max-target-seqs/-k` option for the DAA `view` workflow. - Removed AVX2 support from the Windows release binary to ensure compatibility with older systems. - Permitted the `--ignore-warnings` option for the `cluster` and `deepclust` workflows. - Use unlinked temporary files for database blocks in clustering workflows. - Fixed a bug that could cause invalid results when using a clustering step with linearization as the final round in combination with database processing in multiple super blocks. - The `--lin-stage1` option can now be used without compilation using the `-DEXTRA=ON` cmake option. - Added the option to specify the `_lin` suffix for sensitivity keywords for the `--iterate` option to activate linear-time feature. - Added the option `--linsearch` to activate linear-time feature for the search workflows. - Fixed a bug that caused the `ppos` and `positive` output fields not to work for the `realign` workflow. - Fixed an issue that caused motif masking not to work when compiled with link time optimization. [2.1.1] - Fixed compilation errors on non-x86 systems and for the clang compiler. - Fixed an error message when running the `recluster` workflow. - Fixed a bug that could cause an `invalid varint encoding` error when using the DAA format. - Fixed a bug that could cause corrupted DAA output. - Fixed a bug that caused an error in the `view` workflow. - Adjusted the hit culling heuristic of the frameshift alignment mode to be less aggressive. [2.1.0] - Added the `cluster` workflow to cluster protein sequences. - Added the `realign` workflow to generate clustering output. - Added the `recluster` workflow to correct errors in clusterings. - Added the `reassign` workflow to reassign cluster members to their closest centroid. - Added the option `-M/--memory-limit` to set a memory limit for clustering workflows. - Added the `--approx-id` option to filter alignments by approximate sequence identity and to set an approximate sequence identity threshold for clustering. - Added the `--member-cover` option to set the coverage threshold of the cluster member sequence. - Added the `--cluster-steps` option to set steps for cascaded clustering. - Added the `--clusters` option to specify clustering input file. - The `blastx` mode will now mask any open reading frame below the minimum required length as specified by `--min-orf`. - The `blastx` mode will only count unmasked letters towards the block size. - Fixed a bug that caused an error when using the global ranking mode. - Added the fast mode as the first round in iterative searches. - Fixed a bug that caused the program not to function on systems without support for SSE4.1. - Improved multi-threaded load balancing of gapped extension computations. - Improved performance of seed extension stage when HSP filter settings are used. - Added the option `--soft-masking` with possible values `0` and `tantan` to permit soft-masking using the tantan algorithm. - Fixed a bug that could cause an `inflate error` in multiprocessing mode. - Added the option `--swipe` to compute full Smith Waterman alignments of all queries against all targets. - Added the sensitivity mode `--faster`. - Added the output fields `approx_pident` and `corrected_bitscore` to the tabular format. - Added the `--lin-stage1` option to linearize comparisons in the seeding stage by only considering hits against the longest query sequence for identical seeds (only supported when compiled with `-DEXTRA=ON`). - Added the `--kmer-ranking` option to rank sequences when `--lin-stage1` is used (only supported when compiled with `-DKEEP_TARGET_ID=ON`). - Added the option `--no-block-size-limit` to deactivate upper limits for the block size when the `--memory-limit` option is used. - Added the `greedy-vertex-cover` workflow to compute clustering based on alignments. - Added the `--edge-format` option to set edge format for greedy vertex cover. - Added the `--edges` option to set input file for greedy vertex cover. - Added the `--centroid-out` option to output centroid sequences for greedy vertex cover. - Added the `--unaligned-targets` option to generate an output file of unaligned targets. - Fixed an issue that failed compilation using the Intel Compiler. - Fixed an issue that could cause a segmentation fault in rare cases. - The `--header` option can now be used with the parameter `simple` to enable simple headers for the tabular format, or without a parameter to enable headers for the clustering format. - Added the option `--mp-self` to optimize self-alignment in multiprocessing mode. - Added the option `--query-or-subject-cover` to report alignments if the query or the subject cover (or both) are above the given threshold. - Removed support for the `--comp-based-stats 2` option (now equivalent to `--comp-based-stats 3`). - Removed hit culling in case of overlapping target ranges in frameshift alignment mode. - Added the option `--anchored-swipe` to activate anchored SWIPE extension. [2.0.15] - Fixed a bug (present since v2.0.12) that caused the `diamond view` workflow to report a zero bit score for all alignments. [2.0.14] - Fixed a compiler error on Linux systems that do not define `_SC_LEVEL3_CACHE_SIZE`. - Fixed an error when using `--unal 1` with the `cigar` output field. - Fixed an `illegal instruction` error on systems that did not support AVX2. - Fixed a bug (present since v2.0.12) that could cause an error or suboptimal alignments when HSP filter settings were used. [2.0.13] - Fixed a bug that caused invalid bit scores in frameshift alignment mode. [2.0.12] - Fixed an error when using HSP filter settings together with a BLAST database. - Optimized the performance of alignment traceback. - A non-default setting of `--max-hsps` will now recompute a full-matrix Smith Waterman alignment with the ranges of the known HSPs masked in the target. - A non-default setting for `--max-hsps` can now be used together with `--ext full`. - The sensitivity levels used for iterated searches can now be manually set by using a space-separated list after the `--iterate` option. - Seeds are masked based on complexity instead of frequency by default. - Added the option `--seed-cut` to set a complexity cutoff for indexed seeds. - Added the option `--freq-masking` to enable masking seeds based on frequency. - The fast, default, mid-sensitive and sensitive modes will by default softmask a fixed set of highly abundant sequence motifs. - Added the option `--motif-masking (0,1)` to enable or disable motif masking. - Added the option `--masking seg` to enable SEG masking of target sequences (BLAST default) instead of tantan masking. - Fixed a bug that caused the `full_sseq` output field to contain invalid information or to produce an error when using a BLAST database. - Changed composition based statistics to use BLOSUM62 background frequencies. - Fixed the zstd dependency in the Dockerfile. - Added support for gap letters in BLAST databases. - Fixed a bug that caused the `--custom-matrix` option not to function correctly. - Changed the overlap for merging adjoining bands to >0.0. - Use more moderate filtering of HPSs in the chaining stage. [2.0.11] - Fixed a bug that could cause invalid output when using `--masking 0` combined with the global ranking mode. - Enabled lazy repeat masking in the query-indexed and contiguous seed modes when using global ranking. - Added detection of cache size to auto-enable query-indexed mode. [2.0.10] - Using BLAST databases now requires a preprocessing step using the command `prepdb`. - Improved performance of searching small query files. - Added "iterative" search mode (option `--iterate`) to search the query dataset with increasing sensitivity, only searching queries at the target sensitivity that fail to align at a lower sensitivity search. - Added the "global ranking" mode (option `-g`) to set a limit on the number of Smith Waterman extensions per query, with the target sequences ranked by their ungapped extension scores. - Added the `--fast` sensitivity mode that is faster and less sensitive than the default mode. - Reduced the time for loading target sequences from BLAST databases. - Added the contiguous-seed mode (option `--algo ctg`) to improve performance for small query files. - Added support for using `--comp-based-stats (3,4)` in combination with `--ext full`. - Fixed a bug that could cause a `Traceback error` when using `--comp-based-stats (3,4)` in rare cases. - Changed the `full_sseq` output field to always contain unmasked sequences. - Fixed an issue that could cause target output order to be nondeterministic in case of identically scoring hits. - Added support for reading zstd-compressed input files (auto-detected) and writing zstd-compressed output files (option `--compress zstd`) (requires compilation using `cmake -DWITH_ZSTD=ON`). - Compilation with BLAST database support requires the zstd library. - Added error message when reading protein sequences from FASTA files that only contain DNA letters (can be disabled using `--ignore-warnings`). [2.0.9] - Reduced the memory use of database building with taxonomy mapping. - Removed the limitation of sequence accession length. - Fixed a bug that could cause using a BLAST database not to function correctly. - Added support for using BLAST alias databases (created by `blastdb_aliastool`). - Reduced the memory use of the seed hit sorting stage. - Improved the consistency of results when running in query-indexed mode (`--algo 1`). - Added the option `--skip-missing-seqids` to ignore cases of missing sequences in the database when using the `--seqidlist` option. - The `--min-orf` parameter now defaults to 1 in frameshift alignment mode. [2.0.8] - Added support for using BLAST database files instead of the Diamond-formatted `.dmnd` files. - Added the option `--seqidlist` to filter the database by sequence accession (only supported for BLAST databases). - Fixed a bug that caused the `--dbsize` option not to function correctly. - Added the command `makeidx` and the option `--target-indexed` that provide an optimisation specialized for small databases (<10 Mb). - Added the option `--mp-recover` to recover aborted runs in multiprocessing mode. [2.0.7] - Added support for computing full-matrix instead of banded Smith Waterman extensions (command line option `--ext full`). - Added support for the new `prot.accession2taxid.FULL.gz` taxonomy mapping file from NCBI. - Added the option `--gapped-filter-evalue` to set the e-value threshold of the gapped filter heuristic. - Added setting the scores of the mask letter according to BLAST rules when a compositionally adjusted matrix is used. - Changed formatting of e-values to print two decimals instead of one. - Added the output field `qseq_translated` to print the translation of the aligned part of the query sequence. - Added support for providing two input files to `--query/-q` when running alignment in blastx mode. - Added the output field `full_qseq_mate` to print the sequence of the query's mate (enabled when using two query files in blastx mode). - Fixed a bug that could cause a crash in blastx mode for very long queries. [2.0.6] - Changed the computation of expected values to use the method described in Park, Y., Sheetlin, S., Ma, N. et al. New finite-size correction for local alignment score distributions. *BMC Res Notes* **5**, 286 (2012). - Enabled the use of a custom scoring matrix without having to specify the statistical parameters (option `--custom-matrix`). - Added support for compositional matrix adjust as described in Yi-Kuo Yu, Stephen F. Altschul, The construction of amino acid substitution matrices for the comparison of proteins with non-standard compositions, *Bioinformatics*, Volume 21, Issue 7, 1 April 2005, Pages 902–911. Three additional modes have been added that can be enabled by setting `--comp-based-stats (2,3,4)` (*the feature is not enabled by default and does not support translated searches at the moment*). - Fixed a bug that could cause incorrect alignment coordinates, gaps counts and sequence identities being reported by `diamond view`. - Targets are sorted by bit score instead of e-value in the alignment output when the `--top` parameter is used. - Disabled support of custom scoring matrices for the DAA format. - Fixed a bug that caused the use of a custom scoring matrix not to function correctly. - Fixed an issue that caused the portable binary not to function on systems that did not support AVX. - Added the option `--no-unlink` to prevent unlinking of temporary files. [2.0.5] - Fixed an issue that could cause high memory use in frameshift alignment mode. [2.0.4] - Fixed a bug that could cause the `--max-target-seqs/-k`, `--ext-chunk-size` and `--file-buffer-size` options not to function correctly on macOS. [2.0.3] - Added a new sensitivity mode that is between the default mode and the sensitive mode in sensitivity (option `--mid-sensitive`). - Added counters for total number of reference blocks, shapes and index chunks to the status messages. - Fixed a bug (persisting since v2.0.2) that could cause secondary HSPs within one target not to be reported if the `--max-hsps` option was used with a non-default setting. - Fixed a bug that could cause an invalid error message with regard to the database format in certain cases. - The `--no-self-hits` option is no longer supported in `blastx` mode. - Changed the semantics of the `--no-self-hits` option to check for equality of both sequence and sequence id, independent of the computed alignment. - The selection of the top hit when using `--top` will respect the identity, coverage and no-self-hits filter settings (does not apply when frameshift alignment is enabled). - The inclusion criterion for `--top` is applied to the bit score instead of the raw score and is no longer affected by integer rounding (does not apply when frameshift alignment is enabled). - Improved the accuracy of the ranking heuristic. - Added the options `--ext-chunk-size` and `--no-ranking` to control the ranking heuristic. [2.0.2] - Fixed a bug (persisting since v2.0.0) that could cause incomplete results in `blastx` mode. - Reduced the use of temporary disk space. - Fixed an issue that could cause long runtimes when using the `--taxon-list` option. [2.0.1] - Added feature for using the tool in a distributed computing environment. - Fixed an issue that could cause increased memory usage and runtimes for very long queries. - Fixed a bug that could cause a crash when using `--comp-based-stats 0`. - Fixed a bug that could cause a crash for small input files in certain cases. - Fixed a bug that could cause filtering hits for identity or range cover not to function correctly when using the tabular format without traceback being enabled. - Added warning messages to recommend block size parameters based on system RAM. [2.0.0] - Added the sensitivity modes `--very-sensitive` and `--ultra-sensitive`. - The `--block-size`/`-b` parameter is set to 0.4 and the `--index-chunks`/`-c` parameter is set to 1 by default in the new sensitivity modes. - Improved performance. - Added the option `--ext` with possible values `banded-fast` and `banded-slow` to adjust band setup for Smith Waterman extensions (new default is `banded-fast` for the default and sensitive mode, and `banded-slow` otherwise). - Added automatic disabling of alignment traceback if not required by the user-defined output fields in tabular output format. - Changed the default value of the `--max-hsps` parameter to 1. - Changed the default value of the `--freq-sd` parameter from 10 to 20 for the sensitive mode. - Fixed a compiler error on FreeBSD. [0.9.36] - Fixed a bug that could cause `makedb` to produce invalid database files when using taxonomy features. - Fixed a bug that could cause a crash when running in query-indexed mode. [0.9.35] - Fixed a bug in `diamond view` that would cause high memory usage and erroneous output. - Reduced the use of temporary disk space. - Fixed a database compatibility issue with big endian architectures. - Fixed a bug that would cause a crash for query sequences shorter than 5 letters in blastx mode. - Fixed a bug that would cause a crash when using a FASTA file as database parameter in blastx mode. - Added support for the following new ranks in the NCBI taxonomy: biotype, clade, forma specialis, genotype, isolate, morph, pathogroup, serogroup, serotype, strain, subvariety. [0.9.34] - Fixed a compiler error for native builds. - Fixed a compiler error for GCC 4.8. - Fixed a compiler error when support for SSSE3 was enabled without support for SSE4.1. - Implemented asynchronous loading of seed hits. [0.9.33] - Improved performance and sensitivity. - Increased use of temporary disk space. - Implemented support for the AVX2 instruction set. - Fixed a bug on big-endian architectures. - Fixed bugs for compilers with unsigned char. - Fixed compiler errors for generic builds. - Added compatibility of database files between little and big endian architectures. - Fixed various issues related to `Illegal instruction` errors on macOS. - Added option `--file-buffer-size` to set the size of the I/O buffers and set the default value to 64 MB. [0.9.32] - Fixed a bug that would generate an incorrect count of positive scoring letters in all output formats. - Fixed a compiler error on macOS. - Fixed an `illegal instruction` error on macOS. [0.9.31] - Improved performance. - Composition based statistics use integer scoring. - Option `--quiet` will suppress startup message. - Added output field `scovhsp` to print the subject coverage per HSP to the tabular format. - Added option `--culling-overlap` to set the minimum overlap with a higher scoring hit for a hit to be deleted and changed the default value from 90% to 50%. - Added command `diamond test` to run a series of regression tests. - Fixed an off-by-one error of the query end position in the XML output format. - (Update 2020/06/08) Due to a bug, since this version DAA files are not backward compatible with previous versions when using frameshift alignment (option `-F`). [0.9.30] - Added support for output field `cigar` to the tabular format. - Changed the maximum repeat period to 50 for tantan masking. - Changed the tantan masking to ungapped mode. - Improved the performance of repeat masking. - Added output fields sskingdoms, skingdoms, and sphylums to print subject super kingdoms, subject kingdoms, and subject phylums. [0.9.29] - Fixed a bug that could cause taxonomy features to function incorrectly for databases created by versions 0.9.27 and 0.9.28. [0.9.28] - Fixed a bug that could cause alignment score overflows for scores > 65535 in frameshift alignment mode. - Fixed a clang compiler error. [0.9.27] - Improved performance of the seed matching stage. - Seed frequency counts are computed based on hit seeds. - Added option `--taxon-exclude` to exclude list of taxon ids from search. - Compiling from source will no longer perform a native build. Instead, a portable binary that contains code paths for multiple architectures will be produced, with dispatch logic that is invoked at runtime. [0.9.26] - Fixed a bug that could cause undefined behaviour when using a database file of format version < 2. - Fixed a compiler error when compiled as generic C++. - Program will no longer terminate with an error if unlink system call fails. - Added option `--tantan-minMaskProb` to set minimum repeat probability for tantan masking and changed the default value to 0.9. - Added option `--tantan-maxRepeatOffset` to set maximum tandem repeat period to consider and changed the default value to 15. - Added option `--tantan-ungapped` to use tantan in ungapped mode and changed the default to gapped mode. - Changed score matrix lambda calculation for tantan masking. - Reference masking is recomputed during alignment runs. [0.9.25] - Added support for the `sscinames` output field to print subject scientific names to the tabular output format. - Fixed a compiler error for GCC 8.2. - Added option `--stop-match-score` to set the match score of stop codons. - Fixed a bug that caused the `qqual` output field to not be correctly clipped to the aligned part of the query. - Added output fields `qseq_gapped` and `sseq_gapped` to the tabular format. - Raised compiler requirement to GCC 4.8. - Fixed a bug that caused the final sequence positions to not be printed in the pairwise format. - Allow using `--min-score` instead of `--top` for the LCA computation of the taxonomy output format. - Reduced the number of temporary files. - Added output field `qstrand` to the tabular format. - Database format version changed to 3. - Fixed a bug in the `--range-culling` mode that could cause undefined behaviour. [0.9.24] - Fixed a compiler error on macOS. - Added --header option to output header for tabular output format. - The quality string output in tabular format (qqual field) is clipped to the aligned part of the query. - Print '*' as quality string if quality values are not available in tabular output format. - Added field 'full_qqual' to print unclipped query quality values to the tabular format. - Added field 'full_qseq' to print unclipped query sequence to the tabular format. - Added support for using the hyphen character '-' to denote the standard input for input file parameters. - Status messages are written to stderr. - Fixed a bug that could incorrectly report queries as unaligned in the output of the --un option. - Added option '--al' to write aligned queries to file. - Added options '--alfmt' and '--unfmt' to set the format of the aligned/unaligned query file (supported values: fasta, fastq). [0.9.23] - Fixed an issue that could cause too high memory usage. - Added output field 'qqual' to print query FASTQ quality values to the tabular format. - Changed license to GPL. - Raised compiler requirement to GCC 4.6. - Added option to use the DAA output format for diamond view. - Added support for using a FASTA file as the --db parameter in alignment workflows. - Added CL (command line) and VN (version) fields to the @PG SAM format header line. - Fixed a performance issue for very long query sequences. - Added shortcut --long-reads for --range-culling --top 10 -F 15. [0.9.22] - Added output field full_sseq to tabular output format. - Database sequences that exceed the maximum accession length will no longer cause an error. - Added support for PAF output format. - Optimized performance of database taxonomy filtering. [0.9.21] - Fixed compiler errors on some systems. [0.9.20] - Added Bioconda installation instructions to manual. - Added official docker release: https://hub.docker.com/r/buchfink/diamond/ - Fixed a bug that could cause corrupted output if compression was activated. - Fixed an issue that could cause high memory usage by automatic use of the query-indexed algorithm. [0.9.19] - Fixed a bug in the --un function to write unaligned reads. - Fixed an issue in the LCA algorithm that could cause an assignment to a higher node. - --taxonmap and --taxonnodes parameters now apply exclusively to the makedb command. - Added option --taxonlist to filter searches by subject taxonomic id. - Changed database format; rebuilding is required. [0.9.18] - Optimized output writing performance. - Fixed a bug in the XML output format. [0.9.17] - Fixed a compiler error on FreeBSD. - Added option --range-culling. - Fixed escape sequences in XML output. [0.9.16] - Fixed a bug that caused an error for non-SSSE3 builds. [0.9.15] - Improved performance of frameshift alignment mode. [0.9.14] - Added support for frameshift alignments. [0.9.13] - Fixed query positions in pairwise format for translated searches. - Changed default behaviour of --max-hsps option to report unlimited number of HSPs. [0.9.12] - Fixed dbinfo command to be able to read older database formats. - Adjusted XML format for better compatibility with Blast2Go. - Fixed a potential error when running multiple instances of Diamond. [0.9.11] - Added option --xml-blord-format for alternative-style XML format. - Fixed a bug that could cause a crash when writing compressed output files. [0.9.10] - added --strand option to choose query strand - added dbinfo command [0.9.9] - Added taxonomic classification format. - Fixed a bug in getseq printing masked residues. - Fixed parsing of UniRef100_ sequence id prefixes. - Added support for using the staxids output field in diamond view. [0.9.8] - Fixed a compiler error. [0.9.7] - Fixed compiler errors. - Changed XML format to print accessions in the Hit_id and Hit_accession fields. [0.9.6] - Fixed compiler errors. [0.9.5] - Added support for named pipes. - Added support for reading input files from stdin. - Added more elaborate file I/O error messages. [0.9.4] - Improved performance. - Fixed a bug in the query-indexed algorithm. - Empty sequences are ignored instead of generating an error. [0.9.3] - Fixed a bug that could cause hanging. - Fixed a bug that could cause an error when using the staxids output field and the --unal option. [0.9.2] - Fixed a compiler error. - Improved performance for very small query files. [0.9.1] - fixed a performance issue [0.9.0] - improved performance - improved support for alignments with long gaps - removed SEG masking - added low complexity masking using tantan - changed license to AGPL [0.8.38] - fixed std::exception error messages - fixed sequence titles in XML format - XML and pairwise format contain full length titles by default [0.8.37] - fixed a bug that would cause an error message for empty DAA files - all scoring matrices use the respective default gap penalties from BLAST - added check for SSSE3 instruction set - added diamond-sse2 to the binary package - added staxids field to the tabular format [0.8.36] - fixed a compiler error [0.8.35] - added a check to detect incomplete database files - database files will be deleted in case database building fails - fixed a compiler error on 32 bit systems [0.8.34] - fixed a compiler error [0.8.33] - modified option --no-self-hits to also require matching sequence titles for filtering of a self hit - fixed a bug that could cause a crash in the `joining output blocks` stage [0.8.32] - improved speed and sensitivity - fixed an issue that could cause too high memory usage in certain cases [0.8.31] - renamed option --run-len to --min-orf - added compositional score adjustments (option --comp-based-stats (0,1), enabled by default) - removed --single-domain option and replaced by --max-hsps - added option --no-self-hits [0.8.30] - slightly improved sensitivity - added option to report unaligned queries (--unal) - pairwise, XML and SAM format will report unaligned queries by default - added option to filter alignments by subject cover (--subject-cover) [0.8.29] - fixed an issue that could cause a crash when using view on incomplete DAA files [0.8.28] - slightly improved sensitivity - added support for the BLAST pairwise format (option -f 0) [0.8.27] - added support for gzip compressed files containing multiple gzip streams [0.8.26] - fixed a compiler error - now compiles as generic C++ code without SSE being available - added option to write unaligned queries to file (--un) [0.8.25] - fixed a bug with the qseq field in the blast tabular format - added qtitle and btop fields to the blast tabular format - fixed a bug that could cause a crash when passing a nonexistant input file - fixed an issue that could cause unexpectedly long runtimes in certain cases [0.8.24] - error messages when reading sequence files include line numbers [0.8.23] - added option to change the genetic code used for translation in blastx mode [0.8.22] - the Hit_id and Hit_accession fields are now filled for the BLAST XML format [0.8.21] - fixed an error of 'diamond view' when using a custom scoring matrix [0.8.20] - added support for customizing the BLAST tabular output format [0.8.19] - ungapped xdrop score and ungapped and gapped filter scores are now set in bits - added support for custom scoring matrices [0.8.18] - fixed a crash bug - implemented getseq command to retrieve sequences from database files [0.8.17] - slightly improved sensitivity of fast and sensitive mode - added new alignment mode (option --more-sensitive) - the scoring matrix parameter will accept upper case spelling [0.8.16] - optimized performance [0.8.15] - fixed a compiler error on Mac - fixed a crash on some systems [0.8.14] - fixed a memory leak [0.8.13] - fixed a compiler error for GCC 4.1 and 4.2 [0.8.12] - changed database format - block size parameter is set only for the alignment commands - the program will accept databases created by later versions if the format is compatible - improved sensitivity of sensitive mode with some loss in performance [0.8.11] - fixed a compiler error [0.8.10] - added option to directly generate all output formats - fixed some GCC 6.1 compiler errors [0.8.9] - optimized performance - improved local alignment accuracy - fixed some fields in the XML format [0.8.8] - fixed a clang compiler error [0.8.7] - added support for BLAST XML format - fixed the gzip compressed output option [0.8.6] - fixed a problem of the Windows version that could cause errors for larger files - optimized performance [0.8.5] - optimized performance [0.8.4] - fixed a problem that could cause very long runtimes for highly repetitive sequences - optimized performance - fixed a bug that could cause too high memory usage in blastp mode [0.8.3] - fixed a problem that could sometimes cause alignments to be missed - suppressed reporting of alignments that are enveloped by better alignments [0.8.2] - use parameter -k0 to report unlimited number of alignments - fixed a crash bug on Mac OS X - fixed a crash when view was used with terminal output [0.8.1] - added option to disable auto appending of DAA and DMND file extensions (--no-auto-append) - fixed some compiler errors for GCC 4.6 [0.8.0] - fixed a bug that would sometimes cause alignments to be missed - fixed a bug that would cause alignments on the reverse strand to be missed in blastx mode - temporary directory now defaults to output directory - removed dependency on Boost - fixed a bug that would cause stop codons to be translated into 'X' [0.7.12] - fixed header string in SAM output to correctly identify the blastp alignment mode - added option to filter alignments for a given query cover (option --query-cover) - added option to print full subject titles in output files (option --salltitles) [0.7.11] - added --version switch - added static build option for CMake build - fixed a bug that would cause a return code of 1 without an error [0.7.10] - --log option works on OS X - added option to set effective database size (--dbsize) - added CMake build option - fixed a Clang compiler warning - dash characters (-) are ignored (treated as X) in protein sequences [0.7.9] - added --single-domain option - fixed a bug that could cause the program not to use all available threads - optimized performance [0.7.8] - fixed a bug that could produce an incorrect sort order of HSPs [0.7.7] - fixed a number formatting error in the SAM output format [0.7.6] - fixed a formatting error in CIGAR strings [0.7.5] - fixed a compiler error for Clang - compiles on OS X - fixed a bug that would not produce the correct sort order for HSPs with e-value 0 - option --run-len defaults to 1 for sequences shorter than 30 letters [0.7.4] - removed OpenMP dependency - using explicit Makefile instead of autoconf - file extensions can be named explicitly for DAA and database files - HSPs are grouped by target sequence - fixed a bug that could produce incorrect output for view - fixed a bug that could report an incorrect number of alignments - fixed a compiler error for GCC 4.1.2 [0.7.3] - changed database format (makedb required) - optimized multithreading load balancing - removed a non-determinism in alignment computation - IUPAC nucleotide ambiguity codes in DNA sequences are accepted and converted into N's - SEG masking is disabled by default for blastp mode - fixed a memory leak - reduced database file sizes [0.7.2] - fixed a bug that could create invalid DAA files when using the --id option - added integrity check of DAA files to view command - fixed a bug that could cause segmentation fault or file seek errors [0.7.1] - fixed a race condition for opening temporary files - temporary files are deleted on ungraceful termination of the program - blank lines in FASTA files are tolerated - fixed a compiler error for GCC 4.4.7 - view command can write to standard output [0.7.0] - introduced DAA format - reduced usage of temporary disk space and memory - fixed a compiler error for GCC 4.1.2 - fixed a bug that could cause the program to hang when running out of temporary space or memory - added --forwardonly option to view command bbuchfink-diamond-08b3cbc/src/align/000077500000000000000000000000001506104011400174155ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/align/align.cpp000066400000000000000000000244141506104011400212200ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "basic/value.h" #include "align.h" #include "output/output_format.h" #include "output/output.h" #include "legacy/pipeline.h" #include "search/hit_buffer.h" #include "util/parallel/thread_pool.h" #include "extend.h" #include "util/util.h" //#include "util/sort/sort.h" #ifdef WITH_DNA #include "../dna/extension.h" #endif #include "util/util.h" #define _REENTRANT #include "ips4o/ips4o.hpp" #include "data/queries.h" #include "data/sequence_file.h" #include "search/hit_buffer.h" using std::get; using std::tuple; using std::unique_ptr; using std::thread; using std::lock_guard; using std::mutex; using std::pair; using std::vector; DpStat dp_stat; static vector make_partition(Search::Hit* begin, Search::Hit* end) { vector partition; partition.reserve(div_up(end - begin, (ptrdiff_t)config.min_task_trace_pts) + 1); Search::Hit* p = begin; partition.push_back(0); const BlockId c = align_mode.query_contexts; while (p < end) { Search::Hit* q = std::min(p + config.min_task_trace_pts, end - 1); const BlockId query = q->query_ / c; do { ++q; } while (q < end && q->query_ / c == query); partition.push_back(q - begin); p = q; } return partition; } struct HitIterator { static bool single_query() { return config.swipe_all || align_mode.mode == AlignMode::blastn; } HitIterator(BlockId qbegin, BlockId qend, Search::Hit* begin, Search::Hit* end, vector::const_iterator partition, int64_t parts): partition(partition), parts(parts), data(begin), query_begin(qbegin), query_end(qend) {} struct Hits { BlockId query; Search::Hit* begin, * end; }; vector fetch(int64_t i) { vector r; if (single_query()) { r.push_back(Hits{ (BlockId)i,nullptr,nullptr }); return r; } assert(i >= 0 && i < parts); const BlockId c = align_mode.query_contexts; Search::Hit* begin = data + partition[i], * end = data + partition[i + 1]; BlockId last_query = begin > data ? (begin - 1)->query_/c + 1 : query_begin; const int64_t query_count = (end - 1)->query_/c + 1 - last_query; r.reserve(query_count); for (; last_query < begin->query_/c; ++last_query) r.push_back(Hits{ last_query, nullptr,nullptr }); auto it = merge_keys(begin, end, [c](const Search::Hit& h) { return h.query_/c; }); while (it.good()) { for (; last_query < it.key(); ++last_query) r.push_back(Hits{ last_query, nullptr,nullptr }); r.push_back(Hits{ (BlockId)it.key(), it.begin(), it.end() }); ++it; ++last_query; } if (i == parts - 1) { r.reserve(r.size() + query_end - (r.back().query + 1)); for (BlockId j = r.back().query + 1; j < query_end; ++j) r.push_back(Hits{ j, nullptr,nullptr }); } return r; } const vector::const_iterator partition; const int64_t parts; Search::Hit* data; const BlockId query_begin, query_end; }; static TextBuffer* legacy_pipeline(const HitIterator::Hits& hits, Search::Config& cfg, Statistics &stat) { if (hits.end == hits.begin) { TextBuffer *buf = nullptr; if (!cfg.blocked_processing && *cfg.output_format != OutputFormat::daa && cfg.output_format->report_unaligned()) { buf = new TextBuffer; Output::Info info{ cfg.query->seq_info(hits.query), true, cfg.db.get(), *buf, Util::Seq::AccessionParsing(), cfg.db->sequence_count(), cfg.db->letters() }; cfg.output_format->print_query_intro(info); cfg.output_format->print_query_epilog(info); } return buf; } QueryMapper *mapper = new ExtensionPipeline::BandedSwipe::Pipeline(hits.query, hits.begin, hits.end, dp_stat, cfg); TaskTimer timer("Initializing mapper", UINT_MAX); mapper->init(); timer.finish(); mapper->run(stat, cfg); timer.go("Generating output"); TextBuffer *buf = nullptr; if (*cfg.output_format != OutputFormat::null) { buf = new TextBuffer; const bool aligned = mapper->generate_output(*buf, stat, cfg); if (aligned && cfg.track_aligned_queries) { query_aligned_mtx.lock(); if (!query_aligned[hits.query]) { query_aligned[hits.query] = true; ++cfg.iteration_query_aligned; } query_aligned_mtx.unlock(); } } delete mapper; return buf; } static void align_worker(HitIterator* hit_it, Search::Config* cfg, int64_t next) { try { std::pmr::monotonic_buffer_resource pool; const vector hits = hit_it->fetch(next); assert(!hits.empty()); Statistics stat; DpStat dp_stat; const bool parallel = config.swipe_all && (cfg->target->seqs().size() >= cfg->query->seqs().size()); for (auto h = hits.cbegin(); h < hits.cend(); ++h) { if (config.frame_shift != 0) { TextBuffer* buf = legacy_pipeline(*h, *cfg, stat); output_sink->push(h->query, buf); continue; } if (h->begin == nullptr && !HitIterator::single_query()) { output_sink->push(h->query, nullptr); continue; } vector matches = #ifdef WITH_DNA align_mode.mode == AlignMode::blastn ? Dna::extend(*cfg, cfg->query->seqs()[h->query]) : #endif Extension::extend(h->query, h->begin, h->end, *cfg, stat, parallel ? DP::Flags::PARALLEL : DP::Flags::NONE, pool); TextBuffer* buf = cfg->blocked_processing ? Extension::generate_intermediate_output(matches, h->query, *cfg) : Extension::generate_output(matches, h->query, stat, *cfg); if (!matches.empty() && cfg->track_aligned_queries) { std::lock_guard lock(query_aligned_mtx); if (!query_aligned[h->query]) { query_aligned[h->query] = true; ++cfg->iteration_query_aligned; } } if (!config.unaligned_targets.empty()) { lock_guard lock(cfg->aligned_targets_mtx); for (const Extension::Match &m : matches) { const OId oid = cfg->target->block_id2oid(m.target_block_id); if (!cfg->aligned_targets[oid]) cfg->aligned_targets[oid] = true; } } output_sink->push(h->query, buf); } statistics += stat; ::dp_stat += dp_stat; } catch (std::exception& e) { exit_with_error(e); } } void align_queries(Consumer* output_file, Search::Config& cfg) { const int64_t mem_limit = Util::String::interpret_number(config.memory_limit.get("16G")); pair query_range; TaskTimer timer("Allocating memory", 3); if (!cfg.blocked_processing && !cfg.iterated()) cfg.db->init_random_access(cfg.current_query_block, 0, false); int64_t res_size = cfg.query->mem_size() + cfg.target->mem_size(), last_size = 0; cfg.seed_hit_buf->alloc_buffer(); //cfg.seed_hit_buf->load(std::min(mem_limit - res_size - cfg.seed_hit_buf->bin_size(1) * (int64_t)sizeof(Search::Hit), config.trace_pt_fetch_size)); while (true) { timer.go("Loading trace points"); cfg.seed_hit_buf->load(std::min(mem_limit - res_size - cfg.seed_hit_buf->bin_size(1) * (int64_t)sizeof(Search::Hit), config.trace_pt_fetch_size)); tuple input = cfg.seed_hit_buf->retrieve(); if (get<0>(input) == nullptr) break; statistics.inc(Statistics::TIME_LOAD_SEED_HITS, timer.microseconds()); timer.finish(); Search::Hit* hit_buf = get<0>(input); const int64_t hit_count = get<1>(input); log_stream << "Processing " << hit_count << " trace points." << std::endl; res_size += hit_count * sizeof(Search::Hit); query_range = { get<2>(input), get<3>(input) }; //cfg.seed_hit_buf->load(std::min(mem_limit - res_size, config.trace_pt_fetch_size)); if (res_size + last_size > mem_limit) log_stream << "Warning: resident size (" << (res_size + last_size) << ") exceeds memory limit." << std::endl; timer.go("Sorting trace points"); #ifdef NDEBUG //sort::sort_parallel_blocked_inplace(hit_buf, hit_buf + hit_count, std::less(), config.threads_); ips4o::parallel::sort(hit_buf, hit_buf + hit_count, std::less(), config.threads_); #else std::sort(hit_buf, hit_buf + hit_count); #endif statistics.inc(Statistics::TIME_SORT_SEED_HITS, timer.microseconds()); timer.go("Computing partition"); const vector partition = make_partition(hit_buf, hit_buf + hit_count); timer.go("Computing alignments"); HitIterator hit_it(query_range.first, query_range.second, hit_buf, hit_buf + hit_count, partition.begin(), (int64_t)partition.size() - 1); OutputWriter writer{output_file, cfg.blocked_processing ? '\0' : cfg.output_format->query_separator }; output_sink.reset(new ReorderQueue(query_range.first, writer)); unique_ptr heartbeat; if (config.verbosity >= 3 && config.load_balancing == Config::query_parallel && !config.swipe_all && config.heartbeat) heartbeat.reset(new thread(heartbeat_worker, query_range.second, &cfg)); const int threads = config.load_balancing == Config::target_parallel || (config.swipe_all && (cfg.target->seqs().size() >= cfg.query->seqs().size())) ? 1 : (config.threads_align == 0 ? config.threads_ : config.threads_align); auto task = [&hit_it, &cfg](ThreadPool& tp, int64_t i) { return align_worker(&hit_it, &cfg, i); }; cfg.thread_pool.reset(config.swipe_all ? new ThreadPool(task, query_range.first, query_range.second) : new ThreadPool(task, 0, (int64_t)partition.size() - 1)); cfg.thread_pool->run(threads); cfg.thread_pool->join(); if (heartbeat) heartbeat->join(); statistics.inc(Statistics::TIME_EXT, timer.microseconds()); timer.go("Deallocating buffers"); cfg.thread_pool.reset(); output_sink.reset(); last_size = hit_count * sizeof(Search::Hit); res_size -= last_size; } statistics.max(Statistics::SEARCH_TEMP_SPACE, cfg.seed_hit_buf->total_disk_size()); timer.go("Freeing memory"); cfg.seed_hit_buf->free_buffer(); if (!cfg.blocked_processing && !cfg.iterated()) cfg.db->end_random_access(false); }bbuchfink-diamond-08b3cbc/src/align/align.h000066400000000000000000000020161506104011400206570ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "util/io/consumer.h" #include "run/config.h" void align_queries(Consumer* output_file, Search::Config &cfg);bbuchfink-diamond-08b3cbc/src/align/alt_hsp.cpp000066400000000000000000000077351506104011400215670ustar00rootroot00000000000000#include "dp/dp.h" #include "extend.h" #include "util/sequence/sequence.h" #include "stats/hauser_correction.h" using std::list; using std::array; using std::vector; namespace Extension { struct ActiveTarget { ActiveTarget(vector::iterator match, SequenceSet& dst) : match(match), active(0) { masked_seq.fill(nullptr); uint32_t active = 0; const auto l = match->seq.length(); for (const Hsp& h : match->hsp) { if (!(active & (1 << h.frame))) { dst.reserve(l); active |= 1 << h.frame; } } } ActiveTarget(const ActiveTarget& t): match(t.match), masked_seq(t.masked_seq), active(0) { for (int32_t i = 0; i < align_mode.query_contexts; ++i) if (!(t.active & (1 << i))) masked_seq[i] = nullptr; } void copy_seq(SequenceSet& dst, int64_t& i) { for (const Hsp& h : match->hsp) { if (!masked_seq[h.frame]) { dst.assign(i, match->seq.data(), match->seq.end()); masked_seq[h.frame] = dst.ptr(i++); } Letter* seq = masked_seq[h.frame]; std::fill(seq + h.subject_range.begin_, seq + h.subject_range.end_, SUPER_HARD_MASK); } } Sequence masked(int32_t context) const { return Sequence(masked_seq[context], match->seq.length()); } int32_t check_fully_masked() { int32_t n = 0; for (int32_t i = 0; i < align_mode.query_contexts; ++i) if (active & (1 << i)) { if (Util::Seq::is_fully_masked(masked(i))) active &= ~(1 << i); else ++n; } return n; } const vector::iterator match; array masked_seq; uint32_t active; }; using TargetVec = vector; static TargetVec recompute_alt_hsps(const Sequence* query_seq, const int query_source_len, const HauserCorrection* query_cb, TargetVec& targets, const HspValues v, Statistics& stats) { array dp_targets; const Loc qlen = query_seq[0].length(); for (auto it = targets.begin(); it != targets.end(); ++it) { const int64_t dp_size = (int64_t)qlen * (int64_t)it->match->seq.length(); const ::Stats::TargetMatrix* matrix = it->match->matrix.get(); const int bin = DP::BandedSwipe::bin(v, qlen, 0, 0, dp_size, matrix ? matrix->score_width() : 0, 0); for (int32_t context = 0; context < align_mode.query_contexts; ++context) { if (it->masked_seq[context]) { const Sequence target = it->masked(context); dp_targets[context][bin].emplace_back(target, target.length(), BlockId(it - targets.begin()), matrix); } } } for (int32_t context = 0; context < align_mode.query_contexts; ++context) { const int8_t* cbs = ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[context].int8.data() : nullptr; DP::Params params{ query_seq[context], "", Frame(context), query_source_len, cbs, DP::Flags::FULL_MATRIX, false, 0, -1, v, stats, nullptr }; list hsp = DP::BandedSwipe::swipe(dp_targets[context], params); while (!hsp.empty()) { ActiveTarget& t = targets[hsp.front().swipe_target]; list& l = t.match->hsp; l.splice(l.end(), hsp, hsp.begin()); std::fill(t.masked_seq[context] + l.back().subject_range.begin_, t.masked_seq[context] + l.back().subject_range.end_, SUPER_HARD_MASK); t.active |= 1 << context; } } TargetVec out; for (ActiveTarget& t : targets) { if (t.active) { t.match->inner_culling(); if (t.check_fully_masked() > 0 && (t.match->hsp.size() < config.max_hsps || config.max_hsps == 0)) out.emplace_back(t); } } return out; } void recompute_alt_hsps(vector::iterator begin, vector::iterator end, const Sequence* query, const int query_source_len, const HauserCorrection* query_cb, const HspValues v, Statistics& stats) { if (config.max_hsps == 1) return; TargetVec targets; targets.reserve(end - begin); SequenceSet target_seqs; for (auto i = begin; i != end; ++i) targets.emplace_back(i, target_seqs); target_seqs.finish_reserve(); int64_t i = 0; for (ActiveTarget& t : targets) t.copy_seq(target_seqs, i); while(!targets.empty()) targets = recompute_alt_hsps(query, query_source_len, query_cb, targets, v, stats); } }bbuchfink-diamond-08b3cbc/src/align/culling.cpp000066400000000000000000000165401506104011400215640ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "target.h" #include "basic/config.h" #ifdef WITH_MCL #include "contrib/mcl/recursive_parser.h" #endif #include "output/output_format.h" #include "culling.h" using std::vector; using std::list; namespace Extension { static void max_hsp_culling(list& hsps) { if (config.max_hsps > 0 && hsps.size() > config.max_hsps) hsps.resize(config.max_hsps); } static void inner_culling(list& hsps) { if (hsps.size() <= 1) return; hsps.sort(); if (config.max_hsps == 1) { hsps.resize(1); return; } const double overlap = config.inner_culling_overlap / 100.0; for (list::iterator i = hsps.begin(); i != hsps.end();) { if (i->is_enveloped_by(hsps.begin(), i, overlap)) i = hsps.erase(i); else ++i; } if (config.max_hsps > 0) max_hsp_culling(hsps); } void Target::inner_culling() { if (config.max_hsps == 1) { for (int i = 0; i < MAX_CONTEXT; ++i) if (i == best_context) { hsp[i].sort(); hsp[i].resize(1); } else hsp[i].clear(); return; } list hsps; for (int frame = 0; frame < align_mode.query_contexts; ++frame) hsps.splice(hsps.end(), hsp[frame]); Extension::inner_culling(hsps); while (!hsps.empty()) { auto& l = hsp[hsps.front().frame]; l.splice(l.end(), hsps, hsps.begin()); } } void Match::inner_culling() { Extension::inner_culling(hsp); if (!hsp.empty()) { filter_evalue = hsp.front().evalue; filter_score = hsp.front().score; } } void Match::max_hsp_culling() { Extension::max_hsp_culling(hsp); } static void sort_targets(vector& targets) { std::sort(targets.begin(), targets.end(), config.toppercent.present() ? Target::comp_score : Target::comp_evalue); } template static It output_range(const It begin, const It end, const Search::Config& cfg) { if (end <= begin) return begin; It i = begin; if (i->filter_evalue == DBL_MAX) return begin; if (config.toppercent.present()) { const double cutoff = std::max(top_cutoff_score(score_matrix.bitscore(begin->filter_score)), 1.0); while (i < end && (score_matrix.bitscore(i->filter_score) >= cutoff)) ++i; } else { i += std::min((ptrdiff_t)cfg.max_target_seqs, end - begin); while (--i > begin && i->filter_evalue == DBL_MAX); ++i; } return i; } bool append_hits(vector& targets, vector::iterator begin, vector::iterator end, bool with_culling, const Search::Config& cfg) { if (end <= begin) return false; bool new_hits = config.toppercent.blank() && (int64_t)targets.size() < cfg.max_target_seqs; bool append = !with_culling || new_hits; culling(targets, append, cfg); int max_score = 0; double min_evalue = DBL_MAX; for (auto i = begin; i < end; ++i) { max_score = std::max(max_score, i->filter_score); min_evalue = std::min(min_evalue, i->filter_evalue); } vector::const_iterator range_end = output_range(targets.begin(), targets.end(), cfg); if (targets.empty() || (config.toppercent.blank() && min_evalue <= (range_end - 1)->filter_evalue) || (config.toppercent.present() && max_score >= top_cutoff_score((range_end - 1)->filter_score))) { append = true; new_hits = true; } if(append) targets.insert(targets.end(), std::make_move_iterator(begin), std::make_move_iterator(end)); return new_hits; } bool filter_hsp(Hsp& hsp, int source_query_len, const char *query_title, int subject_len, const char* subject_title, const Sequence& query_seq, const Sequence& subject_seq, const double query_self_aln_score, const double target_self_aln_score, const OutputFormat* output_format) { bool cluster_threshold = true; #ifdef WITH_MCL if (config.cluster_threshold.present()) { HspContext context(hsp, 0, 0, TranslatedSequence(query_seq), query_title, 0, subject_len, subject_title, 0, 0, subject_seq, 0, query_self_aln_score, target_self_aln_score); RecursiveParser rp(&context, dynamic_cast(output_format)->format.c_str()); cluster_threshold = rp.evaluate() >= config.cluster_threshold; } #endif const double qcov = hsp.query_cover_percent(source_query_len), tcov = hsp.subject_cover_percent(subject_len), approx_min_id = config.approx_min_id.get(0.0); //const bool filter_uncov = std::max(hsp.query_range.begin_, source_query_len - hsp.query_range.end_) > config.uncov_cap || std::max(hsp.subject_range.begin_, subject_len - hsp.subject_range.end_) > config.uncov_cap; return !cluster_threshold || hsp.id_percent() < config.min_id || (approx_min_id > 0 && hsp.approx_id < approx_min_id) || qcov < config.query_cover || tcov < config.subject_cover //|| filter_uncov || (qcov < config.query_or_target_cover && tcov < config.query_or_target_cover) || (config.no_self_hits && query_seq == subject_seq && strcmp(query_title, subject_title) == 0); } void Match::apply_filters(int source_query_len, const char *query_title, const Sequence& query_seq, const double query_self_aln_score, const Block& targets, const OutputFormat* output_format) { const char* title = config.no_self_hits ? targets.ids()[target_block_id] : nullptr; const Sequence seq = targets.seqs()[target_block_id]; const int len = seq.length(); const double self_aln = targets.has_self_aln() ? targets.self_aln_score(target_block_id) : 0.0; for (list::iterator i = hsp.begin(); i != hsp.end();) { if (filter_hsp(*i, source_query_len, query_title, len, title, query_seq, seq, query_self_aln_score, self_aln, output_format)) i = hsp.erase(i); else ++i; } filter_evalue = hsp.empty() ? DBL_MAX : hsp.front().evalue; filter_score = hsp.empty() ? 0 : hsp.front().score; } void culling(std::vector& targets, bool sort_only, const Search::Config& cfg) { sort_targets(targets); if (!sort_only) targets.erase(output_range(targets.begin(), targets.end(), cfg), targets.end()); } void apply_filters(std::vector::iterator begin, std::vector::iterator end, int source_query_len, const char* query_title, const double query_self_aln_score, const Sequence& query_seq, const Search::Config& cfg) { if (config.min_id > 0 || config.approx_min_id.get(0.0) > 0 || config.query_cover > 0 || config.subject_cover > 0 || config.query_or_target_cover > 0 || config.no_self_hits || config.cluster_threshold.present()) for (auto i = begin; i < end; ++i) i->apply_filters(source_query_len, query_title, query_seq, query_self_aln_score, *cfg.target, cfg.output_format.get()); } void culling(std::vector& targets, const Search::Config& cfg) { std::sort(targets.begin(), targets.end(), config.toppercent.present() ? Match::cmp_score : Match::cmp_evalue); targets.erase(output_range(targets.begin(), targets.end(), cfg), targets.end()); } }bbuchfink-diamond-08b3cbc/src/align/culling.h000066400000000000000000000006031506104011400212220ustar00rootroot00000000000000#pragma once #include "basic/match.h" #include "output/output_format.h" namespace Extension { bool filter_hsp(Hsp& hsp, int source_query_len, const char *query_title, int subject_len, const char* subject_title, const Sequence& query_seq, const Sequence& subject_seq, const double query_self_aln_score, const double target_self_aln_score, const OutputFormat* output_format); }bbuchfink-diamond-08b3cbc/src/align/def.h000066400000000000000000000004431506104011400203250ustar00rootroot00000000000000#pragma once #include "dp/flags.h" namespace Extension { enum class Mode { BANDED_FAST, BANDED_SLOW, FULL, GLOBAL }; int band(int len, const Mode mode); HspValues filter_hspvalues(); } template<> struct EnumTraits { static const SEMap from_string; };bbuchfink-diamond-08b3cbc/src/align/extend.cpp000066400000000000000000000343721506104011400214210ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020-2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "extend.h" #include "data/block/block.h" #include "data/sequence_set.h" #include "data/string_set.h" #include "util/options/option.h" #include "basic/config.h" #include "stats/hauser_correction.h" #include "target.h" #include "util/log_stream.h" #include "util/util.h" #include "global_ranking/global_ranking.h" #include "search/hit.h" #include "load_hits.h" #include "def.h" using std::accumulate; using std::vector; using std::list; using std::array; using std::pair; using std::endl; using std::make_move_iterator; using std::any_of; using std::numeric_limits; using std::tie; using std::min; const SEMap EnumTraits::from_string = { { "banded-fast", Extension::Mode::BANDED_FAST}, { "banded-slow", Extension::Mode::BANDED_SLOW}, { "full", Extension::Mode::FULL}, { "global", Extension::Mode::GLOBAL} }; namespace Extension { const std::map default_ext_mode = { { Sensitivity::FASTER, Mode::BANDED_FAST}, { Sensitivity::FAST, Mode::BANDED_FAST}, { Sensitivity::SHAPES6x10, Mode::BANDED_FAST}, { Sensitivity::SHAPES30x10, Mode::BANDED_FAST}, { Sensitivity::LINCLUST_20, Mode::BANDED_FAST}, { Sensitivity::LINCLUST_40, Mode::BANDED_FAST}, { Sensitivity::DEFAULT, Mode::BANDED_FAST}, { Sensitivity::MID_SENSITIVE, Mode::BANDED_FAST}, { Sensitivity::SENSITIVE, Mode::BANDED_FAST}, { Sensitivity::MORE_SENSITIVE, Mode::BANDED_SLOW}, { Sensitivity::VERY_SENSITIVE, Mode::BANDED_SLOW}, { Sensitivity::ULTRA_SENSITIVE, Mode::BANDED_SLOW} }; constexpr int64_t MAX_CHUNK_SIZE = 400, MIN_CHUNK_SIZE = 128, MAPANY_CHUNK_SIZE = 16; int64_t ranking_chunk_size(int64_t target_count, const int64_t ref_letters, const int64_t max_target_seqs) { if (config.no_ranking || config.global_ranking_targets > 0) return target_count; if (config.ext_chunk_size > 0) return config.ext_chunk_size; if (config.mapany) return MAPANY_CHUNK_SIZE; const double default_letters = config.sensitivity >= Sensitivity::VERY_SENSITIVE ? 800 * 1e6 : 2 * 1e9; const int64_t block_mult = std::max(int64_t(std::round((double)ref_letters / default_letters)), (int64_t)1); if (config.toppercent.present()) return MIN_CHUNK_SIZE * block_mult; const int64_t size = std::max(MIN_CHUNK_SIZE, std::min(make_multiple(max_target_seqs, (int64_t)32), MAX_CHUNK_SIZE)) * block_mult; return config.target_hard_cap ? std::min(size, config.target_hard_cap) : size; } static bool have_filters(const Search::Config& cfg) { return config.min_id > 0 || config.approx_min_id.get(0.0) > 0 || config.query_cover > 0 || config.subject_cover > 0 || config.query_or_target_cover > 0; } static HspValues first_round_hspv(const Search::Config& cfg) { HspValues first_round = HspValues::NONE; if (config.min_id > 0) first_round |= HspValues::IDENT | HspValues::LENGTH; if (config.query_cover > 0) first_round |= HspValues::QUERY_COORDS; if (config.subject_cover > 0) first_round |= HspValues::TARGET_COORDS; if (config.cluster_threshold.present()) first_round |= cfg.output_format->hsp_values; return first_round; } static bool ranking_terminate(bool new_hits, int last_tail_score, int tail_score, int64_t targets_processed, int64_t targets_aligned) { if (config.target_hard_cap && targets_processed >= config.target_hard_cap) return true; if (config.mapany && config.toppercent.blank() && targets_aligned > 0) return true; return !new_hits && (last_tail_score == 0 || double(tail_score) / (double)last_tail_score <= config.ranking_score_drop_factor || score_matrix.bitscore(tail_score) < config.ranking_cutoff_bitscore); } Match Match::self_match(BlockId query_id, Sequence query_seq) { Match m(query_id, query_seq, nullptr, 0, numeric_limits::max(), 0.0); m.hsp.emplace_back(); m.hsp.back().evalue = 0.0; m.hsp.back().score = numeric_limits::max(); m.hsp.back().bit_score = DBL_MAX; m.hsp.back().query_range = { 0,query_seq.length() }; m.hsp.back().query_source_range = { 0,query_seq.length() }; m.hsp.back().subject_range = { 0,query_seq.length() }; return m; } static bool add_self_aln(const Search::Config& cfg) { return config.add_self_aln && ((config.self && cfg.current_ref_block == 0) || (!config.self && cfg.current_query_block == cfg.current_ref_block)); } static size_t lazy_masking(std::vector::const_iterator target_block_ids, vector::const_iterator target_block_ids_end, Block& targets, const MaskingAlgo algo) { if (algo == MaskingAlgo::NONE) return 0; vector seq; const Masking& masking = Masking::get(); size_t n = 0; for (auto i = target_block_ids; i != target_block_ids_end; ++i) if (targets.fetch_seq_if_unmasked(*i, seq)) { masking(seq.data(), seq.size(), algo, *i); targets.write_masked_seq(*i, seq); ++n; } return n; } static vector extend_chunk(BlockId query_id, const Sequence* query_seq, int source_query_len, const HauserCorrection* query_cb, const ::Stats::Composition& query_comp, FlatArray::Iterator seed_hits, FlatArray::Iterator seed_hits_end, vector::const_iterator target_block_ids, const Search::Config& cfg, Statistics& stat, DP::Flags flags, const HspValues hsp_values, std::pmr::monotonic_buffer_resource& pool) { static const Loc GAPPED_FILTER_MIN_QLEN = 85; const int64_t n = seed_hits_end - seed_hits; stat.inc(Statistics::TARGET_HITS2, n); TaskTimer timer(flag_any(flags, DP::Flags::PARALLEL) ? config.target_parallel_verbosity : UINT_MAX); if (cfg.lazy_masking && !config.global_ranking_targets) stat.inc(Statistics::MASKED_LAZY, lazy_masking(target_block_ids, target_block_ids + n, *cfg.target, cfg.target_masking)); pair, vector> gf; if (cfg.gapped_filter_evalue > 0.0 && config.global_ranking_targets == 0 && (!align_mode.query_translated || query_seq[0].length() >= GAPPED_FILTER_MIN_QLEN)) { timer.go("Computing gapped filter"); gf = gapped_filter(query_seq, query_cb, seed_hits, seed_hits_end, target_block_ids, stat, flags, cfg); if (!flag_any(flags, DP::Flags::PARALLEL)) stat.inc(Statistics::TIME_GAPPED_FILTER, timer.microseconds()); seed_hits = gf.first.begin(); seed_hits_end = gf.first.end(); target_block_ids = gf.second.cbegin(); } stat.inc(Statistics::TARGET_HITS3, seed_hits_end - seed_hits); timer.go("Computing chaining"); vector targets = ungapped_stage(query_seq, query_cb, query_comp, seed_hits, seed_hits_end, target_block_ids, flags, stat, *cfg.target, cfg.extension_mode, pool, cfg); if (!flag_any(flags, DP::Flags::PARALLEL)) stat.inc(Statistics::TIME_CHAINING, timer.microseconds()); auto ret = align(targets, query_seq, cfg.query->ids()[query_id], query_cb, source_query_len, flags, hsp_values, cfg.extension_mode, *cfg.thread_pool, cfg, stat, pool); return ret; } vector extend( BlockId query_id, const Search::Config& cfg, Statistics& stat, DP::Flags flags, SeedHitList& l, std::pmr::monotonic_buffer_resource& pool) { const unsigned UNIFIED_TARGET_LEN = 50; const unsigned contexts = align_mode.query_contexts; vector query_seq; vector query_cb; const char* query_title = cfg.query->ids()[query_id]; if (config.log_query || (flag_any(flags, DP::Flags::PARALLEL) && !config.swipe_all)) log_stream << "Query=" << query_title << " Hits=" << l.seed_hits.data_size() << endl; for (unsigned i = 0; i < contexts; ++i) query_seq.push_back(cfg.query->seqs()[query_id * contexts + i]); const unsigned query_len = (unsigned)query_seq.front().length(); if (::Stats::CBS::hauser(config.comp_based_stats)) { for (unsigned i = 0; i < contexts; ++i) query_cb.emplace_back(query_seq[i]); } ::Stats::Composition query_comp; if (::Stats::CBS::matrix_adjust(config.comp_based_stats)) query_comp = ::Stats::composition(query_seq[0]); const int source_query_len = align_mode.query_translated ? (int)cfg.query->source_seqs()[query_id].length() : (int)cfg.query->seqs()[query_id].length(); const double self_aln_score = cfg.query->has_self_aln() ? cfg.query->self_aln_score(query_id) : 0.0; const size_t target_count = l.target_block_ids.size(); const int64_t chunk_size = ranking_chunk_size(target_count, cfg.target->seqs().letters(), cfg.max_target_seqs); vector::const_iterator i0 = l.target_scores.cbegin(), i1 = i0 + std::min((ptrdiff_t)chunk_size, l.target_scores.cend() - i0); if (config.toppercent.blank() && config.min_bit_score == 0.0 && (i1 - i0) < cfg.max_target_seqs && (config.ext_chunk_size == 0 || config.lin_stage1)) #ifdef EVAL_TARGET while (i1 < l.target_scores.cend() && i1->evalue <= config.max_evalue && size_t(i1 - i0) < config.max_alignments) ++i1; #else while (i1 < l.target_scores.cend() && score_matrix.evalue(i1->score, query_len, UNIFIED_TARGET_LEN) <= config.max_evalue) i1 += min((ptrdiff_t)16, l.target_scores.cend() - i1); #endif const HspValues first_round_hspv = config.anchored_swipe || (config.sensitivity <= Sensitivity::SHAPES30x10 && flag_only(cfg.output_format->hsp_values, HspValues::COORDS) && config.toppercent.blank() && (size_t)cfg.max_target_seqs >= l.target_scores.size()) ? HspValues::COORDS : HspValues::NONE; const bool first_round_culling = !have_filters(cfg) || config.toppercent.present(); bool new_hits_ev = false; int tail_score = 0, previous_tail_score = 0; FlatArray seed_hits_chunk; vector target_block_ids_chunk; vector matches; do { vector aligned_targets; bool new_hits; do { const int64_t current_chunk_size = i1 - i0; const bool multi_chunk = current_chunk_size < (int64_t)l.target_scores.size(); if (multi_chunk) { target_block_ids_chunk.clear(); seed_hits_chunk.clear(); target_block_ids_chunk.reserve(i1 - i0); seed_hits_chunk.reserve(i1 - i0, accumulate(i0, i1, (int64_t)0, [&l](int64_t n, const TargetScore& s) { return l.seed_hits.count(s.target) + n; })); for (vector::const_iterator j = i0; j < i1; ++j) { target_block_ids_chunk.push_back(l.target_block_ids[j->target]); seed_hits_chunk.push_back(l.seed_hits.begin(j->target), l.seed_hits.end(j->target)); } } vector v = extend_chunk( query_id, query_seq.data(), source_query_len, query_cb.data(), query_comp, multi_chunk ? seed_hits_chunk.begin() : l.seed_hits.begin(), multi_chunk ? seed_hits_chunk.end() : l.seed_hits.end(), multi_chunk ? target_block_ids_chunk.cbegin() : l.target_block_ids.cbegin(), cfg, stat, flags, first_round_hspv, pool); stat.inc(Statistics::TARGET_HITS4, v.size()); new_hits = new_hits_ev = v.size() > 0; if (multi_chunk) new_hits = append_hits(aligned_targets, v.begin(), v.end(), first_round_culling, cfg); else aligned_targets = std::move(v); i0 = i1; i1 += std::min((ptrdiff_t)chunk_size, l.target_scores.cend() - i1); previous_tail_score = tail_score; if (new_hits) tail_score = (i1 - 1)->score; } while (i0 < l.target_scores.cend() && !ranking_terminate(new_hits, previous_tail_score, (i1 - 1)->score, i1 - l.target_scores.cbegin(), aligned_targets.size())); if (config.swipe_all) aligned_targets = full_db_align(query_seq.data(), query_cb.data(), flags, HspValues::NONE, stat, *cfg.target); culling(aligned_targets, !first_round_culling, cfg); stat.inc(Statistics::TARGET_HITS5, aligned_targets.size()); vector round_matches = align(aligned_targets, matches.size(), query_seq.data(), query_title, query_cb.data(), source_query_len, self_aln_score, flags, first_round_hspv, first_round_culling, stat, cfg); matches.insert(matches.end(), make_move_iterator(round_matches.begin()), make_move_iterator(round_matches.end())); } while (config.toppercent.blank() && (int64_t)matches.size() < config.max_target_seqs_.get(DEFAULT_MAX_TARGET_SEQS) && i0 < l.target_scores.cend() && new_hits_ev && (!config.mapany || (config.mapany && matches.empty()))); if (add_self_aln(cfg) && !any_of(matches.cbegin(), matches.cend(), [query_id](const Match& m) { return m.target_block_id == query_id; })) matches.push_back(Match::self_match(query_id, query_seq[0])); culling(matches, cfg); return matches; } vector extend(BlockId query_id, Search::Hit* begin, Search::Hit* end, const Search::Config &cfg, Statistics &stat, DP::Flags flags, std::pmr::monotonic_buffer_resource& pool) { TaskTimer timer(flag_any(flags, DP::Flags::PARALLEL) ? config.target_parallel_verbosity : UINT_MAX); timer.go("Loading seed hits"); SeedHitList l = load_hits(begin, end, cfg.target->seqs()); stat.inc(Statistics::TARGET_HITS0, l.target_block_ids.size()); stat.inc(Statistics::TIME_LOAD_HIT_TARGETS, timer.microseconds()); timer.finish(); const int64_t target_count = (int64_t)l.target_block_ids.size(); if (target_count == 0 && !config.swipe_all) { if (add_self_aln(cfg)) { vector r; Match match = Match::self_match(query_id, cfg.query->seqs()[query_id]); r.push_back(std::move(match)); return r; } return vector(); } const int64_t chunk_size = ranking_chunk_size(target_count, cfg.target->seqs().letters(), cfg.max_target_seqs); if (chunk_size < target_count || config.global_ranking_targets > 0) { timer.go("Sorting targets by score"); std::sort(l.target_scores.begin(), l.target_scores.end()); stat.inc(Statistics::TIME_SORT_TARGETS_BY_SCORE, timer.microseconds()); timer.finish(); if (config.global_ranking_targets > 0) return GlobalRanking::ranking_list(query_id, l.target_scores.begin(), l.target_scores.end(), l.target_block_ids.begin(), l.seed_hits, cfg); } vector r = extend(query_id, cfg, stat, flags, l, pool); return r; } }bbuchfink-diamond-08b3cbc/src/align/extend.h000066400000000000000000000057131506104011400210630ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "basic/match.h" #include "basic/statistics.h" #include "util/text_buffer.h" #include "run/config.h" #include "dp/flags.h" #include "stats/cbs.h" #include "basic/const.h" namespace Extension { extern const std::map default_ext_mode; struct Match { Match(const BlockId target_block_id, const Sequence& seq, std::unique_ptr<::Stats::TargetMatrix>&& matrix, Score ungapped_score, Score filter_score = 0, double filter_evalue = DBL_MAX): target_block_id(target_block_id), seq(seq), matrix(std::move(matrix)), filter_score(filter_score), filter_evalue(filter_evalue), ungapped_score(ungapped_score) {} void add_hit(std::list &list, std::list::iterator it) { hsp.splice(hsp.end(), list, it); } static bool cmp_evalue(const Match& m, const Match& n) { return m.filter_evalue < n.filter_evalue || (m.filter_evalue == n.filter_evalue && cmp_score(m, n)); } static bool cmp_score(const Match& m, const Match& n) { return m.filter_score > n.filter_score || (m.filter_score == n.filter_score && m.target_block_id < n.target_block_id); } Match(BlockId target_block_id, const Sequence& seq, std::unique_ptr<::Stats::TargetMatrix>&& matrix, std::array, MAX_CONTEXT> &hsp, int ungapped_score); static Match self_match(BlockId query_id, Sequence query_seq); void inner_culling(); void max_hsp_culling(); void apply_filters(int source_query_len, const char *query_title, const Sequence& query_seq, const double query_self_aln_score, const Block& targets, const OutputFormat* output_format); BlockId target_block_id; Sequence seq; std::unique_ptr<::Stats::TargetMatrix> matrix; int filter_score; double filter_evalue; int ungapped_score; std::list hsp; }; std::vector extend(BlockId query_id, Search::Hit* begin, Search::Hit* end, const Search::Config &cfg, Statistics &stat, DP::Flags flags, std::pmr::monotonic_buffer_resource& pool); TextBuffer* generate_output(std::vector &targets, BlockId query_block_id, Statistics &stat, const Search::Config& cfg); TextBuffer* generate_intermediate_output(const std::vector &targets, BlockId query_block_id, const Search::Config& cfg); }bbuchfink-diamond-08b3cbc/src/align/full_db.cpp000066400000000000000000000024511506104011400215320ustar00rootroot00000000000000#include #include "target.h" #include "dp/dp.h" using std::list; using std::map; using std::vector; namespace Extension { vector full_db_align(const Sequence* query_seq, const HauserCorrection* query_cb, DP::Flags flags, const HspValues hsp_values, Statistics& stat, const Block& target_block) { vector v; vector r; list hsp; const SequenceSet& ref_seqs = target_block.seqs(); for (int frame = 0; frame < align_mode.query_contexts; ++frame) { DP::Params params{ query_seq[frame], "", Frame(frame), query_seq[frame].length(), ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[frame].int8.data() : nullptr, flags | DP::Flags::FULL_MATRIX, false, ref_seqs.max_len(0, ref_seqs.size()), -1, hsp_values, stat, nullptr }; list frame_hsp = DP::BandedSwipe::swipe_set(ref_seqs.cbegin(), ref_seqs.cend(), params); hsp.splice(hsp.begin(), frame_hsp, frame_hsp.begin(), frame_hsp.end()); } map subject_idx; while (!hsp.empty()) { BlockId block_id = hsp.begin()->swipe_target; const auto it = subject_idx.emplace(block_id, (BlockId)r.size()); if (it.second) r.emplace_back(block_id, ref_seqs[block_id], 0, nullptr); BlockId i = it.first->second; r[i].add_hit(hsp, hsp.begin()); } return r; } }bbuchfink-diamond-08b3cbc/src/align/gapped_filter.cpp000066400000000000000000000106031506104011400227260ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020-2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include "target.h" #include "util/parallel/thread_pool.h" #include "dp/scan_diags.h" using std::mutex; using std::vector; using std::pair; namespace Extension { int gapped_filter(const SeedHit &hit, const LongScoreProfile *query_profile, const Sequence &target, int band, int window, std::function f) { const int slen = (int)target.length(); const int d = std::max(hit.diag() - band / 2, -(slen - 1)), j0 = std::max(hit.j - window, 0), j1 = std::min(hit.j + window, slen); int scores[128]; f(query_profile[hit.frame], target, d, j0, j1, scores); return DP::diag_alignment(scores, band); } bool gapped_filter(FlatArray::DataConstIterator begin, FlatArray::DataConstIterator end, const LongScoreProfile*query_profile, uint32_t target_block_id, Statistics &stat, const Search::Config ¶ms) { constexpr int window1 = 100, MIN_STAGE2_QLEN = 100; const int qlen = (int)query_profile->length(); const Sequence target = params.target->seqs()[target_block_id]; const int slen = (int)target.length(); for (FlatArray::DataConstIterator hit = begin; hit < end; ++hit) { stat.inc(Statistics::GAPPED_FILTER_HITS1); const int f1 = gapped_filter(*hit, query_profile, target, 64, window1, DP::scan_diags64); if (f1 > params.cutoff_gapped1_new(qlen, slen)) { stat.inc(Statistics::GAPPED_FILTER_HITS2); if (qlen < MIN_STAGE2_QLEN && align_mode.query_translated) return true; const int f2 = gapped_filter(*hit, query_profile, target, 128, config.gapped_filter_window, DP::scan_diags128); if (f2 > params.cutoff_gapped2_new(qlen, slen)) return true; } } return false; } void gapped_filter_worker(size_t i, size_t thread_id, const LongScoreProfile*query_profile, FlatArray::Iterator seed_hits, vector::const_iterator target_block_ids, FlatArray* out, vector *target_ids_out, mutex* mtx, const Search::Config *params) { thread_local Statistics stat; if (gapped_filter(seed_hits.begin(i), seed_hits.end(i), query_profile, target_block_ids[i], stat, *params)) { std::lock_guard guard(*mtx); target_ids_out->push_back(target_block_ids[i]); out->push_back(seed_hits.begin(i), seed_hits.end(i)); } } pair, vector> gapped_filter(const Sequence* query, const HauserCorrection* query_cbs, FlatArray::Iterator seed_hits, FlatArray::Iterator seed_hits_end, vector::const_iterator target_block_ids, Statistics& stat, DP::Flags flags, const Search::Config ¶ms) { const int64_t n = seed_hits_end - seed_hits; FlatArray hits_out; vector target_ids_out; if (n == 0) return make_pair(hits_out, target_ids_out); vector> query_profile; query_profile.reserve(align_mode.query_contexts); for (int i = 0; i < align_mode.query_contexts; ++i) query_profile.push_back(DP::make_profile8(query[i], ::Stats::CBS::hauser(config.comp_based_stats) ? query_cbs[i].int8.data() : nullptr, 0)); if(flag_any(flags, DP::Flags::PARALLEL)) { mutex mtx; Util::Parallel::scheduled_thread_pool_auto(config.threads_, n, gapped_filter_worker, query_profile.data(), seed_hits, target_block_ids, &hits_out, &target_ids_out, &mtx, ¶ms); } else { for (int64_t i = 0; i < n; ++i) { if (gapped_filter(seed_hits.begin(i), seed_hits.end(i), query_profile.data(), target_block_ids[i], stat, params)) { target_ids_out.push_back(target_block_ids[i]); hits_out.push_back(seed_hits.begin(i), seed_hits.end(i)); } } } return make_pair(hits_out, target_ids_out); } }bbuchfink-diamond-08b3cbc/src/align/gapped_final.cpp000066400000000000000000000126061506104011400225370ustar00rootroot00000000000000#include #include "target.h" #include "dp/dp.h" #include "output/output_format.h" #include "util/util.h" #include "def.h" using std::array; using std::list; using std::vector; namespace Extension { HspValues filter_hspvalues() { HspValues hsp_values = HspValues::NONE; if (config.max_hsps != 1) hsp_values |= HspValues::QUERY_COORDS | HspValues::TARGET_COORDS; if (config.min_id > 0) hsp_values |= HspValues::IDENT | HspValues::LENGTH; if (config.approx_min_id.get(0.0) > 0) hsp_values |= HspValues::COORDS; if (config.query_cover > 0) hsp_values |= HspValues::QUERY_COORDS; if (config.subject_cover > 0) hsp_values |= HspValues::TARGET_COORDS; if (config.query_or_target_cover > 0) hsp_values |= HspValues::COORDS; return hsp_values; } static bool first_round_filter_all(const Search::Config& cfg, HspValues first_round_hsp_values) { if (config.min_id > 0 && !flag_all(first_round_hsp_values, HspValues::IDENT | HspValues::LENGTH)) return false; if (config.approx_min_id.get(0.0) > 0 && !flag_all(first_round_hsp_values, HspValues::COORDS)) return false; if (config.query_cover > 0 && !flag_all(first_round_hsp_values, HspValues::QUERY_COORDS)) return false; if (config.subject_cover > 0 && !flag_all(first_round_hsp_values, HspValues::TARGET_COORDS)) return false; if (config.query_or_target_cover > 0 && !flag_all(first_round_hsp_values, HspValues::COORDS)) return false; return true; } static void add_dp_targets(const Target& target, int target_idx, const Sequence* query_seq, array& dp_targets, DP::Flags flags, const HspValues hsp_values, const Mode mode) { const ::Stats::TargetMatrix* matrix = target.matrix.get(); const Loc tlen = target.seq.length(); for (int frame = 0; frame < align_mode.query_contexts; ++frame) { const Loc qlen = query_seq[frame].length(); for (const Hsp& hsp : target.hsp[frame]) { const int64_t dp_size = flag_any(flags, DP::Flags::FULL_MATRIX) ? (int64_t)qlen * (int64_t)tlen : (int64_t)DpTarget::banded_cols(qlen, tlen, hsp.d_begin, hsp.d_end) * int64_t(hsp.d_end - hsp.d_begin); const int b = DP::BandedSwipe::bin(hsp_values, flag_any(flags, DP::Flags::FULL_MATRIX) ? qlen : hsp.d_end - hsp.d_begin, hsp.score, 0, dp_size, matrix ? matrix->score_width() : 0, 0); //dp_targets[frame][b].emplace_back(target.seq, tlen, hsp.d_begin, hsp.d_end, Interval(), 0, target_idx, qlen, matrix); dp_targets[frame][b].emplace_back(target.seq, tlen, hsp.d_begin, hsp.d_end, target_idx, qlen, matrix); } } } vector align(vector& targets, const int64_t previous_matches, const Sequence* query_seq, const char* query_id, const HauserCorrection* query_cb, int source_query_len, double query_self_aln_score, DP::Flags flags, const HspValues first_round, const bool first_round_culling, Statistics& stat, const Search::Config& cfg) { static const int64_t MIN_STEP = 16; vector r; if (targets.empty()) return r; HspValues hsp_values = cfg.output_format->hsp_values; const bool copy_all = config.max_hsps == 1 && flag_all(first_round, hsp_values) && first_round_filter_all(cfg, first_round); if (copy_all) r.reserve(targets.size()); for (Target& t : targets) if (copy_all || t.done) r.emplace_back(t.block_id, t.seq, std::move(t.matrix), t.hsp, t.ungapped_score); if (r.size() == targets.size()) { apply_filters(r.begin(), r.end(), source_query_len, query_id, query_self_aln_score, query_seq[0], cfg); return r; } if (cfg.extension_mode == Mode::FULL) flags |= DP::Flags::FULL_MATRIX; if (cfg.extension_mode == Mode::GLOBAL) flags |= DP::Flags::SEMI_GLOBAL; hsp_values |= filter_hspvalues(); vector::iterator it = targets.begin(); auto goon = [&r, &cfg, previous_matches]() { return config.toppercent.blank() ? ((int64_t)r.size() + previous_matches) < cfg.max_target_seqs : true; }; do { array dp_targets; const int64_t step_size = !first_round_culling && config.toppercent.blank() ? std::min(make_multiple(std::max(cfg.max_target_seqs - (int64_t)r.size(), MIN_STEP), MIN_STEP), int64_t(targets.end() - it)) : targets.size(); r.reserve(r.size() + step_size); const int64_t matches_begin = r.size(); for (auto i = it; i < it + step_size; ++i) { if (i->done) continue; add_dp_targets(*i, (int32_t)r.size(), query_seq, dp_targets, flags, hsp_values, cfg.extension_mode); r.emplace_back(i->block_id, i->seq, std::move(i->matrix), i->ungapped_score); } for (int frame = 0; frame < align_mode.query_contexts; ++frame) { if (dp_targets[frame].empty()) continue; DP::Params params{ query_seq[frame], query_id, Frame(frame), source_query_len, ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[frame].int8.data() : nullptr, flags, false, 0, -1, hsp_values, stat, cfg.thread_pool.get() }; list hsp = DP::BandedSwipe::swipe(dp_targets[frame], params); while (!hsp.empty()) r[hsp.front().swipe_target].add_hit(hsp, hsp.begin()); } for (int64_t i = matches_begin; i < (int64_t)r.size(); ++i) r[i].inner_culling(); apply_filters(r.begin() + matches_begin, r.end(), source_query_len, query_id, query_self_aln_score, query_seq[0], cfg); culling(r, cfg); stat.inc(Statistics::TARGET_HITS6, step_size); it += step_size; } while (it < targets.end() && goon()); recompute_alt_hsps(r.begin(), r.end(), query_seq, source_query_len, query_cb, hsp_values, stat); return r; } } bbuchfink-diamond-08b3cbc/src/align/gapped_score.cpp000066400000000000000000000206531506104011400225620ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "target.h" #include "dp/dp.h" #include "util/geo/interval.h" #include "def.h" #include "util/geo/geo.h" #include "stats/cbs.h" using std::vector; using std::array; using std::list; using std::map; using std::endl; using std::unique_ptr; using std::pair; using std::numeric_limits; namespace Extension { int band(int len, const Mode mode) { if (config.padding > 0) return config.padding; if (mode == Mode::BANDED_FAST) { if (len < 50) return 12; if (len < 100) return 16; if (len < 250) return 30; if (len < 350) return 40; return 64; } else { if (len < 50) return 15; if (len < 100) return 20; if (len < 150) return 30; if (len < 200) return 50; if (len < 250) return 60; if (len < 350) return 100; if (len < 500) return 120; return 150; } } static int hsp_band(int base_band, int qlen, int tlen, const ApproxHsp& hsp) { /*if (!config.classic_band) { return std::max(Loc((hsp.d_max - hsp.d_min) * 0.15), 32); }*/ if (config.narrow_band_cov == 0.0) return base_band; if ((double)hsp.query_range.length() / qlen >= config.narrow_band_cov || (double)hsp.subject_range.length() / tlen >= config.narrow_band_cov) { return (Loc)((hsp.d_max - hsp.d_min) * config.narrow_band_factor); } return base_band; } Match::Match(BlockId target_block_id, const Sequence& seq, std::unique_ptr<::Stats::TargetMatrix>&& matrix, std::array, MAX_CONTEXT>& hsps, int ungapped_score) : target_block_id(target_block_id), seq(seq), matrix(std::move(matrix)), filter_score(0), filter_evalue(DBL_MAX), ungapped_score(ungapped_score) { if (config.max_hsps != 1) throw std::runtime_error("Match::Match max_hsps != 1."); for (int i = 0; i < align_mode.query_contexts; ++i) hsp.splice(hsp.end(), hsps[i]); if (hsp.empty()) throw std::runtime_error("Match::Match hsp.empty()"); hsp.sort(); hsp.resize(1); filter_evalue = hsp.front().evalue; filter_score = hsp.front().score; } static void add_dp_targets(const WorkTarget& target, int target_idx, const Sequence* query_seq, array& dp_targets, DP::Flags flags, const HspValues hsp_values, const Mode mode, const Search::Config& cfg) { const Loc band = Extension::band(query_seq->length(), mode), slen = target.seq.length(); const ::Stats::TargetMatrix* matrix = target.matrix.get(); const unsigned score_width = matrix ? matrix->score_width() : 0; for (int frame = 0; frame < align_mode.query_contexts; ++frame) { const Loc qlen = query_seq[frame].length(); if (mode == Mode::FULL) { if (target.ungapped_score[frame] == 0) continue; const unsigned b = DP::BandedSwipe::bin(hsp_values, qlen, 0, target.ungapped_score[frame], (int64_t)qlen * (int64_t)slen, score_width, 0); //dp_targets[frame][b].emplace_back(target.seq, slen, 0, 0, Interval(), 0, target_idx, qlen, matrix); dp_targets[frame][b].emplace_back(target.seq, slen, 0, 0, target_idx, qlen, matrix); continue; } if (target.hsp[frame].empty()) continue; int d0 = INT_MAX, d1 = INT_MIN, score = 0; Loc j_min = numeric_limits::max(), j_max = numeric_limits::min(); Anchor anchor; for (const ApproxHsp &hsp : target.hsp[frame]) { Geo::assert_diag_bounds(hsp.d_max, qlen, slen); Geo::assert_diag_bounds(hsp.d_min, qlen, slen); assert(hsp.score > 0); assert(hsp.max_diag.score > 0); const int b = hsp_band(band, qlen, slen, hsp); const int b0 = std::max(hsp.d_min - b, -(slen - 1)), b1 = std::min(hsp.d_max + 1 + b, qlen); const double overlap = intersect(Interval(d0, d1), Interval(b0, b1)).length(); if ((overlap / (d1 - d0) > config.min_band_overlap || overlap / (b1 - b0) > config.min_band_overlap) && !config.anchored_swipe) { d0 = std::min(d0, b0); d1 = std::max(d1, b1); score = std::max(score, hsp.score); j_min = std::min(j_min, hsp.subject_range.begin_); j_max = std::max(j_max, hsp.subject_range.end_); if (hsp.max_diag.score > anchor.score) anchor = hsp.max_diag; } else { if (d0 != INT_MAX) { const int64_t dp_size = (int64_t)DpTarget::banded_cols(qlen, slen, d0, d1) * int64_t(d1 - d0); const auto bin = DP::BandedSwipe::bin(hsp_values, d1 - d0, 0, score, dp_size, score_width, 0); //dp_targets[frame][bin].emplace_back(target.seq, slen, d0, d1, Interval(j_min, j_max), score, target_idx, qlen, matrix, DpTarget::CarryOver(), anchor); dp_targets[frame][bin].emplace_back(target.seq, slen, d0, d1, target_idx, qlen, matrix, DpTarget::CarryOver(), anchor); dp_targets[frame][bin].back().prof = &target.profile; dp_targets[frame][bin].back().prof_reverse = &target.profile_rev; } d0 = b0; d1 = b1; score = hsp.score; j_min = hsp.subject_range.begin_; j_max = hsp.subject_range.end_; anchor = hsp.max_diag; } } const int64_t dp_size = (int64_t)DpTarget::banded_cols(qlen, slen, d0, d1) * int64_t(d1 - d0); const auto bin = DP::BandedSwipe::bin(hsp_values, d1 - d0, 0, score, dp_size, score_width, 0); //dp_targets[frame][bin].emplace_back(target.seq, slen, d0, d1, Interval(j_min, j_max), score, target_idx, qlen, matrix, DpTarget::CarryOver(), anchor); dp_targets[frame][bin].emplace_back(target.seq, slen, d0, d1, target_idx, qlen, matrix, DpTarget::CarryOver(), anchor); dp_targets[frame][bin].back().prof = &target.profile; dp_targets[frame][bin].back().prof_reverse = &target.profile_rev; } } vector align(vector& targets, const Sequence* query_seq, const char* query_id, const HauserCorrection* query_cb, int source_query_len, DP::Flags flags, const HspValues hsp_values, const Mode mode, ThreadPool& tp, const Search::Config& cfg, Statistics& stat, std::pmr::monotonic_buffer_resource& pool) { array dp_targets; vector r; if (targets.empty()) return r; r.reserve(targets.size()); size_t cbs_targets = 0; for (int i = 0; i < (int)targets.size(); ++i) { if (targets[i].done) r.back().add_hit(targets[i].hsp[0].front(), query_seq[targets[i].hsp[0].front().frame].length()); else add_dp_targets(targets[i], i, query_seq, dp_targets, flags, hsp_values, mode, cfg); if (targets[i].matrix) ++cbs_targets; r.emplace_back(targets[i].block_id, targets[i].seq, targets[i].ungapped_score.front(), std::move(targets[i].matrix)); } stat.inc(Statistics::TARGET_HITS3_CBS, cbs_targets); if (mode == Mode::FULL) flags |= DP::Flags::FULL_MATRIX; if (mode == Mode::GLOBAL) flags |= DP::Flags::SEMI_GLOBAL; for (int frame = 0; frame < align_mode.query_contexts; ++frame) { const int64_t n = std::accumulate(dp_targets[frame].begin(), dp_targets[frame].end(), (int64_t)0, [](int64_t n, const DP::TargetVec& v) { return n + v.size(); }); if (n == 0) continue; DP::Params params{ query_seq[frame], query_id, Frame(frame), source_query_len, ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[frame].int8.data() : nullptr, flags, false, 0, -1, hsp_values, stat, &tp }; DP::AnchoredSwipe::Config acfg{ query_seq[frame], ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[frame].int8.data() : nullptr, 0, stat, &tp, false, cfg.extension_mode, false }; list hsp = config.anchored_swipe ? DP::BandedSwipe::anchored_swipe(dp_targets[frame], acfg, pool) : DP::BandedSwipe::swipe(dp_targets[frame], params); while (!hsp.empty()) r[hsp.front().swipe_target].add_hit(hsp, hsp.begin()); } vector r2; r2.reserve(r.size()); for (vector::iterator i = r.begin(); i != r.end(); ++i) if (i->filter_evalue != DBL_MAX) { if(config.max_hsps == 1 || have_coords(hsp_values)) i->inner_culling(); r2.push_back(std::move(*i)); } return r2; } }bbuchfink-diamond-08b3cbc/src/align/global_ranking/000077500000000000000000000000001506104011400223665ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/align/global_ranking/extend.cpp000066400000000000000000000204761506104011400243720ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020-2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "global_ranking.h" #include "output/output.h" #include "align/target.h" #include "data/queries.h" #include "masking/masking.h" #include "data/sequence_file.h" using std::unique_ptr; using std::mutex; using std::thread; using std::unordered_map; using std::endl; using std::pair; using std::vector; namespace Extension { namespace GlobalRanking { typedef unordered_map TargetMap; void extend_query(const QueryList& query_list, const TargetMap& db2block_id, const Search::Config& cfg, Statistics& stats, std::pmr::monotonic_buffer_resource& pool) { SeedHitList l; const size_t n = query_list.targets.size(); l.target_block_ids.reserve(n); l.target_scores.reserve(n); l.seed_hits.reserve(n, 0); for (size_t i = 0; i < n; ++i) { l.target_block_ids.push_back(db2block_id.at(query_list.targets[i].database_id)); l.target_scores.push_back({ (uint32_t)i, query_list.targets[i].score }); l.seed_hits.next(); l.seed_hits.push_back({ 0,0,query_list.targets[i].score,0 }); } DP::Flags flags = DP::Flags::FULL_MATRIX; vector matches = Extension::extend( query_list.query_block_id, cfg, stats, flags, l, pool); TextBuffer* buf = Extension::generate_output(matches, query_list.query_block_id, stats, cfg); if (!matches.empty() && (!config.unaligned.empty() || !config.aligned_file.empty())) { std::lock_guard lock(query_aligned_mtx); query_aligned[query_list.query_block_id] = true; } output_sink->push(query_list.query_block_id, buf); } void align_worker(InputFile* query_list, const TargetMap* db2block_id, const Search::Config* cfg, uint32_t* next_query) { std::pmr::monotonic_buffer_resource pool; try { QueryList input; Statistics stats; while (input = fetch_query_targets(*query_list, *next_query), !input.targets.empty()) { for (uint32_t i = input.last_query_block_id; i < input.query_block_id; ++i) output_sink->push(i, nullptr); extend_query(input, *db2block_id, *cfg, stats, pool); } statistics += stats; } catch (std::exception& e) { exit_with_error(e); } } void extend(SequenceFile& db, TempFile& merged_query_list, BitVector& ranking_db_filter, Search::Config& cfg, Consumer& master_out) { TaskTimer timer("Loading reference sequences"); InputFile query_list(merged_query_list); db.set_seqinfo_ptr(0); cfg.target.reset(db.load_seqs(INT64_MAX, &ranking_db_filter, SequenceFile::LoadFlags::SEQS)); TargetMap db2block_id; const BlockId db_count = cfg.target->seqs().size(); db2block_id.reserve(db_count); for (BlockId i = 0; i < db_count; ++i) db2block_id[cfg.target->block_id2oid(i)] = i; timer.finish(); verbose_stream << "#Ranked database sequences: " << cfg.target->seqs().size() << endl; if (cfg.target_masking != MaskingAlgo::NONE) { timer.go("Masking reference"); size_t n = mask_seqs(cfg.target->seqs(), Masking::get(), true, cfg.target_masking); timer.finish(); log_stream << "Masked letters: " << n << endl; } else { timer.go("Converting alphabet"); cfg.target->seqs().convert_all_to_std_alph(config.threads_); } timer.go("Computing alignments"); OutputWriter writer{ &master_out }; output_sink.reset(new ReorderQueue(0, writer)); uint32_t next_query = 0; vector threads; for (size_t i = 0; i < (config.threads_align ? config.threads_align : config.threads_); ++i) threads.emplace_back(align_worker, &query_list, &db2block_id, &cfg, &next_query); for (auto& i : threads) i.join(); timer.go("Cleaning up"); query_list.close_and_delete(); output_sink.reset(); cfg.target.reset(); } void extend_query(BlockId source_query_block_id, const TargetMap& db2block_id, Search::Config& cfg, Statistics& stats, std::pmr::monotonic_buffer_resource& pool) { const size_t N = config.global_ranking_targets; SeedHitList l; vector::const_iterator table_begin = cfg.ranking_table->cbegin() + source_query_block_id * N, table_end = table_begin + N; while (table_end > table_begin && (table_end - 1)->score == 0) --table_end; const size_t n = table_end - table_begin; TextBuffer* buf = nullptr; if (n) { l.target_block_ids.reserve(n); l.target_scores.reserve(n); l.seed_hits.reserve(n, 0); for (size_t i = 0; i < n; ++i) { l.target_block_ids.push_back(db2block_id.at(table_begin[i].oid)); l.target_scores.push_back({ (uint32_t)i, table_begin[i].score }); l.seed_hits.next(); l.seed_hits.push_back({ 0,0,table_begin[i].score, table_begin[i].context }); } DP::Flags flags = DP::Flags::FULL_MATRIX; vector matches = Extension::extend( source_query_block_id, cfg, stats, flags, l, pool); buf = cfg.iterated() ? Extension::generate_intermediate_output(matches, source_query_block_id, cfg) : Extension::generate_output(matches, source_query_block_id, stats, cfg); if (!matches.empty() && cfg.track_aligned_queries) { std::lock_guard lock(query_aligned_mtx); if (!query_aligned[source_query_block_id]) { query_aligned[source_query_block_id] = true; ++cfg.iteration_query_aligned; } } } output_sink->push(source_query_block_id, buf); } static BitVector db_filter(const Search::Config::RankingTable& table, size_t db_size) { BitVector v(db_size); for (const Hit& hit : table) if (hit.score) v.set(hit.oid); return v; } void extend(Search::Config& cfg, Consumer& out) { TaskTimer timer("Listing target sequences"); const BitVector filter = db_filter(*cfg.ranking_table, cfg.db->sequence_count()); timer.go("Loading target sequences"); cfg.db->set_seqinfo_ptr(0); auto flags = SequenceFile::LoadFlags::SEQS; if (!flag_any(cfg.db->format_flags(), SequenceFile::FormatFlags::TITLES_LAZY)) flags |= SequenceFile::LoadFlags::TITLES; cfg.target.reset(cfg.db->load_seqs(INT64_MAX, &filter, flags)); TargetMap db2block_id; const BlockId db_count = cfg.target->seqs().size(); db2block_id.reserve(db_count); for (BlockId i = 0; i < db_count; ++i) db2block_id[cfg.target->block_id2oid(i)] = i; timer.finish(); verbose_stream << "#Ranked database sequences: " << db_count << endl; if (cfg.target_masking != MaskingAlgo::NONE) { timer.go("Masking reference"); size_t n; n = mask_seqs(cfg.target->seqs(), Masking::get(), true, cfg.target_masking); timer.finish(); log_stream << "Masked letters: " << n << endl; } else { timer.go("Converting alphabet"); cfg.target->seqs().convert_all_to_std_alph(config.threads_); timer.finish(); } if (cfg.iterated()) { cfg.current_ref_block = 0; cfg.db->init_dict_block(0, db_count, true); } else cfg.db->init_random_access(cfg.current_query_block, 0); timer.go("Computing alignments"); OutputWriter writer{ &out }; output_sink.reset(new ReorderQueue(0, writer)); std::atomic next_query(0); const BlockId query_count = cfg.query->seqs().size() / align_mode.query_contexts; auto worker = [&next_query, &db2block_id, &cfg, query_count] { try { Statistics stats; BlockId q; std::pmr::monotonic_buffer_resource pool; while ((q = next_query++) < query_count) extend_query(q, db2block_id, cfg, stats, pool); statistics += stats; } catch (std::exception& e) { exit_with_error(e); } }; vector threads; for (size_t i = 0; i < (config.threads_align ? config.threads_align : config.threads_); ++i) threads.emplace_back(worker); for (auto& i : threads) i.join(); timer.go("Deallocating memory"); cfg.target.reset(); output_sink.reset(); if (!cfg.iterated()) cfg.db->end_random_access(); else { cfg.db->close_dict_block(true); IntermediateRecord::finish_file(out); } } }}bbuchfink-diamond-08b3cbc/src/align/global_ranking/global_ranking.cpp000066400000000000000000000075121506104011400260500ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "global_ranking.h" #include "util/sequence/sequence.h" #include "dp/ungapped.h" #include "util/util.h" using std::mutex; using std::vector; namespace Extension { namespace GlobalRanking { uint16_t recompute_overflow_scores(FlatArray::DataConstIterator begin, FlatArray::DataConstIterator end, size_t query_id, uint32_t target_id, const Search::Config& cfg) { const auto query = cfg.query->seqs()[query_id]; const auto target = cfg.target->seqs()[target_id]; int score = 0; for (auto it = begin; it < end; ++it) { if (it->score != UCHAR_MAX) continue; const Sequence query_clipped = Util::Seq::clip(query.data() + it->i - config.ungapped_window, config.ungapped_window * 2, config.ungapped_window); const ptrdiff_t window_left = query.data() + it->i - query_clipped.data(); const int s = ungapped_window(query_clipped.data(), target.data() + it->j - window_left, (int)query_clipped.length()); score = std::max(score, s); } return (uint16_t)std::min(score, USHRT_MAX); } std::vector ranking_list(size_t query_id, std::vector::iterator begin, std::vector::iterator end, std::vector::const_iterator target_block_ids, const FlatArray& seed_hits, const Search::Config& cfg) { size_t overflows = 0; for (auto it = begin; it < end && it->score >= UCHAR_MAX; ++it) if (it->score == UCHAR_MAX) { it->score = recompute_overflow_scores(seed_hits.begin(it->target), seed_hits.end(it->target), query_id, target_block_ids[it->target], cfg); ++overflows; } if (overflows > 0) std::sort(begin, end); // should also sort by target block id int64_t n = 0; vector r; r.reserve(std::min(end - begin, (ptrdiff_t)config.global_ranking_targets)); for (auto i = begin; i < end && n < config.global_ranking_targets; ++i, ++n) { r.emplace_back(target_block_ids[i->target], Sequence(), nullptr, i->score); } return r; } size_t write_merged_query_list_intro(uint32_t query_id, TextBuffer& buf) { size_t seek_pos = buf.size(); buf.write(query_id).write((uint32_t)0); return seek_pos; } void write_merged_query_list(const IntermediateRecord& r, TextBuffer& out, BitVector& ranking_db_filter, Statistics& stat) { /*out.write(r.subject_oid); out.write(uint16_t(r.score)); ranking_db_filter.set(r.subject_oid); stat.inc(Statistics::TARGET_HITS1);*/ } void finish_merged_query_list(TextBuffer& buf, size_t seek_pos) { *(uint32_t*)(&buf[seek_pos + sizeof(uint32_t)]) = safe_cast(buf.size() - seek_pos - sizeof(uint32_t) * 2); } QueryList fetch_query_targets(InputFile& query_list, uint32_t& next_query) { static mutex mtx; std::lock_guard lock(mtx); QueryList r; r.last_query_block_id = next_query; uint32_t size; try { query_list >> r.query_block_id; } catch (EndOfStream&) { return r; } next_query = r.query_block_id + 1; query_list >> size; size_t n = size / 6; r.targets.reserve(n); for (size_t i = 0; i < n; ++i) { uint32_t target; uint16_t score; query_list >> target >> score; r.targets.push_back({ target,score }); } return r; } }}bbuchfink-diamond-08b3cbc/src/align/global_ranking/global_ranking.h000066400000000000000000000052241506104011400255130ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "output/output.h" #include "basic/statistics.h" #include "util/data_structures/bit_vector.h" #include "../extend.h" #include "../target.h" namespace Extension { namespace GlobalRanking { struct QueryList { struct Target { uint32_t database_id; uint16_t score; }; uint32_t query_block_id, last_query_block_id; std::vector targets; }; std::vector ranking_list(size_t query_id, std::vector::iterator begin, std::vector::iterator end, std::vector::const_iterator target_block_ids, const FlatArray& seed_hits, const Search::Config& cfg); void write_merged_query_list(const IntermediateRecord& r, TextBuffer& out, BitVector& ranking_db_filter, Statistics& stat); size_t write_merged_query_list_intro(uint32_t query_id, TextBuffer& buf); void finish_merged_query_list(TextBuffer& buf, size_t seek_pos); void extend(SequenceFile& db, TempFile& merged_query_list, BitVector& ranking_db_filter, Search::Config& cfg, Consumer& master_out); void extend(Search::Config& cfg, Consumer& out); QueryList fetch_query_targets(InputFile& query_list, uint32_t& next_query); void update_table(Search::Config& cfg); struct Hit { Hit(): oid(), score(0) {} Hit(uint32_t oid, uint16_t score, unsigned context): oid(oid), score(score), context((uint8_t)context) {} Hit(ptrdiff_t target_id): oid((uint32_t)target_id), score() {} uint32_t oid; uint16_t score; uint8_t context; bool operator<(const Hit& x) const { return score > x.score || (score == x.score && oid < x.oid); } struct Target { uint32_t operator()(const Hit& h) const { return h.oid; } }; struct CmpOidScore { bool operator()(const Hit&x, const Hit& y) const { return x.oid < y.oid || (x.oid == y.oid && x.score > y.score); } }; struct CmpOid { bool operator()(const Hit&x, const Hit& y) const { return x.oid == y.oid; } }; }; }}bbuchfink-diamond-08b3cbc/src/align/global_ranking/table.cpp000066400000000000000000000160411506104011400241630ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "global_ranking.h" #define _REENTRANT #include "ips4o/ips4o.hpp" #include "search/hit.h" #include "util/data_structures/deque.h" #include "util/util.h" #include "util/algo/algo.h" #include "dp/ungapped.h" #include "search/search.h" #include "../load_hits.h" using std::endl; using std::thread; using std::pair; using std::vector; using SeedHits = Search::Config::RankingBuffer; // #define BATCH_BINSEARCH namespace Extension { namespace GlobalRanking { static void get_query_hits(SeedHits::Iterator begin, SeedHits::Iterator end, vector& hits, Search::Config& cfg) { hits.clear(); const SequenceSet& target_seqs = cfg.target->seqs(); if (Search::keep_target_id(cfg)) { auto get_target = [](const Search::Hit& hit) { return (BlockId)hit.subject_; }; auto it = merge_keys(begin, end, get_target); while (it.good()) { uint16_t score = 0; for (SeedHits::Iterator i = it.begin(); i != it.end(); ++i) score = std::max(score, i->score_); hits.emplace_back((uint32_t)cfg.target->block_id2oid(it.key()), score, 0); ++it; } } else { #ifdef BATCH_BINSEARCH vector hit1; hit1.reserve(end - begin); target_seqs.local_position_batch(begin, end, std::back_inserter(hit1), Search::Hit::CmpTargetOffset()); for (size_t i = 0; i < hit1.size(); ++i) { hit1[i].score = begin[i].score_; } auto it = merge_keys(hit1.begin(), hit1.end(), Hit::Target()); while (it.good()) { uint16_t score = 0; for (auto i = it.begin(); i != it.end(); ++i) score = std::max(score, i->score); hits.emplace_back((uint32_t)cfg.target->block_id2oid(it.key()), score); ++it; } #else auto get_target = [&target_seqs](const Search::Hit& hit) { return target_seqs.local_position((uint64_t)hit.subject_).first; }; auto it = merge_keys(begin, end, get_target); while (it.good()) { uint16_t score = 0; for (SeedHits::Iterator i = it.begin(); i != it.end(); ++i) score = std::max(score, i->score_); hits.emplace_back((uint32_t)cfg.target->block_id2oid(it.key()), score, 0); ++it; } #endif } } static pair target_score(const FlatArray::DataIterator begin, const FlatArray::DataIterator end, const Sequence* query_seq, const Sequence& target_seq) { if (config.no_reextend) { int score = begin->score; unsigned context = begin->frame; for (auto i = begin + 1; i != end; ++i) { if (i->score > score) { score = i->score; context = i->frame; } } return { score,context }; } std::sort(begin, end); DiagonalSegment d = xdrop_ungapped(query_seq[begin->frame], nullptr, target_seq, begin->i, begin->j, false); int score = d.score; unsigned context = begin->frame; for (auto i = begin + 1; i != end; ++i) { if (d.diag() == i->diag() && d.subject_end() >= i->j) continue; d = xdrop_ungapped(query_seq[i->frame], nullptr, target_seq, i->i, i->j, false); if (d.score > score) { score = d.score; context = i->frame; } } return { score,context }; } static void get_query_hits_reextend(size_t source_query_block_id, SeedHits::Iterator begin, SeedHits::Iterator end, vector& hits, Search::Config& cfg) { const unsigned contexts = align_mode.query_contexts; vector query_seq; for (unsigned i = 0; i < contexts; ++i) query_seq.push_back(cfg.query->seqs()[source_query_block_id * contexts + i]); const SequenceSet& target_seqs = cfg.target->seqs(); hits.clear(); Extension::SeedHitList l = Extension::load_hits(begin, end, cfg.target->seqs()); for (size_t i = 0; i < l.target_block_ids.size(); ++i) { const auto score = target_score(l.seed_hits.begin(i), l.seed_hits.end(i), query_seq.data(), target_seqs[l.target_block_ids[i]]); hits.emplace_back((uint32_t)cfg.target->block_id2oid(l.target_block_ids[i]), score.first, score.second); } } static void merge_hits(const size_t query, vector& hits, vector& merged, Search::Config& cfg, size_t& merged_count) { const size_t N = config.global_ranking_targets; //std::sort(hits.begin(), hits.end()); vector::iterator table_begin = cfg.ranking_table->begin() + query * N, table_end = table_begin + N; while (table_end > table_begin && (table_end - 1)->score == 0) --table_end; const auto count = table_end - table_begin; hits.insert(hits.end(), table_begin, table_end); std::sort(hits.begin(), hits.end(), Hit::CmpOidScore()); merged.clear(); std::unique_copy(hits.begin(), hits.end(), std::back_inserter(merged), Hit::CmpOid()); std::sort(merged.begin(), merged.end()); const auto n = std::min(N, merged.size()); std::copy(merged.begin(), merged.begin() + n, table_begin); merged_count += n - count; //merged.clear(); //merged_count += Util::Algo::merge_capped(table_begin, table_end, hits.begin(), hits.end(), N, std::back_inserter(merged)); //std::copy(merged.begin(), merged.end(), table_begin); } void update_table(Search::Config& cfg) { SeedHits& hits = *cfg.global_ranking_buffer; log_stream << "Seed hits = " << hits.size() << endl; if (hits.size() == 0) return; TaskTimer timer("Sorting seed hits"); #if _MSC_FULL_VER == 191627042 merge_sort(hits.begin(), hits.end(), config.threads_, Search::Hit::CmpQueryTarget()); #else ips4o::parallel::sort(hits.begin(), hits.end(), Search::Hit::CmpQueryTarget(), config.threads_); #endif timer.go("Creating partition"); auto p = Util::Algo::partition_table(hits.begin(), hits.end(), config.threads_ * 8, ::Search::Hit::SourceQuery{ align_mode.query_contexts }); timer.go("Processing seed hits"); std::atomic_size_t merged_count(0), next(0); auto worker = [&cfg, &merged_count, &next, &p]() { vector hits, merged; while (true) { auto i = next++; if (i + 1 >= p.size()) break; auto begin = p[i], end = p[i + 1]; auto it = merge_keys(begin, end, ::Search::Hit::SourceQuery{ align_mode.query_contexts }); size_t n = 0; while (it.good()) { const size_t query = it.begin()->query_ / align_mode.query_contexts; get_query_hits_reextend(query, it.begin(), it.end(), hits, cfg); merge_hits(query, hits, merged, cfg, n); ++it; } merged_count += n; } }; vector threads; for (int i = 0; i < config.threads_; ++i) threads.emplace_back(worker); for (thread& t : threads) t.join(); timer.go("Deallocating seed hit list"); cfg.global_ranking_buffer.reset(); timer.finish(); log_stream << "Merged targets = " << merged_count << endl; } }}bbuchfink-diamond-08b3cbc/src/align/legacy/000077500000000000000000000000001506104011400206615ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/align/legacy/banded_swipe_pipeline.cpp000066400000000000000000000222711506104011400257020ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2019 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include "pipeline.h" #include "dp/dp.h" #include "util/geo/interval_partition.h" using std::thread; using std::list; using std::max; using std::atomic; using std::endl; using std::vector; namespace ExtensionPipeline { namespace BandedSwipe { struct Target : public ::Target { void ungapped_stage(QueryMapper &mapper) { vector::iterator hits = mapper.seed_hits.begin() + begin, hits_end = mapper.seed_hits.begin() + end; top_hit = hits[0]; for (vector::iterator i = hits + 1; i < hits_end; ++i) if (i->ungapped.score > top_hit.ungapped.score) top_hit = *i; filter_score = top_hit.ungapped.score; } Interval ungapped_query_range(int query_dna_len) const { const Frame f = Frame(top_hit.frame_); const int i0 = std::max((int)top_hit.query_pos_ - (int)top_hit.subject_pos_, 0), i1 = std::min((int)top_hit.query_pos_ + (int)subject.length() - (int)top_hit.subject_pos_, f.length(query_dna_len)); return TranslatedPosition::absolute_interval(TranslatedPosition(i0, f), TranslatedPosition(i1, f), query_dna_len); } void add_strand(QueryMapper &mapper, vector &v, vector::iterator begin, vector::iterator end, int target_idx) { if (end == begin) return; const int band = config.padding, d_min = -int(subject.length() - 1), d_max = int(mapper.query_seq(0).length() - 1); vector::iterator i = begin; int d0 = std::max(i->diagonal() - band, d_min), d1 = std::min(i->diagonal() + band, d_max); ++i; for (; i < end; ++i) { if (i->diagonal() - d1 <= band) { d1 = std::min(i->diagonal() + band, d_max); } else { //v.emplace_back(subject, subject.length(), d0, d1, Interval(), 0, target_idx, 0); // set cols here? v.emplace_back(subject, subject.length(), d0, d1, target_idx, 0); // set cols here? d0 = std::max(i->diagonal() - band, d_min); d1 = std::min(i->diagonal() + band, d_max); } } //v.emplace_back(subject, subject.length(), d0, d1, Interval(), 0, target_idx, 0); v.emplace_back(subject, subject.length(), d0, d1, target_idx, 0); } void add(QueryMapper &mapper, vector &vf, vector &vr, int target_idx) { vector::iterator hits = mapper.seed_hits.begin() + begin, hits_end = mapper.seed_hits.begin() + end; Strand strand = top_hit.strand(); if(mapper.target_parallel) std::stable_sort(hits, hits_end, SeedHit::compare_diag_strand); else std::stable_sort(hits, hits_end, SeedHit::compare_diag_strand2); const auto it = find_if(hits, hits_end, [](const SeedHit &x) { return x.strand() == REVERSE; }); //if(strand == FORWARD || mapper.target_parallel) add_strand(mapper, vf, hits, it, target_idx); //if (strand == REVERSE || mapper.target_parallel) add_strand(mapper, vr, it, hits_end, target_idx); //const int d = hits[0].diagonal(); //const DpTarget t(subject, std::max(d - 32, -int(subject.length() - 1)), std::min(d + 32, int(mapper.query_seq(0).length() - 1)), &hsps, subject_id); } void set_filter_score() { filter_score = 0; filter_evalue = DBL_MAX; for (list::const_iterator i = hsps.begin(); i != hsps.end(); ++i) { filter_score = std::max(filter_score, (int)i->score); filter_evalue = std::min(filter_evalue, i->evalue); } } void reset() { hsps.clear(); } void finish(QueryMapper &mapper) { inner_culling(); if (config.frame_shift) return; for (list::iterator i = hsps.begin(); i != hsps.end(); ++i) i->query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(i->query_range.begin_, Frame(i->frame)), TranslatedPosition(i->query_range.end_, Frame(i->frame)), mapper.source_query_len); } bool is_outranked(const IntervalPartition &ip, int source_query_len, double rr) const { const Interval r = ungapped_query_range(source_query_len); if (config.toppercent.blank()) { const int min_score = int((double)filter_score / rr); return (double)ip.covered(r, min_score, IntervalPartition::MinScore()) / r.length() * 100.0 >= config.query_range_cover; } else { const int min_score = int((double)filter_score / rr / (1.0 - config.toppercent / 100.0)); return (double)ip.covered(r, min_score, IntervalPartition::MaxScore()) / r.length() * 100.0 >= config.query_range_cover; } } }; void Pipeline::range_ranking(const int64_t max_target_seqs) { const double rr = config.rank_ratio == -1 ? 0.4 : config.rank_ratio; std::stable_sort(targets.begin(), targets.end(), Target::compare_score); IntervalPartition ip(max_target_seqs); for (PtrVector< ::Target>::iterator i = targets.begin(); i < targets.end();) { Target* t = ((Target*)*i); if (t->is_outranked(ip, source_query_len, rr)) { i = targets.erase(i, i + 1); } else { ip.insert(t->ungapped_query_range(source_query_len), t->filter_score); ++i; } } } Target& Pipeline::target(size_t i) { return (Target&)(this->targets[i]); } void Pipeline::run_swipe(bool score_only) { vector vf, vr; for (int64_t i = 0; i < n_targets(); ++i) target(i).add(*this, vf, vr, (int)i); list hsp; hsp = banded_3frame_swipe(translated_query, FORWARD, vf.begin(), vf.end(), this->dp_stat, score_only, target_parallel); hsp.splice(hsp.end(), banded_3frame_swipe(translated_query, REVERSE, vr.begin(), vr.end(), this->dp_stat, score_only, target_parallel)); while (!hsp.empty()) { list &l = target(hsp.begin()->swipe_target).hsps; l.splice(l.end(), hsp, hsp.begin()); } } void build_ranking_worker(PtrVector<::Target>::iterator begin, PtrVector<::Target>::iterator end, atomic *next, vector *intervals) { PtrVector<::Target>::iterator it; while ((it = begin + next->fetch_add(64)) < end) { auto e = min(it + 64, end); for (; it < e; ++it) { (*it)->add_ranges(*intervals); } } } void Pipeline::run(Statistics &stat, const Search::Config& cfg) { TaskTimer timer("Init banded swipe pipeline", target_parallel ? 3 : UINT_MAX); Config::set_option(config.padding, 32); if (n_targets() == 0) return; stat.inc(Statistics::TARGET_HITS0, n_targets()); if (!target_parallel) { timer.go("Ungapped stage"); for (int64_t i = 0; i < n_targets(); ++i) target(i).ungapped_stage(*this); timer.go("Ranking"); if (!config.query_range_culling) rank_targets(config.rank_ratio == -1 ? 0.4 : config.rank_ratio, config.rank_factor == -1.0 ? 1e3 : config.rank_factor, cfg.max_target_seqs); else range_ranking(cfg.max_target_seqs); } else { timer.finish(); log_stream << "Query: " << query_id << "; Seed hits: " << seed_hits.size() << "; Targets: " << n_targets() << endl; } if (n_targets() > cfg.max_target_seqs || config.toppercent.present()) { stat.inc(Statistics::TARGET_HITS1, n_targets()); timer.go("Swipe (score only)"); run_swipe(true); if (target_parallel) { timer.go("Building score ranking intervals"); vector> intervals(config.threads_); const size_t interval_count = (source_query_len + ::Target::INTERVAL - 1) / ::Target::INTERVAL; for (vector &v : intervals) v.resize(interval_count); vector threads; atomic next(0); for (int i = 0; i < config.threads_; ++i) threads.emplace_back(build_ranking_worker, targets.begin(), targets.end(), &next, &intervals[i]); for (auto &t : threads) t.join(); timer.go("Merging score ranking intervals"); for (auto it = intervals.begin() + 1; it < intervals.end(); ++it) { vector::iterator i = intervals[0].begin(), i1 = intervals[0].end(), j = it->begin(); for (; i < i1; ++i, ++j) *i = max(*i, *j); } if (config.toppercent.present()) { timer.go("Finding outranked targets"); for (auto i = targets.begin(); i < targets.end(); ++i) if ((*i)->is_outranked(intervals[0], 1.0 - config.toppercent / 100)) { delete* i; *i = nullptr; } timer.go("Removing outranked targets"); vector<::Target*>& v(*static_cast*>(&targets)); auto it = remove_if(v.begin(), v.end(), [](::Target* t) { return t == nullptr; }); v.erase(it, v.end()); timer.finish(); } log_stream << "Targets after score-only ranking: " << targets.size() << endl; } else { timer.go("Score only culling"); for (int64_t i = 0; i < n_targets(); ++i) target(i).set_filter_score(); score_only_culling(cfg.max_target_seqs); } } timer.go("Swipe (traceback)"); stat.inc(Statistics::TARGET_HITS2, n_targets()); for (int64_t i = 0; i < n_targets(); ++i) target(i).reset(); run_swipe(false); timer.go("Inner culling"); for (int64_t i = 0; i < n_targets(); ++i) target(i).finish(*this); } }}bbuchfink-diamond-08b3cbc/src/align/legacy/pipeline.h000066400000000000000000000011061506104011400226350ustar00rootroot00000000000000#pragma once #include "query_mapper.h" #include "dp/dp.h" namespace ExtensionPipeline { namespace BandedSwipe { struct Target; struct Pipeline : public QueryMapper { Pipeline(size_t query_id, Search::Hit* begin, Search::Hit* end, DpStat& dp_stat, const Search::Config& cfg) : QueryMapper(query_id, begin, end, cfg), dp_stat(dp_stat) {} Target& target(size_t i); virtual void run(Statistics& stat, const Search::Config& cfg) override; void run_swipe(bool score_only); void range_ranking(const int64_t max_target_seqs); DpStat& dp_stat; }; } } bbuchfink-diamond-08b3cbc/src/align/legacy/query_mapper.cpp000066400000000000000000000262611506104011400241050ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "query_mapper.h" #include "data/sequence_file.h" #include "data/taxonomy_nodes.h" #include "dp/ungapped.h" #include "output/output.h" #include "output/output_format.h" #include "output/daa/daa_write.h" #include "output/target_culling.h" #include "util/util.h" #include "stats/cbs.h" #include "util/log_stream.h" using std::tie; using std::list; using std::vector; using std::unique_ptr; using std::min; using std::max; using std::set; using std::string; bool Target::envelopes(const ApproxHsp &t, double p) const { for (list::const_iterator i = ts.begin(); i != ts.end(); ++i) if (t.query_source_range.overlap_factor(i->query_source_range) >= p) return true; return false; } bool Target::is_enveloped(const Target &t, double p) const { for (list::const_iterator i = ts.begin(); i != ts.end(); ++i) if (!t.envelopes(*i, p)) return false; return true; } bool Target::is_enveloped(PtrVector::const_iterator begin, PtrVector::const_iterator end, double p, int min_score) const { for (; begin != end; ++begin) if (is_enveloped(**begin, p) && (*begin)->filter_score >= min_score) return true; return false; } void Target::add_ranges(vector &v) { for (const Hsp &hsp : hsps) { const int i0 = hsp.query_source_range.begin_ / INTERVAL, i1 = min(hsp.query_source_range.end_ / INTERVAL, int(v.size() - 1)); for (int i = i0; i <= i1; ++i) v[i] = max(v[i], hsp.score); } } bool Target::is_outranked(const vector &v, double treshold) { for (const Hsp &hsp : hsps) { const int i0 = hsp.query_source_range.begin_ / INTERVAL, i1 = min(hsp.query_source_range.end_ / INTERVAL, int(v.size() - 1)); for (int i = i0; i <= i1; ++i) if (hsp.score >= v[i] * treshold) return false; } return true; } QueryMapper::QueryMapper(size_t query_id, Search::Hit* begin, Search::Hit* end, const Search::Config &metadata) : source_hits(std::make_pair(begin, end)), query_id((unsigned)query_id), targets_finished(0), next_target(0), source_query_len(metadata.query->source_len((unsigned)query_id)), translated_query(metadata.query->translated(query_id)), metadata(metadata), target_parallel(false) { seed_hits.reserve(source_hits.second - source_hits.first); } void QueryMapper::init() { if(config.log_query) message_stream << "Query = " << metadata.query->ids()[query_id] << '\t' << query_id << std::endl; if (Stats::CBS::hauser(config.comp_based_stats)) for (int i = 0; i < align_mode.query_contexts; ++i) query_cb.emplace_back(query_seq(i)); targets.resize(count_targets()); if (targets.empty()) return; load_targets(); } unsigned QueryMapper::count_targets() { std::sort(source_hits.first, source_hits.second, Search::Hit::CmpSubject()); const size_t n = source_hits.second - source_hits.first; const Search::Hit* hits = source_hits.first; size_t subject_id = std::numeric_limits::max(); unsigned n_subject = 0; for (size_t i = 0; i < n; ++i) { std::pair l = metadata.target->seqs().local_position((uint64_t)hits[i].subject_); const unsigned frame = hits[i].query_ % align_mode.query_contexts; /*const Diagonal_segment d = config.comp_based_stats ? xdrop_ungapped(query_seq(frame), query_cb[frame], ref_seqs::get()[l.first], hits[i].seed_offset_, (int)l.second) : xdrop_ungapped(query_seq(frame), ref_seqs::get()[l.first], hits[i].seed_offset_, (int)l.second);*/ if (target_parallel) { seed_hits.emplace_back(frame, (unsigned)l.first, (unsigned)l.second, (unsigned)hits[i].seed_offset_, DiagonalSegment()); if (l.first != subject_id) { subject_id = l.first; ++n_subject; } } else { const DiagonalSegment d = xdrop_ungapped(query_seq(frame), nullptr, metadata.target->seqs()[l.first], hits[i].seed_offset_, (int)l.second, false); if (d.score > 0) { if (l.first != subject_id) { subject_id = l.first; ++n_subject; } seed_hits.emplace_back(frame, (unsigned)l.first, (unsigned)l.second, (unsigned)hits[i].seed_offset_, d); } } } return n_subject; } void QueryMapper::load_targets() { unsigned subject_id = std::numeric_limits::max(), n = 0; for (size_t i = 0; i < seed_hits.size(); ++i) { if (seed_hits[i].subject_ != subject_id) { if (n > 0) { targets[n - 1].end = i; } const size_t oid = metadata.target->block_id2oid(seed_hits[i].subject_); targets.get(n) = new Target(i, seed_hits[i].subject_, metadata.target->seqs()[seed_hits[i].subject_], config.taxon_k ? metadata.db->taxon_nodes().rank_taxid(metadata.db->taxids(oid), Rank::species) : set()); ++n; subject_id = seed_hits[i].subject_; } } targets[n - 1].end = seed_hits.size(); } void QueryMapper::rank_targets(double ratio, double factor, const int64_t max_target_seqs) { if (config.taxon_k && config.toppercent.blank()) return; std::stable_sort(targets.begin(), targets.end(), Target::compare_score); int score = 0; if (config.toppercent.present()) { score = int((double)targets[0].filter_score * (1.0 - config.toppercent / 100.0) * ratio); } else { int64_t min_idx = std::min((int64_t)targets.size(), max_target_seqs); score = int((double)targets[min_idx - 1].filter_score * ratio); } const int64_t cap = (config.toppercent.present() || max_target_seqs == INT64_MAX) ? INT64_MAX : int64_t(max_target_seqs * factor); int64_t i = 0; for (; i < (int64_t)targets.size(); ++i) if (targets[i].filter_score < score || i >= cap) break; targets.erase(targets.begin() + i, targets.end()); } void QueryMapper::score_only_culling(const int64_t max_target_seqs) { static const double COV_INCLUDE_CUTOFF = 0.1; std::stable_sort(targets.begin(), targets.end(), config.toppercent.blank() ? Target::compare_evalue : Target::compare_score); unique_ptr target_culling(TargetCulling::get(max_target_seqs)); const unsigned query_len = (unsigned)query_seq(0).length(); PtrVector::iterator i; for (i = targets.begin(); ifilter_score, (*i)->filter_evalue)) break; int code; double cov; tie(code, cov) = target_culling->cull(**i); if (code == TargetCulling::FINISHED) break; else if (code == TargetCulling::NEXT) { i = targets.erase(i, i + 1); } else { if (cov < COV_INCLUDE_CUTOFF) target_culling->add(**i); ++i; } } targets.erase(i, targets.end()); } bool QueryMapper::generate_output(TextBuffer &buffer, Statistics &stat, const Search::Config& cfg) { std::stable_sort(targets.begin(), targets.end(), config.toppercent.blank() ? Target::compare_evalue : Target::compare_score); unsigned n_hsp = 0, n_target_seq = 0, hit_hsps = 0; unique_ptr target_culling(TargetCulling::get(cfg.max_target_seqs)); const unsigned query_len = (unsigned)query_seq(0).length(); size_t seek_pos = 0; const char *query_title = metadata.query->ids()[query_id]; unique_ptr f(cfg.output_format->clone()); Output::Info info{ cfg.query->seq_info(query_id), true, cfg.db.get(), buffer, Util::Seq::AccessionParsing(), cfg.db->sequence_count(), cfg.db->letters() }; for (size_t i = 0; i < targets.size(); ++i) { const BlockId subject_id = targets[i].subject_block_id; const OId database_id = metadata.target->block_id2oid(subject_id); string target_title; size_t dict_id; if (!cfg.blocked_processing) target_title = metadata.target->has_ids() ? metadata.target->ids()[subject_id] : metadata.db->seqid(database_id); else dict_id = metadata.target->dict_id(cfg.current_ref_block, subject_id, *metadata.db, *f); const unsigned subject_len = (unsigned)metadata.target->seqs()[subject_id].length(); targets[i].apply_filters(source_query_len, subject_len, query_title); if (targets[i].hsps.size() == 0) continue; const int c = target_culling->cull(targets[i]).first; if (c == TargetCulling::NEXT) continue; else if (c == TargetCulling::FINISHED) break; target_culling->add(targets[i]); hit_hsps = 0; for (list::iterator j = targets[i].hsps.begin(); j != targets[i].hsps.end(); ++j) { info.unaligned = false; if (config.max_hsps > 0 && hit_hsps >= config.max_hsps) break; if (cfg.blocked_processing) { if (n_hsp == 0) seek_pos = IntermediateRecord::write_query_intro(buffer, query_id); IntermediateRecord::write(buffer, *j, query_id, dict_id, database_id, cfg.output_format.get()); } else { if (n_hsp == 0) { if (*f == OutputFormat::daa) seek_pos = write_daa_query_record(buffer, query_title, align_mode.query_translated ? metadata.query->source_seqs()[query_id] : metadata.query->seqs()[query_id]); else f->print_query_intro(info); } if (*f == OutputFormat::daa) write_daa_record(buffer, *j, safe_cast(metadata.target->dict_id(cfg.current_ref_block, subject_id, *metadata.db, *f))); else f->print_match(HspContext(*j, query_id, cfg.query->block_id2oid(query_id), translated_query, query_title, database_id, subject_len, target_title.c_str(), n_target_seq, hit_hsps, metadata.target->seqs()[subject_id]), info); } ++n_hsp; ++hit_hsps; } ++n_target_seq; } if (n_hsp > 0) { if (!cfg.blocked_processing) { if (*f == OutputFormat::daa) finish_daa_query_record(buffer, seek_pos); else f->print_query_epilog(info); } else IntermediateRecord::finish_query(buffer, seek_pos); } else if (!cfg.blocked_processing && *f != OutputFormat::daa && f->report_unaligned()) { f->print_query_intro(info); f->print_query_epilog(info); } if (!cfg.blocked_processing) { stat.inc(Statistics::MATCHES, n_hsp); stat.inc(Statistics::PAIRWISE, n_target_seq); if (n_hsp > 0) stat.inc(Statistics::ALIGNED); } return n_hsp > 0; } void Target::inner_culling() { hsps.sort(); if (hsps.size() > 0) { filter_score = hsps.front().score; filter_evalue = hsps.front().evalue; } else { filter_score = 0; filter_evalue = DBL_MAX; } for (list::iterator i = hsps.begin(); i != hsps.end();) { if (i->query_range_enveloped_by(hsps.begin(), i, 0.5)) i = hsps.erase(i); else ++i; } } void Target::apply_filters(int dna_len, int subject_len, const char *query_title) { for (list::iterator i = hsps.begin(); i != hsps.end();) { if (i->id_percent() < config.min_id || i->query_cover_percent(dna_len) < config.query_cover || i->subject_cover_percent(subject_len) < config.subject_cover) i = hsps.erase(i); else ++i; } }bbuchfink-diamond-08b3cbc/src/align/legacy/query_mapper.h000066400000000000000000000146451506104011400235550ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include "util/ptr_vector.h" #include "util/hsp/approx_hsp.h" #include "basic/match.h" #include "run/config.h" #include "search/hit.h" #include "stats/hauser_correction.h" #include "basic/statistics.h" #include "data/block/block.h" struct SeedHit { SeedHit() {} SeedHit(unsigned frame, unsigned subject, unsigned subject_pos, unsigned query_pos, const DiagonalSegment &ungapped) : frame_(frame), subject_(subject), subject_pos_(subject_pos), query_pos_(query_pos), ungapped(ungapped), prefix_score(ungapped.score) { } int diagonal() const { return (int)query_pos_ - (int)subject_pos_; } bool operator<(const SeedHit &rhs) const { return ungapped.score > rhs.ungapped.score; } bool is_enveloped(std::list::const_iterator begin, std::list::const_iterator end, int dna_len) const { const DiagonalSegmentT d(ungapped, ::Frame(frame_)); for (std::list::const_iterator i = begin; i != end; ++i) if (i->envelopes(d, dna_len)) return true; return false; } DiagonalSegmentT diagonal_segment() const { return DiagonalSegmentT(ungapped, ::Frame(frame_)); } Interval query_source_range(int dna_len) const { return diagonal_segment().query_absolute_range(dna_len); } Strand strand() const { return ::Frame(frame_).strand; } static bool compare_pos(const SeedHit &x, const SeedHit &y) { return DiagonalSegment::cmp_subject_end(x.ungapped, y.ungapped); } static bool compare_diag(const SeedHit &x, const SeedHit &y) { return x.frame_ < y.frame_ || (x.frame_ == y.frame_ && (x.diagonal() < y.diagonal() || (x.diagonal() == y.diagonal() && x.ungapped.j < y.ungapped.j))); } static bool compare_diag_strand(const SeedHit &x, const SeedHit &y) { return x.strand() < y.strand() || (x.strand() == y.strand() && (x.diagonal() < y.diagonal() || (x.diagonal() == y.diagonal() && x.ungapped.j < y.ungapped.j))); } static bool compare_diag_strand2(const SeedHit &x, const SeedHit &y) { return x.strand() < y.strand() || (x.strand() == y.strand() && (x.diagonal() < y.diagonal() || (x.diagonal() == y.diagonal() && x.subject_pos_ < y.subject_pos_))); } struct Frame { unsigned operator()(const SeedHit &x) const { return x.frame_; } }; unsigned frame_, subject_, subject_pos_, query_pos_; DiagonalSegment ungapped; unsigned prefix_score; }; struct Target { Target(int filter_score, double filter_evalue): filter_score(filter_score), filter_evalue(filter_evalue) {} Target(size_t begin, unsigned subject_id, const Sequence& subject, const std::set &taxon_rank_ids) : subject_block_id(subject_id), subject(subject), filter_score(0), filter_evalue(DBL_MAX), outranked(false), begin(begin), taxon_rank_ids(taxon_rank_ids) {} static bool compare_evalue(Target* lhs, Target *rhs) { return lhs->filter_evalue < rhs->filter_evalue || (lhs->filter_evalue == rhs->filter_evalue && compare_score(lhs, rhs)); } static bool compare_score(Target* lhs, Target* rhs) { return lhs->filter_score > rhs->filter_score || (lhs->filter_score == rhs->filter_score && lhs->subject_block_id < rhs->subject_block_id); } void fill_source_ranges(size_t query_len) { for (std::list::iterator i = ts.begin(); i != ts.end(); ++i) i->query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(i->query_range.begin_, Frame(i->frame)), TranslatedPosition(i->query_range.end_, Frame(i->frame)), (int)query_len); } void add_ranges(std::vector &v); bool is_outranked(const std::vector &v, double treshold); bool envelopes(const ApproxHsp &t, double p) const; bool is_enveloped(const Target &t, double p) const; bool is_enveloped(PtrVector::const_iterator begin, PtrVector::const_iterator end, double p, int min_score) const; void inner_culling(); void apply_filters(int dna_len, int subject_len, const char *query_title); unsigned subject_block_id; Sequence subject; int filter_score; double filter_evalue; float filter_time; bool outranked; size_t begin, end; std::list hsps; std::list ts; SeedHit top_hit; std::set taxon_rank_ids; enum { INTERVAL = 64 }; }; struct QueryMapper { QueryMapper(size_t query_id, Search::Hit* begin, Search::Hit* end, const Search::Config &metadata); void init(); bool generate_output(TextBuffer &buffer, Statistics &stat, const Search::Config& cfg); void rank_targets(double ratio, double factor, const int64_t max_target_seqs); void score_only_culling(const int64_t max_target_seqs); int64_t n_targets() const { return (int64_t)targets.size(); } bool finished() const { return targets_finished == targets.size(); } Sequence query_seq(unsigned frame) const { return metadata.query->seqs()[(size_t)query_id*(size_t)align_mode.query_contexts + frame]; } void fill_source_ranges() { for (size_t i = 0; i < targets.size(); ++i) targets[i].fill_source_ranges(source_query_len); } virtual void run(Statistics &stat, const Search::Config& cfg) = 0; virtual ~QueryMapper() {} std::pair source_hits; unsigned query_id, targets_finished, next_target; unsigned source_query_len, unaligned_from; PtrVector targets; std::vector seed_hits; std::vector query_cb; TranslatedSequence translated_query; const Search::Config &metadata; bool target_parallel; private: static std::pair get_query_data(); unsigned count_targets(); Sequence query_source_seq() const { return align_mode.query_translated ? metadata.query->source_seqs()[query_id] : metadata.query->seqs()[query_id]; } void load_targets(); };bbuchfink-diamond-08b3cbc/src/align/load_hits.h000066400000000000000000000077531506104011400215500ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020-2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "target.h" #include "search/hit.h" #include "data/sequence_set.h" namespace Extension { template static int64_t count_targets(It begin, It end) { if (begin == end) return 0; auto last = (begin++)->subject_; int64_t n = 1; for (It i = begin; i < end; ++i) if (i->subject_ != last) { last = i->subject_; ++n; } return n; } template static SeedHitList load_hits(It begin, It end, const SequenceSet& ref_seqs) { std::sort(begin, end, Search::Hit::CmpSubject()); const auto targets = count_targets(begin, end); const auto hits = end - begin; SeedHitList list; list.seed_hits.reserve(targets, hits); list.target_block_ids.reserve(targets); list.target_scores.reserve(targets); if (hits <= 0) return list; const size_t total_subjects = ref_seqs.size(); unsigned target_len; uint32_t target = UINT32_MAX; uint16_t score = 0; #ifdef HIT_KEEP_TARGET_ID if(true) { #else if (std::log2(total_subjects) * hits < total_subjects / 10) { #endif for (auto i = begin; i < end; ++i) { #ifdef HIT_KEEP_TARGET_ID std::pair l{ (size_t)i->target_block_id, (size_t)i->subject_ - ref_seqs.position(i->target_block_id, 0) }; #else std::pair l = ref_seqs.local_position((uint64_t)i->subject_); #endif const uint32_t t = (uint32_t)l.first; if (t != target) { if (target != UINT32_MAX) { #ifdef EVAL_TARGET list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score, score_matrix.evalue(score, query_len, target_len) }); #else list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score }); #endif score = 0; } list.seed_hits.next(); target = t; target_len = (unsigned)ref_seqs[target].length(); list.target_block_ids.push_back(target); } list.seed_hits.push_back({ (int)i->seed_offset_, (int)l.second, i->score_, (unsigned)i->query_ % align_mode.query_contexts }); score = std::max(score, i->score_); } } else { typename std::vector::const_iterator limit_begin = ref_seqs.limits_begin(), it = limit_begin; for (auto i = begin; i < end; ++i) { const int64_t subject_offset = i->subject_; while (*it <= subject_offset) ++it; uint32_t t = (uint32_t)(it - limit_begin) - 1; if (t != target) { if (target != UINT32_MAX) { #ifdef EVAL_TARGET list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score, score_matrix.evalue(score, query_len, target_len) }); #else list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score }); #endif score = 0; } list.seed_hits.next(); list.target_block_ids.push_back(t); target = t; target_len = (unsigned)ref_seqs[target].length(); } list.seed_hits.push_back({ (int)i->seed_offset_, (int)(subject_offset - *(it - 1)), i->score_, (unsigned)i->query_ % align_mode.query_contexts }); score = std::max(score, i->score_); } } if (target != UINT32_MAX) #ifdef EVAL_TARGET list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score, score_matrix.evalue(score, query_len, target_len) }); #else list.target_scores.push_back({ uint32_t(list.target_block_ids.size() - 1), score }); #endif return list; } }bbuchfink-diamond-08b3cbc/src/align/output.cpp000066400000000000000000000122231506104011400214610ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "extend.h" #include "output/output_format.h" #include "output/daa/daa_write.h" #include "util/sequence/sequence.h" #include "util/util.h" using std::vector; using std::string; namespace Extension { TextBuffer* generate_output(vector &targets, BlockId query_block_id, Statistics &stat, const Search::Config& cfg) { const bool aligned = !targets.empty(); if (!aligned && !cfg.output_format->report_unaligned()) return nullptr; const SequenceSet& query_seqs = cfg.query->seqs(), &ref_seqs = cfg.target->seqs(); TextBuffer* out = new TextBuffer; std::unique_ptr f(cfg.output_format->clone()); size_t seek_pos = 0; unsigned n_hsp = 0, hit_hsps = 0; Output::Info info{ cfg.query->seq_info(query_block_id), targets.empty(), cfg.db.get(), *out, Util::Seq::AccessionParsing(), cfg.db->sequence_count(), cfg.db->letters() }; TranslatedSequence query = query_seqs.translated_seq(align_mode.query_translated ? cfg.query->source_seqs()[query_block_id] : query_seqs[query_block_id], query_block_id * align_mode.query_contexts); const char *query_title = cfg.query->ids()[query_block_id]; const double query_self_aln_score = cfg.query->has_self_aln() ? cfg.query->self_aln_score(query_block_id) : 0.0; if (cfg.iterated()) { if (aligned) seek_pos = IntermediateRecord::write_query_intro(*out, query_block_id); } else if (*f == OutputFormat::daa) { if (aligned) seek_pos = write_daa_query_record(*out, query_title, query.source()); } else if (aligned || config.report_unaligned != 0) f->print_query_intro(info); for (int i = 0; i < (int)targets.size(); ++i) { if (targets[i].hsp.empty()) throw std::runtime_error("generate_output: target with no hsps."); const BlockId subject_id = targets[i].target_block_id; const int64_t database_id = cfg.target->block_id2oid(subject_id); const unsigned subject_len = (unsigned)ref_seqs[subject_id].length(); const double target_self_aln_score = cfg.target->has_self_aln() ? cfg.target->self_aln_score(subject_id) : 0.0; hit_hsps = 0; for (Hsp &hsp : targets[i].hsp) { if (*f == OutputFormat::daa) write_daa_record(*out, hsp, safe_cast(cfg.target->dict_id(cfg.current_ref_block, subject_id, *cfg.db, *f))); else if(cfg.iterated()) IntermediateRecord::write(*out, hsp, query_block_id, cfg.target->dict_id(cfg.current_ref_block, subject_id, *cfg.db, *f), database_id, cfg.output_format.get()); else { const string target_title = cfg.target->has_ids() ? cfg.target->ids()[subject_id] : (flag_any(f->flags, Output::Flags::SSEQID) ? cfg.db->seqid(database_id, config.sallseqid) : ""); f->print_match(HspContext(hsp, query_block_id, cfg.query->block_id2oid(query_block_id), query, query_title, database_id, subject_len, target_title.c_str(), i, hit_hsps, cfg.target->unmasked_seqs().empty() ? cfg.target->seqs()[subject_id] : cfg.target->unmasked_seqs()[subject_id], targets[i].ungapped_score, query_self_aln_score, target_self_aln_score), info); } ++n_hsp; ++hit_hsps; } } if (cfg.iterated()) { if (aligned) IntermediateRecord::finish_query(*out, seek_pos); } else { stat.inc(Statistics::MATCHES, n_hsp); stat.inc(Statistics::PAIRWISE, targets.size()); if (aligned) stat.inc(Statistics::ALIGNED); if (*f == OutputFormat::daa) { if (aligned) finish_daa_query_record(*out, seek_pos); } else if (aligned || config.report_unaligned != 0) f->print_query_epilog(info); } return out; } TextBuffer* generate_intermediate_output(const vector &targets, BlockId query_block_id, const Search::Config& cfg) { TextBuffer* out = new TextBuffer; if (targets.empty()) return out; size_t seek_pos = 0; seek_pos = IntermediateRecord::write_query_intro(*out, query_block_id); const Block& target = *cfg.target; for (size_t i = 0; i < targets.size(); ++i) { const BlockId block_id = targets[i].target_block_id; const size_t dict_id = target.dict_id(cfg.current_ref_block, block_id, *cfg.db, *cfg.output_format); for (const Hsp &hsp : targets[i].hsp) IntermediateRecord::write(*out, hsp, query_block_id, dict_id, target.block_id2oid(block_id), cfg.output_format.get()); /*if (config.global_ranking_targets > 0) IntermediateRecord::write(*out, subject_id, targets[i].ungapped_score, cfg);*/ } IntermediateRecord::finish_query(*out, seek_pos); return out; } }bbuchfink-diamond-08b3cbc/src/align/target.h000066400000000000000000000156531506104011400210660ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include "util/memory_resource.h" #include "util/geo/diagonal_segment.h" #include "basic/const.h" #include "util/hsp/approx_hsp.h" #include "stats/hauser_correction.h" #include "extend.h" #include "util/data_structures/flat_array.h" #include "stats/cbs.h" #include "dp/flags.h" #include "data/block/block.h" #include "util/parallel/thread_pool.h" #include "dp/score_profile.h" struct SequenceSet; namespace Search { struct Hit; } namespace Extension { struct SeedHit { int diag() const { return i - j; } bool operator<(const SeedHit& x) const { const int d1 = diag(), d2 = x.diag(); return d1 < d2 || (d1 == d2 && j < x.j); } Interval query_range() const { return { i,i + 1 }; } Interval target_range() const { return { j,j + 1 }; } DiagonalSegment diag_segment() const { return DiagonalSegment(i, j, 1, score); } int i, j, score; unsigned frame; }; struct WorkTarget { WorkTarget(BlockId block_id, const Sequence& seq, Sequence query, Loc query_len_true_aa, const ::Stats::Composition& query_comp, Loc max_target_len, Statistics& stats, std::pmr::monotonic_buffer_resource& pool); BlockId block_id; Sequence seq; std::array ungapped_score; std::array, MAX_CONTEXT> hsp; std::unique_ptr<::Stats::TargetMatrix> matrix; LongScoreProfile profile, profile_rev; bool done; }; std::vector ungapped_stage(const Sequence *query_seq, const HauserCorrection *query_cb, const ::Stats::Composition& query_comp, FlatArray::Iterator seed_hits, FlatArray::Iterator seed_hits_end, std::vector::const_iterator target_block_ids, DP::Flags flags, Statistics& stat, const Block& target_block, const Mode mode, std::pmr::monotonic_buffer_resource& pool, const Search::Config& cfg); struct Target { Target(const BlockId block_id, const Sequence &seq, int ungapped_score, std::unique_ptr<::Stats::TargetMatrix>&& matrix): block_id(block_id), seq(seq), filter_score(0), filter_evalue(DBL_MAX), best_context(0), ungapped_score(ungapped_score), matrix(std::move(matrix)), done(false) { } void add_hit(Hsp&& hsp) { if(hsp.evalue < filter_evalue) { filter_evalue = hsp.evalue; filter_score = hsp.score; best_context = hsp.frame; } this->hsp[hsp.frame].push_back(std::move(hsp)); } void add_hit(std::list &list, std::list::iterator it) { std::list &l = hsp[it->frame]; l.splice(l.end(), list, it); if (l.back().score > filter_score) { // should be evalue filter_evalue = l.back().evalue; filter_score = l.back().score; best_context = l.back().frame; } } void add_hit(const ApproxHsp& h, Loc qlen) { hsp[h.frame].emplace_back(h, qlen, seq.length()); if (h.evalue < filter_evalue) { filter_evalue = h.evalue; filter_score = h.score; } done = true; } static bool comp_evalue(const Target &t, const Target& u) { return t.filter_evalue < u.filter_evalue || (t.filter_evalue == u.filter_evalue && comp_score(t, u)); } static bool comp_score(const Target& t, const Target& u) { return t.filter_score > u.filter_score || (t.filter_score == u.filter_score && t.block_id < u.block_id); } void inner_culling(); void max_hsp_culling(); BlockId block_id; Sequence seq; int filter_score; double filter_evalue; int best_context; int ungapped_score; std::array, MAX_CONTEXT> hsp; std::unique_ptr<::Stats::TargetMatrix> matrix; bool done; }; struct TargetScore { uint32_t target; uint16_t score; #ifdef EVAL_TARGET double evalue; #endif bool operator<(const TargetScore& x) const { #ifdef EVAL_TARGET return evalue < x.evalue || (evalue == x.evalue && target < x.target); #else return score > x.score || (score == x.score && target < x.target); #endif } }; struct SeedHitList { FlatArray seed_hits; std::vector target_block_ids; std::vector target_scores; }; void culling(std::vector& targets, bool sort_only, const Search::Config& cfg); void culling(std::vector& targets, const Search::Config& cfg); bool append_hits(std::vector& targets, std::vector::iterator begin, std::vector::iterator end, const bool with_culling, const Search::Config& cfg); std::vector gapped_filter(const Sequence *query, const HauserCorrection* query_cbs, std::vector& targets, Statistics &stat); std::pair, std::vector> gapped_filter(const Sequence* query, const HauserCorrection* query_cbs, FlatArray::Iterator seed_hits, FlatArray::Iterator seed_hits_end, std::vector::const_iterator target_block_ids, Statistics& stat, DP::Flags flags, const Search::Config ¶ms); std::vector align(std::vector &targets, const Sequence *query_seq, const char* query_id, const HauserCorrection *query_cb, int source_query_len, DP::Flags flags, const HspValues hsp_values, const Mode mode, ThreadPool& tp, const Search::Config& cfg, Statistics &stat, std::pmr::monotonic_buffer_resource& pool); std::vector align(std::vector &targets, const int64_t previous_matches, const Sequence *query_seq, const char* query_id, const HauserCorrection *query_cb, int source_query_len, double query_self_aln_score, DP::Flags flags, const HspValues first_round, const bool first_round_culling, Statistics &stat, const Search::Config& cfg); std::vector full_db_align(const Sequence *query_seq, const HauserCorrection* query_cb, DP::Flags flags, const HspValues hsp_values, Statistics &stat, const Block& target_block); void recompute_alt_hsps(std::vector::iterator begin, std::vector::iterator end, const Sequence* query, const int query_source_len, const HauserCorrection* query_cb, const HspValues v, Statistics& stats); void apply_filters(std::vector::iterator begin, std::vector::iterator end, int source_query_len, const char* query_title, const double query_self_aln_score, const Sequence& query_seq, const Search::Config& cfg); std::vector extend( BlockId query_id, const Search::Config& cfg, Statistics &stat, DP::Flags flags, SeedHitList &l, std::pmr::monotonic_buffer_resource& pool); }bbuchfink-diamond-08b3cbc/src/align/ungapped.cpp000066400000000000000000000170141506104011400217270ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "basic/config.h" #include "stats/hauser_correction.h" #include "target.h" #include "dp/ungapped.h" #include "target.h" #include "util/parallel/thread_pool.h" #include "chaining/chaining.h" #include "def.h" #include "util/geo/geo.h" using std::array; using std::vector; using std::list; using std::atomic; using std::mutex; using std::pair; namespace Extension { WorkTarget::WorkTarget(BlockId block_id, const Sequence& seq, Sequence query, Loc query_len_true_aa, const ::Stats::Composition& query_comp, Loc max_target_len, Statistics& stats, std::pmr::monotonic_buffer_resource& pool) : block_id(block_id), seq(seq), done(false) { ungapped_score.fill(0); Stats::EMatrixAdjustRule rule; if ((rule = ::Stats::adjust_matrix(query_comp, query_len_true_aa, config.comp_based_stats, seq)) != Stats::eDontAdjustMatrix) { matrix.reset(new ::Stats::TargetMatrix(query_comp, query_len_true_aa, config.comp_based_stats, seq, stats, pool, rule)); if (config.anchored_swipe) { profile = DP::make_profile16(query, *matrix, query.length() + max_target_len + 32); profile_rev = profile.reverse(); } } } WorkTarget ungapped_stage(FlatArray::DataIterator begin, FlatArray::DataIterator end, const Sequence *query_seq, const HauserCorrection *query_cb, const ::Stats::Composition& query_comp, uint32_t block_id, Loc max_target_len, Statistics& stats, const Block& targets, const Mode mode, std::pmr::monotonic_buffer_resource& pool, const Search::Config& cfg) { array, MAX_CONTEXT> diagonal_segments; const SequenceSet& ref_seqs = targets.seqs(), &ref_seqs_unmasked = targets.unmasked_seqs(); //const bool masking = config.comp_based_stats == ::Stats::CBS::COMP_BASED_STATS_AND_MATRIX_ADJUST ? ::Stats::use_seg_masking(query_seq[0], ref_seqs_unmasked[block_id]) : true; const bool masking = true; const bool with_diag_filter = (config.hamming_ext || config.diag_filter_cov.present() || config.diag_filter_id.present()) && !config.mutual_cover.present() && align_mode.query_contexts == 1; WorkTarget target(block_id, masking ? ref_seqs[block_id] : ref_seqs_unmasked[block_id], *query_seq, ::Stats::count_true_aa(query_seq[0]), query_comp, max_target_len, stats, pool); if (mode == Mode::FULL) { for (FlatArray::DataIterator hit = begin; hit < end; ++hit) target.ungapped_score[hit->frame] = std::max(target.ungapped_score[hit->frame], hit->score); if (!with_diag_filter) return target; } if (end - begin == 1 && align_mode.query_translated) { // ??? target.ungapped_score[begin->frame] = begin->score; target.hsp[begin->frame].emplace_back(begin->diag(), begin->diag(), begin->score, begin->frame, begin->query_range(), begin->target_range(), begin->diag_segment()); return target; } std::sort(begin, end); for (FlatArray::DataIterator hit = begin; hit < end; ++hit) { const auto f = hit->frame; target.ungapped_score[f] = std::max(target.ungapped_score[f], hit->score); if (!diagonal_segments[f].empty() && diagonal_segments[f].back().diag() == hit->diag() && diagonal_segments[f].back().subject_end() >= hit->j) continue; const int8_t* cbs = ::Stats::CBS::hauser(config.comp_based_stats) ? query_cb[f].int8.data() : nullptr; const DiagonalSegment d = xdrop_ungapped(query_seq[f], cbs, target.seq, hit->i, hit->j, with_diag_filter); if (d.score > 0) diagonal_segments[f].push_back(d); } if (with_diag_filter) { const ApproxHsp h = Chaining::hamming_ext(diagonal_segments[0].begin(), diagonal_segments[0].end(), query_seq[0].length(), target.seq.length(), !cfg.lin_stage1_target && !config.lin_stage1); if (h.score > 0) { target.done = true; target.hsp[0].push_back(h); return target; } if (h.score < 0) { target.ungapped_score[0] = 0; return target; } } if (mode == Mode::FULL) return target; for (int frame = 0; frame < align_mode.query_contexts; ++frame) { if (diagonal_segments[frame].empty()) continue; std::stable_sort(diagonal_segments[frame].begin(), diagonal_segments[frame].end(), DiagonalSegment::cmp_diag); tie(std::ignore, target.hsp[frame]) = Chaining::run(query_seq[frame], target.seq, diagonal_segments[frame].begin(), diagonal_segments[frame].end(), config.log_extend, frame); target.hsp[frame].sort(ApproxHsp::cmp_diag); } return target; } void ungapped_stage_worker(size_t i, size_t thread_id, const Sequence *query_seq, const HauserCorrection *query_cb, const ::Stats::Composition* query_comp, FlatArray::Iterator seed_hits, vector::const_iterator target_block_ids, Loc max_target_len, vector *out, mutex *mtx, Statistics* stat, const Block* targets, const Mode mode, std::pmr::monotonic_buffer_resource* pool, const Search::Config *cfg) { Statistics stats; WorkTarget target = ungapped_stage(seed_hits.begin(i), seed_hits.end(i), query_seq, query_cb, *query_comp, target_block_ids[i], max_target_len, stats, *targets, mode, *pool, *cfg); { std::lock_guard guard(*mtx); out->push_back(std::move(target)); *stat += stats; } } vector ungapped_stage(const Sequence *query_seq, const HauserCorrection *query_cb, const ::Stats::Composition& query_comp, FlatArray::Iterator seed_hits, FlatArray::Iterator seed_hits_end, vector::const_iterator target_block_ids, DP::Flags flags, Statistics& stat, const Block& target_block, const Mode mode, std::pmr::monotonic_buffer_resource& pool, const Search::Config &cfg) { vector targets; const int64_t n = seed_hits_end - seed_hits; if(n == 0) return targets; Loc max_target_len = 0; /*if (config.anchored_swipe) { for(int64_t i= 0; i < n; ++i) max_target_len = std::max(max_target_len, target_block.seqs()[target_block_ids[i]].length()); }*/ targets.reserve(n); if (flag_any(flags, DP::Flags::PARALLEL)) { mutex mtx; Util::Parallel::scheduled_thread_pool_auto(config.threads_, n, ungapped_stage_worker, query_seq, query_cb, &query_comp, seed_hits, target_block_ids, max_target_len, &targets, &mtx, &stat, &target_block, mode, &pool, &cfg); } else { for (int64_t i = 0; i < n; ++i) { /*const double len_ratio = query_seq->length_ratio(target_block.seqs()[target_block_ids[i]]); if (len_ratio < config.min_length_ratio) continue;*/ targets.push_back(ungapped_stage(seed_hits.begin(i), seed_hits.end(i), query_seq, query_cb, query_comp, target_block_ids[i], max_target_len, stat, target_block, mode, pool, cfg)); for (const ApproxHsp& hsp : targets.back().hsp[0]) { Geo::assert_diag_bounds(hsp.d_max, query_seq[0].length(), targets.back().seq.length()); Geo::assert_diag_bounds(hsp.d_min, query_seq[0].length(), targets.back().seq.length()); assert(hsp.score > 0); assert(hsp.max_diag.score > 0); } } } return targets; } }bbuchfink-diamond-08b3cbc/src/basic/000077500000000000000000000000001506104011400174045ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/basic/basic.cpp000066400000000000000000000336241506104011400212010ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "value.h" #include "shape_config.h" #include "util/sequence/translate.h" #include "statistics.h" #include "sequence.h" #include "stats/standard_matrix.h" #include "util/log_stream.h" const char* Const::version_string = "2.1.14"; using std::string; using std::vector; using std::count; const char* Const::program_name = "diamond"; AlignMode::AlignMode(unsigned mode) : mode(mode) { sequence_type = SequenceType::amino_acid; switch (mode) { case blastx: input_sequence_type = SequenceType::nucleotide; query_contexts = 6; query_translated = true; query_len_factor = 3; break; case blastn: input_sequence_type = SequenceType::nucleotide; query_translated = false; query_contexts = 1; query_len_factor = 1; sequence_type = SequenceType::nucleotide; break; default: input_sequence_type = SequenceType::amino_acid; query_contexts = 1; query_translated = false; query_len_factor = 1; } } unsigned AlignMode::from_command(unsigned command) { switch (command) { case Config::blastx: return blastx; case Config::blastn: return blastn; default: return blastp; } } AlignMode align_mode(AlignMode::blastp); Statistics statistics; ShapeConfig shapes; unsigned shape_from, shape_to; const Letter Translator::reverseLetter[5] = { 3, 2, 1, 0, 4 }; Letter Translator::lookup[5][5][5]; Letter Translator::lookupReverse[5][5][5]; const char* Translator::codes[] = { 0, "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 1 "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG", // 2 "FFLLSSSSYY**CCWWTTTTPPPPHHQQRRRRIIMMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 3 "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 4 "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSSSVVVVAAAADDEEGGGG", // 5 "FFLLSSSSYYQQCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 6 0, 0, "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG", // 9 "FFLLSSSSYY**CCCWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 10 "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 11 "FFLLSSSSYY**CC*WLLLSPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 12 "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSGGVVVVAAAADDEEGGGG", // 13 "FFLLSSSSYYY*CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG", // 14 0, "FFLLSSSSYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 16 0, 0, 0, 0, "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNNKSSSSVVVVAAAADDEEGGGG", // 21 "FFLLSS*SYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 22 "FF*LSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 23 "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSSKVVVVAAAADDEEGGGG", // 24 "FFLLSSSSYY**CCGWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", // 25 "FFLLSSSSYY**CC*WLLLAPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG" // 26 }; void Translator::init(unsigned id) { static const unsigned idx[] = { 2, 1, 3, 0 }; if (id >= sizeof(codes) / sizeof(codes[0]) || codes[id] == 0) throw std::runtime_error("Invalid genetic code id."); for (unsigned i = 0; i < 5; ++i) for (unsigned j = 0; j < 5; ++j) for (unsigned k = 0; k < 5; ++k) if (i == 4 || j == 4 || k == 4) { lookup[i][j][k] = value_traits.mask_char; lookupReverse[i][j][k] = value_traits.mask_char; } else { lookup[i][j][k] = value_traits.from_char(codes[id][(int)idx[i] * 16 + (int)idx[j] * 4 + (int)idx[k]]); lookupReverse[i][j][k] = value_traits.from_char(codes[id][idx[(int)reverseLetter[i]] * 16 + idx[(int)reverseLetter[j]] * 4 + idx[(int)reverseLetter[k]]]); } for (unsigned i = 0; i < 4; ++i) for (unsigned j = 0; j < 4; ++j) { if (count(lookup[i][j], lookup[i][j] + 4, lookup[i][j][0]) == 4) lookup[i][j][4] = lookup[i][j][0]; if (count(lookupReverse[i][j], lookupReverse[i][j] + 4, lookupReverse[i][j][0]) == 4) lookupReverse[i][j][4] = lookupReverse[i][j][0]; } } vector Sequence::from_string(const char* str, const ValueTraits&vt, int64_t line) { vector seq; seq.reserve(strlen(str)); while (*str) seq.push_back(vt.from_char(*(str++))); return seq; } void Seed::enum_neighborhood(unsigned pos, int treshold, vector& out, int score) { const size_t l = data_[pos]; score -= score_matrix(l, l); for (size_t i = 0; i < 20; ++i) { int new_score = score + score_matrix(l, i); data_[pos] = (Letter)i; if (new_score >= treshold) { if (pos < config.seed_weight - 1) enum_neighborhood(pos + 1, treshold, out, new_score); else out.push_back(*this); } } data_[pos] = (Letter)l; } void Seed::enum_neighborhood(int treshold, vector& out) { out.clear(); enum_neighborhood(0, treshold, out, score(*this)); } std::vector Sequence::reverse() const { std::vector v; v.reserve(len_); std::reverse_copy(data(), end(), std::back_inserter(v)); return v; } void Statistics::print() const { using std::endl; //log_stream << "Used ref size = " << data_[REF_SIZE] << endl; //log_stream << "Traceback errors = " << data_[BIAS_ERRORS] << endl; //log_stream << "Low complexity seeds = " << data_[LOW_COMPLEXITY_SEEDS] << endl; log_stream << "Hits (filter stage 0) = " << data_[SEED_HITS] << endl; log_stream << "Hits (filter stage 1) = " << data_[TENTATIVE_MATCHES1] << " (" << data_[TENTATIVE_MATCHES1] * 100.0 / data_[SEED_HITS] << " %)" << endl; log_stream << "Hits (filter stage 2) = " << data_[TENTATIVE_MATCHES2] << " (" << data_[TENTATIVE_MATCHES2] * 100.0 / data_[TENTATIVE_MATCHES1] << " %)" << endl; log_stream << "Hits (filter stage 3) = " << data_[TENTATIVE_MATCHES3] << " (" << data_[TENTATIVE_MATCHES3] * 100.0 / data_[TENTATIVE_MATCHES2] << " %)" << endl; //log_stream << "Hits (filter stage 4) = " << data_[TENTATIVE_MATCHES4] << " (" << data_[TENTATIVE_MATCHES4] * 100.0 / data_[TENTATIVE_MATCHES3] << " %)" << endl; log_stream << "Target hits (stage 0) = " << data_[TARGET_HITS0] << endl; log_stream << "Target hits (stage 1) = " << data_[TARGET_HITS1] << endl; log_stream << "Target hits (stage 2) = " << data_[TARGET_HITS2] << endl; log_stream << "Target hits (stage 3) = " << data_[TARGET_HITS3] << " (" << data_[TARGET_HITS3_CBS] << " (" << (double)data_[TARGET_HITS3_CBS] * 100.0 / data_[TARGET_HITS3] << "%) with CBS)" << endl; log_stream << "Target hits (stage 4) = " << data_[TARGET_HITS4] << endl; log_stream << "Target hits (stage 5) = " << data_[TARGET_HITS5] << endl; log_stream << "Target hits (stage 6) = " << data_[TARGET_HITS6] << endl; log_stream << "Swipe realignments = " << data_[SWIPE_REALIGN] << endl; if (data_[MASKED_LAZY]) log_stream << "Lazy maskings = " << data_[MASKED_LAZY] << endl; log_stream << "Matrix adjusts = " << data_[MATRIX_ADJUST_COUNT] << endl; log_stream << "Comp. based stats = " << data_[COMP_BASED_STATS_COUNT] << endl; log_stream << "Failed cbs = " << data_[FAILED_COMP_BASED_STATS] << endl; log_stream << "Extensions (8 bit) = " << data_[EXT8] << endl; log_stream << "Extensions (16 bit) = " << data_[EXT16] << endl; log_stream << "Extensions (32 bit) = " << data_[EXT32] << endl; log_stream << "Overflows (8 bit) = " << data_[EXT_OVERFLOW_8] << endl; log_stream << "Wasted (16 bit) = " << data_[EXT_WASTED_16] << endl; log_stream << "Effort (Extension) = " << 2 * data_[EXT16] + data_[EXT8] << endl; log_stream << "Effort (Cells) = " << 2 * data_[DP_CELLS_16] + data_[DP_CELLS_8] << endl; log_stream << "Cells (8 bit) = " << data_[DP_CELLS_8] << endl; log_stream << "Cells (16 bit) = " << data_[DP_CELLS_16] << endl; log_stream << "SWIPE tasks = " << data_[SWIPE_TASKS_TOTAL] << endl; log_stream << "SWIPE tasks (async) = " << data_[SWIPE_TASKS_ASYNC] << endl; log_stream << "Trivial aln = " << data_[TRIVIAL_ALN] << endl; log_stream << "Hard queries = " << data_[HARD_QUERIES] << endl; #ifdef DP_STAT log_stream << "Gross DP Cells = " << data_[GROSS_DP_CELLS] << endl; log_stream << "Net DP Cells = " << data_[NET_DP_CELLS] << " (" << data_[NET_DP_CELLS] * 100.0 / data_[GROSS_DP_CELLS] << " %)" << endl; #endif log_stream << "Gapped filter (targets) = " << data_[GAPPED_FILTER_TARGETS] << endl; log_stream << "Gapped filter (hits) stage 1 = " << data_[GAPPED_FILTER_HITS1] << endl; log_stream << "Gapped filter (hits) stage 2 = " << data_[GAPPED_FILTER_HITS2] << endl; log_stream << "Time (Load seed hit targets) = " << (double)data_[TIME_LOAD_HIT_TARGETS] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Sort targets by score) = " << (double)data_[TIME_SORT_TARGETS_BY_SCORE] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Gapped filter) = " << (double)data_[TIME_GAPPED_FILTER] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Matrix adjust) = " << (double)data_[TIME_MATRIX_ADJUST] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Chaining) = " << (double)data_[TIME_CHAINING] / 1e6 << "s (CPU)" << endl; log_stream << "Time (DP target sorting) = " << (double)data_[TIME_TARGET_SORT] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Query profiles) = " << (double)data_[TIME_PROFILE] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Smith Waterman) = " << (double)data_[TIME_SW] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Anchored SWIPE Alloc) = " << (double)data_[TIME_ANCHORED_SWIPE_ALLOC] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Anchored SWIPE Sort) = " << (double)data_[TIME_ANCHORED_SWIPE_SORT] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Anchored SWIPE Add) = " << (double)data_[TIME_ANCHORED_SWIPE_ADD] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Anchored SWIPE Output) = " << (double)data_[TIME_ANCHORED_SWIPE_OUTPUT] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Anchored SWIPE) = " << (double)data_[TIME_ANCHORED_SWIPE] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Smith Waterman TB) = " << (double)data_[TIME_TRACEBACK_SW] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Smith Waterman-32) = " << (double)data_[TIME_EXT_32] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Traceback) = " << (double)data_[TIME_TRACEBACK] / 1e6 << "s (CPU)" << endl; log_stream << "Time (Target parallel) = " << (double)data_[TIME_TARGET_PARALLEL] / 1e6 << "s (wall)" << endl; log_stream << "Time (Load seed hits) = " << (double)data_[TIME_LOAD_SEED_HITS] / 1e6 << "s (wall)" << endl; log_stream << "Time (Sort seed hits) = " << (double)data_[TIME_SORT_SEED_HITS] / 1e6 << "s (wall)" << endl; log_stream << "Time (Extension) = " << (double)data_[TIME_EXT] / 1e6 << "s (wall)" << endl; //log_stream << "Time (greedy extension) = " << data_[TIME_GREEDY_EXT]/1e9 << "s" << endl; //log_stream << "Gapped hits = " << data_[GAPPED_HITS] << endl; //log_stream << "Overlap hits = " << data_[DUPLICATES] << endl; //log_stream << "Secondary hits = " << data_[SECONDARY_HITS] << endl; //log_stream << "Erased hits = " << data_[ERASED_HITS] << endl; //log_stream << "High similarity hits = " << data_[HIGH_SIM] << endl; //log_stream << "Net hits = " << data_[OUT_HITS] << endl; //log_stream << "Matches = " << data_[OUT_MATCHES] << endl; //log_stream << "Total score = " << data_[SCORE_TOTAL] << endl; //log_stream << "Aligned query len = " << data_[ALIGNED_QLEN] << endl; //log_stream << "Gapped matches = " << data_[GAPPED] << endl; //log_stream << "MSE = " << (double)data_[SQUARED_ERROR] / (double)data_[OUT_HITS] << endl; //log_stream << "Cells = " << data_[CELLS] << endl; verbose_stream << "Temporary disk space used (search): " << (double)data_[SEARCH_TEMP_SPACE] / (1 << 30) << " GB" << endl; message_stream << "Reported " << data_[PAIRWISE] << " pairwise alignments, " << data_[MATCHES] << " HSPs." << endl; message_stream << data_[ALIGNED] << " queries aligned." << endl; } Reduction::Reduction(const char* definition_string) { memset(map_, 0, sizeof(map_)); memset(map8_, 0, sizeof(map8_)); memset(map8b_, 0, sizeof(map8b_)); map_[(long)MASK_LETTER] = MASK_LETTER; map_[(long)STOP_LETTER] = MASK_LETTER; const vector tokens(Util::String::tokenize(definition_string, " ")); size_ = (unsigned)tokens.size(); bit_size_exact_ = log(size_) / log(2); bit_size_ = (int)ceil(bit_size_exact_); freq_.fill(0.0); for (unsigned i = 0; i < size_; ++i) for (unsigned j = 0; j < tokens[i].length(); ++j) { const char ch = tokens[i][j]; const long letter = (long)value_traits.from_char(ch); map_[letter] = i; map8_[letter] = i; map8b_[letter] = i; freq_[i] += Stats::blosum62.background_freqs[letter]; } for (double& f : freq_) f = std::log(f); map8_[(long)MASK_LETTER] = (Letter)size_; map8_[(long)STOP_LETTER] = (Letter)size_; map8_[(long)DELIMITER_LETTER] = (Letter)size_; map8b_[(long)MASK_LETTER] = (Letter)(size_ + 1); map8b_[(long)STOP_LETTER] = (Letter)(size_ + 1); map8b_[(long)DELIMITER_LETTER] = (Letter)(size_ + 1); } std::string Reduction::decode_seed(const uint64_t seed, const size_t len) const { string s(len, '-'); uint64_t c = seed; for (size_t i = 0; i < len; ++i) { s[len - i - 1] = amino_acid_traits.alphabet[c % size_]; c /= size_; } return s; }bbuchfink-diamond-08b3cbc/src/basic/config.cpp000066400000000000000000001340701506104011400213620ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include "util/command_line_parser.h" #include "config.h" #include "util/util.h" #include "util/log_stream.h" #include "basic/value.h" #include "stats/score_matrix.h" #include "util/io/temp_file.h" #include "util/sequence/translate.h" #include "masking/masking.h" #include "util/system/system.h" #include "util/simd.h" #include "search/search.h" #include "stats/cbs.h" #include "basic/shape.h" #include "util/io/input_file.h" using std::thread; using std::stringstream; using std::endl; using std::ostream; using std::unique_ptr; using std::string; using std::pair; using std::cout; using std::cerr; using std::vector; const EMap EnumTraits::to_string = { { Sensitivity::FASTER, "faster" }, { Sensitivity::FAST, "fast" }, { Sensitivity::DEFAULT, "default" }, { Sensitivity::LINCLUST_40, "linclust-40" }, { Sensitivity::LINCLUST_20, "linclust-20" }, { Sensitivity::MID_SENSITIVE, "mid-sensitive" }, { Sensitivity::SHAPES6x10, "shapes-6x10" }, { Sensitivity::SHAPES30x10, "shapes-30x10" }, { Sensitivity::SENSITIVE, "sensitive" }, { Sensitivity::MORE_SENSITIVE, "more-sensitive" }, { Sensitivity::VERY_SENSITIVE, "very-sensitive" }, { Sensitivity::ULTRA_SENSITIVE, "ultra-sensitive" } }; const SEMap EnumTraits::from_string = { { "faster", Sensitivity::FASTER }, { "fast", Sensitivity::FAST }, { "default", Sensitivity::DEFAULT }, { "mid-sensitive", Sensitivity::MID_SENSITIVE }, { "shapes-6x10", Sensitivity::SHAPES6x10 }, { "shapes-30x10", Sensitivity::SHAPES30x10 }, { "linclust-40", Sensitivity::LINCLUST_40 }, { "linclust-20", Sensitivity::LINCLUST_20 }, { "sensitive", Sensitivity::SENSITIVE }, { "more-sensitive", Sensitivity::MORE_SENSITIVE }, { "very-sensitive", Sensitivity::VERY_SENSITIVE }, { "ultra-sensitive", Sensitivity::ULTRA_SENSITIVE } }; const SEMap EnumTraits::from_string = { { "gvc", GraphAlgo::GREEDY_VERTEX_COVER }, { "len", GraphAlgo::LEN_SORTED } }; const EMap EnumTraits::to_string = { { Config::Algo::DOUBLE_INDEXED, "Double-indexed" }, { Config::Algo::QUERY_INDEXED, "Query-indexed"}, {Config::Algo::CTG_SEED, "Query-indexed with contiguous seed"} }; const SEMap EnumTraits::from_string = { {"", Config::Algo::AUTO}, { "0", Config::Algo::DOUBLE_INDEXED}, {"1", Config::Algo::QUERY_INDEXED}, {"ctg", Config::Algo::CTG_SEED} }; const EMap EnumTraits::to_string = { {SequenceType::amino_acid,"prot"}, { SequenceType::nucleotide,"nucl"} }; const SEMap EnumTraits::from_string = { {"prot",SequenceType::amino_acid}, {"nucl",SequenceType::nucleotide} }; Config config; pair block_size(int64_t memory_limit, int64_t db_letters, Sensitivity s, bool lin, int thread_count) { const double AVG_SEQ_LENGTH_EST = 200; const double m = (double)memory_limit / 1e9; const int min = Search::sensitivity_traits.at(s).minimizer_window, sketch_size = Search::sensitivity_traits.at(s).sketch_size, max_c = min > 0 || sketch_size > 0 ? 1 : (lin ? 16 : 4), shape_weight = Shape(Search::shape_codes.at(s).front().c_str(), 0).weight_; const double max_b = lin ? 32768 : (s <= Sensitivity::DEFAULT ? 12.0 : (s <= Sensitivity::MORE_SENSITIVE ? 6.0 : 1.6)); // c = m < 40.0 && s <= Sensitivity::MORE_SENSITIVE && min == 0 && sketch_size == 0 ? 4 : 1; assert(min == 0 || sketch_size == 0); int c = 0; double b; do { ++c; double seeds_per_letter = (sketch_size > 0 ? 1 / AVG_SEQ_LENGTH_EST * sketch_size : 1.0) / c; if (min > 0) seeds_per_letter /= (double)min / 2; const double hash_join_factor = 1.0 + (double)thread_count / (seedp_count(Search::seedp_bits(shape_weight, thread_count, c)) / c); const double seed_array_entry_size = 18.0 * hash_join_factor; b = m / (seed_array_entry_size * seeds_per_letter + 2.0); } while ((int64_t)b * 1000000000 < db_letters && b < max_b && c < max_c); /*if (b > 4) b = floor(b); else if (b > 0.4) b = floor(b * 10) / 10; else b = floor(b * 1000) / 1000;*/ if (!config.no_block_size_limit) b = std::min(b, max_b); return { std::max(b, 0.001), c }; } template T set_string_option(const string& s, const string& name, const vector>& values) { if (s.empty()) return (T)0; for (auto& i : values) if (s == i.first) return i.second; throw std::runtime_error("Invalid argument for option " + name + ". Allowed values are:" + std::accumulate(values.begin(), values.end(), string(), [](const string& s, const pair& v) { return s + ' ' + v.first; })); } void Config::set_sens(Sensitivity sens) { if (sensitivity != Sensitivity::DEFAULT) throw std::runtime_error("Sensitivity switches are mutually exclusive."); sensitivity = sens; } std::string Config::single_query_file() const { return query_file.empty() ? string() : query_file.front(); } Compressor Config::compressor() const { if (compression.empty() || compression == "0") return Compressor::NONE; else if (compression == "1") return Compressor::ZLIB; else if (compression == "zstd") return Compressor::ZSTD; else throw std::runtime_error("Invalid compression algorithm: " + compression); } Config::Config(int argc, const char **argv, bool check_io, CommandLineParser& parser) { parser.add_command("makedb", "Build DIAMOND database from a FASTA file", makedb) .add_command("prepdb", "", prep_db) .add_command("blastp", "Align amino acid query sequences against a protein reference database", blastp) .add_command("blastx", "Align DNA query sequences against a protein reference database", blastx) .add_command("cluster", "Cluster protein sequences", cluster) .add_command("linclust", "Cluster protein sequences in linear time", LINCLUST) .add_command("realign", "Realign clustered sequences against their centroids", CLUSTER_REALIGN) .add_command("recluster", "Recompute clustering to fix errors", RECLUSTER) .add_command("reassign", "Reassign clustered sequences to the closest centroid", CLUSTER_REASSIGN) .add_command("view", "View DIAMOND alignment archive (DAA) formatted file", view) .add_command("merge-daa", "Merge DAA files", MERGE_DAA) .add_command("help", "Produce help message", help) .add_command("version", "Display version information", version) .add_command("getseq", "Retrieve sequences from a DIAMOND database file", getseq) .add_command("dbinfo", "Print information about a DIAMOND database file", dbinfo) .add_command("test", "Run regression tests", regression_test) .add_command("makeidx", "Make database index", makeidx) .add_command("greedy-vertex-cover", "Compute greedy vertex cover", GREEDY_VERTEX_COVER) .add_command("roc", "", roc) .add_command("benchmark", "", benchmark) .add_command("deepclust", "", DEEPCLUST) #ifdef EXTRA .add_command("random-seqs", "", random_seqs) .add_command("sort", "", sort) .add_command("dbstat", "", db_stat) .add_command("mask", "", mask) .add_command("fastq2fasta", "", fastq2fasta) .add_command("info", "", info) .add_command("seed-stat", "", seed_stat) .add_command("smith-waterman", "", smith_waterman) .add_command("translate", "", translate) .add_command("simulate-seqs", "", simulate_seqs) .add_command("split", "", split) .add_command("upgma", "", upgma) .add_command("upgmamc", "", upgma_mc) .add_command("reverse", "", reverse_seqs) .add_command("compute-medoids", "", compute_medoids) .add_command("mutate", "", mutate) .add_command("roc-id", "", rocid) .add_command("find-shapes", "", find_shapes) .add_command("hashseqs", "", HASH_SEQS) .add_command("listseeds", "", LIST_SEEDS) .add_command("blastn", "Align DNA query sequences against a DNA reference database", blastn) .add_command("length-sort", "", LENGTH_SORT) .add_command("wc", "", WORD_COUNT) .add_command("cut", "", CUT) .add_command("model-seqs", "", MODEL_SEQS) .add_command("make-seed-table", "", MAKE_SEED_TABLE) #endif ; auto& general = parser.add_group("General options", { makedb, blastp, blastx, cluster, view, getseq, dbinfo, makeidx, CLUSTER_REALIGN, GREEDY_VERTEX_COVER, DEEPCLUST, RECLUSTER, MERGE_DAA, LINCLUST, CLUSTER_REASSIGN }); general.add() ("threads", 'p', "number of CPU threads", threads_) ("verbose", 'v', "verbose console output", verbose) ("log", 0, "enable debug log", debug_log) ("quiet", 0, "disable console output", quiet) ("tmpdir", 't', "directory for temporary files", tmpdir); auto& general_db = parser.add_group("General/database options", { makedb, blastp, blastx, cluster, getseq, dbinfo, makeidx, CLUSTER_REALIGN, GREEDY_VERTEX_COVER, DEEPCLUST, RECLUSTER, LINCLUST, CLUSTER_REASSIGN }); general_db.add() ("db", 'd', "database file", database); auto& general_out = parser.add_group("General/output", { blastp, blastx, cluster, view, getseq, CLUSTER_REALIGN, GREEDY_VERTEX_COVER, DEEPCLUST, RECLUSTER, MERGE_DAA, LINCLUST, CLUSTER_REASSIGN }); general_out.add() ("out", 'o', "output file", output_file); auto& general_out2 = parser.add_group("General/output2", { blastp, blastx, cluster, view, CLUSTER_REALIGN, GREEDY_VERTEX_COVER, DEEPCLUST, RECLUSTER, LINCLUST, CLUSTER_REASSIGN }); general_out2.add() ("header", 0, "Use header lines in tabular output format (0/simple/verbose).", output_header, Option>(), 0); string dbstring; auto& makedb_opt = parser.add_group("Makedb options", { makedb, MERGE_DAA }); makedb_opt.add() ("in", 0, "input reference file in FASTA format/input DAA files for merge-daa", input_ref_file); auto& makedb_tax_opt = parser.add_group("Makedb/taxon options", { makedb }); makedb_tax_opt.add() ("taxonmap", 0, "protein accession to taxid mapping file", prot_accession2taxid) ("taxonnodes", 0, "taxonomy nodes.dmp from NCBI", nodesdmp) ("taxonnames", 0, "taxonomy names.dmp from NCBI", namesdmp); auto& align_clust_realign = parser.add_group("Aligner/Clustering/Realign options", { blastp, blastx, cluster, RECLUSTER, CLUSTER_REASSIGN, DEEPCLUST, CLUSTER_REALIGN, LINCLUST }); align_clust_realign.add() ("comp-based-stats", 0, "composition based statistics mode (0-4)", comp_based_stats, 1u) ("masking", 0, "masking algorithm (none, seg, tantan=default)", masking_) ("soft-masking", 0, "soft masking (none=default, seg, tantan)", soft_masking) ("no-block-size-limit", 0, "", no_block_size_limit); auto& align_clust = parser.add_group("Aligner/Clustering options", { blastp, blastx, cluster, RECLUSTER, CLUSTER_REASSIGN, DEEPCLUST, LINCLUST }); align_clust.add() ("evalue", 'e', "maximum e-value to report alignments (default=0.001)", max_evalue, 0.001) ("motif-masking", 0, "softmask abundant motifs (0/1)", motif_masking) ("approx-id", 0, "minimum approx. identity% to report an alignment/to cluster sequences", approx_min_id) ("ext", 0, "Extension mode (banded-fast/banded-slow/full)", ext_); auto& aligner_view = parser.add_group("Aligner/view options", { blastp, blastx, view }); aligner_view.add() ("max-target-seqs", 'k', "maximum number of target sequences to report alignments for (default=25)", max_target_seqs_) ("top", 0, "report alignments within this percentage range of top alignment score (overrides --max-target-seqs)", toppercent); auto& aligner_sens = parser.add_group("Aligner/sens options", { blastp, blastx, makeidx }); aligner_sens.add() ("faster", 0, "enable faster mode", mode_faster) ("fast", 0, "enable fast mode", mode_fast) ("mid-sensitive", 0, "enable mid-sensitive mode", mode_mid_sensitive) ("linclust-20", 0, "enable mode for linear search at 20% identity", mode_linclust_20) ("shapes-6x10", 0, "enable mode using 30 seed shapes of weight 10", mode_shapes6x10) ("shapes-30x10", 0, "enable mode using 30 seed shapes of weight 10", mode_shapes30x10) ("sensitive", 0, "enable sensitive mode)", mode_sensitive) ("more-sensitive", 0, "enable more sensitive mode", mode_more_sensitive) ("very-sensitive", 0, "enable very sensitive mode", mode_very_sensitive) ("ultra-sensitive", 0, "enable ultra sensitive mode", mode_ultra_sensitive) ("shapes", 's', "number of seed shapes (default=all available)", shapes); auto& aligner = parser.add_group("Aligner options", { blastp, blastx }); aligner.add() ("query", 'q', "input query file", query_file) ("strand", 0, "query strands to search (both/minus/plus)", query_strands, string("both")) ("un", 0, "file for unaligned queries", unaligned) ("al", 0, "file or aligned queries", aligned_file) ("unfmt", 0, "format of unaligned query file (fasta/fastq)", unfmt, string("fasta")) ("alfmt", 0, "format of aligned query file (fasta/fastq)", alfmt, string("fasta")) ("unal", 0, "report unaligned queries (0=no, 1=yes)", report_unaligned, -1) ("max-hsps", 0, "maximum number of HSPs per target sequence to report for each query (default=1)", max_hsps, 1u) ("range-culling", 0, "restrict hit culling to overlapping query ranges", query_range_culling) ("compress", 0, "compression for output files (0=none, 1=gzip, zstd)", compression) ("min-score", 0, "minimum bit score to report alignments (overrides e-value setting)", min_bit_score) ("id", 0, "minimum identity% to report an alignment", min_id) ("query-cover", 0, "minimum query cover% to report an alignment", query_cover) ("subject-cover", 0, "minimum subject cover% to report an alignment", subject_cover) ("swipe", 0, "exhaustive alignment against all database sequences", swipe_all) ("iterate", 0, "iterated search with increasing sensitivity", iterate, Option>(), 0) ("global-ranking", 'g', "number of targets for global ranking", global_ranking_targets) ("block-size", 'b', "sequence block size in billions of letters (default=2.0)", chunk_size) ("index-chunks", 'c', "number of chunks for index processing (default=4)", lowmem_) ("gapopen", 0, "gap open penalty", gap_open, -1) ("gapextend", 0, "gap extension penalty", gap_extend, -1) ("matrix", 0, "score matrix for protein alignment (default=BLOSUM62)", matrix, string("blosum62")) ("custom-matrix", 0, "file containing custom scoring matrix", matrix_file) ("frameshift", 'F', "frame shift penalty (default=disabled)", frame_shift) ("long-reads", 0, "short for --range-culling --top 10 -F 15", long_reads) ("query-gencode", 0, "genetic code to use to translate query (see user manual)", query_gencode, 1u) ("salltitles", 0, "include full subject titles in DAA file", salltitles) ("sallseqid", 0, "include all subject ids in DAA file", sallseqid) ("no-self-hits", 0, "suppress reporting of identical self hits", no_self_hits) ("taxonlist", 0, "restrict search to list of taxon ids (comma-separated)", taxonlist) ("taxon-exclude", 0, "exclude list of taxon ids (comma-separated)", taxon_exclude) ("seqidlist", 0, "filter the database by list of accessions", seqidlist) ("skip-missing-seqids", 0, "ignore accessions missing in the database", skip_missing_seqids); auto& format = parser.add_group("Output format options", { blastp, blastx, view, CLUSTER_REALIGN }); format.add() ("outfmt", 'f', "output format\n\ \t0 = BLAST pairwise\n\ \t5 = BLAST XML\n\ \t6 = BLAST tabular\n\ \t100 = DIAMOND alignment archive (DAA)\n\ \t101 = SAM\n\ \t102 = Taxonomic classification\n\ \t103 = PAF\n\ \t104 = JSON (flat)\n\n\ \tValues 6 and 104 may be followed by a space-separated list of these keywords:\n\n\ \tqseqid means Query Seq - id\n\ \tqlen means Query sequence length\n\ \tsseqid means Subject Seq - id\n\ \tsallseqid means All subject Seq - id(s), separated by a ';'\n\ \tslen means Subject sequence length\n\ \tqstart means Start of alignment in query\n\ \tqend means End of alignment in query\n\ \tsstart means Start of alignment in subject\n\ \tsend means End of alignment in subject\n\ \tqseq means Aligned part of query sequence\n\ \tqseq_gapped means Aligned part of query sequence (with gaps)\n\ \tqseq_translated means Aligned part of query sequence (translated)\n\ \tfull_qseq means Query sequence\n\ \tfull_qseq_mate means Query sequence of the mate\n\ \tsseq means Aligned part of subject sequence\n\ \tsseq_gapped means Aligned part of subject sequence (with gaps)\n\ \tfull_sseq means Subject sequence\n\ \tevalue means Expect value\n\ \tbitscore means Bit score\n\ \tcorrected_bitscore means Bit score corrected for edge effects\n\ \tscore means Raw score\n\ \tlength means Alignment length\n\ \tpident means Percentage of identical matches\n\ \tapprox_pident means Approximate percentage of identical matches\n\ \tnident means Number of identical matches\n\ \tmismatch means Number of mismatches\n\ \tpositive means Number of positive - scoring matches\n\ \tgapopen means Number of gap openings\n\ \tgaps means Total number of gaps\n\ \tppos means Percentage of positive - scoring matches\n\ \tqframe means Query frame\n\ \tbtop means Blast traceback operations(BTOP)\n\ \tcigar means CIGAR string\n\ \tstaxids means unique Subject Taxonomy ID(s), separated by a ';' (in numerical order)\n\ \tsscinames means unique Subject Scientific Name(s), separated by a ';'\n\ \tsskingdoms means unique Subject Super Kingdom(s), separated by a ';'\n\ \tskingdoms means unique Subject Kingdom(s), separated by a ';'\n\ \tsphylums means unique Subject Phylum(s), separated by a ';'\n\ \tstitle means Subject Title\n\ \tsalltitles means All Subject Title(s), separated by a '<>'\n\ \tqcovhsp means Query Coverage Per HSP\n\ \tscovhsp means Subject Coverage Per HSP\n\ \tqtitle means Query title\n\ \tqqual means Query quality values for the aligned part of the query\n\ \tfull_qqual means Query quality values\n\ \tqstrand means Query strand\n\ \n\tDefault: qseqid sseqid pident length mismatch gapopen qstart qend sstart send evalue bitscore", output_format) ; auto& taxon_format = parser.add_group("Taxon output format options", { blastp, blastx }); taxon_format.add() ("include-lineage", 0, "Include lineage in the taxonomic classification format", include_lineage); auto& cluster_opt = parser.add_group("Clustering options", { cluster, RECLUSTER, DEEPCLUST, LINCLUST }); kmer_ranking = false; cluster_opt.add() ("cluster-steps", 0, "Clustering steps", cluster_steps) ("kmer-ranking", 0, "Rank sequences based on kmer frequency in linear stage", kmer_ranking) ("round-coverage", 0, "Per-round coverage cutoffs for cascaded clustering", round_coverage) ("round-approx-id", 0, "Per-round approx-id cutoffs for cascaded clustering", round_approx_id); auto& memory_opt = parser.add_group("Memory options", { cluster, RECLUSTER, CLUSTER_REASSIGN, GREEDY_VERTEX_COVER, DEEPCLUST, LINCLUST, CLUSTER_REALIGN }); memory_opt.add() ("memory-limit", 'M', "Memory limit in GB (default = 16G)", memory_limit); auto& cluster_reassign_opt = parser.add_group("Clustering/reassign options", { cluster, RECLUSTER, CLUSTER_REASSIGN, GREEDY_VERTEX_COVER, DEEPCLUST, LINCLUST }); cluster_reassign_opt.add() ("member-cover", 0, "Minimum coverage% of the cluster member sequence (default=80.0)", member_cover) ("mutual-cover", 0, "Minimum mutual coverage% of the cluster member and representative sequence", mutual_cover) ("connected-component-depth", 0, "Depth to cluster connected components", connected_component_depth) ("no-reassign", 0, "Do not reassign to closest representative", no_gvc_reassign); auto& gvc_opt = parser.add_group("GVC options", { GREEDY_VERTEX_COVER }); gvc_opt.add() ("centroid-out", 0, "Output file for centroids", centroid_out) ("edges", 0, "Input file for greedy vertex cover", edges) ("edge-format", 0, "Edge format for greedy vertex cover (default/triplet)", edge_format) ("symmetric", 0, "Edges are symmetric", symmetric); auto& realign_opt = parser.add_group("Cluster input options", { CLUSTER_REALIGN, RECLUSTER, CLUSTER_REASSIGN }); realign_opt.add() ("clusters", 0, "Clustering input file mapping sequences to representatives", clustering); string algo_str; #ifdef WITH_DNA string dna_extension_string; #endif auto& advanced_gen = parser.add_group("Advanced/general", { blastp, blastx, blastn, CLUSTER_REASSIGN, regression_test, cluster, DEEPCLUST, LINCLUST, makedb }); advanced_gen.add() ("file-buffer-size", 0, "file buffer size in bytes (default=67108864)", file_buffer_size, INT64_C(67108864)) ("no-unlink", 0, "Do not unlink temporary files.", no_unlink) ("ignore-warnings", 0, "Ignore warnings", ignore_warnings) ("no-parse-seqids", 0, "Print raw seqids without parsing", no_parse_seqids); auto& advanced_aln_cluster = parser.add_group("Advanced options aln/cluster", { blastp, blastx, blastn, CLUSTER_REASSIGN, regression_test, cluster, DEEPCLUST, LINCLUST, RECLUSTER }); advanced_aln_cluster.add() ("parallel-tmpdir", 0, "directory for temporary files used by multiprocessing", parallel_tmpdir) ("bin", 0, "number of query bins for seed search", query_bins_) ("ext-chunk-size", 0, "chunk size for adaptive ranking (default=auto)", ext_chunk_size) ("no-ranking", 0, "disable ranking heuristic", no_ranking) ("dbsize", 0, "effective database size (in letters)", db_size) ("no-auto-append", 0, "disable auto appending of DAA and DMND file extensions", no_auto_append) ("tantan-minMaskProb", 0, "minimum repeat probability for masking (default=0.9)", tantan_minMaskProb, 0.9) ("oid-output", 0, "Output OIDs instead of accessions (clustering)", oid_output) ("swipe-task-size", 0, "task size for DP parallelism (100000000)", swipe_task_size, INT64_C(100000000)) ("anchored-swipe", 0, "Enable anchored SWIPE extension", anchored_swipe); auto& advanced = parser.add_group("Advanced options", { blastp, blastx, blastn, regression_test }); advanced.add() ("algo", 0, "Seed search algorithm (0=double-indexed/1=query-indexed/ctg=contiguous-seed)", algo_str) ("min-orf", 'l', "ignore translated sequences without an open reading frame of at least this length", run_len) ("seed-cut", 0, "cutoff for seed complexity", seed_cut_) ("freq-masking", 0, "mask seeds based on frequency", freq_masking) ("freq-sd", 0, "number of standard deviations for ignoring frequent seeds", freq_sd_, 0.0) ("sketch-size", 0, "Subsample seeds based on minimizer sketch of the given size", sketch_size) ("id2", 0, "minimum number of identities for stage 1 hit", min_identities_) ("linsearch", 0, "only consider seed hits against longest target for identical seeds", linsearch) ("lin-stage1", 0, "only consider seed hits against longest query for identical seeds", lin_stage1) ("xdrop", 'x', "xdrop for ungapped alignment", ungapped_xdrop, 12.3) ("ungapped-evalue", 0, "E-value threshold for ungapped filter (auto)", ungapped_evalue_, -1.0) ("ungapped-evalue-short", 0, "E-value threshold for ungapped filter (short reads) (auto)", ungapped_evalue_short_, -1.0) ("short-query-ungapped-bitscore", 0, "Bit score threshold for ungapped alignments for short queries", short_query_ungapped_bitscore, 25.0) ("gapped-filter-evalue", 0, "E-value threshold for gapped filter (auto)", gapped_filter_evalue_, -1.0) ("band", 0, "band for dynamic programming computation", padding) ("shape-mask", 0, "seed shapes", shape_mask) ("multiprocessing", 0, "enable distributed-memory parallel processing", multiprocessing) ("mp-init", 0, "initialize multiprocessing run", mp_init) ("mp-recover", 0, "enable continuation of interrupted multiprocessing run", mp_recover) ("mp-query-chunk", 0, "process only a single query chunk as specified", mp_query_chunk, -1) ("culling-overlap", 0, "minimum range overlap with higher scoring hit to delete a hit (default=50%)", inner_culling_overlap, 50.0) ("taxon-k", 0, "maximum number of targets to report per species", taxon_k, UINT64_C(0)) ("range-cover", 0, "percentage of query range to be covered for range culling (default=50%)", query_range_cover, 50.0) ("xml-blord-format", 0, "Use gnl|BL_ORD_ID| style format in XML output", xml_blord_format) ("sam-query-len", 0, "add the query length to the SAM format (tag ZQ)", sam_qlen_field) ("stop-match-score", 0, "Set the match score of stop codons against each other.", stop_match_score, 1) ("target-indexed", 0, "Enable target-indexed mode", target_indexed) ("unaligned-targets", 0, "", unaligned_targets) ("cut-bar", 0, "", cut_bar) ("check-multi-target", 0, "", check_multi_target) ("roc-file", 0, "", roc_file) ("family-map", 0, "", family_map) ("family-map-query", 0, "", family_map_query) ("query-parallel-limit", 0, "", query_parallel_limit, 3000000u) ("log-evalue-scale", 0, "", log_evalue_scale, 1.0 / std::log(2.0)) ("bootstrap", 0, "", bootstrap) ("heartbeat", 0, "", heartbeat) ("mp-self", 0, "", mp_self) #ifdef WITH_DNA ("zdrop", 'z', "zdrop for gapped dna alignment", zdrop, 40) ("repetition-cutoff", 0 ,"filter out top FLOAT fraction of repetitive minimizers ",repetitive_cutoff,0.0002) ("extension", 0, "extension algorithm (wfa, ksw=default)", dna_extension_string, string("ksw")) ("chaining-out", 0, "use chaining without extension", chaining_out) ("align-long-reads", 0, "use chaining with extension", align_long_reads) ("best-hsp-only", 0, "only show the best HSP for any single query-subject pair", best_hsp_only) ("chain-pen-gap-scale", 0, "scaling factor for the chaining gap penalty", chain_pen_gap_scale, 0.8) ("chain-pen-skip-scale", 0, "scaling factor for the chaining skip penalty", chain_pen_skip_scale, 0.0) ("penalty", 0, "blastn mismatch penalty", mismatch_penalty, -3) ("reward", 0, "blastn match reward", match_reward, 2) ("chain-align-cutoff", 0, "percentage of chains not mapped/aligned in comparison to the best chaining score", chain_fraction_align_) ("min-chain-score", 0, "minimum chaining score to be considered for an alignment", min_chain_score_) ("max-overlap-extension", 0, "minimum chaining score to be considered for an alignment", max_overlap_extension_) ("zdrop-extension", 0, "zdrop for extension at chain ends", zdrop_extension, 80) ("zdrop-global", 0, "zdrop for global extension between anchors", zdrop_global, 150) ("band-extension", 0, "min band for extension at chain ends", band_extension, 40) ("band-global", 0, "min band for global extension between anchors", band_global, 40) #endif ("query-or-subject-cover", 0, "", query_or_target_cover); auto& view_align_options = parser.add_group("View/Align options", { view, blastp, blastx }); view_align_options.add() ("daa", 'a', "DIAMOND alignment archive (DAA) file", daa_file); auto& view_options = parser.add_group("View options", { view }); view_options.add() ("forwardonly", 0, "only show alignments of forward strand", forwardonly); auto& getseq_options = parser.add_group("Getseq options", { getseq }); getseq_options.add() ("seq", 0, "Space-separated list of sequence numbers to display.", seq_no); double rank_ratio2, lambda, K; unsigned window, min_ungapped_score, hit_band, min_hit_score; auto& deprecated_options = parser.add_group("", { blastp, blastx }); deprecated_options.add() ("window", 'w', "window size for local hit search", window) ("ungapped-score", 0, "minimum alignment score to continue local extension", min_ungapped_score) ("hit-band", 0, "band for hit verification", hit_band) ("hit-score", 0, "minimum score to keep a tentative alignment", min_hit_score) ("gapped-xdrop", 'X', "xdrop for gapped alignment in bits", gapped_xdrop, 20.0) ("rank-ratio2", 0, "include subjects within this ratio of last hit (stage 2)", rank_ratio2, -1.0) ("rank-ratio", 0, "include subjects within this ratio of last hit", rank_ratio, -1.0) ("lambda", 0, "lambda parameter for custom matrix", lambda) ("K", 0, "K parameter for custom matrix", K); double query_match_distance_threshold; double length_ratio_threshold; double cbs_angle; #ifdef EXTRA auto& hidden_options = parser.add_group("", {}); #else auto& hidden_options = parser.add_group("", {}, true); #endif hidden_options.add() ("match1", 0, "", match_file1) ("match2", 0, "", match_file2) ("seed-freq", 0, "maximum seed frequency", max_seed_freq, -15.0) ("space-penalty", 0, "", space_penalty, 0.5) ("reverse", 0, "", reverse) ("neighborhood-score", 0, "", neighborhood_score) ("seed-weight", 'w', "", seed_weight, 7u) ("superblock", 0, "", superblock, 128) ("load-balancing", 0, "", load_balancing, (unsigned)Config::query_parallel) ("log-query", 0, "", log_query) ("log-subject", 0, "", log_subject) ("palign", 0, "", threads_align) ("score-ratio", 0, "", score_ratio, 0.9) ("fetch-size", 0, "trace point fetch size", fetch_size, 4096u) ("target-fetch-size", 0, "number of target sequences to fetch for seed extension", target_fetch_size, 4u) ("rank-factor", 0, "", rank_factor, -1.0) ("transcript-len-estimate", 0, "", transcript_len_estimate, 1.0) ("family-counts", 0, "", family_counts_file) ("radix-cluster-buffered", 0, "", radix_cluster_buffered) ("join-split-size", 0, "", join_split_size, 100000u) ("join-split-key-len", 0, "", join_split_key_len, 17u) ("radix-bits", 0, "", radix_bits, 8u) ("join-ht-factor", 0, "", join_ht_factor, 1.3) ("sort-join", 0, "", sort_join) ("simple-freq", 0, "", simple_freq) ("freq-treshold", 0, "", freq_treshold) ("use-dataset-field", 0, "", use_dataset_field) ("store-query-quality", 0, "", store_query_quality) ("swipe-chunk-size", 0, "", swipe_chunk_size, 256u) ("hard-masked", 0, "", hardmasked) ("cbs-window", 0, "", cbs_window, 40) ("no-dict", 0, "", no_dict) ("upgma-edge-limit", 0, "", upgma_edge_limit, (uint64_t)10000000) ("tree", 0, "", tree_file) ("upgma-dist", 0, "", upgma_dist) ("upgma-input", 0, "", upgma_input) ("log-extend", 0, "", log_extend) ("chaining-maxgap", 0, "", chaining_maxgap, 2000) ("tantan-maxRepeatOffset", 0, "maximum tandem repeat period to consider (50)", tantan_maxRepeatOffset, 15) ("tantan-ungapped", 0, "use tantan masking in ungapped mode", tantan_ungapped) ("chaining-range-cover", 0, "", chaining_range_cover, (size_t)8) ("no-swipe-realign", 0, "", no_swipe_realign) ("chaining-maxnodes", 0, "", chaining_maxnodes) ("cutoff-score-8bit", 0, "", cutoff_score_8bit, 240) ("min-band-overlap", 0, "", min_band_overlap, 0.0) ("min-realign-overhang", 0, "", min_realign_overhang, 30) ("ungapped-window", 0, "", ungapped_window, 48) ("gapped-filter-diag-score", 0, "", gapped_filter_diag_bit_score, 12.0) ("gapped-filter-window", 0, "", gapped_filter_window, 200) ("output-hits", 0, "", output_hits) ("no-logfile", 0, "", no_logfile) ("band-bin", 0, "", band_bin, 24) ("col-bin", 0, "", col_bin, 400) ("self", 0, "", self) ("trace-pt-fetch-size", 0, "", trace_pt_fetch_size, (int64_t)10e9) ("tile-size", 0, "", tile_size, (uint32_t)1024) ("short-query-max-len", 0, "", short_query_max_len, 60) ("gapped-filter-evalue1", 0, "", gapped_filter_evalue1, 2000.0) ("ext-yield", 0, "", ext_min_yield) ("full-sw-len", 0, "", full_sw_len) ("relaxed-evalue-factor", 0, "", relaxed_evalue_factor, 1.0) ("type", 0, "", type) ("raw", 0, "", raw) ("chaining-len-cap", 0, "", chaining_len_cap, 2.0) ("chaining-min-nodes", 0, "", chaining_min_nodes, (size_t)200) ("fast-tsv", 0, "", fast_tsv) ("target-parallel-verbosity", 0, "", target_parallel_verbosity, UINT_MAX) ("query-memory", 0, "", query_memory) ("memory-intervals", 0, "", memory_intervals, (size_t)2) ("seed-hit-density", 0, "", seedhit_density) ("chunk-size-multiplier", 0, "", chunk_size_multiplier, (size_t)4) ("score-drop-factor", 0, "", ranking_score_drop_factor, 0.95) ("left-most-interval", 0, "", left_most_interval, 32) ("ranking-cutoff-bitscore", 0, "", ranking_cutoff_bitscore, 25.0) ("no-forward-fp", 0, "", no_forward_fp) ("no-ref-masking", 0, "", no_ref_masking) ("target-bias", 0, "", target_bias) ("output-fp", 0, "", output_fp) ("family-cap", 0, "", family_cap) ("cbs-matrix-scale", 0, "", cbs_matrix_scale, 1) ("query-count", 0, "", query_count, (size_t)1) ("cbs-angle", 0, "", cbs_angle, -1.0) ("cbs-err-tolerance", 0, "", cbs_err_tolerance, 0.1) ("cbs-it-limit", 0, "", cbs_it_limit, 2000) ("hash_join_swap", 0, "", hash_join_swap) ("deque_bucket_size", 0, "", deque_bucket_size, (size_t)524288) ("query-match-distance-threshold", 0, "", query_match_distance_threshold, -1.0) ("length-ratio-threshold", 0, "", length_ratio_threshold, -1.0) ("max-swipe-dp", 0, "", max_swipe_dp, INT64_C(1000000)) ("no-reextend", 0, "", no_reextend) ("no-reorder", 0, "", no_reorder) ("file1", 0, "", file1) ("file2", 0, "", file2) ("key2", 0, "", key2) ("motif-mask-file", 0, "", motif_mask_file) ("max-motif-len", 0, "", max_motif_len, 30) ("chaining-stacked-hsp-ratio", 0, "", chaining_stacked_hsp_ratio, 0.5) ("minimizer-window", 0, "", minimizer_window_) ("min_task_trace_pts", 0, "", min_task_trace_pts, (int64_t)1024) ("oid-list", 0, "", oid_list) ("bootstrap-block", 0, "", bootstrap_block, (int64_t)1000000) ("centroid-factor", 0, "", centroid_factor, (int64_t)3) ("timeout", 0, "", timeout) ("resume", 0, "", resume) ("target_hard_cap", 0, "", target_hard_cap) ("mapany", 0, "", mapany) ("neighbors", 0, "", neighbors) ("reassign-overlap", 0, "", reassign_overlap, 0.3) ("reassign-ratio", 0, "", reassign_ratio, 0.5) ("reassign-max", 0, "", reassign_max) ("add-self-aln", 0, "", add_self_aln) ("weighted-gvc", 0, "", weighted_gvc) ("hamming-ext", 0, "", hamming_ext) ("diag-filter-id", 0, "", diag_filter_id) ("diag-filter-cov", 0, "", diag_filter_cov) ("strict-gvc", 0, "", strict_gvc) ("dbtype", 0, "type of sequences in database file (nucl/prot)", dbstring, string("prot")) ("cluster-similarity", 0, "Clustering similarity measure (default=\"normalized_bitscore_global\")", cluster_similarity) ("cluster-threshold", 0, "Threshold for the similarity measure (default=50%)", cluster_threshold) ("cluster-graph-file", 0, "Filename for dumping the graph or reading the graph if cluster-restart", cluster_graph_file) ("cluster-restart", 0, "Restart clustering from dumped graph", cluster_restart) ("mcl-expansion", 0, "MCL expansion coefficient (default=2)", cluster_mcl_expansion, (uint32_t)2) ("mcl-inflation", 0, "MCL inflation coefficient (default=2.0)", cluster_mcl_inflation, 2.0) ("mcl-chunk-size", 0, "MCL chunk size per thread (default=100)", cluster_mcl_chunk_size, (uint32_t)1) ("mcl-max-iterations", 0, "MCL maximum iterations (default=100)", cluster_mcl_max_iter, (uint32_t)100) ("mcl-sparsity-switch", 0, "MCL switch to sparse matrix computation (default=0.8) ", cluster_mcl_sparsity_switch, 0.8) ("mcl-nonsymmetric", 0, "Do not symmetrize the transition matrix before clustering", cluster_mcl_nonsymmetric) ("mcl-stats", 0, "Some stats about the connected components in MCL", cluster_mcl_stats) ("cluster-algo", 0, "Clustering algorithm (\"mcl\")", cluster_algo) ("approx-backtrace", 0, "", approx_backtrace) ("narrow-band-cov", 0, "", narrow_band_cov) ("narrow-band-factor", 0, "", narrow_band_factor) ("anchor-window", 0, "", anchor_window, 12) ("anchor-score", 0, "", anchor_score, 1.0) ("classic-band", 0, "", classic_band) ("no_8bit_extension", 0, "", no_8bit_extension) ("no_chaining_merge_hsps", 0, "", no_chaining_merge_hsps) ("graph-algo", 0, "", graph_algo, string("gvc")) ("tsv-read-size", 0, "", tsv_read_size, int64_t(GIGABYTES)) ("min-len-ratio", 0, "", min_length_ratio) ("max-indirection", 0, "", max_indirection) ("aln-out", 0, "", aln_out) ("linclust-chunk-size", 0, "", linclust_chunk_size, string("10G")) ("promiscuous-seed-ratio", 0 , "", promiscuous_seed_ratio, 1000.0); parser.store(argc, argv, command); if (debug_log) verbosity = 3; else if (quiet) verbosity = 0; else if (verbose) verbosity = 2; else if (((command == Config::view || command == blastx || command == blastp || command == blastn) && output_file == "" && argc != 2) || command == Config::version || command == getseq || command == fastq2fasta || command == regression_test) verbosity = 0; else verbosity = 1; if (verbosity >= 1 || command == regression_test) { ostream& header_out = command == Config::help ? cout : cerr; header_out << Const::program_name << " v" << Const::version_string << "." << (unsigned)Const::build_version << " (C) Max Planck Society for the Advancement of Science, Benjamin Buchfink, University of Tuebingen" << endl; header_out << "Documentation, support and updates available at http://www.diamondsearch.org" << endl; header_out << "Please cite: http://dx.doi.org/10.1038/s41592-021-01101-x Nature Methods (2021)" << endl << endl; } log_stream << Const::program_name << " v" << Const::version_string << "." << (unsigned)Const::build_version << endl; if(argc == 2 && command != version && command != regression_test) { if (command != help) { parser.print_documentation(command); } else { parser.print_help(); } } if (toppercent.present() && max_target_seqs_.present()) throw std::runtime_error("--top and -k/--max-target-seqs are mutually exclusive."); if (command == blastx && no_self_hits) throw std::runtime_error("--no-self-hits option is not supported in blastx mode."); if (long_reads) { query_range_culling = true; if (toppercent.blank()) toppercent = 10.0; if (frame_shift == 0) frame_shift = 15; } if (global_ranking_targets > 0 && (query_range_culling || taxon_k || multiprocessing || mp_init || mp_recover || comp_based_stats >= 2 || frame_shift > 0)) throw std::runtime_error("Global ranking is not supported in this mode."); #ifdef EXTRA if (comp_based_stats >= Stats::CBS::COUNT) #else if (comp_based_stats >= 5) #endif throw std::runtime_error("Invalid value for --comp-based-stats. Permitted values: 0, 1, 2, 3, 4."); Stats::comp_based_stats = Stats::CBS(comp_based_stats, query_match_distance_threshold, length_ratio_threshold, cbs_angle); if (command == blastx && !Stats::CBS::support_translated(comp_based_stats)) throw std::runtime_error("This mode of composition based stats is not supported for translated searches."); if (check_io) { switch (command) { case Config::makedb: { if (database == "") throw std::runtime_error("Missing parameter: database file (--db/-d)"); if (chunk_size != 0.0) throw std::runtime_error( "Invalid option: --block-size/-b. Block size is set for the alignment commands."); break; } case Config::blastp: case Config::blastx: case Config::blastn: if (database == "") throw std::runtime_error("Missing parameter: database file (--db/-d)"); if (daa_file.length() > 0) { if (output_file.length() > 0) throw std::runtime_error("Options --daa and --out cannot be used together."); if (output_format.size() > 0 && output_format[0] != "daa") throw std::runtime_error("Invalid parameter: --daa/-a. Output file is specified with the --out/-o parameter."); output_file = daa_file; } if (daa_file.length() > 0 || (output_format.size() > 0 && (output_format[0] == "daa" || output_format[0] == "100"))) { if (!compression.empty()) throw std::runtime_error("Compression is not supported for DAA format."); if (!no_auto_append) auto_append_extension(output_file, ".daa"); } break; default: ; } switch (command) { case Config::dbinfo: if (database == "") throw std::runtime_error("Missing parameter: database file (--db/-d)"); } } switch (verbosity) { case 0: message_stream = MessageStream(false); break; case 3: log_stream = MessageStream(true, !config.no_logfile); verbose_stream = MessageStream(true, !config.no_logfile); message_stream = MessageStream(true, !config.no_logfile); break; case 2: verbose_stream = MessageStream(); default: ; } invocation = join(" ", vector(&argv[0], &argv[argc])); log_stream << invocation << endl; if (!no_auto_append) { if (command == Config::makedb) auto_append_extension(database, ".dmnd"); if (command == Config::view) auto_append_extension(daa_file, ".daa"); if (compression == "1") auto_append_extension(output_file, ".gz"); if (compression == "zstd") auto_append_extension(output_file, ".zst"); } #ifndef NDEBUG verbose_stream << "Assertions enabled." << endl; #endif set_option(threads_, (int)std::thread::hardware_concurrency()); switch (command) { case Config::makedb: case Config::blastp: case Config::blastx: case Config::blastn: case Config::view: case Config::cluster: case Config::DEEPCLUST: case Config::LINCLUST: case Config::regression_test: case Config::compute_medoids: case Config::CLUSTER_REASSIGN: case Config::GREEDY_VERTEX_COVER: case Config::RECLUSTER: if (argc != 2) message_stream << "#CPU threads: " << threads_ << endl; default: ; } switch (command) { case Config::blastp: case Config::blastx: case Config::benchmark: case Config::model_sim: case Config::opt: case Config::mask: case Config::makedb: case Config::cluster: case Config::DEEPCLUST: case Config::LINCLUST: case Config::regression_test: case Config::compute_medoids: case Config::LIST_SEEDS: case Config::CLUSTER_REASSIGN: case Config::CLUSTER_REALIGN: case Config::RECLUSTER: case Config::MODEL_SEQS: case Config::MAKE_SEED_TABLE: if (frame_shift != 0 && command == Config::blastp) throw std::runtime_error("Frameshift alignments are only supported for translated searches."); if (query_range_culling && frame_shift == 0) throw std::runtime_error("Query range culling is only supported in frameshift alignment mode (option -F)."); if (matrix_file == "") { score_matrix = ScoreMatrix(to_upper_case(matrix), gap_open, gap_extend, frame_shift, stop_match_score, 0, cbs_matrix_scale); //blosum80 = ScoreMatrix("BLOSUM80", 11, 1, frame_shift, stop_match_score, 0, cbs_matrix_scale); //pam70 = ScoreMatrix("PAM70", 11, 1, frame_shift, stop_match_score, 0, cbs_matrix_scale); //pam30 = ScoreMatrix("PAM30", 10, 1, frame_shift, stop_match_score, 0, cbs_matrix_scale); } else { if (gap_open == -1 || gap_extend == -1) throw std::runtime_error("Custom scoring matrices require setting the --gapopen and --gapextend options."); if (!output_format.empty() && (output_format.front() == "daa" || output_format.front() == "100")) throw std::runtime_error("Custom scoring matrices are not supported for the DAA format."); if (comp_based_stats > 1) throw std::runtime_error("This value for --comp-based-stats is not supported when using a custom scoring matrix."); score_matrix = ScoreMatrix(matrix_file, gap_open, gap_extend, stop_match_score, ScoreMatrix::Custom()); } if (argc != 2) message_stream << "Scoring parameters: " << score_matrix << endl; Masking::instance = unique_ptr(new Masking(score_matrix)); } if (command == Config::blastp || command == Config::blastx || command == Config::blastn || command == Config::benchmark || command == Config::model_sim || command == Config::opt || command == Config::mask || command == Config::cluster || command == Config::compute_medoids || command == Config::regression_test || command == Config::CLUSTER_REASSIGN || command == Config::RECLUSTER || command == Config::DEEPCLUST || command == Config::LINCLUST) { if (tmpdir == "") tmpdir = extract_dir(output_file); temp_file_handler.init(tmpdir.c_str()); raw_ungapped_xdrop = score_matrix.rawscore(ungapped_xdrop); verbose_stream << "CPU features detected: " << SIMD::features() << endl; log_stream << "L3 cache size: " << l3_cache_size() << endl; } sensitivity = Sensitivity::DEFAULT; if (mode_faster) set_sens(Sensitivity::FASTER); if (mode_fast) set_sens(Sensitivity::FAST); if (mode_mid_sensitive) set_sens(Sensitivity::MID_SENSITIVE); if (mode_sensitive) set_sens(Sensitivity::SENSITIVE); if (mode_more_sensitive) set_sens(Sensitivity::MORE_SENSITIVE); if (mode_very_sensitive) set_sens(Sensitivity::VERY_SENSITIVE); if (mode_ultra_sensitive) set_sens(Sensitivity::ULTRA_SENSITIVE); if (mode_shapes30x10) set_sens(Sensitivity::SHAPES30x10); if (mode_shapes6x10) set_sens(Sensitivity::SHAPES6x10); if (mode_linclust_20) set_sens(Sensitivity::LINCLUST_20); algo = from_string(algo_str); dbtype = from_string(dbstring); #ifdef WITH_DNA dna_extension = from_string(dna_extension_string); #endif Translator::init(query_gencode); if (command == blastx || command == blastn) input_value_traits = nucleotide_traits; if (query_strands != "both" && query_strands != "minus" && query_strands != "plus") throw std::runtime_error("Invalid value for parameter --strand"); if (unfmt == "fastq" || alfmt == "fastq") store_query_quality = true; if (!aligned_file.empty()) log_stream << "Aligned file format: " << alfmt << endl; if (command == blastx) { if (query_file.size() > 2) throw std::runtime_error("A maximum of 2 query files is supported in blastx mode."); } else if (query_file.size() > 1) throw std::runtime_error("--query/-q has more than one argument."); if (target_indexed && lowmem_ != 1) throw std::runtime_error("--target-indexed requires -c1."); if (swipe_all) { algo = Algo::DOUBLE_INDEXED; } if (query_range_culling && taxon_k != 0) throw std::runtime_error("--taxon-k is not supported for --range-culling mode."); if (multiprocessing && parallel_tmpdir.empty()) throw std::runtime_error("--multiprocessing requires setting --parallel-tmpdir"); if (multiprocessing) { // char * env_str = std::getenv("SLURM_JOBID"); // if (env_str) { // parallel_tmpdir = join_path(parallel_tmpdir, "diamond_job_"+string(env_str)); // } mkdir(parallel_tmpdir); } if (!memory_limit.empty()) trace_pt_membuf = Util::String::interpret_number(memory_limit) > 1024 * (1ll << 30); log_stream << "MAX_SHAPE_LEN=" << MAX_SHAPE_LEN; #ifdef SEQ_MASK log_stream << " SEQ_MASK"; #endif #ifdef STRICT_BAND log_stream << " STRICT_BAND"; #endif log_stream << endl; } bbuchfink-diamond-08b3cbc/src/basic/config.h000066400000000000000000000275161506104011400210350ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include "util/options/option.h" #include "value.h" #include "util/enum.h" enum class Sensitivity { FASTER = -1, FAST = 0, DEFAULT = 1, LINCLUST_40 = 2, LINCLUST_20 = 3, SHAPES6x10 = 4, SHAPES30x10 = 5, MID_SENSITIVE = 6, SENSITIVE = 7, MORE_SENSITIVE = 8, VERY_SENSITIVE = 9, ULTRA_SENSITIVE = 10 }; enum class Compressor; template<> struct EnumTraits { static const EMap to_string; static const SEMap from_string; }; template<> struct EnumTraits { static const EMap to_string; static const SEMap from_string; }; enum class DNAExtensionAlgo{KSW,WFA}; template<> struct EnumTraits{ static const EMap to_string; static const SEMap from_string; }; enum class GraphAlgo { GREEDY_VERTEX_COVER, LEN_SORTED }; template<> struct EnumTraits { static const SEMap from_string; }; struct CommandLineParser; constexpr int64_t DEFAULT_MAX_TARGET_SEQS = 25; struct Config { using string = std::string; using string_vector = std::vector; string_vector input_ref_file; int threads_; Option database; string_vector query_file; unsigned merge_seq_treshold; unsigned shapes; Option max_target_seqs_; string match_file1; string match_file2; int padding; unsigned output_threads; string compression; unsigned lowmem_; double chunk_size; unsigned min_identities_; unsigned min_identities2; double ungapped_xdrop; int raw_ungapped_xdrop; unsigned min_compressed_identities; int min_seed_score; unsigned seed_signatures; double min_bit_score; unsigned run_len; double max_seed_freq; string tmpdir; string parallel_tmpdir; bool long_mode; double gapped_xdrop; double max_evalue; string kegg_file; int gap_open; int gap_extend; int mismatch_penalty; int match_reward; string matrix; bool debug_log, verbose, quiet; bool salltitles; int reward; int penalty; double min_id; unsigned compress_temp; Option toppercent; string daa_file; string_vector output_format; string output_file; bool forwardonly; unsigned fetch_size; uint64_t db_size; double query_cover; double query_or_target_cover; bool mode_sensitive; unsigned verbosity; bool no_auto_append; string_vector seq_no; double rank_factor; double rank_ratio; double freq_sd_; unsigned target_fetch_size; bool mode_more_sensitive; string matrix_file; string_vector shape_mask; unsigned query_gencode; string unaligned; double space_penalty; bool new_prefilter; bool reverse; unsigned comp_based_stats; int neighborhood_score; unsigned seed_weight; int report_unaligned; double subject_cover; bool mode_very_sensitive; unsigned max_hsps; bool no_self_hits; unsigned query_bins_; string prot_accession2taxid; int superblock; Option masking_; bool log_query; bool log_subject; unsigned threads_align; double score_ratio; string nodesdmp; bool sallseqid; string query_strands; bool xml_blord_format; int frame_shift; bool query_range_culling; double query_range_cover; double transcript_len_estimate; string family_counts_file; string taxonlist; bool radix_cluster_buffered; unsigned join_split_size; unsigned join_split_key_len; unsigned radix_bits; double join_ht_factor; bool sort_join; bool simple_freq; double freq_treshold; string aligned_file; bool use_dataset_field; bool store_query_quality; string invocation; unsigned swipe_chunk_size; unsigned query_parallel_limit; bool long_reads; Option output_header; string alfmt; string unfmt; string namesdmp; bool hardmasked; int cbs_window; double tantan_r; double tantan_minMaskProb; bool no_unlink; bool no_dict; int stop_match_score; int tantan_maxRepeatOffset; bool tantan_ungapped; string taxon_exclude; bool swipe_all; uint64_t taxon_k; uint64_t upgma_edge_limit; string tree_file; string upgma_dist; string upgma_input; bool log_extend; int chaining_maxgap; string family_map; string family_map_query; size_t chaining_range_cover; bool no_swipe_realign; bool cut_bar; bool bootstrap; size_t chaining_maxnodes; int cutoff_score_8bit; double inner_culling_overlap; double min_band_overlap; int min_realign_overhang; int ungapped_window; int gapped_filter_diag_score; double gapped_filter_diag_bit_score; double gapped_filter_evalue_; int gapped_filter_window; bool output_hits; double ungapped_evalue_; bool no_logfile; int band_bin; int col_bin; int64_t file_buffer_size; bool self; int64_t trace_pt_fetch_size; uint32_t tile_size; double short_query_ungapped_bitscore; int short_query_max_len; double gapped_filter_evalue1; size_t ext_chunk_size; double ext_min_yield; string ext_; int full_sw_len; double relaxed_evalue_factor; string type; bool raw; bool mode_ultra_sensitive; double chaining_len_cap; size_t chaining_min_nodes; bool fast_tsv; unsigned target_parallel_verbosity; int64_t global_ranking_targets; bool mode_mid_sensitive; bool no_ranking; bool query_memory; size_t memory_intervals; size_t seedhit_density; size_t chunk_size_multiplier; double ranking_score_drop_factor; double ranking_cutoff_bitscore; int left_most_interval; bool no_forward_fp; bool no_ref_masking; string roc_file; bool target_bias; bool check_multi_target; bool output_fp; int family_cap; int cbs_matrix_scale; size_t query_count; double cbs_err_tolerance; int cbs_it_limit; double query_match_distance_threshold; double length_ratio_threshold; bool hash_join_swap; bool target_indexed; size_t deque_bucket_size; bool mode_fast; double log_evalue_scale; double ungapped_evalue_short_; int64_t max_swipe_dp; std::string seqidlist; bool skip_missing_seqids; Option iterate; bool ignore_warnings; bool no_reextend; double seed_cut_; bool no_reorder; string file1; string file2; size_t key2; string motif_mask_file; string motif_masking; bool freq_masking; Loc max_motif_len; double chaining_stacked_hsp_ratio; Option cluster_threshold; Option memory_limit; int64_t swipe_task_size; Loc minimizer_window_; bool lin_stage1; int64_t min_task_trace_pts; Loc sketch_size; string soft_masking; string oid_list; int64_t bootstrap_block; int64_t centroid_factor; int timeout; string resume; int64_t target_hard_cap; bool mapany; Option clustering; Option neighbors; double reassign_overlap; double reassign_ratio; int64_t reassign_max; bool add_self_aln; string centroid_out; string unaligned_targets; Option approx_min_id; bool mode_faster; Option member_cover; bool weighted_gvc; bool kmer_ranking; bool hamming_ext; Option diag_filter_id; Option diag_filter_cov; bool strict_gvc; string edge_format; bool no_block_size_limit; string edges; bool mp_self; bool approx_backtrace; double narrow_band_cov; double narrow_band_factor; Loc anchor_window; double anchor_score; bool classic_band; bool no_8bit_extension; bool anchored_swipe; bool no_chaining_merge_hsps; bool pipeline_short; string graph_algo; bool linsearch; int64_t tsv_read_size; int zdrop; bool heartbeat; bool no_parse_seqids; bool sam_qlen_field; #ifdef WITH_DNA DNAExtensionAlgo dna_extension; double repetitive_cutoff; bool chaining_out; bool align_long_reads; bool best_hsp_only; double chain_pen_gap_scale; double chain_pen_skip_scale; double chain_fraction_align_; int min_chain_score_; double max_overlap_extension_; int zdrop_extension; int zdrop_global; int band_extension; int band_global; #endif double min_length_ratio; Option mutual_cover; bool symmetric; bool no_gvc_reassign; string_vector connected_component_depth; std::vector round_coverage; string_vector round_approx_id; int max_indirection; bool mode_shapes30x10; bool mode_shapes6x10; string aln_out; bool include_lineage; bool mode_linclust_20; std::string linclust_chunk_size; double promiscuous_seed_ratio; bool oid_output; bool trace_pt_membuf; SequenceType dbtype; Sensitivity sensitivity; bool multiprocessing; bool mp_init; bool mp_recover; int mp_query_chunk; enum { makedb = 0, blastp = 1, blastx = 2, view = 3, help = 4, version = 5, getseq = 6, benchmark = 7, random_seqs = 8, compare = 9, sort = 10, roc = 11, db_stat = 12, model_sim = 13, match_file_stat = 14, model_seqs = 15, opt = 16, mask = 17, fastq2fasta = 18, dbinfo = 19, test_extra = 20, test_io = 21, db_annot_stats = 22, info = 24, seed_stat = 25, smith_waterman = 26, cluster = 27, translate = 28, simulate_seqs = 31, split = 32, upgma = 33, upgma_mc = 34, regression_test = 35, reverse_seqs = 36, compute_medoids = 37, mutate = 38, rocid = 40, makeidx = 41, find_shapes, prep_db, HASH_SEQS, LIST_SEEDS, CLUSTER_REALIGN, GREEDY_VERTEX_COVER, CLUSTER_REASSIGN, blastn, RECLUSTER, LENGTH_SORT, MERGE_DAA, DEEPCLUST, LINCLUST, WORD_COUNT, CUT, MODEL_SEQS, MAKE_SEED_TABLE }; unsigned command; enum class Algo { AUTO = -1, DOUBLE_INDEXED = 0, QUERY_INDEXED = 1, CTG_SEED }; Algo algo; Option cluster_algo; Option cluster_similarity; string cluster_graph_file; bool cluster_restart; size_t max_size_set; string_vector cluster_steps; double cluster_mcl_inflation; uint32_t cluster_mcl_expansion; double cluster_mcl_sparsity_switch; uint32_t cluster_mcl_chunk_size; uint32_t cluster_mcl_max_iter; bool cluster_mcl_stats; bool cluster_mcl_nonsymmetric; enum { query_parallel = 0, target_parallel = 1 }; unsigned load_balancing; Config() {} Config(int argc, const char **argv, bool check_io, CommandLineParser& parser); Loc min_orf_len(Loc length) const { if (run_len == 0) { if (length < 30 || frame_shift != 0) return 1; else if (length < 100) return 20; else return 40; } else return run_len; } inline bool output_range(unsigned n_target_seq, int score, int top_score, const int64_t max_target_seqs) { if (toppercent.present()) return (1.0 - (double)score / top_score) * 100 <= toppercent; else return n_target_seq < max_target_seqs; } int64_t block_size() const { return (int64_t)(chunk_size * 1e9); } void set_sens(Sensitivity sens); std::string single_query_file() const; bool mem_buffered() const { return tmpdir == "/dev/shm"; } Compressor compressor() const; template static void set_option(T& option, T value, T def = 0) { if (option == def) option = value; } template static void set_option(T& option, T value, T def, T alt) { if (value != def) option = value; else option = alt; } }; extern Config config; template T top_cutoff_score(T top_score) { return T((1.0 - config.toppercent / 100.0) * top_score); } template<> struct EnumTraits { static const EMap to_string; static const SEMap from_string; }; extern const char* const DEFAULT_MEMORY_LIMIT; std::pair block_size(int64_t memory_limit, int64_t db_letters, Sensitivity s, bool lin, int thread_count);bbuchfink-diamond-08b3cbc/src/basic/const.h000066400000000000000000000021341506104011400207030ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once struct Const { enum { build_version = 168, max_seed_weight = 32, max_shapes = 64 }; static const char* version_string; static const char* program_name; }; static constexpr int MAX_CONTEXT = 6;bbuchfink-diamond-08b3cbc/src/basic/hssp.cpp000066400000000000000000000263271506104011400210770ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "output/output.h" #include "output/output_format.h" #include "stats/stats.h" using std::list; using std::equal; using std::runtime_error; using std::pair; pair Hsp::diagonal_bounds() const { int d0 = std::numeric_limits::max(), d1 = std::numeric_limits::min(); for (Iterator it = begin(); it.good(); ++it) { const int d = (int)it.query_pos.translated - (int)it.subject_pos; d0 = std::min(d0, d); d1 = std::max(d1, d); } return std::make_pair(d0, d1); } bool Hsp::is_weakly_enveloped(const Hsp &j) const { static const double overlap_factor = 0.9; return score <= j.score && subject_range.overlap_factor(j.subject_range) >= overlap_factor && query_range.overlap_factor(j.query_range) >= overlap_factor; } HspContext& HspContext::parse(const OutputFormat* output_format) { if (output_format && !flag_any(output_format->hsp_values, HspValues::TRANSCRIPT) && config.command != Config::view) { hsp_.query_source_range = TranslatedPosition::absolute_interval( TranslatedPosition(hsp_.query_range.begin_, Frame(hsp_.frame)), TranslatedPosition(hsp_.query_range.end_, Frame(hsp_.frame)), (int)query.source().length()); hsp_.subject_source_range = hsp_.subject_range; if (subject_seq.length() > 0) hsp_.approx_id = hsp_.approx_id_percent(this->query.index(hsp_.frame), subject_seq); return *this; } hsp_.length = hsp_.identities = hsp_.mismatches = hsp_.gap_openings = hsp_.positives = hsp_.gaps = 0; unsigned d = 0; Iterator i = begin(); for (; i.good(); ++i) { ++hsp_.length; assert(query.in_bounds(i.query_pos)); if (!query.in_bounds(i.query_pos)) throw std::runtime_error("Query sequence index out of bounds."); switch (i.op()) { case op_match: ++hsp_.identities; ++hsp_.positives; d = 0; break; case op_substitution: ++hsp_.mismatches; if (score_matrix(i.query(), i.subject()) > 0) ++hsp_.positives; d = 0; break; case op_insertion: case op_deletion: if (d == 0) ++hsp_.gap_openings; ++d; ++hsp_.gaps; break; default: ; } } hsp_.query_range.end_ = i.query_pos.translated; hsp_.subject_range.end_ = i.subject_pos; hsp_.subject_source_range = hsp_.subject_range; hsp_.query_source_range = TranslatedPosition::absolute_interval(begin().query_pos, i.query_pos, (int)query.source().length()); if (subject_seq.length() > 0) hsp_.approx_id = hsp_.approx_id_percent(this->query.index(hsp_.frame), subject_seq); return *this; } void Hsp::push_back(const DiagonalSegmentT &d, const TranslatedSequence &query, const Sequence &subject, bool reversed) { const Sequence &q = query[d.i.frame]; if (reversed) { for (int i = d.query_last().translated, j = d.subject_last(); j >= d.j; --j, --i) { const Letter ls = subject[j], lq = q[i]; if (ls == lq) { transcript.push_back(op_match); ++identities; ++positives; } else { transcript.push_back(op_substitution, ls); ++mismatches; if (score_matrix(ls, lq) > 0) ++positives; } ++length; } } else { for (int i = d.i, j = d.j; j < d.subject_end(); ++j, ++i) { const Letter ls = subject[j], lq = q[i]; if (ls == lq) { transcript.push_back(op_match); ++identities; ++positives; } else { transcript.push_back(op_substitution, ls); ++mismatches; if (score_matrix(ls, lq) > 0) ++positives; } ++length; } } } void Hsp::splice(const DiagonalSegmentT &a, const DiagonalSegmentT &b, const TranslatedSequence &query, const Sequence &subject, bool reversed) { TranslatedPosition i0 = a.query_last(); int j0 = a.subject_last(); const int fs = i0.frame_shift(b.i); if (fs == 1) { i0.shift_forward(); transcript.push_back(op_frameshift_forward); } else if (fs == -1) { i0.shift_back(); transcript.push_back(op_frameshift_reverse); } const int d0 = i0 - j0, d1 = b.diag(); if (d1 > d0) transcript.push_back(op_insertion, unsigned(d1 - d0)); else if (d1 < d0) { if (reversed) transcript.push_back(subject.subseq(j0 + 1, b.j), Reversed()); else transcript.push_back(subject.subseq(j0 + 1, b.j)); } const int shift = abs(d1 - d0); if (shift > 0) { length += shift; ++gap_openings; gaps += shift; } } void Hsp::set_begin(const DiagonalSegmentT &d, int dna_len) { subject_range.begin_ = d.j; query_range.begin_ = d.i; frame = d.i.frame.index(); if (d.i.frame.strand == FORWARD) query_source_range.begin_ = d.i.absolute(dna_len); else query_source_range.end_ = d.i.absolute(dna_len) + 1; } void Hsp::set_end(const DiagonalSegmentT &d, int dna_len) { subject_range.end_ = d.subject_end(); query_range.end_ = d.query_end(); if (d.i.frame.strand == FORWARD) query_source_range.end_ = d.query_end().absolute(dna_len); else query_source_range.begin_ = d.query_end().absolute(dna_len) + 1; } void Hsp::set_begin(int i, int j, Frame frame, int dna_len) { subject_range.begin_ = j; query_range.begin_ = i; this->frame = frame.index(); if (frame.strand == FORWARD) query_source_range.begin_ = TranslatedPosition(i, frame).absolute(dna_len); else query_source_range.end_ = TranslatedPosition(i, frame).absolute(dna_len) + 1; } void Hsp::set_end(int i, int j, Frame frame, int dna_len) { subject_range.end_ = j; query_range.end_ = i; if (frame.strand == FORWARD) query_source_range.end_ = TranslatedPosition(i, frame).absolute(dna_len); else query_source_range.begin_ = TranslatedPosition(i, frame).absolute(dna_len) + 1; } void Hsp::clear() { score = frame = length = identities = mismatches = positives = gap_openings = gaps = 0; transcript.clear(); } bool Hsp::is_weakly_enveloped_by(list::const_iterator begin, list::const_iterator end, int cutoff) const { for (list::const_iterator i = begin; i != end; ++i) if (partial_score(*i) < cutoff) return true; return false; } bool Hsp::is_enveloped_by(const Hsp &hsp, double p) const { return query_source_range.overlap_factor(hsp.query_source_range) >= p || subject_range.overlap_factor(hsp.subject_range) >= p; } bool Hsp::is_enveloped_by(std::list::const_iterator begin, std::list::const_iterator end, double p) const { for (list::const_iterator i = begin; i != end; ++i) if (is_enveloped_by(*i, p)) return true; return false; } bool Hsp::query_range_enveloped_by(const Hsp& hsp, double p) const { return query_source_range.overlap_factor(hsp.query_source_range) >= p; } bool Hsp::query_range_enveloped_by(std::list::const_iterator begin, std::list::const_iterator end, double p) const { for (list::const_iterator i = begin; i != end; ++i) if (query_range_enveloped_by(*i, p)) return true; return false; } void Hsp::push_match(Letter q, Letter s, bool positive) { if (q == s) { transcript.push_back(op_match, 1u); ++identities; ++positives; } else { transcript.push_back(op_substitution, s); ++mismatches; if (positive) ++positives; } ++length; } void Hsp::push_gap(EditOperation op, int length, const Letter *subject) { ++gap_openings; this->length += length; gaps += length; if (op == op_insertion) transcript.push_back(op_insertion, (unsigned)length); else for (int i = 0; i < length; ++i) #ifdef SEQ_MASK transcript.push_back(op_deletion, letter_mask(subject[-i])); #else transcript.push_back(op_deletion, subject[-i]); #endif } #ifdef WITH_DNA Hsp::Hsp(const IntermediateRecord &r, unsigned query_source_len, Loc qlen, Loc tlen, const OutputFormat* output_format, const Stats::Blastn_Score *dna_score_builder): #else Hsp::Hsp(const IntermediateRecord& r, unsigned query_source_len, Loc qlen, Loc tlen, const OutputFormat* output_format) : #endif backtraced(!IntermediateRecord::stats_mode(output_format->hsp_values) && output_format->hsp_values != HspValues::NONE), score(r.score), evalue(r.evalue), transcript(r.transcript) { #ifdef WITH_DNA if(dna_score_builder) bit_score = dna_score_builder->blast_bit_Score(r.score); else #endif { bit_score = score_matrix.bitscore(r.score); corrected_bit_score = score_matrix.bitscore_corrected(r.score, qlen, tlen); } subject_range.begin_ = r.subject_begin; if (align_mode.mode == AlignMode::blastx) { frame = r.frame(query_source_len, align_mode.mode); set_translated_query_begin(r.query_begin, query_source_len); } else { frame = 0; query_range.begin_ = r.query_begin; } if (IntermediateRecord::stats_mode(output_format->hsp_values)) { identities = r.identities; gaps = r.gaps; gap_openings = r.gap_openings; mismatches = r.mismatches; positives = r.positives; length = r.length; if (align_mode.mode == AlignMode::blastx) set_translated_query_end(r.query_end, query_source_len); else query_range.end_ = r.query_end + 1; subject_range.end_ = r.subject_end; } } Hsp::Hsp(const ApproxHsp& h, Loc qlen, Loc tlen) : backtraced(true), score(h.score), frame(0), length(h.query_range.length()), identities(length), mismatches(0), positives(length), gap_openings(0), gaps(0), swipe_target(0), d_begin(0), d_end(0), query_source_range(h.query_range), query_range(h.query_range), subject_source_range(h.subject_range), subject_range(h.subject_range), evalue(h.evalue), bit_score(score_matrix.bitscore(h.score)), corrected_bit_score(score_matrix.bitscore_corrected(h.score, qlen, tlen)), approx_id(100.0) { } bool Hsp::is_identity(const Sequence& query, const Sequence& target) const { query_range.check(query.length()); subject_range.check(target.length()); return query_range.length() == subject_range.length() && std::equal(query.data() + query_range.begin_, query.data() + query_range.end_, target.data() + subject_range.begin_, [](Letter x, Letter y) {return letter_mask(x) == letter_mask(y); }); } double Hsp::approx_id_percent(const Sequence& query, const Sequence& target) const { return is_identity(query, target) ? 100.0 : Stats::approx_id(score, query_range.length(), subject_range.length()); } double HspContext::qcovhsp() const { return (double)query_source_range().length() * 100.0 / query_len; } double HspContext::scovhsp() const { return (double)subject_range().length() * 100.0 / subject_len; } double HspContext::id_percent() const { return (double)identities() * 100 / length(); } pair Hsp::min_range_len(double qcov, double tcov, Loc qlen, Loc tlen) const { return { std::max(query_range.end_ - (Loc)std::floor(double(query_range.end_) - qcov * qlen / 100.0), (Loc)0), std::max(subject_range.end_ - (Loc)std::floor(double(subject_range.end_) - tcov * tlen / 100.0), (Loc)0) }; }bbuchfink-diamond-08b3cbc/src/basic/match.h000066400000000000000000000330151506104011400206530ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "sequence.h" #include "value.h" #include "packed_transcript.h" #include "translated_position.h" #include "util/geo/diagonal_segment.h" #include "util/io/input_file.h" #include "util/hsp/approx_hsp.h" inline Interval normalized_range(unsigned pos, int len, Strand strand) { return strand == FORWARD ? Interval(pos, pos + len) : Interval(pos + 1 + len, pos + 1); } struct IntermediateRecord; struct OutputFormat; namespace Stats { struct TargetMatrix; struct Blastn_Score; } struct Hsp { Hsp(const bool backtraced = false) : backtraced(backtraced), score(0), frame(0), length(0), identities(0), mismatches(0), positives(0), gap_openings(0), gaps(0), swipe_target(0), d_begin(0), d_end(0), evalue(DBL_MAX), bit_score(0.0), corrected_bit_score(0.0), approx_id(0.0), #ifdef WITH_DNA mapping_quality(0), n_anchors(0), #endif matrix(nullptr) {} Hsp(const bool backtraced, int score, int swipe_target = 0) : backtraced(backtraced), score(score), frame(0), length(0), identities(0), mismatches(0), positives(0), gap_openings(0), gaps(0), swipe_target(swipe_target), d_begin(0), d_end(0), evalue(DBL_MAX), bit_score(0.0), corrected_bit_score(0.0), approx_id(0.0), #ifdef WITH_DNA mapping_quality(0), n_anchors(0), #endif matrix(nullptr) {} #ifdef WITH_DNA Hsp(const IntermediateRecord &r, unsigned query_source_len, Loc qlen, Loc tlen, const OutputFormat* output_format, const Stats::Blastn_Score *dna_score_builder = nullptr); #else Hsp(const IntermediateRecord& r, unsigned query_source_len, Loc qlen, Loc tlen, const OutputFormat* output_format); #endif Hsp(const ApproxHsp& h, Loc qlen, Loc tlen); struct Iterator { Iterator(const Hsp &parent) : query_pos(parent.query_range.begin_, Frame(parent.frame)), subject_pos(parent.subject_range.begin_), ptr_(parent.transcript.ptr()), count_(ptr_->count()) { } bool good() const { return *ptr_ != PackedOperation::terminator(); } Iterator& operator++() { switch (op()) { case op_deletion: ++subject_pos; break; case op_insertion: ++query_pos; break; case op_match: case op_substitution: ++query_pos; ++subject_pos; break; case op_frameshift_forward: query_pos.shift_forward(); break; case op_frameshift_reverse: query_pos.shift_back(); break; } --count_; if (count_ == 0) { ++ptr_; count_ = ptr_->count(); } return *this; } EditOperation op() const { return ptr_->op(); } bool to_next_match() { do { this->operator++(); } while (good() && (op() == op_deletion || op() == op_insertion)); return good(); } TranslatedPosition query_pos; unsigned subject_pos; protected: const PackedOperation *ptr_; unsigned count_; }; Iterator begin() const { return Iterator(*this); } Interval oriented_range() const { if (frame < 3) return Interval(query_source_range.begin_, query_source_range.end_ - 1); else return Interval(query_source_range.end_ - 1, query_source_range.begin_); } void set_translated_query_begin(unsigned oriented_query_begin, unsigned dna_len) { int f = frame <= 2 ? frame + 1 : 2 - frame; if (f > 0) query_range.begin_ = (oriented_query_begin - (f - 1)) / 3; else query_range.begin_ = (dna_len + f - oriented_query_begin) / 3; } void set_translated_query_end(unsigned oriented_query_end, unsigned dna_len) { int f = frame <= 2 ? frame + 1 : 2 - frame; if (f > 0) query_range.end_ = (oriented_query_end - 2 - (f - 1)) / 3 + 1; else query_range.end_ = (dna_len + f - oriented_query_end) / 3 + 1; } int blast_query_frame() const { return align_mode.query_translated ? (frame <= 2 ? (int)frame + 1 : 2 - (int)frame) : 0; } bool operator<(const Hsp &rhs) const { return score > rhs.score || (score == rhs.score && (d_begin < rhs.d_begin || (d_begin == rhs.d_begin && query_source_range.begin_ < rhs.query_source_range.begin_))); } static bool cmp_evalue(const Hsp& a, const Hsp& b) { return a.evalue < b.evalue || (a.evalue == b.evalue && a.score > b.score); } double id_percent() const { return (double)identities * 100.0 / (double)length; } double query_cover_percent(unsigned query_source_len) const { return (double)query_source_range.length() * 100 / query_source_len; } double subject_cover_percent(unsigned subject_len) const { return (double)subject_range.length() * 100 / subject_len; } static bool cmp_query_pos(const Hsp &x, const Hsp &y) { return x.query_range.begin_ < y.query_range.begin_; } int partial_score(const Hsp &h) const { const double overlap = std::max(subject_range.overlap_factor(h.subject_range), query_source_range.overlap_factor(h.query_source_range)); return int((1 - overlap)*score); } bool envelopes(const DiagonalSegmentT &d, int dna_len) const { return query_source_range.contains(d.query_absolute_range(dna_len)) || subject_range.contains(d.subject_range()); } bool is_enveloped_by(const Hsp &hsp, double p) const; bool is_enveloped_by(std::list::const_iterator begin, std::list::const_iterator end, double p) const; bool query_range_enveloped_by(const Hsp& hsp, double p) const; bool query_range_enveloped_by(std::list::const_iterator begin, std::list::const_iterator end, double p) const; bool is_weakly_enveloped_by(std::list::const_iterator begin, std::list::const_iterator end, int cutoff) const; void push_back(const DiagonalSegmentT &d, const TranslatedSequence &query, const Sequence& subject, bool reversed); void push_match(Letter q, Letter s, bool positive); void push_gap(EditOperation op, int length, const Letter *subject); void splice(const DiagonalSegmentT &d0, const DiagonalSegmentT &d1, const TranslatedSequence &query, const Sequence& subject, bool reversed); void set_begin(const DiagonalSegmentT &d, int dna_len); void set_end(const DiagonalSegmentT &d, int dna_len); void set_begin(int i, int j, Frame frame, int dna_len); void set_end(int i, int j, Frame frame, int dna_len); void clear(); double approx_id_percent(const Sequence& query, const Sequence& target) const; bool is_identity(const Sequence& query, const Sequence& target) const; std::pair min_range_len(double qcov, double tcov, Loc qlen, Loc tlen) const; bool is_weakly_enveloped(const Hsp &j) const; std::pair diagonal_bounds() const; bool backtraced; int score, frame, length, identities, mismatches, positives, gap_openings, gaps, swipe_target, swipe_bin, d_begin, d_end; #ifdef DP_STAT int reserved1, reserved2; #endif #if WITH_DNA int mapping_quality, n_anchors; #endif Interval query_source_range, query_range, subject_source_range, subject_range; double evalue, bit_score, corrected_bit_score, approx_id; Sequence target_seq; const Stats::TargetMatrix* matrix; PackedTranscript transcript; }; struct HspContext { HspContext() {} HspContext( const Hsp& hsp, BlockId query_id, OId query_oid, const TranslatedSequence &query, const char *query_title, OId subject_oid, unsigned subject_len, const char* subject_title, int hit_num, int hsp_num, const Sequence &subject_seq, int ungapped_score = 0, const double query_self_aln_score = 0.0, const double target_self_aln_score = 0.0) : query(query), query_title(query_title), target_title(subject_title), query_id(query_id), query_oid(query_oid), subject_oid(subject_oid), query_len(query.source().length()), subject_len(subject_len), hit_num(hit_num), hsp_num(hsp_num), ungapped_score(ungapped_score), query_self_aln_score(query_self_aln_score), target_self_aln_score(target_self_aln_score), subject_seq(subject_seq), hsp_(hsp) {} struct Iterator : public Hsp::Iterator { Iterator(const HspContext &parent) : Hsp::Iterator(parent.hsp_), parent_(parent) { } Letter query() const { return parent_.query[query_pos]; } Letter subject() const { switch (op()) { case op_substitution: case op_deletion: return ptr_->letter(); default: return query(); } } char query_char() const { switch (op()) { case op_deletion: return '-'; case op_frameshift_forward: return '\\'; case op_frameshift_reverse: return '/'; default: return value_traits.alphabet[(long)query()]; } } char subject_char() const { switch (op()) { case op_insertion: case op_frameshift_forward: case op_frameshift_reverse: return '-'; default: return value_traits.alphabet[(long)subject()]; } } char midline_char(int score) const { switch (op()) { case op_match: return value_traits.alphabet[(long)query()]; case op_substitution: return score > 0 ? '+' : ' '; default: return ' '; } } private: const HspContext &parent_; }; Iterator begin() const { return Iterator(*this); } PackedTranscript::ConstIterator begin_old() const { return hsp_.transcript.begin(); } unsigned score() const { return hsp_.score; } double evalue() const { return hsp_.evalue; } double bit_score() const { return hsp_.bit_score; } double corrected_bit_score() const { return hsp_.corrected_bit_score; } double approx_id() const { return hsp_.approx_id; } unsigned frame() const { return hsp_.frame; } unsigned length() const { return hsp_.length; } unsigned identities() const { return hsp_.identities; } unsigned mismatches() const { return hsp_.mismatches; } unsigned positives() const { return hsp_.positives; } unsigned gap_openings() const { return hsp_.gap_openings; } unsigned gaps() const { return hsp_.gaps; } double approx_id_percent() const { return hsp_.approx_id_percent(query.index(hsp_.frame), subject_seq); } #if WITH_DNA unsigned mapping_quality() const { return hsp_.mapping_quality; } unsigned n_anchors() const { return hsp_.n_anchors; } #endif double qcovhsp() const; double scovhsp() const; double id_percent() const; const Interval& query_source_range() const { return hsp_.query_source_range; } const Interval& subject_source_range() const { return hsp_.subject_source_range; } const Interval& query_range() const { return hsp_.query_range; } const Interval& subject_range() const { return hsp_.subject_range; } Interval oriented_query_range() const { return hsp_.oriented_range(); } int blast_query_frame() const { return hsp_.blast_query_frame(); } PackedTranscript transcript() const { return hsp_.transcript; } bool operator<(const HspContext& h) const { return query_oid < h.query_oid; } #ifdef DP_STAT int reserved1() const { return hsp_.reserved1; } int reserved2() const { return hsp_.reserved2; } #endif Hsp hsp() const { return hsp_; } HspContext& parse(const OutputFormat* output_format); TranslatedSequence query; std::string query_title, target_title; BlockId query_id; OId query_oid, subject_oid; Loc query_len, subject_len; unsigned hit_num, hsp_num; int ungapped_score; double query_self_aln_score, target_self_aln_score; Sequence subject_seq; private: Hsp hsp_; friend HspContext deserialize(InputFile*); }; inline void serialize(const HspContext& h, TextBuffer& buf) { buf.write(h.query_id); buf.write(h.query_oid); buf.write(h.subject_oid); buf.write_c_str(h.query_title.c_str()); buf.write_c_str(h.target_title.c_str()); buf.write(h.query_len); buf.write(h.subject_len); buf.write(h.identities()); buf.write(h.mismatches()); buf.write(h.positives()); buf.write(h.gaps()); buf.write(h.length()); buf.write(h.gap_openings()); buf.write(h.query_range().begin_); buf.write(h.query_range().end_); buf.write(h.subject_range().begin_); buf.write(h.subject_range().end_); buf.write(h.bit_score()); buf.write(h.evalue()); buf.write(h.score()); buf.write(h.approx_id()); #if WITH_DNA buf.write(h.mapping_quality()); buf.write(h.n_anchors()); #endif } inline HspContext deserialize(InputFile* file_) { HspContext h; file_->read(h.query_id); file_->read(h.query_oid); file_->read(h.subject_oid); *file_ >> h.query_title; *file_ >> h.target_title; file_->read(h.query_len); file_->read(h.subject_len); file_->read(h.hsp_.identities); file_->read(h.hsp_.mismatches); file_->read(h.hsp_.positives); file_->read(h.hsp_.gaps); file_->read(h.hsp_.length); file_->read(h.hsp_.gap_openings); file_->read(h.hsp_.query_range.begin_); file_->read(h.hsp_.query_range.end_); file_->read(h.hsp_.subject_range.begin_); file_->read(h.hsp_.subject_range.end_); file_->read(h.hsp_.bit_score); file_->read(h.hsp_.evalue); file_->read(h.hsp_.score); file_->read(h.hsp_.approx_id); #ifdef WITH_DNA file_->read(h.hsp_.mapping_quality); file_->read(h.hsp_.n_anchors); #endif h.hsp_.query_source_range = h.hsp_.query_range; h.hsp_.subject_source_range = h.hsp_.subject_range; return h; }bbuchfink-diamond-08b3cbc/src/basic/packed_loc.h000066400000000000000000000041701506104011400216430ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "util/system.h" #ifndef __sparc__ #pragma pack(1) #endif struct packed_uint40_t { uint8_t high; uint32_t low; packed_uint40_t(): high (), low () { } packed_uint40_t(uint64_t v) : high((uint8_t)(v >> 32)), low((uint32_t)(v & UINT64_C(0xffffffff))) {} packed_uint40_t& operator=(uint32_t x) { high = 0; low = x; return *this; } operator uint64_t() const { return (uint64_t(high) << 32) | low; } operator int64_t() const { return (int64_t(high) << 32) | (int64_t)low; } operator uint32_t() const { return low; } operator int32_t() const { return low; } bool operator==(const packed_uint40_t& rhs) const { return high == rhs.high && low == rhs.low; } bool operator!=(const packed_uint40_t& rhs) const { return high != rhs.high && low != rhs.low; } bool operator<(const packed_uint40_t &rhs) const { return high < rhs.high || (high == rhs.high && low < rhs.low); } friend uint64_t operator-(const packed_uint40_t &x, const packed_uint40_t &y) { return (uint64_t)(x) - (uint64_t)(y); } } PACKED_ATTRIBUTE ; typedef packed_uint40_t PackedLoc; #pragma pack()bbuchfink-diamond-08b3cbc/src/basic/packed_sequence.h000066400000000000000000000045201506104011400226750ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "value.h" #include "util/binary_buffer.h" #include "sequence.h" inline bool has_n(const Sequence &seq) { for (Loc i = 0; i < seq.length(); ++i) if (seq[i] == 4) return true; return false; } struct PackedSequence { PackedSequence(const Sequence &seq, SequenceType type): has_n_ (type == SequenceType::nucleotide ? ::has_n(seq) : false) { switch (type) { case SequenceType::nucleotide: if (has_n_) pack<3>(seq); else pack<2>(seq); break; case SequenceType::amino_acid: pack<5>(seq); } } PackedSequence(BinaryBuffer::Iterator &it, unsigned len, bool has_n, unsigned b): has_n_ (has_n) { const size_t l = (len*b+7)/8; it.read(data_, l); } void unpack(std::vector &dst, unsigned b, unsigned len) { dst.clear(); unsigned x = 0, n = 0, l = 0; const unsigned mask = (1 << b) - 1; for (unsigned i = 0; i < data_.size(); ++i) { x |= (unsigned)data_[i] << n; n += 8; while (n >= b && l < len) { dst.push_back(x & mask); n -= b; x >>= b; ++l; } } } const std::vector& data() const { return data_; } bool has_n() const { return has_n_; } private: template void pack(const Sequence &seq) { unsigned x = 0, n = 0; for(Loc i=0;i= 8) { data_.push_back(x & 0xff); n -= 8; x >>= 8; } } if(n > 0) data_.push_back(x & 0xff); } bool has_n_; std::vector data_; };bbuchfink-diamond-08b3cbc/src/basic/packed_transcript.h000066400000000000000000000117261506104011400232640ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "util/binary_buffer.h" #include "basic/value.h" #include "sequence.h" typedef enum { op_match = 0, op_insertion = 1, op_deletion = 2, op_substitution = 3, op_frameshift_forward = 4, op_frameshift_reverse = 5 } EditOperation; struct Reversed {}; struct PackedOperation { enum { OP_BITS = 2, COUNT_BITS = 8 - OP_BITS, MAX_COUNT = (1 << COUNT_BITS) - 1 }; PackedOperation(uint8_t code) : code(code) {} PackedOperation(EditOperation op, unsigned count) : code((op << COUNT_BITS) | count) {} PackedOperation(EditOperation op, Letter v) : code((op << COUNT_BITS) | (int)v) {} operator uint8_t() const { return code; } EditOperation op() const { uint8_t o = code >> COUNT_BITS; switch (o) { case op_substitution: switch (letter()) { case (Letter)AMINO_ACID_COUNT: return op_frameshift_reverse; case (Letter)(AMINO_ACID_COUNT + 1) : return op_frameshift_forward; default: return op_substitution; } default: return (EditOperation)o; } } unsigned count() const { switch (op()) { case op_match: case op_insertion: return code & MAX_COUNT; default: return 1; } } Letter letter() const { return code & MAX_COUNT; } static PackedOperation terminator() { return PackedOperation(op_match, 0u); } static PackedOperation frameshift_forward() { return PackedOperation(op_substitution, (unsigned)AMINO_ACID_COUNT + 1); } static PackedOperation frameshift_reverse() { return PackedOperation(op_substitution, (unsigned)AMINO_ACID_COUNT); } uint8_t code; }; struct CombinedOperation { EditOperation op; unsigned count; Letter letter; }; struct PackedTranscript { struct ConstIterator { ConstIterator(const PackedOperation* op) : ptr_(op) { gather(); } bool good() const { return *ptr_ != PackedOperation::terminator(); } ConstIterator& operator++() { ++ptr_; gather(); return *this; } const CombinedOperation& operator*() const { return op_; } const CombinedOperation* operator->() const { return &op_; } private: void gather() { if(!good()) return; op_.op = ptr_->op(); if(op_.op == op_deletion || op_.op == op_substitution || op_.op == op_frameshift_forward || op_.op==op_frameshift_reverse) { op_.letter = ptr_->letter(); op_.count = 1; } else { op_.count = 0; do { op_.count += ptr_->count(); ++ptr_; } while(good() && ptr_->op() == op_.op); --ptr_; } } const PackedOperation* ptr_; CombinedOperation op_; }; void read(BinaryBuffer::Iterator &it) { data_.clear(); uint8_t code; do { it >> code; data_.push_back(code); } while (code != PackedOperation::terminator()); } ConstIterator begin() const { return ConstIterator(data_.data()); } const std::vector& data() const { return data_; } const PackedOperation* ptr() const { return &data_[0]; } void push_back(EditOperation op) { if (op == op_frameshift_forward) data_.push_back(PackedOperation::frameshift_forward()); else if (op == op_frameshift_reverse) data_.push_back(PackedOperation::frameshift_reverse()); else if (data_.empty() || data_.back().op() != op || (data_.back().op() == op && data_.back().count() == PackedOperation::MAX_COUNT)) data_.push_back(PackedOperation(op, 1u)); else ++data_.back().code; } void push_back(EditOperation op, Letter l) { data_.push_back(PackedOperation(op, l)); } void push_back(EditOperation op, unsigned count) { while (count > 0) { const unsigned n = std::min(count, (unsigned)PackedOperation::MAX_COUNT); data_.push_back(PackedOperation(op, n)); count -= n; } } void reverse(size_t begin = 0) { std::reverse(data_.begin() + begin, data_.end()); } size_t raw_length() const { return data_.size(); } void push_terminator() { data_.push_back(PackedOperation::terminator()); } void clear() { data_.clear(); } void push_back(const Sequence &s, const Reversed&) { const int l = (int)s.length(); for (int i = l - 1; i >= 0; --i) push_back(op_deletion, s[i]); } void push_back(const Sequence &s) { const int l = (int)s.length(); for (int i = 0; i < l; ++i) push_back(op_deletion, s[i]); } void reserve(size_t n) { data_.reserve(n); } private: std::vector data_; friend struct Hsp; };bbuchfink-diamond-08b3cbc/src/basic/reduction.h000066400000000000000000000046561506104011400215640ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include "value.h" #include "sequence.h" struct Reduction { Reduction(const char* definition_string); unsigned size() const { return size_; } int bit_size() const { return bit_size_; } double bit_size_exact() const { return bit_size_exact_; } unsigned operator()(Letter a) const { return map_[(long)a]; } unsigned operator()(size_t a) const { return map_[a]; } const Letter* map8() const { return map8_; } const Letter* map8b() const { return map8b_; } inline friend std::ostream& operator<<(std::ostream &os, const Reduction &r) { for (unsigned i = 0; i < r.size_; ++i) { os << '['; for (unsigned j = 0; j < 20; ++j) if (r.map_[j] == i) os << value_traits.alphabet[j]; os << ']'; } return os; } static Reduction& get_reduction() { return instance; } static void set_reduction(const Reduction& r) { get_reduction() = r; } static void reduce_seq(const Sequence &seq, std::vector &dst) { dst.clear(); dst.resize(seq.length()); const Reduction& reduction_instance = get_reduction(); for (Loc i = 0; i < seq.length(); ++i) dst[i] = reduction_instance(seq[i]); } double freq(unsigned bucket) const { return freq_[bucket]; } std::string decode_seed(const uint64_t seed, const size_t len) const; private: unsigned map_[256]; alignas(16) Letter map8_[256], map8b_[256]; unsigned size_; int bit_size_; double bit_size_exact_; std::array freq_; static Reduction instance; };bbuchfink-diamond-08b3cbc/src/basic/seed.h000066400000000000000000000042641506104011400205030ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "const.h" #include "config.h" #include "value.h" #include "stats/score_matrix.h" using PackedSeed = uint64_t; #ifdef LONG_SEEDS using SeedOffset = uint64_t; using SeedPartition = uint32_t; #else using SeedOffset = uint32_t; using SeedPartition = uint32_t; #endif static inline PackedSeed seedp_mask(int seedp_bits) { return ((PackedSeed)1 << seedp_bits) - 1; } static inline PackedSeed seedp_count(int seedp_bits) { return (PackedSeed)1 << seedp_bits; } static inline SeedPartition seed_partition(PackedSeed s, PackedSeed seedp_mask) { return (SeedPartition)(s & seedp_mask); } static inline SeedOffset seed_partition_offset(PackedSeed s, PackedSeed seedp_bits) { return (SeedOffset)(s >> seedp_bits); } struct Seed { Letter& operator[](unsigned i) { return data_[i]; } friend std::ostream& operator<<(std::ostream &str, const Seed &s) { for (unsigned i = 0; i < config.seed_weight; ++i) str << value_traits.alphabet[(size_t)s.data_[i]]; return str; } int score(const Seed &rhs) const { int s = 0; for (unsigned i = 0; i < config.seed_weight; ++i) s += score_matrix(data_[i], rhs.data_[i]); return s; } uint64_t packed() const { uint64_t s = 0; for (unsigned i = 0; i < config.seed_weight; ++i) { s *= 20; s += data_[i]; } return s; } void enum_neighborhood(int treshold, std::vector &out); private: void enum_neighborhood(unsigned pos, int treshold, std::vector& out, int score); Letter data_[Const::max_seed_weight]; };bbuchfink-diamond-08b3cbc/src/basic/seed_iterator.h000066400000000000000000000140631506104011400224120ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "shape.h" #include "sequence.h" #include "util/hash_function.h" struct SeedIterator { SeedIterator(std::vector &seq, const Shape &sh): ptr_ (seq.data()), end_ (ptr_ + seq.size() - sh.length_ + 1) {} bool good() const { return ptr_ < end_; } bool get(uint64_t &seed, const Shape &sh) { return sh.set_seed_reduced(seed, ptr_++); } SeedIterator& operator++() { ptr_++; return *this; } private: const Letter *ptr_, *end_; }; struct MinimizerIterator { MinimizerIterator(std::vector& seq, const Shape& sh, Loc window) : ptr_(seq.data()), begin_(seq.data()), end_(ptr_ + seq.size() - sh.length_ + 1), window_(window), sh_(sh) { next(); if (good()) min_idx_ = get(); } bool good() const { return (Loc)seeds_.size() == window_; } uint64_t operator*() const { return seeds_[min_idx_]; } MinimizerIterator& operator++() { int m = 0; const uint64_t current = **this; do { seeds_.pop_front(); hashes_.pop_front(); pos_.pop_front(); next(); } while (good() && seeds_[m = get()] == current); min_idx_ = m; return *this; } Loc pos() const { return pos_[min_idx_]; } private: void next() { while ((Loc)seeds_.size() < window_ && ptr_ < end_) { uint64_t s; if (sh_.set_seed_reduced(s, ptr_)) { seeds_.push_back(s); hashes_.push_back(MurmurHash()(s)); pos_.push_back(Loc(ptr_ - begin_)); } ++ptr_; } } int get() const { std::deque::const_iterator i = hashes_.begin(), j = i; uint64_t s = *i++; while (i < hashes_.end()) { if (*i < s) { s = *i; j = i; } ++i; } return int(j - hashes_.begin()); } const Letter* ptr_, *begin_, *end_; std::deque seeds_, hashes_; std::deque pos_; const Loc window_; const Shape& sh_; int min_idx_; }; struct SketchIterator { SketchIterator(std::vector& seq, const Shape& sh, Loc n) { std::vector v; v.reserve(seq.size() - sh.length_ + 1); const Letter* end = seq.data() + seq.size() - sh.length_ + 1; uint64_t s; for (const Letter* p = seq.data(); p < end; ++p) if (sh.set_seed_reduced(s, p)) v.emplace_back(s, MurmurHash()(s), Loc(p - seq.data())); std::sort(v.begin(), v.end()); data_.insert(data_.end(), v.begin(), v.begin() + std::min(n, (Loc)v.size())); it_ = data_.begin(); } bool good() const { return it_ < data_.end(); } uint64_t operator*() const { return it_->seed; } Loc pos() const { return it_->pos; } SketchIterator& operator++() { ++it_; return *this; } private: struct Kmer { Kmer(uint64_t seed, uint64_t hash, Loc pos) : seed(seed), hash(hash), pos(pos) {} uint64_t seed, hash; Loc pos; bool operator<(const Kmer& k) const { return hash < k.hash; } }; std::vector data_; std::vector::const_iterator it_; }; template struct HashedSeedIterator { HashedSeedIterator(Letter* seq, Loc len, const Shape &sh): long_mask(sh.long_mask()), ptr_(seq), end_(ptr_ + len), last_(0) { for (int i = 0; i < sh.length_ && ptr_ < end_; ++i) last_ = (last_ << B) | Reduction::get_reduction()(letter_mask(*(ptr_++))); } bool good() const { return ptr_ <= end_; } uint64_t operator*() const { return MurmurHash()(last_ & long_mask); } HashedSeedIterator& operator++() { while (ptr_ < end_) { last_ <<= B; const Letter l = letter_mask(*(ptr_++)); if (!is_amino_acid(l)) continue; last_ |= Reduction::get_reduction()(l); return *this; } ++ptr_; return *this; } Letter* seq_ptr(const Shape& sh) const { return ptr_ - sh.length_; } private: const uint64_t long_mask; Letter *ptr_, *end_; uint64_t last_; }; struct FilterMaskedSeeds { }; template struct ContiguousSeedIterator { ContiguousSeedIterator(const Sequence &seq) : ptr_(seq.data()), end_(ptr_ + seq.length()), last_(0) { for (int i = 0; i < L - 1; ++i) last_ = (last_ << B) | Reduction::get_reduction()(letter_mask(*(ptr_++))); } bool good() const { return ptr_ < end_; } bool get(uint64_t &seed) { for (;;) { last_ <<= B; last_ &= (uint64_t(1) << (B*L)) - 1; const Letter l = letter_mask(*(ptr_++)); last_ |= Reduction::get_reduction()(l); seed = last_; return true; } } static int length() { return L; } private: const Letter *ptr_, *end_; uint64_t last_; unsigned mask_; }; template struct ContiguousSeedIterator { ContiguousSeedIterator(const Sequence &seq) : ptr_(seq.data()), end_(ptr_ + seq.length()), last_(0), mask_(0) { for (int i = 0; i < L - 1; ++i) { const Letter l = letter_mask(*(ptr_++)); last_ = (last_ << B) | Reduction::get_reduction()(l); if (!is_amino_acid(l)) mask_ |= 1; mask_ <<= 1; } } bool good() const { return ptr_ < end_; } bool get(uint64_t &seed) { for (;;) { last_ <<= B; last_ &= (uint64_t(1) << (B*L)) - 1; mask_ <<= 1; mask_ &= (1 << L) - 1; const Letter l = letter_mask(*(ptr_++)); const unsigned r = Reduction::get_reduction()(l); last_ |= r; seed = last_; if (!is_amino_acid(l)) mask_ |= 1; return mask_ == 0; } } static int length() { return L; } private: const Letter *ptr_, *end_; uint64_t last_; unsigned mask_; };bbuchfink-diamond-08b3cbc/src/basic/sequence.h000066400000000000000000000157711506104011400214000ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include "basic/value.h" #include "util/text_buffer.h" #include "translated_position.h" #include "util/geo/interval.h" struct Sequence { static constexpr Letter DELIMITER = DELIMITER_LETTER; struct Reversed {}; struct Hardmasked {}; Sequence(): len_ (0), data_ (nullptr) { } Sequence(const Letter *data, Loc len): len_ (len), data_ (data) { } Sequence(const Letter* data, int64_t len) : len_((Loc)len), data_(data) { } Sequence(const Letter* data, size_t len) : len_((Loc)len), data_(data) { } Sequence(const Letter *begin, const Letter *end) : len_(Loc(end - begin)), data_(begin) {} Sequence(const std::vector &data): len_((Loc)data.size()), data_(data.data()) {} Sequence(const Sequence &seq, int from, int to): len_(to-from+1), data_(seq.data() + from) {} Loc length() const { return len_; } const Letter* data() const { return data_; } const Letter* end() const { return data_ + len_; } const Letter* aligned_data(unsigned padding) const { return data_ + padding; } Letter operator [](size_t i) const { #ifdef SEQ_MASK return data_[i] & LETTER_MASK; #else return data_[i]; #endif } bool empty() const { return len_ == 0; } Sequence operator+(int d) const { return Sequence(data_ + d, len_ - d); } size_t print(char *ptr, unsigned begin, unsigned len) const { for(unsigned i=begin;i= 0; --i) os << v.alphabet[(long)(data_[i] & 127)]; return os; } Sequence subseq(int begin, int end) const { return Sequence(*this, begin, end - 1); } Sequence subseq(int begin) const { return Sequence(data_ + begin, len_ - begin); } Sequence subseq_clipped(int begin, int end) const { return Sequence(*this, std::max(begin, 0), std::min(end, len_)); } friend TextBuffer& operator<<(TextBuffer &buf, const Sequence &s) { return s.print(buf, value_traits); } friend std::ostream& operator<<(std::ostream &buf, const Sequence &s) { return s.print(buf, value_traits); } static Sequence get_window(const Letter *s, int window) { const Letter *p = s; int n = 0; while (*p != Sequence::DELIMITER && n < window) { --p; ++n; } n = 0; while (*s != Sequence::DELIMITER && n < window) { ++s; ++n; } return Sequence(p + 1, Loc(s - p - 1)); } std::vector copy() const { return std::vector(data_, data_ + len_); } std::vector reverse() const; void mask(const Interval &i) { for (int j = i.begin_; j < i.end_; ++j) ((Letter*)data_)[j] = value_traits.mask_char; } bool operator==(const Sequence& s) const { if (len_ != s.len_) return false; for (Loc i = 0; i < len_; ++i) if (letter_mask(data_[i]) != letter_mask(s.data_[i])) return false; return true; } Loc masked_letters() const { Loc n = 0; for (Loc i = 0; i < len_; ++i) if (letter_mask(data_[i]) == MASK_LETTER) ++n; return n; } double masked_letter_ratio() const { return (double)masked_letters() / len_; } double length_ratio(const Sequence& seq) const { return len_ < seq.len_ ? (double)len_ / seq.len_ : (double)seq.len_ / len_; } static std::vector from_string(const char* str, const ValueTraits&vt = value_traits, int64_t line = 0); Loc len_; const Letter *data_; }; struct TranslatedSequence { TranslatedSequence() {} explicit TranslatedSequence(const Sequence &s1): source_(s1) { translated_[0] = s1; } TranslatedSequence(const Sequence&source, const Sequence&s1, const Sequence&s2, const Sequence&s3, const Sequence&s4, const Sequence&s5, const Sequence&s6): source_(source) { translated_[0] = s1; translated_[1] = s2; translated_[2] = s3; translated_[3] = s4; translated_[4] = s5; translated_[5] = s6; } TranslatedSequence(const Sequence&source, const std::vector v[6]): source_(source) { for (int i = 0; i < 6; ++i) translated_[i] = Sequence(v[i]); } const Sequence& operator[](Frame frame) const { return translated_[frame.index()]; } Letter operator[](const TranslatedPosition &i) const { return (*this)[i.frame][i]; } Letter operator()(int in_strand, Strand strand) const { assert(in_strand < (int)source_.length() - 2); return translated_[in_strand % 3 + (strand == FORWARD ? 0 : 3)][in_strand / 3]; } const Sequence& index(unsigned frame) const { return translated_[frame]; } const Sequence&source() const { return source_; } bool in_bounds(const TranslatedPosition &i) const { return i >= 0 && i < int((*this)[i.frame].length()); } void get_strand(Strand strand, Sequence*dst) const { int i = strand == FORWARD ? 0 : 3; dst[0] = translated_[i++]; dst[1] = translated_[i++]; dst[2] = translated_[i]; } private: Sequence source_; Sequence translated_[6]; };bbuchfink-diamond-08b3cbc/src/basic/shape.h000066400000000000000000000100531506104011400206540ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "const.h" #include "value.h" #include "seed.h" #include "reduction.h" #include "util/math/integer.h" struct Shape { Shape(): length_ (0), weight_ (0), d_ (0), mask_ (0), rev_mask_ (0) { memset(positions_, 0, sizeof(uint32_t)*Const::max_seed_weight); } Shape(const char* code, unsigned id) : weight_(0), mask_(0), rev_mask_(0), long_mask_(0) //long_mask_sse_(_mm_setzero_si128()) { assert(strlen(code) <= 32); memset(positions_, 0, sizeof(uint32_t)*Const::max_seed_weight); const uint64_t b = Reduction::get_reduction().bit_size(); unsigned i (0); for(;i config.max_seed_freq) return false; #endif return true; } inline bool set_seed_shifted(PackedSeed &s, const Letter *seq) const { s = 0; const uint64_t b = Reduction::get_reduction().bit_size(); for (int i = 0; i < weight_; ++i) { Letter l = seq[positions_[i]]; #ifdef SEQ_MASK l &= LETTER_MASK; #endif if (l == value_traits.mask_char || l == Sequence::DELIMITER || l == STOP_LETTER) return false; unsigned r = Reduction::get_reduction()(l); s <<= b; s |= uint64_t(r); } return true; } inline bool set_seed_reduced(PackedSeed &s, const Letter *seq) const { s = 0; for (int i = 0; i < weight_; ++i) { Letter l = seq[positions_[i]]; #ifdef SEQ_MASK l &= LETTER_MASK; #endif if (l == MASK_LETTER) return false; s *= Reduction::get_reduction().size(); s += uint64_t(l); } return true; } inline bool set_seed(Seed &s, const Letter *seq) const { for (int i = 0; i < weight_; ++i) { Letter l = seq[positions_[i]]; #ifdef SEQ_MASK l &= LETTER_MASK; #endif if (l >= 20) return false; s[i] = l; } return true; } friend std::ostream& operator<<(std::ostream&s, const Shape &sh) { for (int i = 0; i < sh.length_; ++i) s << ((sh.mask_ & (1 << i)) ? '1' : '0'); return s; } bool contiguous() const { return length_ == weight_; } uint64_t long_mask() const { return long_mask_; } int bit_length() const { return ::bit_length(power((int64_t)Reduction::get_reduction().size(), (int64_t)weight_) - 1); } int32_t length_, weight_, positions_[Const::max_seed_weight]; uint32_t d_, mask_, rev_mask_; uint64_t long_mask_; //__m128i long_mask_sse_; }; bbuchfink-diamond-08b3cbc/src/basic/shape_config.h000066400000000000000000000040071506104011400222030ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "shape.h" class ShapeConfig { public: ShapeConfig(): n_ (0) { } ShapeConfig(const std::vector& codes, unsigned count): n_ (0) { unsigned max_shapes = count == 0 ? (unsigned)codes.size() : std::min(count, (unsigned)codes.size()); for (unsigned i = 0; i < max_shapes; ++i) { shapes_[n_] = Shape(codes[i].c_str(), i); if (shapes_[n_].weight_ != shapes_[0].weight_) throw std::runtime_error("Seed shape weight has to be uniform."); n_++; } } int count() const { return n_; } const Shape& operator[](size_t i) const { return shapes_[i]; } friend std::ostream& operator<<(std::ostream&s, const ShapeConfig& cfg) { for (unsigned i = 0; i < cfg.n_; ++i) s << cfg.shapes_[i] << (i < cfg.n_ - 1 ? "," : ""); return s; } std::vector patterns(unsigned begin, unsigned end) const { std::vector v; for (unsigned i = begin; i < end; ++i) v.push_back(shapes_[i].mask_); return v; } private: Shape shapes_[Const::max_shapes]; unsigned n_; }; extern ShapeConfig shapes; extern unsigned shape_from, shape_to;bbuchfink-diamond-08b3cbc/src/basic/statistics.h000066400000000000000000000056011506104011400217510ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include struct Statistics { using StatType = int64_t; enum value { SEED_HITS, TENTATIVE_MATCHES0, TENTATIVE_MATCHES1, TENTATIVE_MATCHES2, TENTATIVE_MATCHES3, TENTATIVE_MATCHES4, TENTATIVE_MATCHESX, MATCHES, ALIGNED, GAPPED, DUPLICATES, GAPPED_HITS, QUERY_SEEDS, QUERY_SEEDS_HIT, REF_SEEDS, REF_SEEDS_HIT, QUERY_SIZE, REF_SIZE, OUT_HITS, OUT_MATCHES, COLLISION_LOOKUPS, QCOV, BIAS_ERRORS, SCORE_TOTAL, ALIGNED_QLEN, PAIRWISE, HIGH_SIM, SEARCH_TEMP_SPACE, SECONDARY_HITS, ERASED_HITS, SQUARED_ERROR, CELLS, TARGET_HITS0, TARGET_HITS1, TARGET_HITS2, TARGET_HITS3, TARGET_HITS3_CBS, TARGET_HITS4, TARGET_HITS5, TARGET_HITS6, TIME_GREEDY_EXT, LOW_COMPLEXITY_SEEDS, SWIPE_REALIGN, EXT8, EXT16, EXT32, GAPPED_FILTER_TARGETS, GAPPED_FILTER_HITS1, GAPPED_FILTER_HITS2, GROSS_DP_CELLS, NET_DP_CELLS, TIME_TARGET_SORT, TIME_SW, TIME_EXT, TIME_GAPPED_FILTER, TIME_LOAD_HIT_TARGETS, TIME_CHAINING, TIME_LOAD_SEED_HITS, TIME_SORT_SEED_HITS, TIME_SORT_TARGETS_BY_SCORE, TIME_TARGET_PARALLEL, TIME_TRACEBACK_SW, TIME_TRACEBACK, HARD_QUERIES, TIME_MATRIX_ADJUST, MATRIX_ADJUST_COUNT, COMP_BASED_STATS_COUNT, FAILED_COMP_BASED_STATS, MASKED_LAZY, SWIPE_TASKS_TOTAL, SWIPE_TASKS_ASYNC, TRIVIAL_ALN, TIME_EXT_32, EXT_OVERFLOW_8, EXT_WASTED_16, DP_CELLS_8, DP_CELLS_16, DP_CELLS_32, TIME_PROFILE, TIME_ANCHORED_SWIPE, TIME_ANCHORED_SWIPE_ALLOC, TIME_ANCHORED_SWIPE_SORT, TIME_ANCHORED_SWIPE_ADD, TIME_ANCHORED_SWIPE_OUTPUT, COUNT }; Statistics() { reset(); } void reset() { std::fill(data_, data_ + COUNT, (StatType)0); } Statistics& operator+=(const Statistics &rhs) { mtx_.lock(); for(unsigned i=0;i This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "util/geo/interval.h" #include "value.h" enum Strand { FORWARD = 0, REVERSE = 1 }; struct Frame { Frame() {} Frame(Strand strand, int offset): offset(offset), strand(strand) {} explicit Frame(int index) : offset(index % 3), strand(index < 3 ? FORWARD : REVERSE) {} int index() const { return strand * 3 + offset; } int signed_frame() const { return (offset + 1) * (strand == FORWARD ? 1 : -1); } int length(int dna_len) const { return std::max((dna_len - offset) / 3, 0); } int offset; Strand strand; }; struct TranslatedPosition { TranslatedPosition() {} TranslatedPosition(int translated, Frame frame): frame(frame), translated(translated) { } TranslatedPosition(int in_strand, Strand strand): frame(strand, in_strand % 3), translated(in_strand_to_translated(in_strand)) {} operator int() const { return translated; } TranslatedPosition& operator++() { ++translated; return *this; } TranslatedPosition operator+(int x) const { return TranslatedPosition(translated + x, frame); } TranslatedPosition operator-(int x) const { return TranslatedPosition(translated - x, frame); } void shift_forward() { ++frame.offset; if (frame.offset == 3) { frame.offset = 0; ++translated; } } void shift_back() { --frame.offset; if (frame.offset == -1) { frame.offset = 2; --translated; } } void shift_forward(int k) { while (k-- > 0) shift_forward(); } int frame_shift(const TranslatedPosition &x) const { static const int frameshift[3][3] = { { 0, 1, -1 },{ -1, 0, 1 },{ 1, -1, 0 } }; return frameshift[frame.offset][x.frame.offset]; } int absolute(int dna_len) const { if(!frame.offset && align_mode.mode == AlignMode::blastn) return dna_len - 1 - translated; if (!align_mode.query_translated && frame.strand == FORWARD) return translated; return oriented_position(in_strand(), frame.strand, dna_len); } static Interval absolute_interval(const TranslatedPosition &begin, const TranslatedPosition &end, int dna_len) { if (begin.frame.strand == FORWARD) return Interval(begin.in_strand(), end.in_strand()); else return Interval(oriented_position(end.in_strand() - 1, REVERSE, dna_len), oriented_position(begin.in_strand() - 1, REVERSE, dna_len)); } static int in_strand_to_translated(int in_strand) { if (align_mode.query_translated) return in_strand / 3; else return in_strand; } static int translated_to_in_strand(int translated, Frame frame) { if (align_mode.query_translated) return frame.offset + 3 * translated; else return translated; } int in_strand() const { return translated_to_in_strand(translated, frame); } static int oriented_position(int pos, Strand strand, int dna_len) { return strand == FORWARD ? pos : dna_len - pos - 1; } static int absolute_to_translated(int src, Frame frame, int dna_len, bool translated) { if (!translated) return src; return in_strand_to_translated(oriented_position(src, frame.strand, dna_len)); } static int translated_to_absolute(int translated, Frame frame, int dna_len) { return oriented_position(translated_to_in_strand(translated, frame), frame.strand, dna_len); } friend std::ostream& operator<<(std::ostream &s, const TranslatedPosition &a) { s << a.frame.offset << ' ' << a.translated; return s; } Frame frame; int translated; }; bbuchfink-diamond-08b3cbc/src/basic/value.cpp000066400000000000000000000041111506104011400212210ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "value.h" #include "reduction.h" const Letter CharRepresentation::invalid = '\xff'; CharRepresentation::CharRepresentation(unsigned size, const char* chars, char mask, const char* mask_chars) { memset(data_, invalid, sizeof(data_)); for (unsigned i = 0; i < size; ++i) { assert(chars[i] != (char)invalid); data_[(long)chars[i]] = i; data_[(long)tolower(chars[i])] = i; } while (*mask_chars != 0) { const char ch = *mask_chars; data_[(long)ch] = mask; data_[(long)tolower(ch)] = mask; ++mask_chars; } } ValueTraits::ValueTraits(const char* alphabet, Letter mask_char, const char* ignore, SequenceType seq_type) : alphabet(alphabet), alphabet_size((unsigned)strlen(alphabet)), mask_char(mask_char), from_char(CharRepresentation((unsigned)alphabet_size, alphabet, mask_char, ignore)), seq_type(seq_type) {} // 15 = O, 21 = U const Letter IUPACAA_TO_STD[32] = { -1, 0, 20, 4, 3, 6, 13, 7, 8, 9, 21, 11, 10, 12, 2, MASK_LETTER, 14, 5, 1, 15, 16, MASK_LETTER, 19, 17, 23, 18, 22, -1, -1, -1, -1, 24 }; // 24 = U, 26 = O const Letter NCBI_TO_STD[28] = { MASK_LETTER, 0, 20, 4, 3, 6, 13, 7, 8, 9, 11, 10, 12, 2, 14, 5, 1, 15, 16, 19, 17, 23, 18, 22, MASK_LETTER, 24, MASK_LETTER, 21 };bbuchfink-diamond-08b3cbc/src/basic/value.h000066400000000000000000000104511506104011400206720ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include "util/simd.h" typedef signed char Letter; enum class SequenceType : int32_t { amino_acid = 0, nucleotide = 1 }; struct CharRepresentation { CharRepresentation(unsigned size, const char* chars, char mask, const char* mask_chars); Letter operator()(char c) const { if (data_[(long)c] == invalid) throw std::runtime_error("Invalid character in sequence: " + (c >= 32 && c < 127 ? std::string("'") + c + "'" : "ASCII " + std::to_string((long)c))); return data_[(long)c]; } private: static const Letter invalid; Letter data_[256]; }; struct ValueTraits { ValueTraits(const char *alphabet, Letter mask_char, const char *ignore, SequenceType seq_type); const char *alphabet; unsigned alphabet_size; Letter mask_char; CharRepresentation from_char; SequenceType seq_type; }; #define AMINO_ACID_ALPHABET "ARNDCQEGHILKMFPSTWYVBJZX*_" #define AMINO_ACID_COUNT (int(sizeof(AMINO_ACID_ALPHABET) - 1)) #define NUCLEOTIDE_ALPHABET "ACGTN" #define NUCLEOTIDE_COUNT (sizeof(NUCLEOTIDE_ALPHABET) -1) constexpr Letter MASK_LETTER = 23; constexpr Letter STOP_LETTER = 24; constexpr Letter SUPER_HARD_MASK = 25; constexpr Letter DELIMITER_LETTER = 31; constexpr Letter LETTER_MASK = 31; constexpr Letter SEED_MASK = -128; constexpr int32_t TRUE_AA = 20; static inline bool is_amino_acid(Letter x) { return x != MASK_LETTER && x != DELIMITER_LETTER && x != STOP_LETTER; } static inline Letter letter_mask(Letter x) { #ifdef SEQ_MASK return Letter(x & LETTER_MASK); #else return x; #endif } #ifdef __SSE2__ static inline __m128i letter_mask(__m128i x) { #ifdef SEQ_MASK return _mm_and_si128(x, _mm_set1_epi8(LETTER_MASK)); #else return x; #endif } #endif #ifdef __AVX2__ static inline __m256i letter_mask(__m256i x) { #ifdef SEQ_MASK return _mm256_and_si256(x, _mm256_set1_epi8(LETTER_MASK)); #else return x; #endif } #endif #ifdef __ARM_NEON static inline int8x16_t letter_mask(int8x16_t x) { #ifdef SEQ_MASK return vandq_s8(x, vdupq_n_s8(LETTER_MASK)); #else return x; #endif } #endif extern const ValueTraits amino_acid_traits; extern const ValueTraits nucleotide_traits; extern ValueTraits value_traits; extern ValueTraits input_value_traits; static inline char to_char(Letter a) { return value_traits.alphabet[(long)a]; } struct AlignMode { AlignMode(unsigned mode); static unsigned from_command(unsigned command); int check_context(int i) const { if (i >= query_contexts) throw std::runtime_error("Sequence context is out of bounds."); return i; } const char* to_string() const { static const char* mode_str[] = { 0, 0, "blastp", "blastx", "blastn" }; return mode_str[mode]; } enum { blastp = 2, blastx = 3, blastn = 4 }; SequenceType sequence_type, input_sequence_type; int mode, query_contexts, query_len_factor; bool query_translated; }; extern AlignMode align_mode; extern const Letter IUPACAA_TO_STD[32]; extern const Letter NCBI_TO_STD[28]; enum class Alphabet { STD, NCBI }; template void alph_ncbi_to_std(const It begin, const It end) { for (It i = begin; i != end; ++i) { const size_t l = *i; if (l >= sizeof(NCBI_TO_STD)) throw std::runtime_error("Unrecognized sequence character in BLAST database"); *i = NCBI_TO_STD[l]; } } using Loc = int32_t; using BlockId = int32_t; using OId = int_fast64_t; using DictId = int64_t; using Score = int32_t; using TaxId = int32_t; using CentroidId = OId; using SuperBlockId = int32_t;bbuchfink-diamond-08b3cbc/src/chaining/000077500000000000000000000000001506104011400201035ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/chaining/aligner.h000066400000000000000000000030561506104011400217010ustar00rootroot00000000000000#pragma once #include #include "diag_graph.h" #include "basic/match.h" namespace Chaining { struct Aligner { enum { link_padding = 10, reverse_link_min_overhang = 10 }; int get_approximate_link(int d_idx, int e_idx, double space_penalty, int max_i); template void forward_pass(_it begin, _it end, bool init, double space_penalty); void backtrace(const size_t node, const int j_end, Hsp* out, ApproxHsp& t, const int score_max, const int score_min, const int max_shift, unsigned& next) const; bool backtrace_old(size_t node, int j_end, Hsp* out, ApproxHsp& t, int score_max, int score_min, int max_shift, unsigned& next) const; void backtrace(size_t top_node, Hsp* out, ApproxHsp& t, int max_shift, unsigned& next, int max_j) const; int backtrace(size_t top_node, std::list& hsps, std::list& ts, std::list::iterator& t_begin, int cutoff, int max_shift) const; int backtrace(std::list& hsps, std::list& ts, int cutoff, int max_shift) const; int run(std::list& hsps, std::list& ts, double space_penalty, int cutoff, int max_shift); int run(std::list& hsps, std::list& ts, std::vector::const_iterator begin, std::vector::const_iterator end, int band); Aligner(const Sequence& query, const Sequence& subject, bool log, unsigned frame); const Sequence query, subject; //const Bias_correction &query_bc; const bool log; const unsigned frame; static thread_local DiagGraph diags; static thread_local std::map window; }; }bbuchfink-diamond-08b3cbc/src/chaining/backtrace.cpp000066400000000000000000000234621506104011400225350ustar00rootroot00000000000000#include #include #include "aligner.h" #include "basic/config.h" #include "diag_graph.h" using std::vector; using std::cout; using std::endl; using std::list; using std::min; using std::max; using std::numeric_limits; namespace Chaining { static bool disjoint(list::const_iterator begin, list::const_iterator end, const ApproxHsp &t, int cutoff) { for (; begin != end; ++begin) { const double ot = t.subject_range.overlap_factor(begin->subject_range), oq = t.query_range.overlap_factor(begin->query_range); if ((1.0 - min(ot, oq)) * t.score / begin->score >= config.chaining_stacked_hsp_ratio) continue; if ((1.0 - max(ot, oq)) * t.score < cutoff) return false; //if (begin->partial_score(t) < cutoff || !begin->collinear(t)) //if (!begin->disjoint(t) || !begin->collinear(t)) //if (!begin->rel_disjoint(t)) // return false; } return true; } static bool disjoint(list::const_iterator begin, list::const_iterator end, const DiagonalSegment &d, int cutoff) { for (; begin != end; ++begin) { const double ot = d.subject_range().overlap_factor(begin->subject_range), oq = d.query_range().overlap_factor(begin->query_range); if ((1.0 - min(ot, oq)) * d.score / begin->score >= config.chaining_stacked_hsp_ratio) continue; if ((1.0 - max(ot, oq)) * d.score < cutoff) return false; //if (begin->partial_score(d) < cutoff || !begin->collinear(d)) //if (!begin->disjoint(d) || !begin->collinear(d)) //if (!begin->rel_disjoint(d)) //return false; } return true; } bool Aligner::backtrace_old(size_t node, int j_end, Hsp* out, ApproxHsp& t, int score_max, int score_min, int max_shift, unsigned& next) const { const DiagonalNode& d = diags[node]; vector::const_iterator f = diags.get_edge(node, j_end); bool at_end = f >= diags.edges.end(); const int prefix_score = at_end ? d.score : f->prefix_score; if (prefix_score > score_max) return false; int j; score_min = std::min(score_min, at_end ? 0 : f->prefix_score_begin); //if (f != diags.edges.end() && (!stop_at_min || f->path_min == diags[f->node_out].path_min)) { if (!at_end) { const DiagonalNode& e = diags[f->node_out]; const int shift = d.diag() - e.diag(); j = f->j; if (abs(shift) <= max_shift) { const bool bt = backtrace_old(f->node_out, shift > 0 ? j : j + shift, out, t, score_max, score_min, max_shift, next); if (!bt) { if (f->prefix_score_begin > score_min) return false; else at_end = true; } } else { next = f->node_out; at_end = true; } } if (at_end) { if (out) { out->query_range.begin_ = d.i; out->subject_range.begin_ = d.j; out->score = score_max - score_min; } t.query_range.begin_ = d.i; t.subject_range.begin_ = d.j; t.score = score_max - score_min; j = d.j; } else { const DiagonalNode& e = diags[f->node_out]; const int shift = d.diag() - e.diag(); if (out) { if (shift > 0) { out->transcript.push_back(op_insertion, (unsigned)shift); out->length += shift; } else if (shift < 0) { for (int j2 = j + shift; j2 < j; ++j2) { out->transcript.push_back(op_deletion, subject[j2]); ++out->length; } } } } const int dd = d.diag(); t.d_max = std::max(t.d_max, dd); t.d_min = std::min(t.d_min, dd); if (d.score > t.max_diag.score) { t.max_diag = d; t.max_diag.prefix_score = prefix_score; t.max_diag.d_max_left = max(max(t.max_diag.d_max_right, t.max_diag.d_max_left), dd); t.max_diag.d_min_left = min(min(t.max_diag.d_min_right, t.max_diag.d_min_left), dd); t.max_diag.d_max_right = dd; t.max_diag.d_min_right = dd; } else { t.max_diag.d_max_right = std::max(t.max_diag.d_max_right, dd); t.max_diag.d_min_right = std::min(t.max_diag.d_min_right, dd); } if (out) { const int d2 = d.diag(); if (log) cout << "Backtrace node=" << node << " i=" << d2 + j << "-" << d2 + j_end << " j=" << j << "-" << j_end << endl; for (; j < j_end; ++j) { const Letter s = subject[j], q = query[d2 + j]; if (s == q) { out->transcript.push_back(op_match); ++out->identities; } else out->transcript.push_back(op_substitution, s); ++out->length; } } return true; } void Aligner::backtrace(const size_t node, const int j_end, Hsp* out, ApproxHsp& t, const int score_max, const int score_min, const int max_shift, unsigned& next) const { struct Node { size_t node; int score_min, j_end; }; vector nodes; nodes.push_back({ node, score_min, j_end }); bool ret = false, ret_value; while (!nodes.empty()) { Node& c = nodes.back(); const DiagonalNode& d = diags[c.node]; vector::const_iterator f = diags.get_edge(c.node, c.j_end); bool at_end = f >= diags.edges.end(); const int prefix_score = at_end ? d.score : f->prefix_score; if (!ret && prefix_score > score_max) { ret = true; ret_value = false; nodes.pop_back(); continue; } c.score_min = std::min(c.score_min, at_end ? 0 : f->prefix_score_begin); //if (f != diags.edges.end() && (!stop_at_min || f->path_min == diags[f->node_out].path_min)) { if (!at_end) { const DiagonalNode& e = diags[f->node_out]; const int shift = d.diag() - e.diag(); const int j = f->j; if (abs(shift) <= max_shift) { if (!ret) { nodes.push_back({ f->node_out, c.score_min, shift > 0 ? j : j + shift }); continue; } assert(ret == true); if (!ret_value) { if (f->prefix_score_begin > c.score_min) { ret_value = false; nodes.pop_back(); continue; } else at_end = true; } } else { next = f->node_out; at_end = true; } } if (at_end) { if (out) { out->query_range.begin_ = d.i; out->subject_range.begin_ = d.j; out->score = score_max - c.score_min; } t.query_range.begin_ = d.i; t.subject_range.begin_ = d.j; t.score = score_max - c.score_min; } else { const DiagonalNode& e = diags[f->node_out]; const int shift = d.diag() - e.diag(); if (out) { if (shift > 0) { out->transcript.push_back(op_insertion, (unsigned)shift); out->length += shift; } else if (shift < 0) { const int j = f->j; for (int j2 = j + shift; j2 < j; ++j2) { out->transcript.push_back(op_deletion, subject[j2]); ++out->length; } } } } const int dd = d.diag(); t.d_max = std::max(t.d_max, dd); t.d_min = std::min(t.d_min, dd); if (out) { int j = at_end ? d.j : f->j; const int d2 = d.diag(); if (log) cout << "Backtrace node=" << node << " i=" << d2 + j << "-" << d2 + j_end << " j=" << j << "-" << j_end << endl; for (; j < j_end; ++j) { const Letter s = subject[j], q = query[d2 + j]; if (s == q) { out->transcript.push_back(op_match); ++out->identities; } else out->transcript.push_back(op_substitution, s); ++out->length; } } ret = true; ret_value = true; nodes.pop_back(); } } void Aligner::backtrace(size_t top_node, Hsp* out, ApproxHsp& t, int max_shift, unsigned& next, int max_j) const { ApproxHsp traits(frame); if (top_node != DiagGraph::end) { const DiagonalNode& d = diags[top_node]; if (out) { out->transcript.clear(); out->query_range.end_ = d.query_end(); out->subject_range.end_ = d.subject_end(); } traits.subject_range.end_ = d.subject_end(); traits.query_range.end_ = d.query_end(); int score_min = d.prefix_score; backtrace_old(top_node, std::min(d.subject_end(), max_j), out, traits, d.prefix_score, score_min, max_shift, next); } else { traits.score = 0; if (out) out->score = 0; } if (out) out->transcript.push_terminator(); t = traits; } int Aligner::backtrace(size_t top_node, list& hsps, list& ts, list::iterator& t_begin, int cutoff, int max_shift) const { unsigned next; int max_score = 0, max_j = (int)subject.length(); do { Hsp* hsp = log ? new Hsp(true) : 0; ApproxHsp t(frame); next = std::numeric_limits::max(); backtrace(top_node, hsp, t, max_shift, next, max_j); //assert(t.score > 0); //Geo::assert_diag_bounds(t.d_max, query.length(), subject.length()); //Geo::assert_diag_bounds(t.d_min, query.length(), subject.length()); if (t.score > 0) max_j = t.subject_range.begin_; if (t.score >= cutoff && disjoint(t_begin, ts.end(), t, cutoff)) { if (t_begin == ts.end()) { ts.push_back(t); t_begin = ts.end(); t_begin--; } else ts.push_back(t); if (hsp) hsps.push_back(*hsp); max_score = std::max(max_score, t.score); } delete hsp; top_node = next; } while (next != std::numeric_limits::max()); return max_score; } int Aligner::backtrace(list& hsps, list& ts, int cutoff, int max_shift) const { vector top_nodes; for (size_t i = 0; i < diags.nodes.size(); ++i) { DiagonalNode& d = diags.nodes[i]; //cout << "node=" << i << " prefix_score=" << d.prefix_score << " path_max=" << d.path_max << " rel_score=" << d.rel_score() << " cutoff=" << cutoff << endl; //if (d.prefix_score >= cutoff && (d.prefix_score == d.path_max || d.prefix_score - d.path_min >= cutoff)) if (d.rel_score() >= cutoff) top_nodes.push_back(&d); } std::sort(top_nodes.begin(), top_nodes.end(), DiagonalNode::cmp_rel_score); int max_score = 0; list::iterator t_begin = ts.end(); for (vector::const_iterator i = top_nodes.begin(); i < top_nodes.end(); ++i) { const size_t node = *i - diags.nodes.data(); if (log) cout << "Backtrace candidate node=" << node << endl; if (disjoint(t_begin, ts.end(), **i, cutoff)) { if (log) cout << "Backtrace node=" << node << " prefix_score=" << (*i)->prefix_score << " rel_score=" << (*i)->rel_score() << endl; max_score = std::max(max_score, backtrace(node, hsps, ts, t_begin, cutoff, max_shift)); if (log) cout << endl; } } return max_score; } }bbuchfink-diamond-08b3cbc/src/chaining/chaining.h000066400000000000000000000023661506104011400220430ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2019 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "util/hsp/approx_hsp.h" #include "dp/dp.h" namespace Chaining { std::pair> run(Sequence query, Sequence subject, std::vector::const_iterator begin, std::vector::const_iterator end, bool log, unsigned frame); std::list run(Sequence query, const std::vector& targets); ApproxHsp hamming_ext(std::vector::iterator begin, std::vector::iterator end, Loc qlen, Loc tlen, bool use_cov_filter); }bbuchfink-diamond-08b3cbc/src/chaining/diag_graph.h000066400000000000000000000105661506104011400223510ustar00rootroot00000000000000#pragma once #include #include #include #include "util/geo/diagonal_segment.h" #include "basic/sequence.h" struct DiagonalNode : public DiagonalSegment { enum { estimate, finished }; DiagonalNode() : DiagonalSegment(), link_idx(-1), prefix_score(0), path_max(0), path_min(0) {} DiagonalNode(int query_pos, int subject_pos, int len, int score, int link_idx = -1) : DiagonalSegment(query_pos, subject_pos, len, score), link_idx(link_idx), prefix_score(score), path_max(score), path_min(score) {} DiagonalNode(const DiagonalSegment& d) : DiagonalSegment(d), link_idx(-1), prefix_score(d.score), path_max(d.score), path_min(d.score) {} void deactivate() { link_idx = 0; } void reset() { link_idx = -1; prefix_score = score; path_max = score; path_min = score; } bool is_maximum() const { return path_max == prefix_score; } int rel_score() const { return prefix_score == path_max ? prefix_score : prefix_score - path_min; } static bool cmp_prefix_score(const DiagonalNode* x, const DiagonalNode* y) { return x->prefix_score > y->prefix_score; } static bool cmp_rel_score(const DiagonalNode* x, const DiagonalNode* y) { return x->rel_score() > y->rel_score(); } int link_idx, prefix_score, path_max, path_min; }; struct DiagGraph { enum { end = size_t(-1) }; struct Edge { Edge() : prefix_score(0), node_in() { } Edge(int prefix_score, int path_max, int j, unsigned node_in, unsigned node_out, int path_min, int prefix_score_begin) : prefix_score(prefix_score), path_max(path_max), j(j), path_min(path_min), prefix_score_begin(prefix_score_begin), node_in(node_in), node_out(node_out) { } /*operator int() const { return prefix_score; } bool operator<(const Edge &x) const { return prefix_score > x.prefix_score; }*/ int prefix_score, path_max, j, path_min, prefix_score_begin; unsigned node_in, node_out; }; void init() { nodes.clear(); edges.clear(); } void init(unsigned node) { if (edges.size() >= (size_t)std::numeric_limits::max()) throw std::runtime_error("Too many edges."); nodes[node].link_idx = (int)edges.size(); } void load(std::vector::const_iterator begin, std::vector::const_iterator end); void sort(); void prune(); void clear_edges(); std::vector::iterator add_edge(const Edge& edge) { for (std::vector::iterator j = nodes.begin() + edge.node_in + 1; j < nodes.end(); ++j) if (j->link_idx == -1) break; else ++j->link_idx; assert(nodes[edge.node_in].link_idx >= 0 && nodes[edge.node_in].link_idx <= (int)edges.size()); DiagonalNode& d = nodes[edge.node_in]; if (edge.prefix_score > d.prefix_score) { d.prefix_score = edge.prefix_score; d.path_max = edge.path_max; d.path_min = edge.path_min; } return edges.insert(edges.begin() + d.link_idx++, edge); } std::vector::const_iterator get_edge(size_t node, int j) const { const DiagonalNode& d = nodes[node]; if (d.score == 0) return edges.begin() + d.link_idx - 1; if (edges.empty()) return edges.end(); int max_score = d.score; ptrdiff_t max_i = -1; for (ptrdiff_t i = d.link_idx - 1; i >= 0 && edges[i].node_in == node; --i) if (edges[i].j < j && edges[i].prefix_score > max_score) { max_i = i; max_score = edges[i].prefix_score; } /*for (vector::const_iterator i = edges.begin() + d.link_idx - 1; i >= edges.begin() && i->node_in == node; --i) if (i->j < j && i->prefix_score > max_score) { max_edge = i; max_score = i->prefix_score; }*/ return max_i >= 0 ? edges.begin() + max_i : edges.end(); } int prefix_score(size_t node, int j, int& path_max, int& path_min) const { const std::vector::const_iterator i = get_edge(node, j); path_max = i == edges.end() ? nodes[node].score : std::max(nodes[node].score, i->path_max); path_min = i == edges.end() ? nodes[node].score : i->path_min; return i == edges.end() ? nodes[node].score : std::max(nodes[node].score, i->prefix_score); } DiagonalNode& operator[](size_t k) { return nodes[k]; } const DiagonalNode& operator[](size_t k) const { return nodes[k]; } void print(Sequence query, Sequence subject) const; size_t top_node() const; std::vector nodes; std::vector edges; }; void smith_waterman(Sequence q, Sequence s, const DiagGraph& diags);bbuchfink-diamond-08b3cbc/src/chaining/greedy_align.cpp000066400000000000000000000375751506104011400232610ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ // #define _ITERATOR_DEBUG_LEVEL 0 #include #include #include #include #include "basic/sequence.h" #include "basic/match.h" #include "stats/score_matrix.h" #include "output/output_format.h" #include "util/hsp/approx_hsp.h" #include "util/util.h" #include "dp/ungapped.h" #include "aligner.h" #include "diag_graph.h" #include "util/geo/diagonal_segment.h" #include "dp/dp.h" using std::endl; using std::cout; using std::map; using std::list; using std::set; using std::max; using std::min; using std::vector; static const double SPACE_PENALTY = 0.1; void DiagGraph::clear_edges() { edges.clear(); for (vector::iterator i = nodes.begin(); i < nodes.end(); ++i) i->deactivate(); } void DiagGraph::load(vector::const_iterator begin, vector::const_iterator end) { int d = std::numeric_limits::min(), max_j_end = d; for (vector::const_iterator i = begin; i < end; ++i) { const int d2 = i->diag(); if (d2 != d) { d = d2; nodes.push_back(*i); max_j_end = nodes.back().subject_end(); } else if (max_j_end < i->j) { nodes.push_back(*i); max_j_end = std::max(max_j_end, nodes.back().subject_end()); } } } void DiagGraph::print(Sequence query, Sequence subject) const { for (int k = 0; k < (int)nodes.size(); ++k) { const DiagonalSegment &d = nodes[k]; cout << "Diag n=" << k << " i=" << d.i << " j=" << d.j << " d=" << d.diag() << " score=" << d.score << " len=" << d.len << endl; cout << Sequence(query, d.i, d.query_last()) << endl; cout << Sequence(subject, d.j, d.subject_last()) << endl; } } size_t DiagGraph::top_node() const { int top_score = 0, score; size_t top_node = end; for (size_t k = 0; k < nodes.size(); ++k) if ((score = nodes[k].prefix_score) > top_score) { top_node = k; top_score = score; } return top_node; } void DiagGraph::sort() { std::sort(nodes.begin(), nodes.end(), DiagonalSegment::cmp_subject); } void DiagGraph::prune() { vector finished; list window; for (const DiagonalNode&d : nodes) { size_t n = 0; for (list::iterator i = window.begin(); i != window.end();) { if (i->subject_end() > d.j) { if (i->score >= d.score && i->j <= d.j && i->subject_end() >= d.subject_end()) ++n; ++i; } else { finished.push_back(*i); i = window.erase(i); } } if (n <= config.chaining_range_cover) window.push_back(d); } for (const DiagonalNode&d : window) finished.push_back(d); nodes = std::move(finished); } struct Link { Link(): subject_pos1(-1) {} Link(unsigned target, int query_pos, int subject_pos, int score1, int score2) : subject_pos1(subject_pos), query_pos1(query_pos), score1(score1), score2(score2) {} int subject_pos1, query_pos1, subject_pos2, query_pos2, score1, score2; Link& transpose() { std::swap(subject_pos1, query_pos1); std::swap(subject_pos2, query_pos2); return *this; } void reset() { subject_pos1 = -1; score1 = 0; score2 = 0; } }; int get_hgap_link(const DiagonalSegment &d1, const DiagonalSegment &d2, Sequence query, Sequence subject, Link &l, int padding) { const int d = d1.diag() - d2.diag(), j2_end = std::min(std::max((int)d2.j, d1.subject_last() + d + 1 + padding), d2.subject_last()); int j1; bool space; if (d1.subject_last() < d2.j - d - 1) { j1 = d1.subject_last(); space = true; } else { j1 = std::max(d2.j - d - 1 - padding, d1.j); space = false; } int j2 = j1 + d + 1, i1 = d1.i + (j1 - d1.j), i2 = i1 + 1; //cout << "j2=" << j2 << " d2.subject_last=" << d2.subject_last() << endl; if (j2 > d2.subject_last()) { l.reset(); return std::numeric_limits::min(); } int score1 = 0, //score2 = score_range(query, subject, i2, j2, d2.j + d2.len); score2 = score_range(query, subject, i2, j2, d2.j) + d2.score - score_range(query, subject, d2.i, d2.j, j2); int max_score = std::numeric_limits::min(); while (true) { //cout << "i1=" << i1 << " j1=" << j1 << " i2=" << i2 << " j2=" << j2 << " score1=" << score1 << " score2=" << score2 << " total=" << score1 + score2 << endl; if (score1 + score2 > max_score) { max_score = score1 + score2; l.query_pos1 = i1; l.subject_pos1 = j1; l.query_pos2 = i2; l.subject_pos2 = j2; l.score1 = score1; l.score2 = score2; } score2 -= score_matrix(query[i2], subject[j2]); ++i1; ++i2; ++j1; ++j2; if (j2 > j2_end) break; score1 += score_matrix(query[i1], subject[j1]); } const int j1_end = j2_end - d; if (space) l.score1 += d1.score; else l.score1 += d1.score - score_range(query, subject, d1.diag() + j1_end, j1_end, d1.subject_end()) + score_range(query, subject, d1.query_end(), d1.subject_end(), j1_end) - score1; return max_score; } int get_vgap_link(const DiagonalSegment &d1, const DiagonalSegment &d2, Sequence query, Sequence subject, Link &l, int padding) { int s = get_hgap_link(d1.transpose(), d2.transpose(), subject, query, l, padding); l.transpose(); return s; } int get_link(const DiagonalSegment &d1, const DiagonalSegment &d2, Sequence query, Sequence subject, Link &l, int padding) { if (d1.diag() < d2.diag()) return get_vgap_link(d1, d2, query, subject, l, padding); else return get_hgap_link(d1, d2, query, subject, l, padding); } namespace Chaining { enum { link_padding = 10, reverse_link_min_overhang = 10 }; int Aligner::get_approximate_link(int d_idx, int e_idx, double space_penalty, int max_i) { DiagonalNode& d = diags[d_idx]; DiagonalNode& e = diags[e_idx]; const int shift = d.diag() - e.diag(); int gap_score = shift != 0 ? -score_matrix.gap_open() - abs(shift)*score_matrix.gap_extend() : 0; const int space = shift > 0 ? d.j - e.subject_last() : d.i - e.query_last(); int prefix_score = 0, link_score = 0, link_j, diff1 = 0, path_max, path_min, prefix_score_begin; if (space <= 0 || space_penalty == 0.0) { vector::const_iterator edge = diags.get_edge(d_idx, d.j); if (edge != diags.edges.end() && edge->prefix_score > e.prefix_score + gap_score + d.score) return 0; /*if (d.prefix_score > e.prefix_score + gap_score + d.score) return 0;*/ Link link; if (get_link(e, d, query, subject, link, link_padding) > 0) { diff1 = e.score - link.score1; const int prefix_e = diags.prefix_score(e_idx, link.subject_pos1, path_max, path_min); prefix_score = prefix_e - diff1 + gap_score + link.score2; vector::const_iterator edge = diags.get_edge(d_idx, link.subject_pos2); if (edge != diags.edges.end() && edge->prefix_score > prefix_score) return 0; prefix_score_begin = prefix_score - link.score2; path_min = std::min(path_min, prefix_score - link.score2); if (prefix_e == path_max) { path_max -= diff1; } link_score = link.score1 + link.score2 + gap_score; link_j = link.subject_pos2; /*if (log) cout << "Link score1=" << link.score1 << " score2=" << link.score2 << " j1=" << link.subject_pos1 << " j2=" << link.subject_pos2 << endl;*/ } } else { prefix_score = e.prefix_score + gap_score - int(space_penalty*std::max(space - 1, 0)) + d.score; vector::const_iterator edge = diags.get_edge(d_idx, d.j); if (edge != diags.edges.end() && edge->prefix_score > prefix_score) return 0; prefix_score_begin = prefix_score - d.score; path_max = e.path_max; path_min = e.path_min; path_min = std::min(path_min, prefix_score - d.score); link_score = e.score + d.score + gap_score; link_j = d.j; } if (prefix_score > d.score) { path_max = std::max(path_max, prefix_score); diags.add_edge(DiagGraph::Edge(prefix_score, path_max, link_j, d_idx, e_idx, prefix_score == path_max ? prefix_score : path_min, prefix_score_begin)); if (log) cout << "Link n=" << e_idx << " d=" << e.diag() << " i_end=" << e.query_end() << " max_i=" << max_i << " shift=" << shift << " space=" << space << " prefix_score=" << prefix_score << " link_score=" << link_score << " path_min="< void Aligner::forward_pass(_it begin, _it end, bool init, double space_penalty) { window.clear(); for (_it it = begin; it != end; ++it) { unsigned node = (unsigned)(*it); if(init) diags.init(node); DiagonalNode& d = diags[node]; const int dd = d.diag(); if (log) cout << "Node " << node << " Score=" << d.score << endl; map::iterator i = window.find(dd), j; if (i == window.end()) i = window.insert(std::make_pair(dd, node)).first; j = i; int max_j = 0; if (i == window.begin()) goto weiter; do { --j; DiagonalNode&e = diags[j->second]; const int de = j->first, shift = dd - de; //if (d.j - e.subject_end() > max_dist) { if (e.prefix_score - int(space_penalty*(std::max(d.j - e.subject_end(), 0))) <= 0) { map::iterator k = j; if (j == window.begin()) { window.erase(j); break; } else { ++k; window.erase(j); j = k; continue; } } if (e.subject_end() < max_j) continue; get_approximate_link(node, j->second, space_penalty, max_j); max_j = std::max(max_j, std::min(d.j, e.subject_end())); if (e.subject_end() - (d.subject_end() - std::min(e.diag() - d.diag(), 0)) >= reverse_link_min_overhang) { if (log) cout << "Computing reverse link node=" << j->second << endl; get_approximate_link(j->second, node, space_penalty, max_j); } } while (j != window.begin()); weiter: j = i; if (j->second == node) ++j; int max_i = 0; while (j != window.end()) { DiagonalNode &e = diags[j->second]; const int de = j->first, shift = dd - de; //if (d.j - e.subject_end() > max_dist && j != i) { if (e.prefix_score - int(space_penalty*(std::max(d.j - e.subject_end(),0))) <= 0 && j != i) { map::iterator k = j; ++k; window.erase(j); j = k; continue; } if (e.query_end() < max_i) { ++j; continue; } //if (get_approximate_link(node, j->second, space_penalty, max_i) > e.prefix_score) get_approximate_link(node, j->second, space_penalty, max_i); if (e.i < d.i) max_i = std::max(max_i, std::min(e.query_end(), d.i)); if (e.subject_end() - (d.subject_end() - std::min(e.diag() - d.diag(), 0)) >= reverse_link_min_overhang) { if (log) cout << "Computing reverse link node=" << j->second << endl; get_approximate_link(j->second, node, space_penalty, max_i); } ++j; } i->second = node; if (log) cout << "Prefix_score=" << d.prefix_score << " path_max=" << d.path_max << " path_min=" << d.path_min << endl << endl; } } int Aligner::run(list &hsps, list &ts, double space_penalty, int cutoff, int max_shift) { if (config.chaining_maxnodes > 0) { std::sort(diags.nodes.begin(), diags.nodes.end(), DiagonalSegment::cmp_score); if (diags.nodes.size() > config.chaining_maxnodes) diags.nodes.erase(diags.nodes.begin() + config.chaining_maxnodes, diags.nodes.end()); } if (config.chaining_len_cap > 0.0 && diags.nodes.size() > config.chaining_min_nodes) { std::sort(diags.nodes.begin(), diags.nodes.end(), DiagonalSegment::cmp_score); const double cap = query.length() * config.chaining_len_cap; double total_len = 0.0; auto it = diags.nodes.begin(); while (it < diags.nodes.end() && total_len < cap) { total_len += it->len; ++it; } diags.nodes.erase(std::max(diags.nodes.begin() + config.chaining_min_nodes, it), diags.nodes.end()); } diags.sort(); diags.prune(); if (log) { diags.print(query, subject); cout << endl << endl; } forward_pass(IndexIterator(0llu), IndexIterator(diags.nodes.size()), true, space_penalty); int max_score = backtrace(hsps, ts, cutoff, max_shift); if (log) { hsps.sort(Hsp::cmp_query_pos); for (list::iterator i = hsps.begin(); i != hsps.end(); ++i) print_hsp(*i, TranslatedSequence(query)); cout << endl << "Smith-Waterman:" << endl; smith_waterman(query, subject, diags); cout << endl << endl; } return max_score; } int Aligner::run(list &hsps, list &ts, vector::const_iterator begin, vector::const_iterator end, int band) { if (log) cout << "***** Seed hit run " << begin->diag() << '\t' << (end - 1)->diag() << '\t' << (end - 1)->diag() - begin->diag() << endl; diags.init(); diags.load(begin, end); return run(hsps, ts, SPACE_PENALTY, 19, band); } Aligner::Aligner(const Sequence &query, const Sequence &subject, bool log, unsigned frame) : query(query), subject(subject), //query_bc(query_bc), log(log), frame(frame) { } thread_local DiagGraph Aligner::diags; thread_local map Aligner::window; } namespace Chaining { static Score merge_score(const ApproxHsp& h1, const ApproxHsp& h2) { static const double GAP_PENALTY = 0.5; const Loc gq = h2.query_range.begin_ - h1.query_range.end_, gt = h2.subject_range.begin_ - h1.subject_range.end_; if (gq < 0 || gt < 0) return 0; const Score s = h1.score + h2.score; if (gq > gt) { return Score(s - gq * GAP_PENALTY - gt * SPACE_PENALTY); } else return Score(s - gt * GAP_PENALTY - gq * SPACE_PENALTY); } static ApproxHsp merge(const ApproxHsp& h1, const ApproxHsp& h2) { ApproxHsp h(h1.frame); h.d_max = max(h1.d_max, h2.d_max); h.d_min = min(h1.d_min, h2.d_min); h.query_range = { h1.query_range.begin_, h2.query_range.end_ }; h.query_source_range = h.query_range; h.subject_range = { h1.subject_range.begin_, h2.subject_range.end_ }; h.score = merge_score(h1, h2); h.evalue = 0; if (h1.max_diag.score > h2.max_diag.score) { h.max_diag = h1.max_diag; h.max_diag.d_max_right = max(h.max_diag.d_max_right, h2.d_max); h.max_diag.d_min_right = min(h.max_diag.d_min_right, h2.d_min); } else { h.max_diag = h2.max_diag; h.max_diag.d_max_left = max(h.max_diag.d_max_left, h1.d_max); h.max_diag.d_min_left = min(h.max_diag.d_min_left, h1.d_min); } return h; } static void merge_hsps(list& hsps) { auto it = hsps.begin(); while (it != hsps.end()) { auto it2 = it; ++it2; while (it2 != hsps.end()) { if (merge_score(*it, *it2) > max(it->score, it2->score)) { *it = merge(*it, *it2); it2 = hsps.erase(it2); } else if (merge_score(*it2, *it) > max(it->score, it2->score)) { *it = merge(*it2, *it); it2 = hsps.erase(it2); } else ++it2; } ++it; } } std::pair> run(Sequence query, Sequence subject, vector::const_iterator begin, vector::const_iterator end, bool log, unsigned frame) { const int band = config.chaining_maxgap; if (end - begin == 1) { const Loc d = begin->diag(); const Anchor anchor(*begin, d, d, d, d, begin->score); return { begin->score, { { d, d, begin->score, (int)frame, begin->query_range(), begin->subject_range(), anchor}} }; } Chaining::Aligner ga(query, subject, log, frame); list hsps; list ts; int score = ga.run(hsps, ts, begin, end, band); if (!config.no_chaining_merge_hsps) merge_hsps(ts); return std::make_pair(score, std::move(ts)); } list run(Sequence query, const std::vector& targets) { list out; return out; } }bbuchfink-diamond-08b3cbc/src/chaining/hamming_ext.cpp000066400000000000000000000050141506104011400231070ustar00rootroot00000000000000#include #include "basic/config.h" #include "stats/score_matrix.h" #include "stats/stats.h" #include "util/util.h" #include "util/geo/diagonal_segment.h" #include "util/hsp/approx_hsp.h" using std::stable_sort; using std::vector; using std::max; namespace Chaining { static ApproxHsp find_aln(vector::iterator begin, vector::iterator end, Loc qlen, Loc tlen) { for (auto it = begin; it < end; ++it) { const double ev = score_matrix.evalue(it->score, qlen, tlen); if ((it->id_percent() >= config.approx_min_id || Stats::approx_id(it->score, it->len, it->len) >= config.approx_min_id) && ((config.query_or_target_cover > 0 && std::max(it->cov_percent(qlen), it->cov_percent(tlen)) >= config.query_or_target_cover) || (config.query_or_target_cover == 0 && it->cov_percent(qlen) >= config.query_cover && it->cov_percent(tlen) >= config.subject_cover)) && ev <= config.max_evalue) return ApproxHsp(0, 0, it->score, 0, it->query_range(), it->subject_range(), *it, ev); } return ApproxHsp(0); } static ApproxHsp filter(vector::iterator begin, vector::iterator end, Loc qlen, Loc tlen, bool use_cov_filter) { const double TOLERANCE_FACTOR = 1.1, ID_MIN_COV = 80; stable_sort(begin, end, DiagonalSegment::cmp_score); Loc ident = 0, len = 0; const Loc qtol = safe_cast(qlen * TOLERANCE_FACTOR), ttol = safe_cast(tlen * TOLERANCE_FACTOR); for (auto it = begin; it < end; ++it) { if (len + it->len > qtol || len + it->len > ttol) continue; ident += it->ident; len += it->len; } const double qcov = (double)len / qlen * 100, tcov = (double)len / tlen * 100; if (config.diag_filter_cov.present() && use_cov_filter && ((config.query_or_target_cover > 0 && max(qcov, tcov) < config.diag_filter_cov) || (config.query_cover > 0 && qcov < config.diag_filter_cov) || (config.subject_cover > 0 && tcov < config.diag_filter_cov))) return ApproxHsp(0, -1); if (config.diag_filter_id.present() && max(qcov, tcov) >= ID_MIN_COV && (double)ident / len * 100.0 < config.diag_filter_id) return ApproxHsp(0, -1); return ApproxHsp(0); } ApproxHsp hamming_ext(vector::iterator begin, vector::iterator end, Loc qlen, Loc tlen, bool use_cov_filter) { if (config.hamming_ext) { ApproxHsp h = find_aln(begin, end, qlen, tlen); if (h.score > 0) return h; } if (config.diag_filter_cov.present() || config.diag_filter_id.present()) { return filter(begin, end, qlen, tlen, use_cov_filter); } return ApproxHsp(0); } }bbuchfink-diamond-08b3cbc/src/chaining/smith_waterman.cpp000066400000000000000000000040441506104011400236330ustar00rootroot00000000000000#include #include "output/output_format.h" #include "dp/ungapped.h" #include "diag_graph.h" #include "dp/scalar/scalar.h" #include "stats/score_matrix.h" using std::cout; using std::endl; using std::vector; void print_diag(int i0, int j0, int l, int score, const DiagGraph &diags, const Sequence &query, const Sequence &subject) { DiagonalSegment ds(i0, j0, l, 0); unsigned n = 0; int path_max, path_min; for (vector::const_iterator d = diags.nodes.begin(); d != diags.nodes.end(); ++d) { if (d->intersect(ds).len > 0) { if (d->score == 0) continue; const int diff = score_range(query, subject, d->query_end(), d->subject_end(), j0 + l); if (n > 0) cout << "("; cout << "Diag n=" << d - diags.nodes.begin() << " i=" << i0 << " j=" << j0 << " len=" << l << " prefix_score=" << score + score_range(query, subject, i0 + l, j0 + l, d->subject_end()) - std::min(diff, 0) << " prefix_score2=" << diags.prefix_score((unsigned)(d - diags.nodes.begin()), j0 + l, path_max, path_min); if (n > 0) cout << ")"; cout << endl; ++n; } } if (n == 0) cout << "Diag n=x i=" << i0 << " j=" << j0 << " len=" << l << " prefix_score=" << score << endl; } void smith_waterman(Sequence q, Sequence s, const DiagGraph &diags) { Hsp hsp(true); smith_waterman(q, s, hsp); Hsp::Iterator i = hsp.begin(); int i0 = -1, j0 = -1, l = 0, score = 0; for (; i.good(); ++i) { switch (i.op()) { case op_match: case op_substitution: if (i0 < 0) { i0 = i.query_pos.translated; j0 = i.subject_pos; l = 0; } score += score_matrix(q[i.query_pos.translated], s[i.subject_pos]); ++l; break; case op_deletion: case op_insertion: if (i0 >= 0) { print_diag(i0, j0, l, score, diags, q, s); score -= score_matrix.gap_open() + score_matrix.gap_extend(); i0 = -1; j0 = -1; } else score -= score_matrix.gap_extend(); break; case op_frameshift_forward: case op_frameshift_reverse: ; } } print_diag(i0, j0, l, score, diags, q, s); print_hsp(hsp, TranslatedSequence(q)); }bbuchfink-diamond-08b3cbc/src/cluster/000077500000000000000000000000001506104011400200045ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/cluster/cascaded/000077500000000000000000000000001506104011400215335ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/cluster/cascaded/cascaded.cpp000066400000000000000000000153231506104011400237720ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2023 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "cascaded.h" #include "util/algo/algo.h" #include "basic/statistics.h" #include "run/workflow.h" #include "util/log_stream.h" #include "stats/cbs.h" const char* const DEFAULT_MEMORY_LIMIT = "16G"; const double CASCADED_ROUND_MAX_EVALUE = 0.001; using std::vector; using std::shared_ptr; using std::endl; using std::runtime_error; using std::numeric_limits; using std::to_string; using std::tie; using std::string; using std::pair; using std::iota; using std::make_pair; namespace Cluster { string Cascaded::get_description() { return "Cascaded greedy vertex cover algorithm"; } static BitVector rep_bitset(const vector ¢roid, const BitVector *superset = nullptr) { BitVector r(centroid.size()); for (SuperBlockId c : centroid) if (!superset || superset->get(c)) r.set(c); return r; } vector cluster(shared_ptr& db, const shared_ptr& filter, const SuperBlockId* member_counts, int round, int round_count) { using Edge = Util::Algo::Edge; statistics.reset(); const bool mutual_cover = config.mutual_cover.present(); config.command = Config::blastp; config.output_format = { "edge" }; const vector round_coverage = config.round_coverage.empty() ? default_round_cov(round_count) : config.round_coverage; const double cov_cutoff = config.mutual_cover.present() ? config.mutual_cover.get_present() : config.member_cover, round_cov_cutoff = std::max(cov_cutoff, round_value(round_coverage, "--round-coverage", round, round_count)); if (config.mutual_cover.present()) { config.query_cover = config.subject_cover = round_cov_cutoff; } else { config.query_cover = 0; config.subject_cover = 0; config.query_or_target_cover = round_cov_cutoff; } config.algo = Config::Algo::DOUBLE_INDEXED; config.max_target_seqs_ = INT64_MAX; config.self = true; config.iterate.unset(); config.mapany = false; config.linsearch = false; //if (config.db_size == 0 && filter) { if(filter) { config.db_size = db->letters_filtered(*filter); } tie(config.chunk_size, config.lowmem_) = config.lin_stage1 && round == 0 ? make_pair(32768, 1) : block_size(Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)), filter ? config.db_size : db->letters(), config.sensitivity, config.lin_stage1, config.threads_); shared_ptr callback(mutual_cover ? (Callback*)new CallbackBidirectional : (Callback*)new CallbackUnidirectional); Search::run(db, nullptr, callback, filter); message_stream << "Finished search. #Edges: " << callback->count << endl; TaskTimer timer("Allocating buffers"); vector edges(callback->count); timer.go("Loading edges"); InputFile f(callback->edge_file); f.read(edges.data(), callback->count); f.close_and_delete(); if (!config.aln_out.empty()) output_edges(config.aln_out, *db, edges); timer.go("Sorting edges"); FlatArray edge_array = make_flat_array_dense(std::move(edges), (SuperBlockId)db->sequence_count(), config.threads_, Edge::GetKey()); timer.finish(); const auto algo = from_string(config.graph_algo); const int ccd = round_ccd(round, round_count, config.lin_stage1); return algo == GraphAlgo::GREEDY_VERTEX_COVER ? Util::Algo::greedy_vertex_cover(edge_array, config.weighted_gvc ? member_counts : nullptr, !config.strict_gvc, !config.no_gvc_reassign, ccd) : len_sorted_clust(edge_array); //return Util::Algo::cluster_pr(edge_array); } static pair, BitVector> update_clustering(const BitVector& previous_filter, const vector& previous_centroids, vector&& current_centroids, int round) { BitVector oid_filter(round == 0 ? rep_bitset(current_centroids) : rep_bitset(current_centroids, &previous_filter)); if (round > 0) for (size_t i = 0; i < current_centroids.size(); ++i) if (!previous_filter.get(i)) current_centroids[i] = current_centroids[previous_centroids[i]]; return { current_centroids, oid_filter }; } vector cascaded(shared_ptr& db, bool linear) { if (db->sequence_count() > (int64_t)numeric_limits::max()) throw runtime_error("Workflow supports a maximum of " + to_string(numeric_limits::max()) + " input sequences."); const vector steps = cluster_steps(config.approx_min_id, linear); const double evalue_cutoff = config.max_evalue, target_approx_id = config.approx_min_id; const bool anchored_swipe = config.anchored_swipe, linclust = is_linclust(steps); shared_ptr oid_filter(new BitVector); int64_t cluster_count = db->sequence_count(); vector centroids(cluster_count); iota(centroids.begin(), centroids.end(), 0); if (linclust) config.comp_based_stats = 0; for (int i = 0; i < (int)steps.size(); i++) { TaskTimer timer; config.lin_stage1 = ends_with(steps[i], "_lin"); config.anchored_swipe = anchored_swipe && (linclust || !config.lin_stage1); if (anchored_swipe) config.ext_ = "banded-fast"; config.sensitivity = from_string(rstrip(steps[i], "_lin")); const vector round_approx_id = config.round_approx_id.empty() ? default_round_approx_id((int)steps.size()) : config.round_approx_id; config.approx_min_id = std::max(target_approx_id, round_value(round_approx_id, "--round-approx-id", i, (int)steps.size())); config.max_evalue = (size_t)i == steps.size() - 1 ? evalue_cutoff : std::min(evalue_cutoff, CASCADED_ROUND_MAX_EVALUE); tie(centroids, *oid_filter) = update_clustering(*oid_filter, centroids, cluster(db, i == 0 ? nullptr : oid_filter, config.weighted_gvc ? member_counts(centroids).data() : nullptr, i, (int)steps.size()), i); const int64_t n = oid_filter->one_count(); message_stream << "Clustering round " << i + 1 << " complete. #Input sequences: " << cluster_count << " #Clusters: " << n << " #Letters: " << db->letters_filtered(*oid_filter) << " Time: " << timer.seconds() << 's' << endl; cluster_count = n; } return centroids; } }bbuchfink-diamond-08b3cbc/src/cluster/cascaded/cascaded.h000066400000000000000000000052671506104011400234450ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2023 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "../cluster.h" namespace Cluster { struct Cascaded : public ClusteringAlgorithm { ~Cascaded(){}; void run(); std::string get_description(); static std::string get_key(){ return "cascaded"; } }; std::vector cascaded(std::shared_ptr& db, bool linear); std::vector cluster_steps(double approx_id, bool linear); bool is_linclust(const std::vector& steps); std::vector default_round_approx_id(int steps); std::vector default_round_cov(int steps); int round_ccd(int round, int round_count, bool linear); struct Callback : public Consumer { using Edge = Util::Algo::Edge; Callback() : count(0) {} virtual void consume(const char* ptr, size_t n) override = 0; TempFile edge_file; int64_t count; }; struct CallbackUnidirectional : public Callback { virtual void consume(const char* ptr, size_t n) override { const char* end = ptr + n; while (ptr < end) { const auto edge = *(Output::Format::Edge::Data*)ptr; ptr += sizeof(Output::Format::Edge::Data); if (edge.qcovhsp >= config.member_cover) { edge_file.write(Edge((SuperBlockId)edge.target, (SuperBlockId)edge.query, edge.evalue)); ++count; } if (edge.scovhsp >= config.member_cover) { edge_file.write(Edge((SuperBlockId)edge.query, (SuperBlockId)edge.target, edge.evalue)); ++count; } } } }; struct CallbackBidirectional : public Callback { virtual void consume(const char* ptr, size_t n) override { const char* end = ptr + n; while (ptr < end) { const auto edge = *(Output::Format::Edge::Data*)ptr; ptr += sizeof(Output::Format::Edge::Data); if (edge.query != edge.target) { edge_file.write(Edge((SuperBlockId)edge.target, (SuperBlockId)edge.query, edge.evalue)); edge_file.write(Edge((SuperBlockId)edge.query, (SuperBlockId)edge.target, edge.evalue)); count += 2; } } } }; }bbuchfink-diamond-08b3cbc/src/cluster/cascaded/helpers.cpp000066400000000000000000000052541506104011400237070ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2019-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "cascaded.h" using std::stringstream; using std::string; using std::vector; using std::runtime_error; namespace Cluster { vector cluster_steps(double approx_id, bool linear) { if (!config.cluster_steps.empty()) return config.cluster_steps; vector v = { "faster_lin" }; if (approx_id < 90) v.push_back("fast_lin"); if (approx_id < 40) v.push_back("linclust-20_lin"); else if (approx_id < 80) v.push_back("linclust-40_lin"); if (linear) return v; if (approx_id < 80) v.push_back("default"); else v.push_back("fast"); if (approx_id < 50) v.push_back("more-sensitive"); return v; } bool is_linclust(const vector& steps) { for (const string& s : steps) { if (!ends_with(s, "_lin")) return false; } return true; } vector default_round_approx_id(int steps) { return {}; /*switch (steps) { case 1: return {}; case 2: return { "27.0" }; default: return { "27.0", "0.0" }; }*/ } vector default_round_cov(int steps) { return {}; /*switch (steps) { case 1: return {}; case 2: return { "85.0" }; default: return { "87.0", "85.0" }; }*/ } static int round_ccd(const string& depth) { stringstream ss(depth); int i; ss >> i; if (ss.fail() || !ss.eof()) throw runtime_error("Invalid number format for --connected-component-depth"); return i; } int round_ccd(int round, int round_count, bool linear) { if (config.connected_component_depth.size() > 1 && config.connected_component_depth.size() != (size_t)round_count) throw runtime_error("Parameter count for --connected-component-depth has to be 1 or the number of cascaded clustering rounds."); if (config.connected_component_depth.size() == 0) return 0; const int i = round_ccd(config.connected_component_depth.size() == 1 ? config.connected_component_depth[0] : config.connected_component_depth[round]); return (round == round_count - 1) ^ linear ? 1 : i; } }bbuchfink-diamond-08b3cbc/src/cluster/cascaded/recluster.cpp000066400000000000000000000143031506104011400242500ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "cascaded.h" #include "basic/config.h" #include "data/fasta/fasta_file.h" #include "run/workflow.h" #include "basic/statistics.h" #include "util/log_stream.h" using std::unique_ptr; using std::endl; using std::vector; using std::function; using std::make_shared; using std::shared_ptr; using std::for_each; using std::to_string; using std::string; using std::tie; using std::pair; namespace Cluster { static vector recluster(shared_ptr& db, const vector& clustering, int iteration) { TaskTimer timer(("*** Initializing recluster iteration " + to_string(iteration + 1)).c_str()); FlatArray clusters; vector centroids; tie(clusters, centroids) = cluster_sorted(clustering); BitVector centroid_aligned(db->sequence_count()); for_each(centroids.begin(), centroids.end(), [¢roid_aligned](OId c) { centroid_aligned.set(c); }); function callback([¢roid_aligned](const HspContext& h) { if (((config.mutual_cover.present() && h.qcovhsp() >= config.mutual_cover.get_present() && h.scovhsp() >= config.mutual_cover.get_present()) || (!config.mutual_cover.present() && h.scovhsp() >= config.member_cover)) && (h.approx_id() >= config.approx_min_id || h.id_percent() >= config.approx_min_id)) centroid_aligned.set(h.subject_oid); }); timer.finish(); HspValues hsp_values = HspValues::TARGET_COORDS; if (config.mutual_cover.present()) hsp_values |= HspValues::QUERY_COORDS; if (config.approx_min_id > 0) hsp_values |= HspValues::QUERY_COORDS | HspValues::IDENT | HspValues::LENGTH; realign(clusters, centroids, *db, callback, hsp_values); timer.go("Creating database of unaligned sequences"); const vector unal_members = centroid_aligned.negative_list(); if (unal_members.empty()) return clustering; shared_ptr unaligned(db->sub_db(unal_members.cbegin(), unal_members.cend())); unaligned->set_seqinfo_ptr(0); timer.finish(); message_stream << "#Sequences that failed to align against assigned centroid: " << unal_members.size() << endl; timer.go("Creating centroid database"); shared_ptr centroid_db(db->sub_db(centroids.cbegin(), centroids.cend())); centroid_db->set_seqinfo_ptr(0); timer.finish(); statistics.reset(); config.command = Config::blastp; config.max_target_seqs_ = 1; config.iterate = vector(); config.output_format = { "edge" }; config.self = false; if (config.mutual_cover.present()) { config.query_cover = config.subject_cover = config.mutual_cover.get_present(); } else { config.query_cover = config.member_cover; config.subject_cover = 0; } config.query_or_target_cover = 0; config.sensitivity = from_string(cluster_steps(config.approx_min_id, false).back()); //tie(config.chunk_size, config.lowmem_) = block_size(Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)), Search::iterated_sens.at(config.sensitivity).front(), false); config.lowmem_ = 1; config.chunk_size = 4.0; config.lin_stage1 = false; config.linsearch = false; shared_ptr mapback = make_shared(unal_members.size()); Search::run(centroid_db, unaligned, mapback); timer.go("Updating clustering"); vector out = clustering; update_clustering(out.begin(), mapback->centroid_id.cbegin(), unal_members.cbegin(), unal_members.cend(), centroids.cbegin()); timer.go("Deallocating memory"); centroid_db.reset(); timer.finish(); vector unmapped_members = mapback->unmapped(); message_stream << "#Sequences that failed to align against any centroid: " << unmapped_members.size() << endl; if (unmapped_members.empty()) return out; shared_ptr unmapped; timer.go("Creating database of unmapped sequences"); unmapped.reset(unaligned->sub_db(unmapped_members.cbegin(), unmapped_members.cend())); mapback.reset(); timer.finish(); timer.go("Deallocating memory"); clusters.clear(); clusters.shrink_to_fit(); unaligned.reset(); timer.finish(); const vector reclust = recluster(unmapped, convert_mapping(cascaded(unmapped, false), OId()), iteration + 1); timer.go("Deallocating memory"); unmapped.reset(); timer.go("Merging clusterings"); for (SuperBlockId i = 0; i < (SuperBlockId)reclust.size(); ++i) out[unal_members[unmapped_members[i]]] = unal_members[unmapped_members[reclust[i]]]; return out; } void recluster() { config.database.require(); config.clustering.require(); init_thresholds(); //config.strict_gvc = true; message_stream << "Coverage cutoff: " << (config.mutual_cover.present() ? config.mutual_cover.get_present() : config.member_cover) << '%' << endl; TaskTimer timer("Opening the database"); shared_ptr db(SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NEED_LETTER_COUNT | SequenceFile::Flags::ACC_TO_OID_MAPPING | SequenceFile::Flags::OID_TO_ACC_MAPPING, SequenceFile::Metadata())); config.db_size = db->letters(); timer.finish(); unique_ptr out(open_out_tsv()); message_stream << "#Database sequences: " << db->sequence_count() << ", #Letters: " << db->letters() << endl; timer.go("Reading the input file"); const vector clustering = read(config.clustering, *db); timer.finish(); const vector member2centroid = recluster(db, clustering, 0); timer.go("Generating output"); if (flag_any(db->format_flags(), SequenceFile::FormatFlags::TITLES_LAZY)) db->init_random_access(0, 0, false); output_mem(*out, *db, member2centroid); timer.go("Closing the database"); db.reset(); } }bbuchfink-diamond-08b3cbc/src/cluster/cascaded/wrapper.cpp000066400000000000000000000226471506104011400237320ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2019-2024 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "cascaded.h" #include "data/fasta/fasta_file.h" #include "run/workflow.h" #include "util/system/system.h" #include "search/search.h" #include "util/log_stream.h" using std::shared_ptr; using std::endl; using std::tie; using std::pair; using std::iota; using std::string; using std::vector; using std::ostream; using std::ofstream; using std::numeric_limits; using std::tuple; using std::get; using std::ignore; using std::back_inserter; using std::unique_ptr; using std::bind; using std::function; using namespace Util::Tsv; namespace Cluster { void external(); struct Config { Config(shared_ptr& db) : linclust(config.command == ::Config::LINCLUST), message_stream(true), verbosity(1), sens(from_string(rstrip(cluster_steps(config.approx_min_id, linclust).back(), "_lin"))), centroids(new FastaFile("", true, FastaFile::WriteAccess())), seqs_processed(0), letters_processed(0), oid_to_centroid_oid(new File(Schema{ Type::INT64, Type::INT64 }, "", Flags::TEMP)) { } bool linclust; MessageStream message_stream; int verbosity; Sensitivity sens; double block_size; std::shared_ptr centroids; TaskTimer total_time; int64_t seqs_processed; int64_t letters_processed; std::vector centroid2oid; std::unique_ptr oid_to_centroid_oid; }; int64_t seq_mem_use(Loc len, Loc id_len, int c, int min, int sketch_size) { assert(min > 1 || sketch_size > 0); int extend_stage = (min > 1 ? (len / (min / 2)) : sketch_size) * (15 // trace point buffer + 16) // SeedHitList + 12 // SeedHitList + 2 * len; // SequenceSet extend_stage /= 2; return std::max( len + 8 // SequenceSet + id_len + 8 // Seqtitle + (min > 1 ? len / (min / 2) : sketch_size) * 9 / c // SeedArray + 8 // super_block_id_to_oid + 8 // BestCentroid / clustering + 4 // unaligned , extend_stage); } struct BestCentroid : public Consumer, public vector { BestCentroid(OId block_size) : vector(block_size, -1) {} virtual void consume(const char *ptr, size_t n) { const char* const end = ptr + n; while (ptr < end) { const auto edge = *(Output::Format::Edge::Data*)ptr; ptr += sizeof(Output::Format::Edge::Data); this->operator[](edge.query) = edge.target; } } virtual void finalize() {} virtual ~BestCentroid() = default; }; static vector search_vs_centroids(shared_ptr& super_block, const OId* super_block_id_to_oid, Config& cfg) { //if (cfg.verbosity >= 2) message_stream << "Searching vs. centroids #sequences = " << super_block->sequence_count() << ", #letters = " << super_block->letters() << ", #centroids = " << cfg.centroids->sequence_count() << ", #centroid letters = " << cfg.centroids->letters() << endl; config.output_format = { "edge" }; config.self = false; config.max_target_seqs_ = 1; config.toppercent.unset(); config.sensitivity = cfg.sens; if (config.mutual_cover.present()) { config.query_cover = config.subject_cover = config.mutual_cover.get_present(); } else { config.query_cover = config.member_cover; config.subject_cover = 0; } config.query_or_target_cover = 0; config.linsearch = cfg.linclust; config.iterate = vector(); config.lin_stage1 = false; tie(config.chunk_size, config.lowmem_) = block_size(Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)), std::max(super_block->letters(), cfg.centroids->letters()), cfg.sens, cfg.linclust, config.threads_); //if (cfg.linclust) //config.chunk_size = std::max(config.chunk_size, (double)(super_block->letters() + 1024) / 1e9); cfg.centroids->set_seqinfo_ptr(0); shared_ptr best_centroid(new BestCentroid(super_block->sequence_count())); log_rss(); Search::run(cfg.centroids, super_block, best_centroid); int64_t clustered = 0; vector unaligned; for (SuperBlockId i = 0; i < super_block->sequence_count(); ++i) { const OId oid = super_block_id_to_oid[i]; if (best_centroid->operator[](i) == -1) { unaligned.push_back(i); } else { const OId centroid_oid = cfg.centroid2oid[best_centroid->operator[](i)]; cfg.oid_to_centroid_oid->write_record(centroid_oid, oid); ++clustered; } } //if (cfg.verbosity >= 2) cfg.message_stream << clustered << " sequences assigned to clusters, " << unaligned.size() << " unaligned." << endl; return unaligned; } void Cascaded::run() { config.database.require(); init_thresholds(); if (!config.parallel_tmpdir.empty()) { if (config.command == ::Config::LINCLUST) external(); else throw std::runtime_error("Option is not permitted for this workflow: --parallel-tmpdir"); return; } config.hamming_ext = config.approx_min_id >= 50.0; TaskTimer total_time; TaskTimer timer("Opening the input file"); shared_ptr db(SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NEED_LETTER_COUNT | SequenceFile::Flags::OID_TO_ACC_MAPPING | SequenceFile::Flags::NEED_LENGTH_LOOKUP)); if (db->type() == SequenceFile::Type::BLAST) throw std::runtime_error("Clustering is not supported for BLAST databases."); timer.finish(); message_stream << "Input database: " << db->file_name() << " (" << db->sequence_count() << " sequences, " << db->letters() << " letters)" << endl; const int64_t mem_limit = Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)); const int64_t block_size = (int64_t)(::block_size(mem_limit, db->letters(), Sensitivity::FASTER, true, config.threads_).first * 1e9); // take cluster steps into account here unique_ptr out(open_out_tsv()); if (block_size >= (double)db->letters() && db->sequence_count() < numeric_limits::max()) { const auto centroids = cascaded(db, config.command == ::Config::LINCLUST); timer.go("Generating output"); output_mem(*out, *db, centroids); } else { timer.go("Length sorting the input file"); Config cfg(db); config.db_size = db->letters(); const int minimizer_window = Search::sensitivity_traits.at(Sensitivity::FASTER).minimizer_window, sketch_size = Search::sensitivity_traits.at(Sensitivity::FASTER).sketch_size; auto seq_size = function(bind(seq_mem_use, std::placeholders::_1, 0, 1, minimizer_window, sketch_size)); vector, Util::Tsv::File*>> super_blocks = db->length_sort(mem_limit / 2, seq_size); timer.finish(); config.freq_masking = true; int i = 0; for (auto& b : super_blocks) { message_stream << "Processing super block " << (i++) + 1 << '/' << super_blocks.size() << endl; log_rss(); log_stream << "Mem_sizes " << db->mem_size() << ' ' << cfg.centroids->mem_size() << endl; vector super_block_id_to_oid; Util::Tsv::File* oid_mapping; tie(ignore, super_block_id_to_oid, oid_mapping) = b; shared_ptr seqs(get<0>(b)); shared_ptr unaligned_db; vector unaligned; timer.go("Reading super block mapping file"); oid_mapping->template read(back_inserter(super_block_id_to_oid)); timer.finish(); log_rss(); if (i == 1) { unaligned_db = seqs; unaligned.resize(seqs->sequence_count()); iota(unaligned.begin(), unaligned.end(), 0); } else { unaligned = search_vs_centroids(seqs, super_block_id_to_oid.data(), cfg); timer.go("Creating subdatabase"); unaligned_db.reset(seqs->sub_db(unaligned.cbegin(), unaligned.cend())); timer.go("Freeing memory"); seqs->close(); seqs.reset(); timer.finish(); } const vector clustering = cascaded(unaligned_db, cfg.linclust); timer.go("Updating clustering"); vector centroids; for (SuperBlockId i = 0; i < (SuperBlockId)unaligned.size(); ++i) { const OId member_oid = super_block_id_to_oid[unaligned[i]], centroid_oid = super_block_id_to_oid[unaligned[clustering[i]]]; cfg.oid_to_centroid_oid->write_record(centroid_oid, member_oid); if (member_oid == centroid_oid) { cfg.centroid2oid.push_back(centroid_oid); centroids.push_back(i); } } unaligned_db->sub_db(centroids.cbegin(), centroids.cend(), cfg.centroids.get()); timer.go("Freeing memory"); unaligned_db->close(); unaligned_db.reset(); delete oid_mapping; timer.finish(); } message_stream << "Total clusters: " << cfg.centroid2oid.size() << endl; message_stream << "Total time: " << total_time.seconds() << 's' << endl; timer.go("Generating output"); output_mem(*out, *db, *cfg.oid_to_centroid_oid); } db->close(); } }bbuchfink-diamond-08b3cbc/src/cluster/cluster.h000066400000000000000000000114111506104011400216340ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "basic/value.h" #include "data/sequence_file.h" #include "util/data_structures/flat_array.h" #include "basic/match.h" #include "dp/flags.h" #include "output/output_format.h" #include "util/algo/algo.h" #include "util/tsv/tsv.h" class ClusteringAlgorithm { public: virtual void run() = 0; virtual std::string get_description() = 0; virtual ~ClusteringAlgorithm(){}; }; namespace Cluster { const double DEFAULT_MEMBER_COVER = 80.0; struct CentroidSorted {}; void realign(const FlatArray& clusters, const std::vector& centroids, SequenceFile& db, std::function& callback, HspValues hsp_values); void realign(const std::vector& clustering, SequenceFile& db, std::function& callback, HspValues hsp_values); template std::pair, std::vector> read(const std::string& file_name, const SequenceFile& db, CentroidSorted); template std::vector read(const std::string& file_name, const SequenceFile& db); template std::vector member2centroid_mapping(const FlatArray& clusters, const std::vector& centroids); template void output_mem(Util::Tsv::File& out, SequenceFile& db, const std::vector& mapping); void output_mem(Util::Tsv::File& out, SequenceFile& db, Util::Tsv::File& oid_to_centroid_oid); template void output_mem(Util::Tsv::File& out, SequenceFile& db, std::vector>& mapping); template std::pair, std::vector> cluster_sorted(const std::vector& mapping); template std::pair, std::vector> split(const std::vector& mapping); std::vector member_counts(const std::vector& mapping); Util::Tsv::File* open_out_tsv(); void init_thresholds(); std::vector len_sorted_clust(const FlatArray>& edges); void output_edges(const std::string& file, SequenceFile& db, const std::vector>& edges); double round_value(const std::vector& par, const std::string& name, int round, int round_count); template std::vector convert_mapping(const std::vector& mapping, Int2) { std::vector out; out.reserve(mapping.size()); std::transform(mapping.begin(), mapping.end(), std::back_inserter(out), [](Int x) { return (Int2)x; }); return out; } struct Mapback : public Consumer { Mapback(int64_t count) : centroid_id(count, -1) {} virtual void consume(const char* ptr, size_t n) { const char* end = ptr + n; const bool mutual_cov = config.mutual_cover.present(); const double cutoff = mutual_cov ? config.mutual_cover.get_present() : config.member_cover; OId query = -1; for(const char* p = ptr; p < end; p += sizeof(Output::Format::Edge::Data)) { const auto edge = *(Output::Format::Edge::Data*)p; assert(query == -1 || query == edge.query); query = edge.query; if (edge.qcovhsp >= cutoff && ((mutual_cov && edge.scovhsp >= cutoff) || !mutual_cov)) centroid_id[edge.query] = edge.target; } } std::vector unmapped() const { std::vector v; for (OId i = 0; i < (OId)centroid_id.size(); ++i) if (centroid_id[i] == -1) v.push_back(i); return v; } std::vector centroid_id; }; template int64_t update_clustering(It clustering, It2 mapping, It2 query_begin, It2 query_end, It2 db_begin) { const int64_t n = query_end - query_begin; int64_t k = 0; for (OId i = 0; i < n; ++i) if (mapping[i] >= 0 && clustering[query_begin[i]] != db_begin[mapping[i]]) { clustering[query_begin[i]] = (typename It::value_type)db_begin[mapping[i]]; ++k; } return k; } template std::vector cluster_members(It begin, It end, const FlatArray& clusters) { std::vector out; for (It i = begin; i != end; ++i) { for (auto it = clusters.cbegin(*i); it != clusters.cend(*i); ++it) { out.push_back(*it); } } return out; } }bbuchfink-diamond-08b3cbc/src/cluster/cluster_registry.cpp000066400000000000000000000015741506104011400241300ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "cluster_registry.h" namespace Workflow { namespace Cluster{ const ClusterRegistryStatic ClusterRegistry::reg; }} bbuchfink-diamond-08b3cbc/src/cluster/cluster_registry.h000066400000000000000000000043471506104011400235760ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "cluster.h" #ifdef WITH_MCL #include "../contrib/mcl/mcl.h" #endif #include "cascaded/cascaded.h" //#include "incremental/incremental.h" namespace Workflow { namespace Cluster{ class ClusterRegistryStatic{ std::map regMap; public: ClusterRegistryStatic(){ // To include new clustering algorithms add them into regMap #ifdef WITH_MCL regMap[MCL::get_key()] = new MCL(); #endif regMap[::Cluster::Cascaded::get_key()] = new ::Cluster::Cascaded(); //regMap[::Cluster::Incremental::Algo::get_key()] = new ::Cluster::Incremental::Algo(); } ~ClusterRegistryStatic(){ for(auto it = regMap.begin(); it != regMap.end(); it++){ delete it->second; it->second = nullptr; } } ClusteringAlgorithm* get(std::string key) const{ auto ca = regMap.find(key); if(ca == regMap.end()){ throw std::runtime_error("Clustering algorithm not found."); } return ca->second; } bool has(std::string key) const{ return regMap.find(key) != regMap.end(); } std::vector getKeys() const{ std::vector keys; for(auto it = regMap.begin(); it != regMap.end(); it++){ keys.push_back(it->first); } return keys; } }; class ClusterRegistry{ private: static const ClusterRegistryStatic reg; public: static ClusteringAlgorithm* get(std::string key){ return reg.get(key); } static bool has(std::string key){ return reg.has(key); } static std::vector getKeys(){ return reg.getKeys(); } }; }} bbuchfink-diamond-08b3cbc/src/cluster/external/000077500000000000000000000000001506104011400216265ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/cluster/external/align.cpp000066400000000000000000000174301506104011400234310ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #include #include "basic/config.h" #include "external.h" #include "util/parallel/atomic.h" #include "util/util.h" #include "dp/dp.h" #include "util/parallel/thread_pool.h" #include "util/hash_function.h" using std::mutex; using std::thread; using std::vector; using std::string; using std::unique_ptr; using std::atomic; using std::unordered_map; using std::endl; using std::lock_guard; using std::list; using std::pair; using std::array; namespace Cluster { static void align_rep(ThreadPool& tp, const ChunkSeqs& chunk_seqs, vector::const_iterator begin, vector::const_iterator end, int64_t db_size, BufferArray& out) { const int64_t rep_oid = begin->rep_oid, shift = bit_length(db_size - 1) - RADIX_BITS; const Sequence rep = chunk_seqs[rep_oid]; DP::Targets targets; Statistics stats; Loc max_len = 0; for (auto i = begin; i < end; ++i) { const Sequence member = chunk_seqs[i->member_oid]; const int bin = DP::BandedSwipe::bin(HspValues::COORDS, rep.length(), 0, 0, (int64_t)rep.length() * (int64_t)member.length(), 0, 0); targets[bin].emplace_back(member, member.length(), i - begin); max_len = std::max(max_len, member.length()); } DP::Params params{ rep, nullptr, Frame(0), rep.length(), nullptr, DP::Flags::FULL_MATRIX, false, max_len, -1, HspValues::COORDS, stats, &tp }; const list hsps = DP::BandedSwipe::swipe(targets, params); const bool unid = !config.mutual_cover.present(); for (const Hsp& h : hsps) { const int64_t member_oid = begin[h.swipe_target].member_oid; const Sequence member = chunk_seqs[member_oid]; if (h.approx_id_percent(rep, member) < config.approx_min_id.get(0)) continue; if (unid) { if (h.subject_cover_percent(member.length()) >= config.member_cover.get(80)) out.write(MurmurHash()(member_oid) & (RADIX_COUNT - 1), Edge(rep_oid, member_oid, rep.length(), member.length())); if (h.query_cover_percent(rep.length()) >= config.member_cover.get(80)) out.write(MurmurHash()(rep_oid) & (RADIX_COUNT - 1), Edge(member_oid, rep_oid, member.length(), rep.length())); } else if (h.subject_cover_percent(member.length()) >= config.mutual_cover.get_present() && h.query_cover_percent(rep.length()) >= config.mutual_cover.get_present()) { int64_t oid1 = rep_oid; int64_t oid2 = member_oid; int64_t len1 = rep.length(); int64_t len2 = member.length(); if (oid1 > oid2) { std::swap(oid1, oid2); std::swap(len1, len2); } out.write(MurmurHash()(oid1) & (RADIX_COUNT - 1), Edge(oid1, oid2, len1, len2)); } } } vector align(Job& job, int chunk_count, int64_t db_size) { const std::string chunks_path = job.base_dir() + PATH_SEPARATOR + "chunks" + PATH_SEPARATOR, queue_path = chunks_path + "align_queue", aln_path = job.base_dir() + PATH_SEPARATOR + "alignments"; score_matrix.set_db_letters(1000000000); mkdir(aln_path); unique_ptr output_files(new FileArray(aln_path, RADIX_COUNT, job.worker_id())); Atomic queue(queue_path); int chunk, chunks_processed = 0; while (true) { chunk = queue.fetch_add(); if (chunk >= chunk_count) break; TaskTimer timer("Reading sequence files"); const string chunk_path = chunks_path + std::to_string(chunk) + PATH_SEPARATOR; unique_ptr chunk_seqs(new ChunkSeqs(chunk_path)); timer.finish(); job.log("Computing alignments. Chunk=%lli/%lli Volumes=%lli Sequences=%s Letters=%s", chunk + 1, chunk_count, chunk_seqs->volumes(), Util::String::format(chunk_seqs->oids()).c_str(), Util::String::format(chunk_seqs->letters()).c_str()); timer.go("Computing alignments"); InputFile pairs_file(chunk_path + "pairs", InputFile::NO_AUTODETECT); int64_t pairs_processed = 0; ThreadPool tp; ThreadPool::TaskSet task_set(tp, 1); std::function align_worker = [&]() { thread_local vector buf; thread_local BufferArray edge_buf(*output_files, RADIX_COUNT); size_t size; if (pairs_file.read(&size, 1) == 0) return; buf.clear(); buf.resize(size); pairs_file.read(buf.data(), size); pairs_processed += size; task_set.enqueue(align_worker); auto it = merge_keys(buf.begin(), buf.end(), PairEntryShort::Key()); while (it.good()) { align_rep(tp, *chunk_seqs, it.begin(), it.end(), db_size, edge_buf); ++it; } }; task_set.enqueue(align_worker); tp.run(config.threads_, true, &task_set); tp.join(); timer.finish(); log_stream << "pairs=" << pairs_processed << endl; timer.go("Deallocating memory"); pairs_file.close(); remove(pairs_file.file_name.c_str()); chunk_seqs.reset(); ++chunks_processed; timer.finish(); } TaskTimer timer("Closing the output files"); const vector out = output_files->buckets(); output_files.reset(); timer.go("Waiting for other workers"); Atomic finished(aln_path + PATH_SEPARATOR + "finished"); finished.fetch_add(chunks_processed); finished.await(chunk_count); return out; //const auto ccs = cc.largest_cc(); //log_stream << "Connected components = " << ccs.second << endl; //log_stream << "Largest connected component = " << ccs.first << endl; //TaskTimer timer("Allocating buffers"); //vector> edges(edge_count); //vector edges(edge_count); /*timer.go("Loading edges"); output_file->close(); InputFile f(aln_path + "worker_0"); f.read(edges.data(), edge_count); f.close(); timer.go("Sorting edges");*/ //FlatArray> edge_array = make_flat_array_dense(std::move(edges), db_size, config.threads_, Edge::GetKey()); //ips4o::parallel::sort(edges.begin(), edges.end(), std::less(), config.threads_); //timer.finish(); //vector oid2rep = Util::Algo::greedy_vertex_cover(edge_array, nullptr, true, false, 0); /*vector rep(db_size); std::iota(rep.begin(), rep.end(), 0); auto it = merge_keys(edges.begin(), edges.end(), Edge::Member()); while (it.good()) { if (it.begin()->member_len < it.begin()->rep_len || (it.begin()->member_len == it.begin()->rep_len && it.begin()->member_oid > it.begin()->rep_oid)) rep[it.begin()->member_oid] = it.begin()->rep_oid; ++it; } int64_t changed = 0; do { changed = 0; for (int64_t i = 0; i < db_size; ++i) if (rep[rep[i]] != rep[i]) { rep[i] = rep[rep[i]]; ++changed; } } while (changed > 0); int64_t n = 0; for (int64_t i = 0; i < db_size; ++i) if (rep[i] == i) ++n; log_stream << n << endl;*/ } }bbuchfink-diamond-08b3cbc/src/cluster/external/build_pair_table.h000066400000000000000000000066141506104011400252670ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #pragma once #include "util/util.h" #include "util/hash_function.h" #include "external.h" namespace Cluster { struct SeedEntry { SeedEntry() : seed(), oid(), len() {} SeedEntry(uint64_t seed, int64_t oid, int32_t len): seed(seed), oid(oid), len(len) {} uint64_t key() const { return seed; } bool operator<(const SeedEntry& e) const { return seed < e.seed || (seed == e.seed && (len > e.len || (len == e.len && oid < e.oid))); } struct Key { uint64_t operator()(const SeedEntry& e) const { return e.seed; } }; uint64_t seed; int64_t oid; int32_t len; }; void get_pairs_uni_cov(KeyMergeIterator& it, BufferArray& buffers) { const int64_t rep_oid = it.begin()->oid, radix = MurmurHash()(rep_oid) & (RADIX_COUNT - 1); const int32_t rep_len = it.begin()->len; for (auto j = it.begin() + 1; j < it.end(); ++j) { if (rep_oid == j->oid) continue; buffers.write(radix, PairEntry(rep_oid, j->oid, rep_len, j->len)); } } void get_pairs_mutual_cov(KeyMergeIterator& it, BufferArray& buffers) { const double mlr = config.min_length_ratio; const int32_t s = (int)it.count(); int32_t j = 0; const auto begin = it.begin(); for (int32_t i = 0; i < s;) { const Loc qlen = begin[i].len; int32_t j1 = j; for (; j1 < s; ++j1) { const Loc tlen = begin[j1].len; if ((double)tlen / qlen < mlr) break; } const int32_t qpos = i + (j1 - j) / 2; const int64_t rep_oid = begin[qpos].oid; const int32_t rep_len = begin[qpos].len; const int64_t radix = MurmurHash()(rep_oid) & (RADIX_COUNT - 1); for (int k = j; k < j1; ++k) if (rep_oid != begin[k].oid) buffers.write(radix, PairEntry(rep_oid, begin[k].oid, rep_len, begin[k].len)); j = j1; if (j == s) break; const Loc tlen = begin[j].len; for (; i < s; ++i) { const Loc qlen = begin[i].len; if ((double)tlen / qlen >= mlr) break; } } } }bbuchfink-diamond-08b3cbc/src/cluster/external/cluster.cpp000066400000000000000000000234401506104011400240160ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #include #include "basic/config.h" #include "external.h" #include "util/parallel/atomic.h" #define _REENTRANT #include "lib/ips4o/ips4o.hpp" #include "util/util.h" using std::vector; using std::string; using std::unique_ptr; using std::thread; using std::endl; using Util::String::format; using std::atomic; namespace Cluster { struct Assignment { int64_t member_oid, rep_oid; }; static void compute_closure(Job& job, const VolumedFile& volumes, vector& rep) { Partition parts(volumes.records(), config.threads_); atomic cluster_count(0); auto closure_worker = [&](int thread_id) { int64_t clusters = 0; for (int64_t i = parts.begin(thread_id); i < parts.end(thread_id); ++i) { int64_t r = rep[i]; if (r == i) ++clusters; while (rep[r] != r) r = rep[r]; if (r != rep[i]) rep[i] = r; } cluster_count.fetch_add(clusters, std::memory_order_relaxed); }; vector workers; for (int i = 0; i < std::min(config.threads_, (int)parts.parts); ++i) workers.emplace_back(closure_worker, i); for (auto& t : workers) t.join(); job.log("Cluster count = %lli", (int64_t)cluster_count); const string output_dir = job.base_dir() + PATH_SEPARATOR + "clustering" + PATH_SEPARATOR; mkdir(output_dir); for (size_t v = 0; v < volumes.size(); ++v) { OutputFile out(output_dir + "volume" + std::to_string(v)); out.write(&rep[volumes[v].oid_begin], volumes[v].record_count); out.close(); } } static void compute_closure(Job& job, const string& assignment_file, const VolumedFile& volumes) { job.log("Computing transitive closure"); TaskTimer timer("Getting assignment volumes"); VolumedFile v(assignment_file); timer.go("Initializing mapping vector"); vector rep(volumes.records()); std::iota(rep.begin(), rep.end(), (int64_t)0); timer.go("Reading assignments"); atomic next(0); auto read_worker = [&](int thread_id) { int i; while (i = next.fetch_add(1, std::memory_order_relaxed), i < (int)v.size()) { job.log("Reading assignments thread_id=%i volume=%i", thread_id, i); InputFile f(v[i].path); Assignment a; while (f.read(&a, 1) == 1) { rep[a.member_oid] = a.rep_oid; } f.close(); } }; vector workers; for (int i = 0; i < std::min(config.threads_, (int)v.size()); ++i) workers.emplace_back(read_worker, i); for (auto& t : workers) t.join(); workers.clear(); compute_closure(job, volumes, rep); v.remove(); } static string get_reps(Job& job, const VolumedFile& volumes) { if (job.last_round()) return string(); const string base_dir = job.base_dir() + PATH_SEPARATOR + "reps" + PATH_SEPARATOR, qpath = base_dir + "queue"; const string clustering_dir = job.base_dir() + PATH_SEPARATOR + "clustering" + PATH_SEPARATOR; mkdir(base_dir); unique_ptr output_files(new FileArray(base_dir, 1, job.worker_id())); Atomic q(qpath); atomic volumes_processed(0); vector workers; auto worker = [&](int thread_id) { BufferArray buffers(*output_files, 1); int64_t v = 0; vector buf; while (v = q.fetch_add(), v < (int64_t)volumes.size()) { job.log("Writing representatives. Volume=%lli/%lli Records=%s", v + 1, volumes.size(), format(volumes[v].record_count).c_str()); vector rep(volumes[v].record_count); InputFile clustering_file(clustering_dir + "volume" + std::to_string(v)); clustering_file.read(rep.data(), volumes[v].record_count); clustering_file.close(); unique_ptr in(SequenceFile::auto_create({ volumes[v].path })); string id; vector seq; int64_t oid = volumes[v].oid_begin; vector::const_iterator rep_it = rep.begin(); string fasta_record; while (in->read_seq(seq, id, nullptr)) { if (*rep_it == oid) { fasta_record = ">"; fasta_record += std::to_string(oid); fasta_record += '\n'; fasta_record += Sequence(seq).to_string(); fasta_record += '\n'; buffers.write(0, fasta_record.data(), fasta_record.length(), 1); } ++oid; ++rep_it; } in->close(); volumes_processed.fetch_add(1, std::memory_order_relaxed); } }; for (int i = 0; i < config.threads_; ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); const vector buckets = output_files->buckets(); TaskTimer timer("Closing the output files"); output_files.reset(); Atomic finished(base_dir + "finished"); finished.fetch_add(volumes_processed); finished.await((int)volumes.size()); return buckets.front(); } string cluster(Job& job, const vector& edges, const VolumedFile& volumes) { const int64_t db_size = volumes.records(); const std::string base_path = job.base_dir() + PATH_SEPARATOR + "alignments", queue_path = base_path + PATH_SEPARATOR + "queue", clustering_path = job.base_dir() + PATH_SEPARATOR + "clustering"; mkdir(clustering_path); unique_ptr output_file(new FileArray(clustering_path, 1, job.worker_id())); Atomic queue(queue_path); int64_t bucket, buckets_processed = 0; while (bucket = queue.fetch_add(), bucket < (int64_t)edges.size()) { VolumedFile file(edges[bucket]); InputBuffer data(file); job.log("Clustering. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, edges.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); ips4o::parallel::sort(data.begin(), data.end(), std::less(), config.threads_); auto worker = [&](int thread_id) { BufferArray buffer(*output_file, 1); auto it = merge_keys(data.begin(thread_id), data.end(thread_id), Edge::Member()); while (it.good()) { if (it.begin()->member_len < it.begin()->rep_len || (it.begin()->member_len == it.begin()->rep_len && it.begin()->member_oid > it.begin()->rep_oid)) buffer.write(0, Assignment{ it.begin()->member_oid, it.begin()->rep_oid }); ++it; } }; vector workers; for (int i = 0; i < data.parts(); ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); file.remove(); ++buckets_processed; } TaskTimer timer("Closing the output files"); const string assignment_file = output_file->bucket(0); output_file.reset(); Atomic finished(clustering_path + PATH_SEPARATOR + "finished"); const int f = finished.fetch_add(buckets_processed); Atomic closure_finished(clustering_path + PATH_SEPARATOR + "closure_finished"); if (f + buckets_processed < (int)edges.size()) closure_finished.await(1); else { compute_closure(job, assignment_file, volumes); closure_finished.fetch_add(); } return get_reps(job, volumes); } string cluster_bidirectional(Job& job, const vector& edges, const VolumedFile& volumes) { Atomic lock(job.base_dir() + PATH_SEPARATOR + "cluster_bidirectional_lock"); Atomic finished(job.base_dir() + PATH_SEPARATOR + "cluster_bidirectional_finished"); if (lock.fetch_add() == 0) { job.log("Computing clustering (bi-directional coverage)"); vector degree(volumes.records(), 0); for (int bucket = 0; bucket < (int)edges.size(); ++bucket) { VolumedFile file(edges[bucket]); InputBuffer data(file); job.log("Getting node degrees. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, edges.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); const Edge* end = data.end(); for (const Edge* i = data.begin(); i < end; ++i) { ++degree[i->member_oid]; ++degree[i->rep_oid]; } } vector rep(volumes.records()); std::iota(rep.begin(), rep.end(), (int64_t)0); for (int bucket = 0; bucket < (int)edges.size(); ++bucket) { VolumedFile file(edges[bucket]); InputBuffer data(file); job.log("Assigning reps. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, edges.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); const Edge* end = data.end(); for (const Edge* i = data.begin(); i < end; ++i) { if (degree[i->rep_oid] > degree[rep[i->member_oid]] || (degree[i->rep_oid] == degree[rep[i->member_oid]] && i->rep_oid < rep[i->member_oid])) rep[i->member_oid] = i->rep_oid; if (degree[i->member_oid] > degree[rep[i->rep_oid]] || (degree[i->member_oid] == degree[rep[i->rep_oid]] && i->member_oid < rep[i->rep_oid])) rep[i->rep_oid] = i->member_oid; } } compute_closure(job, volumes, rep); finished.fetch_add(); for (int bucket = 0; bucket < (int)edges.size(); ++bucket) VolumedFile(edges[bucket]).remove(); } else finished.await(1); return get_reps(job, volumes); } }bbuchfink-diamond-08b3cbc/src/cluster/external/external.cpp000066400000000000000000000454671506104011400241740ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #include #include #include "../basic/config.h" #include "util/tsv/tsv.h" #include "util/parallel/atomic.h" #include "util/log_stream.h" #include "data/sequence_file.h" #include "basic/reduction.h" #include "basic/shape_config.h" #include "basic/seed_iterator.h" #include "search/search.h" #include "external.h" #include "radix_sort.h" #define _REENTRANT #include "lib/ips4o/ips4o.hpp" #include "util/algo/hyperloglog.h" #include "util/sequence//sequence.h" #include "util/string/string.h" #include "../cascaded/cascaded.h" #include "build_pair_table.h" using std::unique_ptr; using std::thread; using std::string; using std::vector; using std::endl; using std::array; using std::mutex; using std::lock_guard; using std::pair; using std::atomic; using Util::String::format; using std::shared_ptr; using std::to_string; namespace Cluster { struct ChunkTableEntry { ChunkTableEntry(): oid(), chunk() {} ChunkTableEntry(int64_t oid, int32_t chunk): oid(oid), chunk(chunk) {} int64_t key() const { return oid; } bool operator<(const ChunkTableEntry& e) const { return oid < e.oid || (oid == e.oid && chunk < e.chunk); } int64_t oid; int32_t chunk; }; static vector build_seed_table(Job& job, const VolumedFile& volumes, int shape) { const int64_t BUF_SIZE = 4096; const double SKETCH_SIZE_RATIO = 0.1; //Reduction::set_reduction(Search::no_reduction); Loc sketch_size = config.sketch_size == 0 ? Search::sensitivity_traits.at(config.sensitivity).sketch_size : config.sketch_size; if (sketch_size == 0) sketch_size = std::numeric_limits::max(); //const uint64_t shift = shapes[shape].bit_length() - RADIX_BITS; const std::string base_dir = job.base_dir() + PATH_SEPARATOR + "seed_table_" + std::to_string(shape) + PATH_SEPARATOR, qpath = base_dir + "queue"; mkdir(base_dir); unique_ptr output_files(new FileArray(base_dir, RADIX_COUNT, job.worker_id())); Atomic q(qpath); atomic volumes_processed(0); vector workers; auto worker = [&](int thread_id) { BufferArray buffers(*output_files, RADIX_COUNT); int64_t v = 0; vector buf; while (v = q.fetch_add(), v < (int64_t)volumes.size()) { job.log("Building seed table. Shape=%i/%i Volume=%lli/%lli Records=%s", shape + 1, ::shapes.count(), v + 1, volumes.size(), format(volumes[v].record_count).c_str()); unique_ptr oid_out; if (job.round() > 0) oid_out.reset(new OutputFile(volumes[v].path + ".oid")); unique_ptr in(SequenceFile::auto_create({ volumes[v].path })); string id; vector seq; int64_t oid = volumes[v].oid_begin; while (in->read_seq(seq, id, nullptr)) { if (job.round() > 0) { const int64_t prev_oid = atoll(id.c_str()); oid_out->write(&prev_oid, 1); } Reduction::reduce_seq(Sequence(seq), buf); const Shape& sh = shapes[shape]; if (seq.size() < (size_t)sh.length_) { ++oid; continue; } //SketchIterator it(buf, sh, std::min(sketch_size, std::max((int)std::round(seq.size() * SKETCH_SIZE_RATIO), 1))); SketchIterator it(buf, sh, sketch_size); while (it.good()) { const uint64_t key = *it, radix = MurmurHash()(key) & (RADIX_COUNT - 1); buffers.write(radix, SeedEntry(key, oid, (int32_t)seq.size())); ++it; } ++oid; } in->close(); if (job.round() > 0) oid_out->close(); volumes_processed.fetch_add(1, std::memory_order_relaxed); } }; for (int i = 0; i < config.threads_; ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); const vector buckets = output_files->buckets(); TaskTimer timer("Closing the output files"); output_files.reset(); Atomic finished(base_dir + "finished"); finished.fetch_add(volumes_processed); finished.await(volumes.size()); return buckets; } static vector build_pair_table(Job& job, const vector& seed_table, int shape, int64_t db_size, FileArray& output_files) { const int64_t BUF_SIZE = 4096, shift = bit_length(db_size - 1) - RADIX_BITS; // promiscuous_cutoff = db_size / config.promiscuous_seed_ratio; const string seed_table_base = job.base_dir() + PATH_SEPARATOR + "seed_table_" + to_string(shape); const string queue_path = seed_table_base + PATH_SEPARATOR + "build_pair_table_queue"; const bool unid = !config.mutual_cover.present(); Atomic queue(queue_path); int64_t bucket, buckets_processed = 0; while (bucket = queue.fetch_add(), bucket < (int64_t)seed_table.size()) { VolumedFile file(seed_table[bucket]); InputBuffer data(file); job.log("Building pair table. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, seed_table.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); ips4o::parallel::sort(data.begin(), data.end(), std::less(), config.threads_); auto worker = [&](int thread_id) { BufferArray buffers(output_files, RADIX_COUNT); auto it = merge_keys(data.begin(thread_id), data.end(thread_id), SeedEntry::Key()); while (it.good()) { /*if (it.count() >= promiscuous_cutoff) { ++it; continue; }*/ if (unid) get_pairs_uni_cov(it, buffers); else get_pairs_mutual_cov(it, buffers); ++it; } }; vector workers; for (int i = 0; i < data.parts(); ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); file.remove(); ++buckets_processed; } const vector buckets = output_files.buckets(); Atomic finished(seed_table_base + PATH_SEPARATOR + "pair_table_finished"); finished.fetch_add(buckets_processed); finished.await(seed_table.size()); return buckets; } struct SizeCounter { void add(int64_t oid, int32_t len) { const int64_t x = oid << 17, n = x + int64_t(len + 63) / 64; for (int64_t i = x; i < n; ++i) hll.add(i); } HyperLogLog hll; }; struct Chunk { Chunk(Atomic& next_chunk, const string& chunks_path): id(next_chunk.fetch_add()) { mkdir(chunks_path + std::to_string(id)); pairs_out.reset(new OutputFile(chunks_path + std::to_string(id) + PATH_SEPARATOR + "pairs")); } void write(vector& pairs_buffer, SizeCounter& size) { lock_guard lock(mtx); pairs_out->write(pairs_buffer.size()); pairs_out->write(pairs_buffer.data(), pairs_buffer.size()); pairs_buffer.clear(); this->size.merge(size.hll); size.hll = HyperLogLog(); } ~Chunk() { pairs_out->close(); } const int id; unique_ptr pairs_out; HyperLogLog size; mutex mtx; }; static pair, int> build_chunk_table(Job& job, const vector& pair_table, int64_t db_size) { const int64_t BUF_SIZE = 4096, shift = bit_length(db_size - 1) - RADIX_BITS, max_chunk_size = Util::String::interpret_number(config.linclust_chunk_size) / 64, max_processed = std::max(std::min(INT64_C(262144), max_chunk_size / config.threads_ / 16), INT64_C(1)); // ??? const std::string base_path = job.base_dir() + PATH_SEPARATOR + "chunk_table", chunks_path = job.base_dir() + PATH_SEPARATOR + "chunks" + PATH_SEPARATOR; mkdir(base_path); mkdir(chunks_path); unique_ptr output_files(new FileArray(base_path, RADIX_COUNT, job.worker_id())); Atomic queue(base_path + PATH_SEPARATOR + "queue"); Atomic next_chunk(base_path + PATH_SEPARATOR + "next_chunk"); shared_ptr current_chunk(new Chunk(next_chunk, chunks_path)); int64_t bucket, total_pairs = 0, total_distinct_pairs = 0, buckets_processed = 0; mutex mtx; while (bucket = queue.fetch_add(), bucket < (int64_t)pair_table.size()) { VolumedFile file(pair_table[bucket]); InputBuffer data(file); job.log("Building chunk table. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, pair_table.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); total_pairs += data.size(); ips4o::parallel::sort(data.begin(), data.end(), std::less(), config.threads_); auto worker = [&](int thread_id) { shared_ptr my_chunk(current_chunk); BufferArray buffers(*output_files, RADIX_COUNT); vector pairs_buffer; SizeCounter size; int64_t distinct_pairs = 0, processed = 0; auto it = merge_keys(data.begin(thread_id), data.end(thread_id), PairEntry::Key()); while (it.good()) { const int64_t rep_oid = it.begin()->rep_oid, radix = rep_oid >> shift; // Hashing? buffers.write(radix, ChunkTableEntry(rep_oid, my_chunk->id)); size.add(rep_oid, it.begin()->rep_len); processed += it.begin()->rep_len; for (auto j = it.begin(); j < it.end(); ++j) { if (j > it.begin() && j->member_oid == (j - 1)->member_oid) continue; const int64_t radix = j->member_oid >> shift; buffers.write(radix, ChunkTableEntry(j->member_oid, my_chunk->id)); size.add(j->member_oid, j->member_len); pairs_buffer.emplace_back(rep_oid, j->member_oid); ++distinct_pairs; processed += j->member_len; if (processed >= max_processed) { my_chunk->write(pairs_buffer, size); processed = 0; bool new_chunk = false; if (my_chunk != current_chunk) { my_chunk = current_chunk; new_chunk = true; } else { const int64_t est = my_chunk->size.estimate(); if (est >= max_chunk_size) { lock_guard lock(mtx); if (my_chunk == current_chunk) { log_stream << "build_chunk_table chunk=" << current_chunk->id << " est_size=" << est * 64 << endl; current_chunk.reset(new Chunk(next_chunk, chunks_path)); my_chunk = current_chunk; new_chunk = true; } else { // should not happen? } } } if (new_chunk) { buffers.write(rep_oid >> shift, ChunkTableEntry(rep_oid, my_chunk->id)); size.add(rep_oid, it.begin()->rep_len); processed += it.begin()->rep_len; } } } ++it; } my_chunk->write(pairs_buffer, size); total_distinct_pairs += distinct_pairs; }; vector workers; for (int i = 0; i < data.parts(); ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); const int64_t est = current_chunk->size.estimate(); if (est >= max_chunk_size) { log_stream << "build_chunk_table chunk=" << current_chunk->id << " est_size=" << est * 64 << endl; current_chunk.reset(new Chunk(next_chunk, chunks_path)); } file.remove(); ++buckets_processed; } log_stream << "build_chunk_table chunk=" << current_chunk->id << " est_size=" << current_chunk->size.estimate() << " total_pairs=" << total_pairs << " total_distinct_pairs=" << total_distinct_pairs << endl; const vector buckets = output_files->buckets(); TaskTimer timer("Closing the output files"); output_files.reset(); current_chunk.reset(); timer.go("Waiting for other workers"); Atomic finished(base_path + PATH_SEPARATOR + "finished"); finished.fetch_add(buckets_processed); finished.await(pair_table.size()); return { buckets, next_chunk.get() }; } static void build_chunks(Job& job, const VolumedFile& db, const vector& chunk_table, int chunk_count) { const int64_t BUF_SIZE = 64 * 1024; const std::string base_path = job.base_dir() + PATH_SEPARATOR + "chunks" + PATH_SEPARATOR, queue_path = base_path + "queue"; unique_ptr output_files(new FileArray(base_path, chunk_count, job.worker_id(), 1024 * 1024 * 1024)); Atomic queue(queue_path); int64_t bucket, buckets_processed = 0; atomic oid_counter(0), distinct_oid_counter(0); while (bucket = queue.fetch_add(), bucket < (int64_t)chunk_table.size()) { VolumedFile file(chunk_table[bucket]); InputBuffer data(file); job.log("Building chunks. Bucket=%lli/%lli Records=%s Size=%s", bucket + 1, chunk_table.size(), format(data.size()).c_str(), format(data.byte_size()).c_str()); if (data.size() > 0) { ips4o::parallel::sort(data.begin(), data.end(), std::less(), config.threads_); const int64_t oid_begin = data.front().oid, oid_end = data.back().oid + 1; const pair::const_iterator, vector::const_iterator> volumes = db.find(oid_begin, oid_end); atomic next(0); auto worker = [&]() { int64_t volume; const ChunkTableEntry* table_ptr = data.begin(); BufferArray output_bufs(*output_files, chunk_count); TextBuffer buf; while (volume = next.fetch_add(1, std::memory_order_relaxed), volume < volumes.second - volumes.first) { const Volume& v = volumes.first[volume]; while (table_ptr->oid < v.oid_begin) ++table_ptr; unique_ptr in(SequenceFile::auto_create({ v.path })); string id; vector seq; int64_t file_oid = v.oid_begin; while (file_oid < oid_end && in->read_seq(seq, id, nullptr)) { if (table_ptr->oid > file_oid) { ++file_oid; continue; } Util::Seq::format(seq, std::to_string(file_oid).c_str(), nullptr, buf, "fasta", amino_acid_traits); const ChunkTableEntry* begin = table_ptr; while (table_ptr < data.end() && table_ptr->oid == file_oid) { if (table_ptr == begin || table_ptr->chunk != table_ptr[-1].chunk) { output_bufs.write(table_ptr->chunk, buf.data(), buf.size()); oid_counter.fetch_add(1, std::memory_order_relaxed); } ++table_ptr; } buf.clear(); distinct_oid_counter.fetch_add(1, std::memory_order_relaxed); ++file_oid; } in->close(); } }; vector workers; for (int i = 0; i < std::min(config.threads_, int(volumes.second - volumes.first)); ++i) workers.emplace_back(worker); for (auto& t : workers) t.join(); } file.remove(); ++buckets_processed; } TaskTimer timer("Closing the output files"); output_files.reset(); timer.go("Waiting for other workers"); Atomic finished(base_path + "finished"); finished.fetch_add(buckets_processed); finished.await(chunk_table.size()); timer.finish(); log_stream << "build_chunks oids=" << oid_counter << '/' << db.records() << " distinct_oids=" << distinct_oid_counter << endl; } string round(Job& job, const VolumedFile& volumes) { ::shapes = ShapeConfig(Search::shape_codes.at(config.sensitivity), 0); if (config.mutual_cover.present()) { config.min_length_ratio = config.sensitivity < Sensitivity::LINCLUST_40 ? std::min(config.mutual_cover.get_present() / 100 + 0.05, 1.0) : config.mutual_cover.get_present() / 100 - 0.05; } job.log("Starting round %i sensitivity %s %i shapes\n", job.round(), to_string(config.sensitivity).c_str(), ::shapes.count()); job.set_round(volumes.size(), volumes.records()); const std::string pair_table_base = job.base_dir() + PATH_SEPARATOR + "pair_table"; mkdir(pair_table_base); unique_ptr pair_table_files(new FileArray(pair_table_base, RADIX_COUNT, job.worker_id())); vector pair_table; for (int shape = 0; shape < ::shapes.count(); ++shape) { const vector buckets = build_seed_table(job, volumes, shape); const vector sorted_seed_table = radix_sort(job, buckets, shapes[0].bit_length() - RADIX_BITS); pair_table = build_pair_table(job, sorted_seed_table, shape, volumes.records(), *pair_table_files); } pair_table_files.reset(); const vector sorted_pair_table = radix_sort(job, pair_table, bit_length(volumes.records() - 1) - RADIX_BITS); const pair, int> chunk_table = build_chunk_table(job, sorted_pair_table, volumes.records()); const vector sorted_chunk_table = radix_sort(job, chunk_table.first, bit_length(volumes.records() - 1) - RADIX_BITS); build_chunks(job, volumes, sorted_chunk_table, chunk_table.second); const vector edges = align(job, chunk_table.second, volumes.records()); if (config.mutual_cover.present()) { return cluster_bidirectional(job, edges, volumes); } else { const vector sorted_edges = radix_sort(job, edges, bit_length(volumes.records() - 1) - RADIX_BITS); //const vector sorted_edges = read_list(job.base_dir() + PATH_SEPARATOR + "alignments" + PATH_SEPARATOR + "radix_sort_out"); return cluster(job, sorted_edges, volumes); } } void external() { if (config.output_file.empty()) throw std::runtime_error("Option missing: output file (--out/-o)"); config.file_buffer_size = 64 * 1024; TaskTimer total; Job job; VolumedFile volumes(config.database.get_present()); if (job.worker_id() == 0) { if(config.mutual_cover.present()) job.log("Bi-directional coverage = %f", config.mutual_cover.get_present()); else job.log("Uni-directional coverage = %f", config.member_cover.get(80)); job.log("Approx. id = %f", config.approx_min_id.get(0)); job.log("#Volumes = %lli", volumes.size()); job.log("#Sequences = %lli", volumes.records()); } if (config.mutual_cover.present()) { config.query_or_target_cover = 0; config.query_cover = config.mutual_cover.get_present(); config.subject_cover = config.mutual_cover.get_present(); } else { config.query_or_target_cover = config.member_cover.get(80); config.query_cover = 0; config.subject_cover = 0; } #ifdef WIN32 _setmaxstdio(8192); #endif vector steps = Cluster::cluster_steps(config.approx_min_id.get(0), true); string reps; job.set_round_count((int)steps.size()); for (size_t i = 0; i < steps.size(); ++i) { config.sensitivity = from_string(rstrip(steps[i], "_lin")); reps = round(job, i == 0 ? volumes : VolumedFile(reps)); if (i < steps.size() - 1) job.next_round(); } Atomic output_lock(job.base_dir() + PATH_SEPARATOR + "output_lock"); if(output_lock.fetch_add() == 0) output(job); log_stream << "Total time = " << (double)total.milliseconds() / 1000 << 's' << endl; } }bbuchfink-diamond-08b3cbc/src/cluster/external/external.h000066400000000000000000000410201506104011400236160ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #pragma once #include #include #include #include #include #include "util/system/system.h" #include "util/io/output_file.h" #include "util/tsv/file.h" #include "util/algo/partition.h" #include "util/parallel/filestack.h" #include "util/parallel/atomic.h" #include "util/io/compressed_buffer.h" #include "basic/sequence.h" #include "data/block/block.h" #include "data/sequence_file.h" #ifdef WIN32 const char PATH_SEPARATOR = '\\'; #else #include const char PATH_SEPARATOR = '/'; #endif namespace Cluster { const uint64_t RADIX_BITS = 8; const int_fast16_t RADIX_COUNT = INT64_C(1) << RADIX_BITS; const int_fast64_t MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; struct PairEntry { PairEntry() : rep_oid(), member_oid(), rep_len(), member_len() {} PairEntry(int_fast64_t rep_oid, int_fast64_t member_oid, int_fast32_t rep_len, int_fast32_t member_len) : rep_oid(rep_oid), member_oid(member_oid), rep_len(rep_len), member_len(member_len) {} int_fast64_t key() const { return rep_oid; } bool operator<(const PairEntry& e) const { return rep_oid < e.rep_oid || (rep_oid == e.rep_oid && member_oid < e.member_oid); } struct Key { int64_t operator()(const PairEntry& e) const { return e.rep_oid; } }; int_fast64_t rep_oid, member_oid; int_fast32_t rep_len, member_len; }; struct PairEntryShort { PairEntryShort() : rep_oid(), member_oid() {} PairEntryShort(int64_t rep_oid, int64_t member_oid) : rep_oid(rep_oid), member_oid(member_oid) {} struct Key { int64_t operator()(const PairEntryShort& e) const { return e.rep_oid; } }; int64_t rep_oid, member_oid; }; struct Edge { Edge(int64_t rep_oid, int64_t member_oid, int32_t rep_len, int32_t member_len) : rep_oid(rep_oid), member_oid(member_oid), rep_len(rep_len), member_len(member_len) {} Edge() : rep_oid(), member_oid(), rep_len(), member_len() {} int64_t key() const { return member_oid; } bool operator<(const Edge& e) const { return member_oid < e.member_oid || (member_oid == e.member_oid && (rep_len > e.rep_len || (rep_len == e.rep_len && rep_oid < e.rep_oid))); } struct Member { int64_t operator()(const Edge& e) const { return e.member_oid; } }; int64_t rep_oid, member_oid; int32_t rep_len, member_len; }; inline std::string path(const std::string& file_name) { return file_name.substr(0, file_name.find_last_of(PATH_SEPARATOR)); } inline std::string base_path(const std::string& file_name) { static const std::string s = std::string(&PATH_SEPARATOR, 1) + "0" + PATH_SEPARATOR + "bucket.tsv"; if (file_name.compare(file_name.length() - s.length(), s.length(), s) != 0) throw std::runtime_error("base_path"); return file_name.substr(0, file_name.length() - s.length()); } struct Job { Job(): base_dir_(config.parallel_tmpdir + PATH_SEPARATOR + "diamond-tmp-" + Const::version_string), round_(0), start_(std::chrono::system_clock::now()) { mkdir(base_dir_); mkdir(base_dir()); log_file_.reset(new FileStack(base_dir_ + PATH_SEPARATOR + "diamond_job.log")); Atomic worker_id(base_dir_ + PATH_SEPARATOR + "worker_id"); worker_id_ = worker_id.fetch_add(); } int worker_id() const { return worker_id_; } std::string base_dir(int round = -1) const { return base_dir_ + PATH_SEPARATOR + "round" + std::to_string(round == -1 ? round_ : round); } void log(const char* format, ...) { char buffer[1024]; char* ptr = buffer + snprintf(buffer, 1024, "[%i, %lli] ", worker_id_, std::chrono::duration_cast>(std::chrono::system_clock::now() - start_).count()); va_list args; va_start(args, format); int i = vsnprintf(ptr, 1024 - (ptr - buffer), format, args); #ifdef WIN32 ptr[i++] = '\r'; #endif ptr[i++] = '\n'; ptr[i] = '\0'; log_stream << buffer; log_file_->push(buffer); va_end(args); } void next_round() { ++round_; mkdir(base_dir()); } int round() const { return round_; } void set_round(int volumes, int64_t input_count) { volume_count_.push_back(volumes); input_count_.push_back(input_count); } int volume_count(int round) const { return volume_count_[round]; } int input_count(int round) const { return input_count_[round]; } void set_round_count(int n) { round_count_ = n; } bool last_round() const { return round_ == round_count_ - 1; } private: std::string base_dir_; int worker_id_, round_, round_count_; std::unique_ptr log_file_; std::chrono::system_clock::time_point start_; std::vector volume_count_; std::vector input_count_; }; struct FileArray { FileArray(const std::string& base_dir, int size, int worker_id, int64_t max_file_size = MAX_FILE_SIZE) : max_file_size(max_file_size), size_(size), worker_id_(worker_id), base_dir(base_dir), mtx_(size), records_(size, 0), bytes_(size, 0), next_(size, 1) { for (int64_t i = 0; i < size; ++i) { const std::string dir = base_dir + PATH_SEPARATOR + std::to_string(i) + PATH_SEPARATOR; mkdir(dir); output_files_.push_back(new OutputFile(dir + "worker_" + std::to_string(worker_id) + "_volume_0")); bucket_files_.emplace_back(new FileStack(dir + "bucket.tsv")); } } ~FileArray() { for (int64_t i = 0; i < size_; ++i) { output_files_[i]->close(); if (records_[i] > 0) bucket_files_[i]->push(output_files_[i]->file_name() + '\t' + std::to_string(records_[i])); else ::remove(output_files_[i]->file_name().c_str()); delete output_files_[i]; } } bool write(int i, const char* ptr, int64_t count, int64_t records) { std::lock_guard lock(mtx_[i]); output_files_[i]->write(ptr, count); records_[i] += records; bytes_[i] += count; if (bytes_[i] >= max_file_size) { bucket_files_[i]->push(output_files_[i]->file_name() + '\t' + std::to_string(records_[i])); records_[i] = 0; bytes_[i] = 0; output_files_[i]->close(); delete output_files_[i]; output_files_[i] = new OutputFile(base_dir + PATH_SEPARATOR + std::to_string(i) + PATH_SEPARATOR + "worker_" + std::to_string(worker_id_) + "_volume_" + std::to_string(next_[i]++)); return true; } return false; } int64_t records(int i) const { return records_[i]; } std::string bucket(int i) const { return bucket_files_[i]->file_name(); } std::vector buckets() const { std::vector buckets; buckets.reserve(size_); for (int i = 0; i < size_; ++i) buckets.push_back(bucket(i)); return buckets; } std::string file_name(int i) { return output_files_[i]->file_name(); } private: const int64_t max_file_size; const int size_, worker_id_; const std::string base_dir; std::vector output_files_; std::vector mtx_; std::vector records_, bytes_, next_; std::vector> bucket_files_; }; /*template struct BufferArray { static constexpr int64_t BUF_SIZE = 4096; BufferArray(FileArray& file_array) : file_array_(file_array) {} void write(int radix, const T& x) { data_[radix].push_back(x); if (data_[radix].size() >= BUF_SIZE) { file_array_.write(radix, data_[radix].data(), data_[radix].size()); data_[radix].clear(); } } ~BufferArray() { for (int i = 0; i < N; ++i) file_array_.write(i, data_[i].data(), data_[i].size()); } private: std::array, N> data_; FileArray& file_array_; };*/ struct BufferArray { static constexpr int64_t BUF_SIZE = 65536; BufferArray(FileArray& file_array, int size) : data_(size), records_(size, 0), file_array_(file_array) { } template bool write(int radix, const T* ptr, int64_t n, int64_t record_count = -1) { data_[radix].write((const char*)ptr, n * sizeof(T)); records_[radix] += record_count >= 0 ? record_count : n; if (data_[radix].size() >= BUF_SIZE) { data_[radix].finish(); const bool r = file_array_.write(radix, data_[radix].data(), data_[radix].size(), records_[radix]); data_[radix].clear(); records_[radix] = 0; return r; } return false; } template bool write(int radix, const T& x) { return write(radix, &x, 1); } ~BufferArray() { for (int i = 0; i < (int)data_.size(); ++i) { data_[i].finish(); file_array_.write(i, data_[i].data(), data_[i].size(), records_[i]); } } private: std::vector data_; std::vector records_; FileArray& file_array_; }; struct Volume { Volume(const std::string& path, int64_t oid_begin, int64_t record_count) : path(path), oid_begin(oid_begin), record_count(record_count) {} std::string path; int64_t oid_begin, record_count; int64_t oid_end() const { return oid_begin + record_count; } bool operator<(int64_t oid) const { return oid_end() <= oid; } }; struct VolumedFile : public std::vector { VolumedFile(const std::string& file_name): list_file_(file_name) { Util::Tsv::File volume_file({ Util::Tsv::Type::STRING, Util::Tsv::Type::INT64 }, file_name); const Util::Tsv::Table volume_table = volume_file.read(config.threads_); reserve(volume_table.size()); int64_t oid = 0; for (int64_t i = 0; i < volume_table.size(); ++i) { const int64_t n = volume_table[i].get(1); emplace_back(volume_table[i].get(0), oid, n); oid += n; } } int64_t records() const { return empty() ? 0 : back().oid_end(); } std::pair::const_iterator, std::vector::const_iterator> find(int64_t oid_begin, int64_t oid_end) const { auto it = std::lower_bound(begin(), end(), oid_begin); if (it == end()) throw std::runtime_error("OID out of bounds"); auto end = it + 1; while (end < this->end() && end->oid_begin < oid_end) ++end; return { it,end }; } void remove() const { for (const Volume& v : *this) ::remove(v.path.c_str()); ::remove(list_file_.c_str()); rmdir(path(list_file_).c_str()); } private: const std::string list_file_; }; inline std::vector read_list(const std::string& file_name) { std::vector v; Util::Tsv::File file({ Util::Tsv::Type::STRING }, file_name); const Util::Tsv::Table table = file.read(config.threads_); v.reserve(table.size()); for (int64_t i = 0; i < table.size(); ++i) { v.push_back(table[i].get(0)); } return v; } template struct InputBuffer { InputBuffer(const VolumedFile& f, int parts = config.threads_): size_(f.records()), data_(new T[size_]), part_(size_, parts) { std::atomic next(0); auto worker = [&]() { int64_t v; while (v = next.fetch_add(1, std::memory_order_relaxed), v < (int64_t)f.size()) { InputFile in(f[v].path); in.read(&data_[f[v].oid_begin], f[v].record_count); in.close(); } }; std::vector t; for (int i = 0; i < std::min(config.threads_, (int)f.size()); ++i) t.emplace_back(worker); for (auto& i : t) i.join(); } int64_t size() const { return size_; } int64_t byte_size() const { return size_ * sizeof(T); } T* begin() { return data_.get(); } T* end() { return data_.get() + size_; } const T* end() const { return data_.get() + size_; } const T* begin(int part) const { const T* begin = data_.get() + part_.begin(part), * end = this->end(); if (part > 0) while (begin < end && begin[-1].key() == begin[0].key()) ++begin; return begin; } const T* end(int part) const { const T* ptr = data_.get() + part_.end(part), *end = this->end(); while (ptr < end && ptr[-1].key() == ptr[0].key()) ++ptr; return ptr; } int64_t parts() const { return part_.parts; } const T& front() const { return data_[0]; } const T& back() const { return data_[size_ - 1]; } private: const int64_t size_; std::unique_ptr data_; const Partition part_; }; struct ChunkSeqs { ChunkSeqs(const std::string& chunk_path): seq_file_(chunk_path + "bucket.tsv"), oid_count_(0), letter_count_(0) { std::atomic next(0); seq_blocks_.resize(seq_file_.size()); oid2seq_.resize(seq_file_.size()); oid_range_.resize(seq_file_.size()); //std::mutex mtx; auto worker = [&]() { int i; while (i = next.fetch_add(1, std::memory_order_relaxed), i < (int)seq_file_.size()) { std::unique_ptr in(SequenceFile::auto_create({ seq_file_[i].path })); seq_blocks_[i] = in->load_seqs(INT64_MAX); in->close(); Block& b = *seq_blocks_[i]; const StringSet& ids = b.ids(); const SequenceSet& seqs = b.seqs(); const BlockId n = ids.size(); std::unordered_map& m = *(oid2seq_[i] = new std::unordered_map()); m.reserve(n); int64_t oid_min = INT64_MAX, oid_max = INT64_MIN; for (BlockId j = 0; j < n; ++j) { const int64_t oid = std::atoll(ids[j]); oid_min = std::min(oid_min, oid); oid_max = std::max(oid_max, oid); m[oid] = seqs[j]; } { //std::lock_guard lock(mtx); //range2block_.insert(std::make_pair(std::pair(oid_min, oid_max), i)); oid_range_[i] = { oid_min, oid_max }; } } }; std::vector workers; for (int i = 0; i < std::min(config.threads_, int(seq_file_.size())); ++i) workers.emplace_back(worker); for (auto& t : workers) t.join(); int64_t oid_count = 0, letter_count = 0; for (const Block* b : seq_blocks_) { oid_count_ += b->seqs().size(); letter_count_ += b->seqs().letters(); } } ~ChunkSeqs() { std::vector workers; std::atomic next(0); auto worker = [&]() { int i; while(i = next.fetch_add(1, std::memory_order_relaxed), i < (int)seq_blocks_.size()) { delete seq_blocks_[i]; delete oid2seq_[i]; } }; for (int i = 0; i < std::min(config.threads_, int(seq_blocks_.size())); ++i) workers.emplace_back(worker); for (auto& t : workers) t.join(); seq_file_.remove(); } int64_t oids() const { return oid_count_; } int64_t letters() const { return letter_count_; } int64_t volumes() const { return seq_blocks_.size(); } Sequence operator[](int64_t oid) const { //const auto r = range2block_.equal_range(std::make_pair(oid, oid)); //for (auto i = r.first; i != r.second; ++i) { for (int i = 0; i < (int)oid_range_.size(); ++i) { if (oid < oid_range_[i].first || oid > oid_range_[i].second) continue; std::unordered_map::const_iterator it; if ((it = oid2seq_[i]->find(oid)) != oid2seq_[i]->end()) return it->second; } throw std::out_of_range("ChunkSeqs"); } private: /*struct CmpRange { bool operator()(const std::pair& a, const std::pair& b) const { return a.second < b.first; } };*/ VolumedFile seq_file_; int64_t oid_count_, letter_count_; std::vector seq_blocks_; //std::multimap, int, ChunkSeqs::CmpRange> range2block_; std::vector> oid_range_; std::vector*> oid2seq_; }; std::vector align(Job& job, int chunk_count, int64_t db_size); std::string cluster(Job& job, const std::vector& edges, const VolumedFile& volumes); std::string cluster_bidirectional(Job& job, const std::vector& edges, const VolumedFile& volumes); void output(Job& job); }bbuchfink-diamond-08b3cbc/src/cluster/external/output.cpp000066400000000000000000000077731506104011400237100ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #include #include "external.h" using std::vector; using std::unordered_map; namespace Cluster { static vector read_clustering(Job& job, int round) { vector v(job.input_count(round)); vector::iterator it = v.begin(); for (int i = 0; i < job.volume_count(round); ++i) { InputFile in(job.base_dir(round) + PATH_SEPARATOR + "clustering" + PATH_SEPARATOR + "volume" + std::to_string(i), InputFile::NO_AUTODETECT); const int64_t n = in.file_size() / sizeof(int64_t); in.read(&(*it), n); it += n; in.close(); } return v; } void output(Job& job) { job.log("Generating output"); vector inner = read_clustering(job, job.round()); for (int round = job.round() - 1; round >= 0; --round) { VolumedFile reps(job.base_dir(round) + PATH_SEPARATOR + "reps" + PATH_SEPARATOR + "0" + PATH_SEPARATOR + "bucket.tsv"); vector inner_to_outer(reps.records()); vector::iterator it = inner_to_outer.begin(); for (int i = 0; i < (int)reps.size(); ++i) { InputFile f(reps[i].path + ".oid"); f.read(&(*it), reps[i].record_count); it += reps[i].record_count; f.close(); } unordered_map outer_to_inner; outer_to_inner.reserve(inner_to_outer.size()); for (int64_t i = 0; i < (int64_t)inner_to_outer.size(); ++i) outer_to_inner[inner_to_outer[i]] = i; vector outer = read_clustering(job, round); for (int64_t i = 0; i < (int64_t)outer.size(); ++i) outer[i] = inner_to_outer[inner[outer_to_inner.at(outer[i])]]; inner = std::move(outer); } FILE* out = fopen(config.output_file.c_str(), "wt"); if (!out) throw std::runtime_error("Error opening file: " + config.output_file); int64_t n = 0; for (int64_t i = 0; i < (int64_t)inner.size(); ++i) { if (inner[i] == i) ++n; fprintf(out, "%" PRId64 "\t%" PRId64 "\n", inner[i], i); } fclose(out); job.log("Cluster count = %lli", n); for (int i = 0; i < job.volume_count(job.round()); ++i) remove((job.base_dir(job.round()) + PATH_SEPARATOR + "clustering" + PATH_SEPARATOR + "volume" + std::to_string(i)).c_str()); for (int round = job.round() - 1; round >= 0; --round) { VolumedFile reps(job.base_dir(round) + PATH_SEPARATOR + "reps" + PATH_SEPARATOR + "0" + PATH_SEPARATOR + "bucket.tsv"); for (int i = 0; i < (int)reps.size(); ++i) remove((reps[i].path + ".oid").c_str()); reps.remove(); for (int i = 0; i < job.volume_count(round); ++i) remove((job.base_dir(round) + PATH_SEPARATOR + "clustering" + PATH_SEPARATOR + "volume" + std::to_string(i)).c_str()); } } }bbuchfink-diamond-08b3cbc/src/cluster/external/radix_sort.h000066400000000000000000000106561506104011400241650ustar00rootroot00000000000000/**** Copyright Š 2013-2025 Benjamin J. Buchfink Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****/ // SPDX-License-Identifier: BSD-3-Clause #pragma once #include #include "external.h" #include "util/io/input_file.h" #include "util/log_stream.h" #include "util/parallel/atomic.h" #include "util/string/string.h" namespace Cluster { template std::vector radix_cluster(Job& job, const VolumedFile& bucket, const std::string& output_dir, int bits_unsorted) { const int64_t BUF_SIZE = 4096; const uint64_t shift = bits_unsorted - RADIX_BITS; std::unique_ptr output_files(new FileArray(output_dir, RADIX_COUNT, job.worker_id())); std::atomic next(0); std::vector workers; auto worker = [&](int thread_id) { BufferArray buffers(*output_files, RADIX_COUNT); int64_t v = 0; while (v = next.fetch_add(1, std::memory_order_relaxed), v < (int64_t)bucket.size()) { InputFile in(bucket[v].path); const int64_t n = bucket[v].record_count; std::unique_ptr data(new T[n]); in.read(data.get(), n); in.close(); const T* end = data.get() + n; for (const T* ptr = data.get(); ptr < end; ++ptr) { const uint64_t radix = (ptr->key() >> shift) & (RADIX_COUNT - 1); buffers.write(radix, *ptr); } } }; for (int i = 0; i < std::min(config.threads_, (int)bucket.size()); ++i) workers.emplace_back(worker, i); for (auto& t : workers) t.join(); std::vector buckets; buckets.reserve(RADIX_COUNT); for (int i = 0; i < RADIX_COUNT; ++i) buckets.push_back(output_files->bucket(i)); TaskTimer timer("Closing the output files"); output_files.reset(); timer.finish(); job.log("Radix sorted bucket records=%zu", bucket.records()); return buckets; } template std::vector radix_sort(Job& job, const std::vector& buckets, int bits_unsorted) { const std::string base_path = Cluster::base_path(buckets.front()), queue_path = base_path + PATH_SEPARATOR + "radix_sort_queue", result_path = base_path + PATH_SEPARATOR + "radix_sort_out"; const int64_t size_limit = Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)); Atomic queue(queue_path); FileStack out(result_path); int64_t i, buckets_processed = 0; while (i = queue.fetch_add(), i < (int64_t)buckets.size()) { VolumedFile bucket(buckets[i]); const int64_t data_size = bucket.records() * sizeof(T); job.log("Radix sorting. Bucket=%lli/%lli Records=%s Size=%s", i + 1, buckets.size(), Util::String::format(bucket.records()).c_str(), Util::String::format(data_size).c_str()); if (data_size > size_limit) { const std::vector v = radix_cluster(job, bucket, path(buckets[i]), bits_unsorted); out.lock(); for (const std::string& s : v) out.push_non_locked(s); out.unlock(); } else if (bucket.records() > 0) out.push(buckets[i]); else bucket.remove(); ++buckets_processed; } Atomic finished(base_path + PATH_SEPARATOR + "radix_sort_finished"); finished.fetch_add(buckets_processed); finished.await(buckets.size()); return read_list(result_path); } }bbuchfink-diamond-08b3cbc/src/cluster/helpers.cpp000066400000000000000000000242601506104011400221560ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "cluster.h" #include "util/tsv/tsv.h" #include "util/string/tokenizer.h" #include "basic/config.h" #include "util/log_stream.h" const char* const HEADER_LINE = "centroid\tmember"; using std::pair; using std::endl; using std::vector; using std::ofstream; using std::ostream; using std::runtime_error; using std::string; using std::for_each; using std::floor; using std::unique_ptr; using std::back_inserter; using std::less; using std::stringstream; using namespace Util::Tsv; namespace Cluster { template pair, vector> read(const string& file_name, const SequenceFile& db, CentroidSorted) { const int64_t lines = Util::Tsv::count_lines(file_name); TextInputFile in(file_name); string centroid, member; vector> pairs; pairs.reserve(lines); int64_t mappings = 0; if (TabularFormat::header_format(::Config::cluster) == Header::SIMPLE) { in.getline(); if (in.line != HEADER_LINE) throw runtime_error("Clusters file is missing header line."); } while (in.getline(), !in.eof() || !in.line.empty()) { Util::String::Tokenizer(in.line, Util::String::CharDelimiter('\t')) >> centroid >> member; const Int centroid_oid = (Int)db.accession_to_oid(centroid).front(); const Int member_oid = (Int)db.accession_to_oid(member).front(); pairs.emplace_back(centroid_oid, member_oid); ++mappings; if (mappings % 1000000 == 0) log_stream << "#Entries: " << mappings << endl; } in.close(); return make_flat_array(pairs.begin(), pairs.end(), config.threads_); } template pair, vector> read(const string&, const SequenceFile&, CentroidSorted); template pair, vector> read(const string&, const SequenceFile&, CentroidSorted); template vector read(const string& file_name, const SequenceFile& db) { const int64_t lines = Util::Tsv::count_lines(file_name); TextInputFile in(file_name); string centroid, member; vector v(db.sequence_count()); int64_t mappings = 0; if (TabularFormat::header_format(::Config::cluster) == Header::SIMPLE) { in.getline(); if (in.line != HEADER_LINE) throw runtime_error("Clustering input file is missing header line."); } while (in.getline(), !in.eof() || !in.line.empty()) { Util::String::Tokenizer(in.line, Util::String::CharDelimiter('\t')) >> centroid >> member; const auto centroid_oid = db.accession_to_oid(centroid); const auto member_oid = db.accession_to_oid(member); v[member_oid.front()] = (Int)centroid_oid.front(); ++mappings; if (mappings % 1000000 == 0) log_stream << "#Entries: " << mappings << endl; } in.close(); if (mappings != db.sequence_count()) throw runtime_error("Invalid/incomplete clustering."); return v; } template vector read(const string&, const SequenceFile&); template vector read(const string&, const SequenceFile&); template vector member2centroid_mapping(const FlatArray& clusters, const vector& centroids) { vector v(clusters.data_size()); for (Int i = 0; i < (Int)centroids.size(); ++i) { for (Int j : clusters[i]) v[j] = centroids[i]; } return v; } template vector member2centroid_mapping(const FlatArray&, const vector&); template pair, vector> cluster_sorted(const vector& mapping) { vector> pairs; pairs.reserve(mapping.size()); for (typename vector::const_iterator i = mapping.begin(); i < mapping.end(); ++i) pairs.emplace_back(*i, Int(i - mapping.begin())); return make_flat_array(pairs.begin(), pairs.end(), config.threads_); } template pair, vector> cluster_sorted(const vector&); template pair, vector> cluster_sorted(const vector&); void output(File& out, SequenceFile& db, File& oid_to_centroid_oid) { unique_ptr sorted1(oid_to_centroid_oid.sort(1, config.threads_)); unique_ptr joined1(join(*sorted1, db.seqid_file(), 1, 0, { {0,0},{1,1} })); sorted1.reset(); unique_ptr sorted2(joined1->sort(0, config.threads_)); join(*sorted2, db.seqid_file(), 0, 0, { {1,1}, {0,1} }, out); } template void output_mem(File& out, SequenceFile& db, const FlatArray& clusters, const vector& centroids) { if (config.oid_output) { for (Int i = 0; i < (Int)centroids.size(); ++i) { const string centroid = std::to_string(centroids[i]); for (auto j = clusters.cbegin(i); j != clusters.cend(i); ++j) out.write_record(centroid, std::to_string(*j)); } } else { const Util::Tsv::Table acc_mapping = db.seqid_file().read(config.threads_); for (Int i = 0; i < (Int)centroids.size(); ++i) { const string centroid = acc_mapping[centroids[i]].template get(0); for (auto j = clusters.cbegin(i); j != clusters.cend(i); ++j) out.write_record(centroid, acc_mapping[*j].template get(0)); } } } template void output_mem(File&, SequenceFile&, const FlatArray&, const vector&); template void output_mem(File&, SequenceFile&, const FlatArray&, const vector&); template void output_mem(File& out, SequenceFile& db, const vector& mapping) { vector centroids; FlatArray clusters; tie(clusters, centroids) = cluster_sorted(mapping); output_mem(out, db, clusters, centroids); } template void output_mem(File&, SequenceFile&, const vector&); template void output_mem(File&, SequenceFile&, const vector&); template void output_mem(File& out, SequenceFile& db, File& oid_to_centroid_oid) { vector> centroid_oid; oid_to_centroid_oid.template read(back_inserter(centroid_oid)); vector centroids; FlatArray clusters; tie(clusters, centroids) = make_flat_array(centroid_oid.begin(), centroid_oid.end(), config.threads_); output_mem(out, db, clusters, centroids); } void output_mem(File& out, SequenceFile& db, File& oid_to_centroid_oid) { if (db.sequence_count() > (int64_t)INT32_MAX) output_mem(out, db, oid_to_centroid_oid); else output_mem(out, db, oid_to_centroid_oid); } template pair, vector> split(const vector& mapping) { pair, vector> r; r.second.reserve(mapping.size()); for (Int i = 0; i < (Int)mapping.size(); ++i) if (mapping[i] == i) r.first.push_back(i); else r.second.push_back(i); return r; } template pair, vector> split(const vector&); template pair, vector> split(const vector&); vector member_counts(const vector& mapping) { vector v(mapping.size(), 0); for (SuperBlockId c : mapping) ++v[c]; return v; } void init_thresholds() { if (config.member_cover.present() && config.mutual_cover.present()) throw runtime_error("--member-cover and --mutual-cover are mutually exclusive."); if (!config.mutual_cover.present()) config.member_cover.set_if_blank(DEFAULT_MEMBER_COVER); if (!config.approx_min_id.present()) config.approx_min_id = config.command == ::Config::DEEPCLUST ? 0.0 : (config.command == ::Config::LINCLUST ? 90.0 : 50.0); if (config.soft_masking.empty()) config.soft_masking = "tantan"; if (!config.masking_.present()) config.masking_ = "0"; if (config.approx_min_id < 90.0 || config.mutual_cover.present()) return; config.diag_filter_id.set_if_blank(config.approx_min_id - (config.command == ::Config::CLUSTER_REASSIGN ? 10.0 : 10.0)); if (config.approx_min_id < 90.0) return; if(config.command == ::Config::CLUSTER_REASSIGN) { config.diag_filter_cov.set_if_blank(config.member_cover > 50.0 ? config.member_cover - 10.0 : 0.0); } else { config.diag_filter_cov.set_if_blank(config.member_cover > 50.0 ? config.member_cover - 10.0 : 0.0); } } File* open_out_tsv() { File* file = new File(Schema{ Type::STRING, Type::STRING }, config.output_file, Flags::WRITE); if (TabularFormat::header_format(::Config::cluster) == Header::SIMPLE) file->write_record("centroid", "member"); return file; } vector len_sorted_clust(const FlatArray>& edges) { vector v(edges.size(), -1); for (int64_t i = 0; i < edges.size(); ++i) { if (v[i] != -1) continue; v[i] = (BlockId)i; for (auto it = edges.cbegin(i); it != edges.cend(i); ++it) if (v[it->node2] == -1) v[it->node2] = (BlockId)i; } return v; } void output_edges(const string& file, SequenceFile& db, const vector>& edges) { File out(Schema{ Type::STRING, Type::STRING }, file, Flags::WRITE); const Util::Tsv::Table acc_mapping = db.seqid_file().read(config.threads_); for (const auto& e : edges) { out.write_record(acc_mapping[e.node1].get(0), acc_mapping[e.node2].get(0)); } } double round_value(const vector& par, const string& name, int round, int round_count) { if (par.empty()) return 0.0; if (round >= round_count - 1) return 0.0; if ((int64_t)par.size() >= round_count) throw runtime_error("Too many values provided for " + name); vector v; for(const string& s : par) { stringstream ss(s); double i; ss >> i; if (ss.fail() || !ss.eof()) throw runtime_error("Invalid value provided for " + name + ": " + s); v.push_back(i); } v.insert(v.begin(), round_count - 1 - v.size(), v.front()); return v[round]; } }bbuchfink-diamond-08b3cbc/src/cluster/output.cpp000066400000000000000000000151221506104011400220510ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "cluster.h" #include "util/parallel/thread_pool.h" #include "util/algo/merge_files.h" #include "dp/dp.h" #include "stats/hauser_correction.h" #include "output/output.h" using std::vector; using std::unique_ptr; using std::endl; using std::to_string; using std::mutex; using std::lock_guard; using std::thread; using std::make_pair; using std::list; using std::lower_bound; using std::atomic; using std::shared_ptr; using std::function; using std::string; namespace Cluster { struct Cfg { Cfg(HspValues hsp_values, bool lazy_titles, const FlatArray& clusters, const vector& centroids, SequenceFile& db): hsp_values(hsp_values), lazy_titles(lazy_titles), clusters(clusters), centroids(centroids), db(db) {} const HspValues hsp_values; const bool lazy_titles; const FlatArray& clusters; const vector& centroids; SequenceFile& db; shared_ptr centroid_block, member_block; }; static void align_centroid(CentroidId centroid, ReorderQueue& out, Statistics& stats, ThreadPool& tp, Cfg& cfg) { DP::Targets dp_targets; const OId centroid_oid = cfg.centroids[centroid]; const BlockId centroid_id = cfg.centroid_block->oid2block_id(centroid_oid); const Sequence centroid_seq = cfg.centroid_block->seqs()[centroid_id]; auto begin = lower_bound(cfg.clusters.cbegin(centroid), cfg.clusters.cend(centroid), cfg.member_block->oid_begin()); auto end = lower_bound(cfg.clusters.cbegin(centroid), cfg.clusters.cend(centroid), cfg.member_block->oid_end()); for (auto it = begin; it != end; ++it) { const BlockId block_id = cfg.member_block->oid2block_id(*it); const Sequence seq(cfg.member_block->seqs()[block_id]); const int bin = DP::BandedSwipe::bin(cfg.hsp_values, centroid_seq.length(), 0, 0, (int64_t)seq.length() * (int64_t)centroid_seq.length(), 0, 0); dp_targets[bin].emplace_back(seq, seq.length(), block_id); } const HauserCorrection cbs(centroid_seq); const string centroid_seqid = cfg.lazy_titles ? cfg.db.seqid(centroid_oid) : cfg.centroid_block->ids()[centroid_id]; DP::Params p{ centroid_seq, centroid_seqid.c_str(), Frame(0), centroid_seq.length(), config.comp_based_stats == 1 ? cbs.int8.data() : nullptr, DP::Flags::FULL_MATRIX, false, 0, 0, cfg.hsp_values, stats, &tp }; list hsps = DP::BandedSwipe::swipe(dp_targets, p); TextBuffer* buf = new TextBuffer; for (Hsp& hsp : hsps) { serialize(HspContext(hsp, centroid_id, centroid_oid, TranslatedSequence(centroid_seq), centroid_seqid.c_str(), cfg.member_block->block_id2oid(hsp.swipe_target), cfg.member_block->seqs().length(hsp.swipe_target), cfg.lazy_titles ? cfg.db.seqid(cfg.member_block->block_id2oid(hsp.swipe_target)).c_str() : cfg.member_block->ids()[hsp.swipe_target], 0, 0, Sequence()), *buf); } out.push(centroid, buf); } static InputFile* run_block_pair(CentroidId begin, CentroidId end, Cfg& cfg) { TempFile out; OutputWriter writer{ &out }; output_sink.reset(new ReorderQueue(begin, writer)); auto worker = [&](ThreadPool& tp, int64_t i) { Statistics stats; align_centroid(i, *output_sink, stats, tp, cfg); statistics += stats; }; ThreadPool tp(worker, begin, end); tp.run(config.threads_, true); tp.join(); InputFile* f = new InputFile(out); return f; } void realign(const FlatArray& clusters, const vector& centroids, SequenceFile& db, function& callback, HspValues hsp_values) { const int64_t block_size = Util::String::interpret_number(config.memory_limit.get(DEFAULT_MEMORY_LIMIT)) / 2; message_stream << "Block size: " << block_size << " byte." << endl; db.set_seqinfo_ptr(0); score_matrix.set_db_letters(config.db_size ? config.db_size : db.letters()); OId centroid_offset = 0; int n1 = 0; TaskTimer timer; Cfg cfg{ hsp_values, flag_any(db.format_flags(), SequenceFile::FormatFlags::TITLES_LAZY), clusters, centroids, db }; SequenceFile::LoadFlags flags = SequenceFile::LoadFlags::SEQS | SequenceFile::LoadFlags::CONVERT_ALPHABET; if (!cfg.lazy_titles) flags |= SequenceFile::LoadFlags::TITLES; while (centroid_offset < db.sequence_count()) { timer.go("Loading centroid block"); db.set_seqinfo_ptr(centroid_offset); cfg.centroid_block.reset(db.load_seqs(block_size, nullptr, flags)); centroid_offset = db.tell_seq(); db.set_seqinfo_ptr(0); int n2 = 0; const CentroidId begin = lower_bound(centroids.cbegin(), centroids.cend(), cfg.centroid_block->oid_begin()) - centroids.cbegin(), end = lower_bound(centroids.cbegin(), centroids.cend(), cfg.centroid_block->oid_end()) - centroids.cbegin(); timer.finish(); log_stream << "Total centroids = " << end - begin << endl; vector tmp; for (;;) { if (cfg.centroid_block->seqs().size() == db.sequence_count()) cfg.member_block = cfg.centroid_block; else { timer.go("Loading member block"); cfg.member_block.reset(db.load_seqs(block_size, nullptr, flags)); } if (cfg.member_block->empty()) break; timer.go("Processing centroid block " + to_string(n1 + 1) + ", member block " + to_string(n2 + 1)); tmp.push_back(run_block_pair(begin, end, cfg)); ++n2; if (cfg.centroid_block->seqs().size() == db.sequence_count()) break; } timer.go("Joining centroid block " + to_string(n1 + 1)); merge_sorted_files::iterator, decltype(callback)>(tmp.begin(), tmp.end(), callback); for (InputFile* f : tmp) { f->close_and_delete(); delete f; } ++n1; } timer.finish(); statistics.print(); } void realign(const vector& clustering, SequenceFile& db, function& callback, HspValues hsp_values) { TaskTimer timer("Finding clusters"); FlatArray clusters; vector centroids; tie(clusters, centroids) = cluster_sorted(clustering); timer.finish(); realign(clusters, centroids, db, callback, hsp_values); } }bbuchfink-diamond-08b3cbc/src/cluster/realign.cpp000066400000000000000000000066541506104011400221440ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "basic/config.h" #include "util/log_stream.h" #include "data/sequence_file.h" #include "cluster.h" #include "basic/match.h" #include "output/output_format.h" using std::endl; using std::vector; using std::unique_ptr; using std::function; using std::runtime_error; using std::string; static const vector DEFAULT_FORMAT = { "6", "qseqid", "sseqid", "approx_pident", "qstart", "qend", "sstart", "send", "evalue", "bitscore" }; namespace Cluster { void realign() { config.database.require(); config.clustering.require(); if (config.output_format.empty()) config.output_format = DEFAULT_FORMAT; unique_ptr output_format(get_output_format()); if (output_format->code != OutputFormat::blast_tab) throw runtime_error("The realign workflow only supports tabular output format."); for (int64_t i : dynamic_cast(output_format.get())->fields) { if (i == 6 || i == 17 || i == 18 || (i >= 30 && i <= 38) || i == 48 || i == 54 || i == 55 || i == 56 || i == 58 || i == 59 || i == 60) throw std::runtime_error("Unsupported output field for the realign workflow: " + TabularFormat::field_def.at(i).key); } TaskTimer timer("Opening the output file"); OutputFile out(config.output_file); if (TabularFormat::header_format(Config::cluster) == Header::SIMPLE) dynamic_cast(output_format.get())->output_header(out, true); timer.go("Opening the database"); unique_ptr db(SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NEED_LETTER_COUNT | SequenceFile::Flags::ACC_TO_OID_MAPPING, SequenceFile::Metadata())); score_matrix.set_db_letters(config.db_size ? config.db_size : db->letters()); config.max_evalue = DBL_MAX; timer.finish(); message_stream << "#Database sequences: " << db->sequence_count() << ", #Letters: " << db->letters() << endl; if (flag_any(db->format_flags(), SequenceFile::FormatFlags::TITLES_LAZY)) db->init_random_access(0, 0, false); FlatArray clusters; vector centroids; tie(clusters, centroids) = read(config.clustering, *db, CentroidSorted()); message_stream << "Found " << centroids.size() << " centroids, " << clusters.data_size() << " mappings in input file." << endl; TextBuffer buf; function format_output([&buf, &out, &output_format](const HspContext& h) { Output::Info info{ SeqInfo(), false, nullptr, buf, Util::Seq::AccessionParsing(), 0, 0 }; info.query.title = h.query_title.c_str(); output_format->print_match(h, info); out.write(buf.data(), buf.size()); buf.clear(); }); realign(clusters, centroids, *db, format_output, output_format->hsp_values); timer.go("Freeing memory"); db->close(); out.close(); } }bbuchfink-diamond-08b3cbc/src/cluster/reassign.cpp000066400000000000000000000066441506104011400223350ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022-2023 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "basic/config.h" #include "util/log_stream.h" #include "cluster.h" #include "basic/statistics.h" #include "run/workflow.h" #include "data/fasta/fasta_file.h" #include "cascaded/cascaded.h" using std::endl; using std::shared_ptr; using std::for_each; using std::vector; using std::tie; using std::make_shared; using std::unique_ptr; namespace Cluster { void reassign() { config.database.require(); config.clustering.require(); init_thresholds(); message_stream << "Coverage cutoff: " << (config.mutual_cover.present() ? config.mutual_cover.get_present() : config.member_cover) << '%' << endl; TaskTimer timer("Opening the database"); shared_ptr db(SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NEED_LETTER_COUNT | SequenceFile::Flags::ACC_TO_OID_MAPPING | SequenceFile::Flags::OID_TO_ACC_MAPPING, SequenceFile::Metadata())); config.db_size = db->letters(); timer.finish(); message_stream << "#Database sequences: " << db->sequence_count() << ", #Letters: " << db->letters() << endl; unique_ptr out(open_out_tsv()); timer.go("Reading the input file"); vector clustering = read(config.clustering, *db); timer.go("Finding centroids"); vector centroids, members; tie(centroids, members) = split(clustering); timer.go("Creating member database"); shared_ptr member_db(db->sub_db(members.cbegin(), members.cend())); member_db->set_seqinfo_ptr(0); timer.go("Creating centroid database"); shared_ptr centroid_db(db->sub_db(centroids.cbegin(), centroids.cend())); centroid_db->set_seqinfo_ptr(0); timer.finish(); statistics.reset(); config.command = Config::blastp; config.max_target_seqs_ = 1; config.output_format = { "edge" }; config.self = false; if (config.mutual_cover.present()) config.query_cover = config.subject_cover = config.mutual_cover.get_present(); else { config.query_cover = config.member_cover; config.subject_cover = 0; } config.sensitivity = from_string(cluster_steps(config.approx_min_id, false).back()); shared_ptr mapback = make_shared(members.size()); Search::run(centroid_db, member_db, mapback); timer.go("Updating clustering"); const int64_t n = update_clustering(clustering.begin(), mapback->centroid_id.cbegin(), members.cbegin(), members.cend(), centroids.cbegin()); timer.finish(); message_stream << "Reassigned members: " << n << '/' << members.size() << endl; timer.go("Generating output"); if (flag_any(db->format_flags(), SequenceFile::FormatFlags::TITLES_LAZY)) db->init_random_access(0, 0, false); output_mem(*out, *db, clustering); timer.go("Closing the database"); db.reset(); } }bbuchfink-diamond-08b3cbc/src/compile-osx.sh000077500000000000000000000034121506104011400211210ustar00rootroot00000000000000#!/bin/bash -e CPUS=$(sysctl -n hw.ncpu) export CFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.15" export CXXFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.15" export MACOSX_DEPLOYMENT_TARGET=10.15 git clone https://github.com/facebook/zstd.git cd zstd make -j $CPUS cd .. git clone https://github.com/ncbi/ncbi-cxx-toolkit-public.git cd ncbi-cxx-toolkit-public ./cmake-configure --without-debug --with-projects="objtools/blast/seqdb_reader;objtools/blast/blastdb_format" --with-build-root=build cd build/build make -j $CPUS cd .. cp inc/ncbiconf_unix.h ../include cd ../.. mkdir build_x86 cd build_x86 export CFLAGS="-arch x86_64 -mmacosx-version-min=10.15" export CXXFLAGS="-arch x86_64 -mmacosx-version-min=10.15" cmake -DCMAKE_BUILD_TYPE=Release \ -DBLAST_INCLUDE_DIR=src/ncbi-cxx-toolkit-public/include \ -DBLAST_LIBRARY_DIR=src/ncbi-cxx-toolkit-public/build/lib \ -DZSTD_LIBRARY="../zstd/lib/libzstd.a" \ -DZSTD_INCLUDE_DIR=src/zstd/lib/ \ -DCROSS_COMPILE=ON \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DWITH_ZSTD=ON -DX86=ON -DARM=OFF -DAARCH64=OFF ../.. make -j $CPUS cd .. mkdir build_arm cd build_arm export CFLAGS="-arch arm64 -mmacosx-version-min=11.0" export CXXFLAGS="-arch arm64 -mmacosx-version-min=11.0" export MACOSX_DEPLOYMENT_TARGET=11.0 cmake -DCMAKE_BUILD_TYPE=Release \ -DBLAST_INCLUDE_DIR=src/ncbi-cxx-toolkit-public/include \ -DBLAST_LIBRARY_DIR=src/ncbi-cxx-toolkit-public/build/lib \ -DZSTD_LIBRARY="../zstd/lib/libzstd.a" \ -DZSTD_INCLUDE_DIR=src/zstd/lib/ \ -DCROSS_COMPILE=ON \ -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DWITH_ZSTD=ON -DX86=OFF -DARM=ON ../.. make -j $CPUS cd .. lipo \ -create \ -arch x86_64 "build_x86/diamond" \ -arch arm64 "build_arm/diamond" \ -output "diamond" bbuchfink-diamond-08b3cbc/src/contrib/000077500000000000000000000000001506104011400177635ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/contrib/dna/000077500000000000000000000000001506104011400205255ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/contrib/dna/alignment.cpp000066400000000000000000000245731506104011400232220ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "alignment.h" #include "../lib/ksw2/ksw2.h" #include "seed_set_dna.h" #include "../util/util.h" #include "bindings/cpp/WFAligner.hpp" #include "timer.h" #include "chain.h" #include "extension_chain.h" #include "../align/target.h" namespace Dna { AlignmentStatus compute_ksw_cigar(const Sequence &targetSequence, const Sequence &querySequence, const Search::Config &cfg, int flag, Cigar &extension, const int zdrop, const int band) { int a = cfg.score_builder->reward(), b = cfg.score_builder->penalty() < 0 ? cfg.score_builder->penalty() : -cfg.score_builder->penalty(); // a>0 and b<0 int8_t mat[NUCLEOTIDE_COUNT * NUCLEOTIDE_COUNT] = {static_cast(a), static_cast(b), static_cast(b), static_cast(b), 0, static_cast(b), static_cast(a), static_cast(b), static_cast(b), 0, static_cast(b), static_cast(b), static_cast(a), static_cast(b), 0, static_cast(b), static_cast(b), static_cast(b), static_cast(a), 0, 0, 0, 0, 0, 0}; ksw_extz_t ez; memset(&ez, 0, sizeof(ksw_extz_t)); #ifdef __APPLE__ ksw_extz(nullptr, querySequence.length(), reinterpret_cast(querySequence.data()), targetSequence.length(), reinterpret_cast(targetSequence.data()), NUCLEOTIDE_COUNT, mat, (int8_t) cfg.score_builder->gap_open(), (int8_t) cfg.score_builder->gap_extend(), band, //config.padding zdrop, flag, &ez); #else ksw_extz2_sse(nullptr, querySequence.length(), reinterpret_cast(querySequence.data()), targetSequence.length(), reinterpret_cast(targetSequence.data()), NUCLEOTIDE_COUNT, mat, (int8_t) cfg.score_builder->gap_open(), (int8_t) cfg.score_builder->gap_extend(), band, zdrop, KSW2_END_BONUS, flag, &ez); #endif // ez.max is extension (peak) score, ez.score is global alignment score const auto alignment_status = static_cast(ez.zdropped); if (flag == KSW_FLAG_L || flag == KSW_FLAG_R || alignment_status == DROPPED) { extension.score += ez.max; } else { extension.score += ez.score; } if (flag == KSW_FLAG_L) extension.setMaxValues(ez.max_q, ez.max_t); else if (extension.score < 1) { return NEGATIVE_SCORE; } for (int i = 0; i < ez.n_cigar; ++i) extension.extendCigar(ez.cigar[i] >> 4, "MID"[ez.cigar[i] & 0xf]); free(ez.cigar); return alignment_status; } std::pair compute_wfa_extension(const std::string &querySequence, const std::string &targetSequence, const int band) { thread_local std::unique_ptr aligner_extension; if (!aligner_extension) { aligner_extension.reset(new wfa::WFAlignerGapAffine(0, -config.mismatch_penalty, config.gap_open, config.gap_extend, wfa::WFAligner::Alignment)); aligner_extension->setHeuristicNone(); aligner_extension->setHeuristicWFadaptive(10,50,1); //aligner_extension->setHeuristicZDrop(WFA_ZDROP_EXTENSION, WFA_CUTOFF_STEPS); aligner_extension->setHeuristicXDrop(100, 1); //aligner_extension->setHeuristicBandedAdaptive(-band,band,1); } aligner_extension->alignExtension(targetSequence.c_str(), targetSequence.length(), querySequence.c_str(), querySequence.length()); return std::make_pair(static_cast(aligner_extension->getAlignmentStatus()), aligner_extension->getCIGAR(true)); } std::pair compute_wfa_global(const std::string &querySequence, const std::string &targetSequence, int band) { band = std::min(band, WFA_BAND_EXTENSION); thread_local std::unique_ptr aligner_global; if (!aligner_global) { aligner_global.reset(new wfa::WFAlignerGapAffine(0, -config.mismatch_penalty, config.gap_open, config.gap_extend, wfa::WFAligner::Alignment)); aligner_global->setHeuristicNone(); aligner_global->setHeuristicWFadaptive(10,50,1); //aligner_global->setHeuristicZDrop(WFA_ZDROP_GLOBAL, WFA_CUTOFF_STEPS); aligner_global->setHeuristicXDrop(100, 1); //aligner_global->setHeuristicBandedAdaptive(-band,band,1); } aligner_global->alignEnd2End(targetSequence.c_str(), targetSequence.length(), querySequence.c_str(), querySequence.length()); return std::make_pair(static_cast(aligner_global->getAlignmentStatus()), aligner_global->getCIGAR(true)); } AlignmentStatus compute_wfa_cigar(const Search::Config &cfg, const std::string &querySequence, Cigar &extension, bool left, bool global, const std::string &targetSequence, const int band) { auto [alignment_status, cigar] = global ? compute_wfa_global(querySequence, targetSequence, band) : compute_wfa_extension(querySequence, targetSequence, band); std::vector> cigar_data; // TODO: gibt es eine effizientere (aber elegante) Methode, als jedes Mal max_query und max_target zu berechnen? int max_query = -1; int max_target = -1; int steps = 0; for (char c: cigar) { if (isdigit(c)) { steps = steps * 10 + (c - '0'); continue; } cigar_data.emplace_back(steps, c); switch (c) { case '=': extension.score += steps * cfg.score_builder->reward(); max_query += steps; max_target += steps; break; case 'X': extension.score += steps * cfg.score_builder->penalty(); max_query += steps; max_target += steps; break; case 'I': extension.score -= cfg.score_builder->gap_open() + (steps * cfg.score_builder->gap_extend()); max_query += steps; break; case 'D': extension.score -= cfg.score_builder->gap_open() + (steps * cfg.score_builder->gap_extend()); max_target += steps; break; default: throw std::runtime_error(std::string("WFA Cigar_short: Invalid Cigar_short Symbol ") + c); } steps = 0; } if (left) { std::reverse(cigar_data.begin(), cigar_data.end()); extension.setMaxValues(max_query, max_target); } else if (extension.score < 1) { return NEGATIVE_SCORE; } extension.extendCigar(cigar_data); // return z-dropped return alignment_status; } Hsp build_hsp_from_cigar(const Cigar &cigar, const Sequence &target, const Sequence &query, const int firstAnchor_i, const int firstAnchor_j, bool isReverse, const Search::Config &cfg) { // timer ExtensionTimer timer_build; auto start_build = std::chrono::high_resolution_clock::now(); Hsp alignHsp = Hsp(); int query_pos = firstAnchor_i - cigar.query_extension_distance() - 1; int target_pos = firstAnchor_j - cigar.target_extension_distance() - 1; alignHsp.query_range.begin_ = query_pos; alignHsp.subject_range.begin_ = target_pos; for (auto& operation: cigar.getCigarDataConst()) { switch (operation.second) { case 'M': case '=': case 'X': for (int j = 0; j < operation.first; ++j) { alignHsp.push_match(target[target_pos++], query[query_pos++], true); } break; case 'D': alignHsp.push_gap(op_deletion, operation.first, target.data() + operation.first + target_pos); target_pos += operation.first; break; case 'I': alignHsp.push_gap(op_insertion, operation.first, query.data() + operation.first + query_pos); query_pos += operation.first; break; default: break; } } alignHsp.score = cigar.score; alignHsp.bit_score = cfg.score_builder->blast_bit_Score(alignHsp.score); alignHsp.evalue = cfg.score_builder->blast_eValue(alignHsp.score, query.length()); if (alignHsp.evalue >= config.max_evalue) return alignHsp; alignHsp.query_range.end_ = query_pos; alignHsp.subject_range.end_ = target_pos; alignHsp.transcript.push_terminator(); alignHsp.target_seq = target; alignHsp.query_source_range = alignHsp.query_range; alignHsp.subject_source_range = isReverse ? Interval(alignHsp.subject_range.end_, alignHsp.subject_range.begin_) : Interval( alignHsp.subject_range.begin_, alignHsp.subject_range.end_); alignHsp.frame = isReverse;//+ 2; //time auto end_build = std::chrono::high_resolution_clock::now(); timer_build.update(2,end_build-start_build); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_build; } return alignHsp; } }bbuchfink-diamond-08b3cbc/src/contrib/dna/alignment.h000066400000000000000000000072171506104011400226630ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "../data/block/block.h" #include "../align/extend.h" #include "../lib/ksw2/ksw2.h" #include "seed_set_dna.h" #include "../util/util.h" #include "../util/sequence/translate.h" #include "../basic/shape_config.h" #include #pragma once namespace Dna{ const int KSW2_ZDROP_EXTENSION = 40; // TODO: should be different for short and long reads const int KSW2_ZDROP_BETWEEN_ANCHORS = 100; const int KSW2_BAND_EXTENSION = 40; const int KSW2_BAND_GLOBAL = 30; const int WFA_BAND_EXTENSION = 20; const int WFA_ZDROP_EXTENSION = 100; const int WFA_ZDROP_GLOBAL = 500; struct Cigar { public: Cigar() : query_extension_distance_(0), target_extension_distance_(0) {} explicit Cigar(std::size_t reserveSize = 100) : query_extension_distance_(0), target_extension_distance_(0) { cigar_data.reserve(reserveSize); } void reserveCigarSpace(std::size_t reserveSize) { cigar_data.reserve(reserveSize); } void extendCigar(const std::vector>& otherVector) { this->cigar_data.insert(this->cigar_data.end(), otherVector.begin(), otherVector.end()); } void extendCigar(uint32_t length, char cigarOperation) { cigar_data.emplace_back(length, cigarOperation); } int query_extension_distance() const { return query_extension_distance_; } int target_extension_distance() const { return target_extension_distance_; } void setMaxValues(int queryStart, int targetStart) { query_extension_distance_ = queryStart; target_extension_distance_ = targetStart; } const std::vector>& getCigarDataConst() const { return cigar_data; } std::vector>& getCigarData() { return cigar_data; } int score = 0; int peakScore = 0; int peakScoreCigarIndex = 0; int peakScoreAnchorIndex = 0; private: int query_extension_distance_{0}, target_extension_distance_{0}; std::vector> cigar_data; }; enum AlignmentStatus : uint8_t { NOT_DROPPED = 0, DROPPED = 1, NEGATIVE_SCORE = 2 }; AlignmentStatus compute_ksw_cigar(const Sequence &targetSequence, const Sequence &querySequence, const Search::Config &cfg, int flag, Cigar &extension, const int zdrop, const int band); AlignmentStatus compute_wfa_cigar(const Search::Config &cfg, const std::string &querySequence, Cigar &extension, bool left, bool global, const std::string &targetSequence, const int band); Hsp build_hsp_from_cigar(const Cigar &cigar, const Sequence &target, const Sequence &query, const int firstAnchor_i, const int firstAnchor_j, bool isReverse, const Search::Config &cfg); } bbuchfink-diamond-08b3cbc/src/contrib/dna/build_score.cpp000066400000000000000000000103451506104011400235260ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "../lib/blast/blast_stat.h" #include "../lib/blast/blast_encoding.h" #include "../lib/blast/blast_setup.h" #include "build_score.h" namespace Stats { Blastn_Score::Blastn_Score(const int reward, const int penalty, const int gapopen, const int gapextend,uint64_t db_letters,int64_t sequence_count) : m_ScoreBlk(BlastScoreBlkNew(BLASTNA_SEQ_CODE, 1)), reward_(reward), penalty_(penalty), gap_open_(gapopen), gap_extend_(gapextend), target_length_(db_letters), db_size_(sequence_count) { int status; if(m_ScoreBlk == nullptr) throw std::runtime_error("Failed to initialize blast score block"); m_ScoreBlk->kbp_gap_std[0] = Blast_KarlinBlkNew(); Blast_ScoreBlkKbpIdealCalc(m_ScoreBlk); m_ScoreBlk->reward = reward_; m_ScoreBlk->penalty = penalty_; EBlastProgramType core_type =eBlastTypeBlastn; BlastScoringOptions *score_options; BlastScoringOptionsNew(core_type, &score_options); BLAST_FillScoringOptions(score_options, core_type, TRUE,penalty_, reward_, "", gap_open_, gap_extend_); status = Blast_ScoreBlkMatrixInit(core_type, score_options, m_ScoreBlk, nullptr); score_options = BlastScoringOptionsFree(score_options); if (status) throw std::runtime_error("Failed to initialize scoring matrix"); //Blast_ScoreBlkKbpIdealCalc(m_ScoreBlk); status = Blast_KarlinBlkNuclGappedCalc(m_ScoreBlk->kbp_gap_std[0], gap_open_, gap_extend_, m_ScoreBlk->reward, m_ScoreBlk->penalty, m_ScoreBlk->kbp_ideal, &(m_ScoreBlk->round_down), nullptr); if (status || m_ScoreBlk->kbp_gap_std[0] == nullptr || m_ScoreBlk->kbp_gap_std[0]->Lambda <= 0.0) { throw std::runtime_error("Failed to initialize Karlin Blocks"); } kbp = m_ScoreBlk->kbp_gap_std[0] ; } double Blastn_Score::blast_bit_Score(int raw_score) const { return ((raw_score * kbp->Lambda) - kbp->logK) / NCBIMATH_LN2; } double Blastn_Score::blast_eValue(int raw_score,int query_length) const { double searchspace = calculate_length_adjustment(query_length,query_length,this->target_length_) * calculate_length_adjustment(this->target_length_, query_length,this->target_length_,this->db_size_); return BLAST_KarlinStoE_simple(raw_score, kbp,static_cast(searchspace)); } double Blastn_Score::calculate_length_adjustment(uint64_t length, int query_length, uint64_t target_length, int64_t db_size) const { return static_cast(length) - (expected_hsp_value(query_length,target_length) * (double)db_size); } double Blastn_Score::calculate_length_adjustment(uint64_t length, int query_length, uint64_t target_length) const { if(expected_hsp_value(query_length,target_length) < (1 / kbp->K)) return(1/kbp->K); else return static_cast(length) - expected_hsp_value(query_length,target_length); } double Blastn_Score::expected_hsp_value(int query_length, uint64_t target_length) const { return (log(kbp->K * query_length * (double)target_length) / kbp->H); } Blastn_Score::~Blastn_Score() { m_ScoreBlk = BlastScoreBlkFree(m_ScoreBlk); } }bbuchfink-diamond-08b3cbc/src/contrib/dna/build_score.h000066400000000000000000000033361506104011400231750ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "blast/blast_stat.h" namespace Stats { struct Blastn_Score{ Blastn_Score(const int reward,const int penalty,const int gapopen,const int gapextend,uint64_t db_letters,int64_t sequence_count); double blast_bit_Score(int raw_score) const; double blast_eValue(int raw_score,int query_length) const; ~Blastn_Score(); int reward()const{return reward_;} int penalty()const{return penalty_;} int gap_open()const{return gap_open_;} int gap_extend()const{return gap_extend_;} private: Blast_KarlinBlk* kbp; BlastScoreBlk *m_ScoreBlk; int reward_,penalty_,gap_open_,gap_extend_; uint64_t target_length_; int64_t db_size_; double calculate_length_adjustment(uint64_t length,int query_length, uint64_t target_length, int64_t db_size) const; double calculate_length_adjustment(uint64_t length,int query_length, uint64_t target_length) const; double expected_hsp_value(int query_length, uint64_t target_length) const; }; } bbuchfink-diamond-08b3cbc/src/contrib/dna/chain.cpp000066400000000000000000000321461506104011400223210ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "chain.h" #include "../util/util.h" #include #include "../util/math/log2_fast.h" namespace Dna { void only_keep_best_chains_per_target(std::vector &chains, const float chainCutoffPercentage) { std::sort(chains.begin(), chains.end(), [](const Chain &a, const Chain &b) { return (a.target_id == b.target_id) ? (a.chain_score > b.chain_score) : (a.target_id < b.target_id); }); int last_target_id = chains[0].target_id; chains[0].is_primary = 1; auto cutoff = int (chainCutoffPercentage * chains[0].chain_score); for (size_t i = 1; i < chains.size(); ++i) { if (chains[i].chain_score >= cutoff && chains[i].target_id == last_target_id) { chains[i].is_primary = 1; } else if (chains[i].target_id != last_target_id) { last_target_id = chains[i].target_id; chains[i].is_primary = 1; cutoff = int (chainCutoffPercentage * chains[i].chain_score); } } std::sort(chains.begin(), chains.end(), [](const Chain &a, const Chain &b) { return a.is_primary > b.is_primary; }); const auto first_secondary = std::find_if(chains.begin(), chains.end(), [](const Chain& chain) { return chain.is_primary == 0; }); chains.erase(first_secondary, chains.end()); } void detect_primary_chains(std::vector &chains) { std::vector best_secondary_score_of_primary(chains.size(), 0); // first chain is always primary std::vector primary_chain_indices = {0}; std::vector chain_span; chain_span.reserve(chains.size()); // pre compute chain span for (Chain chain : chains) { chain_span.push_back(chain.anchors[0].i - chain.anchors.back().i_start()); } for (size_t index_chain = 1; index_chain < chains.size(); ++index_chain) { bool isPrimary = true; for (size_t index_primary_chain : primary_chain_indices) { int overlapLength = chains[index_chain].overlapInQuery(chains[index_primary_chain]); if (overlapLength < 1) { continue; } double overlapPercentage = static_cast(overlapLength) / std::min(chain_span[index_chain], chain_span[index_primary_chain]); if (overlapPercentage >= MIN_OVERLAP_PERCENTAGE_SECONDARY) { isPrimary = false; // Chain index_chain is the best secondary to Chain index_primary_chain best_secondary_score_of_primary[index_primary_chain] = std::max(best_secondary_score_of_primary[index_primary_chain], chains[index_chain].chain_score); } } if (isPrimary) { primary_chain_indices.push_back(index_chain); } } for (size_t i : primary_chain_indices) { chains[i].computeMappingQuality(best_secondary_score_of_primary[i]); } } static int64_t find_chain_start(const int32_t maxDrop, const uint64_t scoreEnd, const uint64_t indexEnd, const AnchorData &anchorData) { int64_t index = indexEnd; int64_t index_max_score = index; int32_t max_score = 0; // check for invalid or visited anchor if (index < 0 || anchorData.anchor_used[index]) return index; // iterate over all anchors in chain while anchor has not been visited do { // move to the previous anchor in the chain index = anchorData.predecessor_anchor[index]; // compute score difference between anchors (if valid anchor) const int32_t score_difference_anchors = index < 0 ? scoreEnd : (int32_t)scoreEnd - anchorData.best_score_anchor[index]; // new max score? (best extension so far) if (score_difference_anchors > max_score) { max_score = score_difference_anchors; index_max_score = index; } // chain does not extend if score drops too much between anchors else if (max_score - score_difference_anchors > maxDrop) break; } while (index > -1 && !anchorData.anchor_used[index]); return index_max_score; } std::vector chain_backtrack(AnchorData &anchorData, const int minChainScore, const int maxDrop, const SeedMatch *seedMatchBegin, bool isReverse) { std::vector> potential_chain_ends; for (int64_t i = 0; i < anchorData.best_score_anchor.size(); ++i) if (anchorData.best_score_anchor[i] >= minChainScore) potential_chain_ends.emplace_back(anchorData.best_score_anchor[i], i); if (potential_chain_ends.empty()) return {}; if (config.best_hsp_only){ std::sort(potential_chain_ends.begin(), potential_chain_ends.end(), [](const ScoreIndexPair& a, const ScoreIndexPair& b) { return a.score > b.score; }); if (potential_chain_ends.size() > 4) { potential_chain_ends.resize(4); } } // sort by score std::sort(potential_chain_ends.begin(), potential_chain_ends.end()); std::vector detectedChains; anchorData.anchor_used.assign(anchorData.anchor_used.size(), false); // iterate over all potential end positions (highest to lowest) for (int64_t k = potential_chain_ends.size() - 1; k > -1; --k) { if (anchorData.anchor_used[potential_chain_ends[k].index]) continue; const int64_t chain_start_index = find_chain_start(maxDrop, potential_chain_ends[k].score, potential_chain_ends[k].index, anchorData); Chain chain = Chain(isReverse); // iterate over all positions in chain, marks used anchors int64_t idx_chain_end; for (idx_chain_end = potential_chain_ends[k].index; idx_chain_end != chain_start_index; idx_chain_end = anchorData.predecessor_anchor[idx_chain_end]) { anchorData.anchor_used[idx_chain_end] = true; chain.anchors.emplace_back(seedMatchBegin[idx_chain_end].i(), seedMatchBegin[idx_chain_end].j(), seedMatchBegin[idx_chain_end].ungapped_score()); } // score of current chain const int32_t score = idx_chain_end < 0 ? potential_chain_ends[k].score : (int32_t)potential_chain_ends[k].score - anchorData.best_score_anchor[idx_chain_end]; // valid chain? if (score >= minChainScore && !chain.anchors.empty()){ chain.target_id = seedMatchBegin->id(); chain.chain_score = score; detectedChains.push_back(std::move(chain)); } } return detectedChains; } int32_t compute_score(const SeedMatch &secondMatch, const SeedMatch &firstMatch, const ChainingParameters &chainingParameters) { const int32_t distance_query = secondMatch.i_start() - firstMatch.i(); const int32_t distance_query_end_to_end = secondMatch.i() - firstMatch.i(); if (distance_query_end_to_end < 1 || distance_query > chainingParameters.MAX_DIST_X) return INT32_MIN; const int32_t distance_target = secondMatch.j_start() - firstMatch.j(); const int32_t distance_target_end_to_end = secondMatch.j() - firstMatch.j(); if (distance_target_end_to_end == 0 || distance_target > chainingParameters.MAX_DIST_Y) return INT32_MIN; // distance off diagonal (0 is on diagonal) const int32_t distance_diagonal = distance_target_end_to_end > distance_query_end_to_end ? distance_target_end_to_end - distance_query_end_to_end : distance_query_end_to_end - distance_target_end_to_end; // too big distance on query or target if (distance_diagonal > chainingParameters.BAND_WIDTH) return INT32_MIN; // smaller distance on query or target const int32_t distance_skip = std::min(std::abs(distance_target), std::abs(distance_query)); const int32_t distance_gap_end_to_end = std::min(distance_target_end_to_end, distance_query_end_to_end); // initial score: smaller matchSpan or distance int32_t score = std::min(secondMatch.ungapped_score(), distance_gap_end_to_end); if (distance_diagonal) { float lin_pen = chainingParameters.CHAIN_PEN_GAP * (float)distance_diagonal + chainingParameters.CHAIN_PEN_SKIP * (float)distance_skip; float log_pen = distance_diagonal > 0 ? log2_approximate(distance_diagonal + 1) : 0.0f; score -= (int)(lin_pen + .5f * log_pen); } return score; } std::vector chaining_dynamic_program(const ChainingParameters &chainingParameters, const SeedMatch *seedMatchBegin, const SeedMatch *seedMatchEnd, bool isReverse) { const auto total_number_matches = std::distance(seedMatchBegin, seedMatchEnd); AnchorData anchorData(total_number_matches); int32_t total_max_score = 0; // fill matrix int64_t max_score_index = -1; for (int64_t index_second_match = 0; index_second_match < total_number_matches; ++index_second_match) { int64_t index_predecessor = -1; int32_t max_score = seedMatchBegin[index_second_match].ungapped_score(); int32_t n_skip = 0; int64_t start = 0; while (start < index_second_match && seedMatchBegin[index_second_match].j_start() > seedMatchBegin[start].j() + chainingParameters.MAX_DIST_X) ++start; start = std::max(start, index_second_match - chainingParameters.MAX_ITERATIONS); int64_t index_first_match; for (index_first_match = index_second_match - 1; index_first_match >= start; --index_first_match) { int32_t score = compute_score(seedMatchBegin[index_second_match], seedMatchBegin[index_first_match], chainingParameters); if (score == INT32_MIN) continue; score += anchorData.best_score_anchor[index_first_match]; if (score > max_score) { max_score = score; index_predecessor = index_first_match; // pending skipped seeds? if (n_skip > 0) --n_skip; // already in chain? } else if (anchorData.pre_predecessor_anchor[index_first_match] == (int32_t)index_second_match) { // increment number of skipped seeds and break if too many if (++n_skip > chainingParameters.MAX_SKIP) break; } // updates the seed information if previous seed was part of the chain if (anchorData.predecessor_anchor[index_first_match] > -1) anchorData.pre_predecessor_anchor[anchorData.predecessor_anchor[index_first_match]] = index_second_match; } int64_t end_j = index_first_match; if (max_score_index < 0 || seedMatchBegin[index_second_match].j_start() - seedMatchBegin[max_score_index].j() > (int64_t)chainingParameters.MAX_DIST_X) { int32_t max = INT32_MIN; max_score_index = -1; // find seed with the highest score for (index_first_match = index_second_match - 1; index_first_match >= start; --index_first_match) { if (max < anchorData.best_score_anchor[index_first_match]){ max = anchorData.best_score_anchor[index_first_match]; max_score_index = index_first_match; } } } // valid max score if (max_score_index >= 0 && max_score_index < end_j) { const int32_t score_extend_max = compute_score(seedMatchBegin[index_second_match], seedMatchBegin[max_score_index], chainingParameters); // score is valid and higher than the current max score if (score_extend_max != INT32_MIN && max_score < score_extend_max + anchorData.best_score_anchor[max_score_index]){ max_score = score_extend_max + anchorData.best_score_anchor[max_score_index]; index_predecessor = max_score_index; } } anchorData.best_score_anchor[index_second_match] = max_score; anchorData.predecessor_anchor[index_second_match] = index_predecessor; anchorData.peak_score_anchor[index_second_match] = index_predecessor > -1 && anchorData.peak_score_anchor[index_predecessor] > max_score ? anchorData.peak_score_anchor[index_predecessor] : max_score; if (max_score_index < 0 || (anchorData.best_score_anchor[max_score_index] < anchorData.best_score_anchor[index_second_match])) max_score_index = index_second_match; // maximum score in entire chaining total_max_score = std::max(total_max_score, max_score); } return chain_backtrack(anchorData, chainingParameters.MIN_CHAIN_SCORE, chainingParameters.BAND_WIDTH, seedMatchBegin, isReverse); } } bbuchfink-diamond-08b3cbc/src/contrib/dna/chain.h000066400000000000000000000111561506104011400217640ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "seed_set_dna.h" namespace Dna { const double MIN_OVERLAP_PERCENTAGE_SECONDARY = 0.5; struct ChainingParameters { int MAX_DIST_X = 1000; // TODO: should be different for max sensitivity and assembly alignment (up to 5000 for less kmers) int MAX_DIST_Y = 1000; const int BAND_WIDTH = 300; // TODO: should be different for max sensitivity and assembly alignment (500) const int MAX_SKIP = 25; const int MAX_ITERATIONS = 3000; // TODO: adapt all for possible short mode? band usw abhängig machen von der query length? const float MAP_PERCENTAGE_TARGET = 0.99f; const int MIN_CHAIN_SCORE; const float CHAIN_PEN_GAP; const float CHAIN_PEN_SKIP; const float MAX_OVERLAP_EXTENSION; ChainingParameters(float gap, float skip, int min_chain_score, float max_overlap_extension) : MIN_CHAIN_SCORE(min_chain_score), CHAIN_PEN_GAP(gap), CHAIN_PEN_SKIP(skip), MAX_OVERLAP_EXTENSION(max_overlap_extension) {} }; struct AnchorData { std::vector predecessor_anchor; std::vector best_score_anchor; std::vector peak_score_anchor; std::vector pre_predecessor_anchor; std::vector anchor_used; explicit AnchorData(size_t n) : predecessor_anchor(n), best_score_anchor(n), peak_score_anchor(n), pre_predecessor_anchor(n, 0), anchor_used(n){} }; struct Chain { explicit Chain(bool rev); int32_t chain_score; BlockId target_id; uint8_t mapping_quality; uint8_t is_primary = 0; bool reverse; struct Anchor { Loc i; Loc j; int span; Loc i_start() const { return i - span; } Loc j_start() const { return j - span; } Anchor(Loc i, Loc j, int span) : i(i), j(j), span(span) {} }; // query/target starting position in reverse (i, j) std::vector anchors; explicit Chain(bool rev) : chain_score(0), target_id(0), mapping_quality(0), reverse(rev), anchors() {} int overlapInQuery(const Chain &otherChain) const { return (std::min(anchors[0].i, otherChain.anchors[0].i)) - std::max(anchors.back().i_start(), otherChain.anchors.back().i_start()); } int overlapInTarget(const Chain &otherChain) const { return (std::min(anchors[0].j, otherChain.anchors[0].j)) - std::max(anchors.back().j_start(), otherChain.anchors.back().j_start()); } void computeMappingQuality(int scoreSecondaryChain) { double score_ratio = static_cast(scoreSecondaryChain) / chain_score; double quality_score = 40 * (1 - score_ratio) * std::min(1.0, static_cast(anchors.size()) / 10) * std::log(chain_score); // compress to 0-60 mapping_quality = static_cast(quality_score * 60 / 312); } bool operator>(const Chain& otherChain)const {return this->chain_score > otherChain.chain_score;} }; template struct ScoreIndexPair { static_assert(std::is_arithmetic::value, "T1 must be an arithmetic type"); static_assert(std::is_arithmetic::value, "T2 must be an arithmetic type"); T1 score; T2 index; ScoreIndexPair() : score(T1()), index(T2()) {} ScoreIndexPair(const T1& first, const T2& second) : score(first), index(second) {} // sort ascending bool operator<(const ScoreIndexPair& other) const { if (score != other.score) return score < other.score; else return index < other.index; } }; std::vector chaining_dynamic_program(const ChainingParameters &chainingParameters, const SeedMatch *seedMatchBegin, const SeedMatch *seedMatchEnd, bool isReverse); void detect_primary_chains(std::vector &chains); void only_keep_best_chains_per_target(std::vector &chains, float chainCutoffPercentage); }bbuchfink-diamond-08b3cbc/src/contrib/dna/dna_index.cpp000066400000000000000000000150711506104011400231660ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "dna_index.h" #include "../data/sequence_set.h" #include "../data/queries.h" #include #include "../util/algo/partition.h" #include #include #include #include "../util/util.h" //#include "google/protobuf/arena.h" using std::atomic; using std::thread; using std::vector; using std::atomic_size_t; using std::pair; namespace Dna { Index::Index(Search::Config &cfg, char *ref_buffer) : ref_buffer_(ref_buffer) { const SeedPartitionRange range(0, Const::seedp); const SeedHistogram &ref_hst = cfg.target->hst(); TaskTimer timer("Building reference seed array", true); const EnumCfg enum_ref{&ref_hst.partition(), 0, 1, cfg.seed_encoding, nullptr, false, false, cfg.seed_complexity_cut, MaskingAlgo::NONE, cfg.minimizer_window, false, false, cfg.sketch_size }; seed_arr_.reset(new SeedArray(*cfg.target, ref_hst.get(0), range, ref_buffer, &no_filter, enum_ref)); timer.go("Building reference index"); count_minimizers(range); build_index(range,filter_repetitive(range)); } Index::~Index() { delete[] ref_buffer_; } pair Index::contains(PackedSeed seed) const { unsigned partition = seed_partition(seed); unsigned key = seed_partition_offset(seed); if (dna_index_[partition]->size() == 0) { return {nullptr, nullptr}; } auto hash_lookup = dna_index_[partition]->find_entry(key); if (hash_lookup == nullptr) { return {nullptr, nullptr}; } SeedArray::Entry *first = seed_arr_->begin(partition) + hash_lookup->value; // SeedArray::Entry *end = seed_arr_->begin(partition) + seed_arr_->size(partition); for (auto i = first + 1; i != end; ++i) { if (i->key != first->key) return {first, i}; } return {first, end}; } void Index::count_worker(std::atomic *seedp) { unsigned part; while ((part = (*seedp)++) < Const::seedp) { std::sort(seed_arr_->begin(part), seed_arr_->begin(part) + seed_arr_->size(part)); auto it = merge_keys(seed_arr_->begin(part), (seed_arr_->begin(part) + seed_arr_->size(part)), SeedArray::Entry::GetKey()); unsigned count = 0; while (it.good()) { ++count; ++it; } this->minimizer_counts[part] = count; } } void Index::count_minimizers(const SeedPartitionRange &range) { std::function *seedp)> functor = [this](atomic *PH1) { count_worker(PH1); }; atomic seedp(range.begin()); vector threads; for (int i = 0; i < config.threads_; ++i) threads.emplace_back(functor, &seedp); for (auto &t: threads) t.join(); this->n_minimizer = std::accumulate(minimizer_counts.begin(), minimizer_counts.end(),static_cast(0)); } void Index::index_worker(atomic *seedp, int cutoff) { unsigned part; while ((part = (*seedp)++) < Const::seedp) { dna_index_[part].reset(new HashTable(this->minimizer_counts[part] * 1.2, MurmurHash())); auto it2 = merge_keys(seed_arr_->begin(part), (seed_arr_->begin(part) + seed_arr_->size(part)),SeedArray::Entry::GetKey()); while (it2.good()) { if (it2.count() < cutoff) dna_index_[part]->insert(it2.key())->value = it2.begin() - seed_arr_->begin(part); ++it2; } } } void Index::build_index(const SeedPartitionRange &range, int repetitive_cutoff) { std::function *seedp, int cutoff)> functor = [this](atomic *PH1, int cutoff) { index_worker(PH1,cutoff); }; atomic seedp(range.begin()); vector threads; for (int i = 0; i < config.threads_; ++i) threads.emplace_back(functor, &seedp, repetitive_cutoff); for (auto &t: threads) t.join(); } void Index::filter_worker(std::atomic *seedp, int index, std::vector, std::greater<>>> &rep_thread, int n) { unsigned part; while ((part = (*seedp)++) < Const::seedp) { auto it = merge_keys(seed_arr_->begin(part), (seed_arr_->begin(part) + seed_arr_->size(part)), SeedArray::Entry::GetKey()); while (it.good()) { if (rep_thread[index].size() < n) { rep_thread[index].emplace(it.count()); } else if (rep_thread[index].top() < it.count()){ rep_thread[index].emplace(it.count()); rep_thread[index].pop(); } ++it; } } } int Index::filter_repetitive(const SeedPartitionRange &range) { const int n = n_minimizer * config.repetitive_cutoff; if(n < 1) return INT_MAX; std::vector, std::greater<>>> rep_thread(config.threads_); std::function *seedp, int heap_index)> functor = [this, &rep_thread, n](atomic *PH1, int heap_index) { filter_worker(PH1,heap_index, rep_thread, n); }; std::priority_queue,std::greater<>> repetitive_max; atomic seedp(range.begin()); vector threads; for (int i = 0; i < config.threads_; ++i) { threads.emplace_back(functor, &seedp, i); } for (auto &t: threads) t.join(); for(auto &heap: rep_thread){ while (!heap.empty()) { if (repetitive_max.size() < n) { repetitive_max.emplace(heap.top()); } else if (heap.top() > repetitive_max.top()) { repetitive_max.emplace(heap.top()); repetitive_max.pop(); } heap.pop(); } } return repetitive_max.top(); } }bbuchfink-diamond-08b3cbc/src/contrib/dna/dna_index.h000066400000000000000000000035661506104011400226410ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "../data/seed_array.h" #include "../util/data_structures/hash_table.h" //#include "google/protobuf/arena.h" #pragma once namespace Dna{ class Index{ public: Index(Search::Config& cfg,char *ref_buffer); std::pair::Entry*,SeedArray::Entry*> contains(PackedSeed seed) const; ~Index(); private: void index_worker(std::atomic *seedp, int cutoff); void build_index(const SeedPartitionRange& range, int repetitive_cutoff); void filter_worker(std::atomic *seedp, int index, std::vector, std::greater<>>> &rep_thread, int n); int filter_repetitive(const SeedPartitionRange &range); void count_worker(std::atomic *seedp); void count_minimizers(const SeedPartitionRange &range); std::unique_ptr> seed_arr_; std::array>, Const::seedp> dna_index_; std::array minimizer_counts; char* ref_buffer_; unsigned n_minimizer; }; }bbuchfink-diamond-08b3cbc/src/contrib/dna/extension.cpp000066400000000000000000000405261506104011400232540ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "../lib/ksw2/ksw2.h" #include "seed_set_dna.h" #include "../util/util.h" #include "bindings/cpp/WFAligner.hpp" #include "extension.h" #include "timer.h" #include "chain.h" #include "extension_chain.h" #include "../align/target.h" #include "extension_seed_matches.h" #include "alignment.h" using std::make_move_iterator; const EMap EnumTraits::to_string = { {DNAExtensionAlgo::KSW,"ksw"}, { DNAExtensionAlgo::WFA,"wfa"} }; const SEMap EnumTraits::from_string = { {"ksw",DNAExtensionAlgo::KSW}, {"wfa",DNAExtensionAlgo::WFA} }; namespace Dna { struct ExtendedSeed { int i_min_extended; int i_max_extended; int j_min_extended; int j_max_extended; int length; // Length of the extended seed ExtendedSeed(int i_min, int i_max, int j_min, int j_max) : i_min_extended(i_min), i_max_extended(i_max), j_min_extended(j_min), j_max_extended(j_max) { length = i_max_extended - i_min_extended; } }; bool intersection(const SeedMatch &hit, const std::vector &extended) { if (extended.empty()) { return false; } return std::any_of(extended.begin(), extended.end(), [&hit](const ExtendedSeed &s) { //bool similar_diagonal = std::abs((hit.i() - hit.j()) - (s.i_max_extended - s.j_max_extended)) < s.length / 2; bool within_range = hit.i_start() >= s.i_min_extended && hit.i() <= s.i_max_extended && hit.j_start() >= s.j_min_extended && hit.j() <= s.j_max_extended; return within_range; //&& similar_diagonal; }); } KswCigar::KswCigar(const Sequence &tseq, const Sequence &qseq, const Search::Config &cfg, int flag, const int ungapped_score, const int band) { int a = cfg.score_builder->reward(), b = cfg.score_builder->penalty() < 0 ? cfg.score_builder->penalty() : -cfg.score_builder->penalty(); // a>0 and b<0 int8_t mat[NUCLEOTIDE_COUNT * NUCLEOTIDE_COUNT] = {static_cast(a), static_cast(b), static_cast(b), static_cast(b), 0, static_cast(b), static_cast(a), static_cast(b), static_cast(b), 0, static_cast(b), static_cast(b), static_cast(a), static_cast(b), 0, static_cast(b), static_cast(b), static_cast(b), static_cast(a), 0, 0, 0, 0, 0, 0}; ksw_extz_t ez; memset(&ez, 0, sizeof(ksw_extz_t)); #ifdef __APPLE__ ksw_extz(nullptr, qseq.length(), reinterpret_cast(qseq.data()), tseq.length(), reinterpret_cast(tseq.data()), NUCLEOTIDE_COUNT, mat, (int8_t) cfg.score_builder->gap_open(), (int8_t) cfg.score_builder->gap_extend(), band, //config.padding config.zdrop, flag, &ez); //TODO: zdrop unerschiedlich machen short/long reads #else ksw_extz2_sse(nullptr, qseq.length(), reinterpret_cast(qseq.data()), tseq.length(), reinterpret_cast(tseq.data()), NUCLEOTIDE_COUNT, mat, (int8_t) cfg.score_builder->gap_open(), (int8_t) cfg.score_builder->gap_extend(), band, config.zdrop, KSW2_END_BONUS, flag, &ez); #endif this->score_ = ez.max; this->max_query_ = ez.max_q; this->max_target_ = ez.max_t; cigar_data.reserve(ez.n_cigar + 1); for (int i = 0; i < ez.n_cigar; ++i) cigar_data.emplace_back(ez.cigar[i] >> 4, "MID"[ez.cigar[i] & 0xf]); if (flag == KSW_FLAG_L){ cigar_data.emplace_back(ungapped_score, 'M'); this->score_ += ungapped_score * cfg.score_builder->reward(); } free(ez.cigar); } WfaCigar::WfaCigar(const Sequence &tseq, const Sequence &qseq, const Search::Config &cfg, bool left, const int score, const int band) { std::string tseq2 = tseq.to_string(); std::string qseq2 = qseq.to_string(); int tl = tseq2.length(), ql = qseq2.length(); thread_local std::unique_ptr aligner; if (!aligner) { aligner.reset(new wfa::WFAlignerGapAffine(0, -config.mismatch_penalty, config.gap_open, config.gap_extend, wfa::WFAligner::Alignment)); aligner->setHeuristicNone(); aligner->setHeuristicWFadaptive(10,50,1); //aligner->setHeuristicZDrop(200, WFA_CUTOFF_STEPS); aligner->setHeuristicXDrop(100, 1); //aligner->setHeuristicBandedAdaptive(-band,band,1); } aligner->alignExtension(tseq2.c_str(), tl, qseq2.c_str(), ql); auto cigar = aligner->getCIGAR(true); max_query_ = -1; //TODO: copilot check reverse anders gemacht? scores davor saven? max_target_ = -1; cigar_data.reserve((cigar.size() / 2) + 1); int steps = 0; for (char c: cigar) { if (isdigit(c)) { steps = steps * 10 + (c - '0'); continue; } cigar_data.emplace_back(steps, c); switch (c) { case '=': this->score_ += cfg.score_builder->reward() * steps; max_query_ += steps; max_target_ += steps; break; case 'X': this->score_ += cfg.score_builder->penalty() * steps; max_query_ += steps; max_target_ += steps; break; case 'I': this->score_ -= cfg.score_builder->gap_open() + steps * cfg.score_builder->gap_extend(); max_query_ += steps; break; case 'D': this->score_ -= cfg.score_builder->gap_open() + steps * cfg.score_builder->gap_extend(); max_target_ += steps; break; default: throw std::runtime_error(std::string("WFA Cigar_short: Invalid Cigar_short Symbol ") + c); } steps = 0; } if (left) { std::reverse(cigar_data.begin(), cigar_data.end()); cigar_data.emplace_back(score, '='); this->score_ += score * cfg.score_builder->reward(); } } void cigar_to_hsp(const Sequence &target, const Sequence &query, const SeedMatch &hit, Hsp &out, bool reverse) { int pattern_pos = hit.i_start(); int text_pos = hit.j_start(); out.query_range.begin_ = pattern_pos; out.subject_range.begin_ = text_pos; for (int i = 0; i < hit.ungapped_score(); ++i) { out.push_match(target[text_pos], query[pattern_pos], true); pattern_pos++; text_pos++; } out.query_range.end_ = pattern_pos; out.subject_range.end_ = text_pos; out.transcript.push_terminator(); out.target_seq = target; out.query_source_range = out.query_range; out.subject_source_range = reverse ? Interval(out.subject_range.end_, out.subject_range.begin_) : Interval( out.subject_range.begin_, out.subject_range.end_); out.frame = reverse;// + 2; } void cigar_to_hsp(const Cigar_short &cigar, const Sequence &target, const Sequence &query, const int pos_i, const int pos_j, Hsp &out, bool reverse) { int pattern_pos = pos_i - cigar.max_query() - 1; int text_pos = pos_j - cigar.max_target() - 1; out.query_range.begin_ = pattern_pos; out.subject_range.begin_ = text_pos; for (auto operation: cigar.cigar_data) { switch (operation.second) { case 'M': case '=': case 'X': for (int j = 0; j < operation.first; ++j) { out.push_match(target[text_pos], query[pattern_pos], true); pattern_pos++; text_pos++; } break; case 'D': out.push_gap(op_deletion, operation.first, target.data() + operation.first + text_pos); text_pos += operation.first; break; case 'I': out.push_gap(op_insertion, operation.first, query.data() + operation.first + pattern_pos); pattern_pos += operation.first; break; default: break; } } out.query_range.end_ = pattern_pos; out.subject_range.end_ = text_pos; out.transcript.push_terminator(); out.target_seq = target; out.query_source_range = out.query_range; out.subject_source_range = reverse ? Interval(out.subject_range.end_, out.subject_range.begin_) : Interval( out.subject_range.begin_, out.subject_range.end_); out.frame = reverse + 2; } Extension::Match target_extension(const Search::Config &cfg, const BlockId id, const Sequence &query, SeedMatch *begin, SeedMatch *end, bool reverse) { std::vector extended{}; Extension::Match m = Extension::Match(id, cfg.target->seqs()[id], ::Stats::TargetMatrix(), 0, 0); for (auto hit = begin; hit != end; ++hit) { if (intersection(*hit, extended)) { //TODO: check if this is correct continue; } const Sequence &target = cfg.target->seqs()[id]; if (hit->ungapped_score() == query.length()) { Hsp out = Hsp(); out.score = hit->ungapped_score() * cfg.score_builder->reward(); out.bit_score = cfg.score_builder->blast_bit_Score(out.score); out.evalue = cfg.score_builder->blast_eValue(out.score, query.length()); if (out.evalue >= config.max_evalue) continue; cigar_to_hsp(cfg.target->seqs()[id], query, *hit, out, reverse); m.hsp.push_back(out); extended.emplace_back(out.query_range.begin_, out.query_range.end_, out.subject_range.begin_, out.subject_range.end_); } else { Sequence query_right = query.subseq(hit->i() , query.length()); Sequence target_right = target.subseq(hit->j(), std::min(target.length(), hit->j() + (int) query_right.length() * 2)); const int band_right = std::min(KSW2_BAND, std::min(query_right.length(), target_right.length()) / 3); std::vector query_left = query.subseq(0, hit->i_start()).reverse(); std::vector target_left = target.subseq(std::max(0, (int) (hit->j_start() - (query_left.size() * 2))), hit->j_start()).reverse(); const int band_left = std::min(KSW2_BAND, (int)std::min(query_left.size(), target_left.size()) / 3); Cigar_short extension = config.dna_extension == DNAExtensionAlgo::WFA ? static_cast (WfaCigar(target_left, query_left, cfg, true, hit->ungapped_score(), WFA_BAND_EXTENSION) + WfaCigar(target_right, query_right, cfg, false, 0, WFA_BAND_EXTENSION)) : KswCigar(target_left, query_left, cfg, KSW_FLAG_L, hit->ungapped_score(), band_left) + KswCigar(target_right, query_right, cfg, KSW_FLAG_R, 0, band_right); Hsp out = Hsp(); out.score = extension.score(); out.bit_score = cfg.score_builder->blast_bit_Score(out.score); out.evalue = cfg.score_builder->blast_eValue(out.score, query.length()); if (out.evalue >= config.max_evalue) continue; cigar_to_hsp(extension, cfg.target->seqs()[id], query, hit->i_start(),hit->j_start(), out, reverse); m.hsp.push_back(out); extended.emplace_back(out.query_range.begin_, out.query_range.end_, out.subject_range.begin_, out.subject_range.end_); } } //m.inner_culling(); return m; } std::vector query_extension(const Search::Config &cfg, const Sequence &query, const bool isReverse) { std::vector matches; auto seed_hits = seed_lookup(query, cfg.target->seqs(), cfg.dna_ref_index.get(), cfg.minimizer_window); auto time_start_ungapped = std::chrono::high_resolution_clock::now(); seed_hits = merge_and_extend_seeds(seed_hits, query, cfg); auto time_end_ungapped = std::chrono::high_resolution_clock::now(); ExtensionTimer timer_ungapped; timer_ungapped.update(1, time_end_ungapped - time_start_ungapped); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_ungapped; } // id and higher score std::sort(seed_hits.begin(), seed_hits.end(), std::greater<>()); auto it = merge_keys(seed_hits.begin(), seed_hits.end(), [](const SeedMatch &hit1) { return hit1.id(); }); auto time_start_extension = std::chrono::high_resolution_clock::now(); while (it.good()) { Extension::Match m = target_extension(cfg, it.key(), query, it.begin().operator->(), it.end().operator->(), isReverse); if (!m.hsp.empty()) { matches.push_back(m); } ++it; } auto time_end_extension = std::chrono::high_resolution_clock::now(); timer_ungapped.update(4, time_end_extension - time_start_extension); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_ungapped; } return matches; } std::pair, Extension::Stats> extend(const Search::Config &cfg,const Sequence &query) { // MODUS: long reads fast, OR all reads the highest accuracy if (config.chaining_out || config.align_long_reads) { return {chaining_and_extension(cfg, query, Translator::reverse(query)), Extension::Stats()}; } else { std::vector matches = query_extension(cfg,query, false); std::vector reverse = query_extension(cfg, Translator::reverse(query), true); matches.insert( matches.end(), make_move_iterator(reverse.begin()), make_move_iterator(reverse.end())); //culling(matches, cfg); return {matches, Extension::Stats()}; } } }bbuchfink-diamond-08b3cbc/src/contrib/dna/extension.h000066400000000000000000000050011506104011400227060ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "../data/block/block.h" #include "../align/extend.h" #include "../lib/ksw2/ksw2.h" #include "seed_set_dna.h" #include "../util/util.h" #include "../util/sequence/translate.h" #include "../basic/shape_config.h" #pragma once namespace Dna{ const int KSW2_END_BONUS = 5; const int KSW2_BAND = 40; const int WFA_CUTOFF_STEPS = 10; const int KSW_FLAG_R = KSW_EZ_EXTZ_ONLY | KSW_EZ_APPROX_MAX | KSW_EZ_APPROX_DROP; const int KSW_FLAG_L = KSW_FLAG_R | KSW_EZ_REV_CIGAR; const int KSW_FLAG_G = KSW_EZ_APPROX_MAX | KSW_EZ_APPROX_DROP; struct Cigar_short { public: Cigar_short &operator+(const Cigar_short &other) { this->cigar_data.insert(this->cigar_data.end(), other.cigar_data.begin(), other.cigar_data.end()); this->score_ += other.score_; return *this; } int32_t score() const { return score_; } int max_query() const { return max_query_; } int max_target() const { return max_target_; } std::vector> cigar_data; protected: Cigar_short() = default; int32_t score_{0}; int max_query_{0}, max_target_{0}; }; struct KswCigar : public Cigar_short { KswCigar(const Sequence &tseq, const Sequence &qseq, const Search::Config &cfg, int flag, const int ungapped_score, const int band); }; struct WfaCigar : public Cigar_short { WfaCigar(const Sequence &tseq, const Sequence &qseq, const Search::Config &cfg, bool left, const int score, const int band); }; void cigar_to_hsp(const Cigar_short &cigar, const Sequence &target, const Sequence &query, const int pos_i, const int pos_j, Hsp &out, bool reverse); std::pair, Extension::Stats> extend(const Search::Config &cfg, const Sequence &query);//, ExtensionTimer& extend_time); } bbuchfink-diamond-08b3cbc/src/contrib/dna/extension_chain.cpp000066400000000000000000000525421506104011400244170ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "extension_chain.h" #include "seed_set_dna.h" #include "timer.h" #include "chain.h" #include "alignment.h" #include "extension_seed_matches.h" namespace Dna { int compute_residue_matches_of_chain(const std::vector &anchors, const int kmer_size) { int totalMatchingResidues = anchors.back().span; for (size_t i = anchors.size() - 1; i > 0; --i) { totalMatchingResidues += std::min(std::min(anchors[i-1].span, anchors[i-1].i - anchors[i].i), anchors[i-1].j - anchors[i].j); } return totalMatchingResidues; } Extension::Match build_map_hsp(const Search::Config &cfg, const BlockId targetBlockId, const Chain *beginChain, const Chain *endChain) { Extension::Match match = Extension::Match(targetBlockId, cfg.target->seqs()[targetBlockId], ::Stats::TargetMatrix(), 0, 0); for (auto chain = beginChain; chain != endChain; ++chain) { //if (!chain->is_primary) continue; // only map primary chains Hsp mapHsp = Hsp(); mapHsp.query_range.begin_ = chain->anchors.back().i_start(); mapHsp.subject_range.begin_ = chain->anchors.back().j_start(); mapHsp.query_range.end_ = chain->anchors[0].i; mapHsp.subject_range.end_ = chain->anchors[0].j; mapHsp.identities = compute_residue_matches_of_chain(chain->anchors, shapes[0].length_); mapHsp.length = std::max(chain->anchors[0].i - chain->anchors.back().i_start(), chain->anchors[0].j - chain->anchors.back().j_start()); // approx, real alignment length might be bigger mapHsp.mapping_quality = chain->mapping_quality; mapHsp.n_anchors = chain->anchors.size(); mapHsp.transcript.push_terminator(); mapHsp.target_seq = cfg.target->seqs()[targetBlockId]; mapHsp.query_source_range = mapHsp.query_range; mapHsp.subject_source_range = chain->reverse ? Interval(mapHsp.subject_range.end_, mapHsp.subject_range.begin_) : Interval( mapHsp.subject_range.begin_, mapHsp.subject_range.end_); mapHsp.frame = chain->reverse + 2; match.hsp.push_back(std::move(mapHsp)); } return match; } std::pair extend_new_at_peak(const Search::Config &cfg, Cigar &extension, const Chain *chain, const Sequence &query, const Sequence &target, const BlockId targetBlockId, const int start_i, const int start_j, const int now_anchor_index) { auto erase_it = extension.getCigarDataConst().begin() + extension.peakScoreCigarIndex; extension.getCigarData().erase(erase_it, extension.getCigarDataConst().end()); extension.score = extension.peakScore; // extend only max to next anchor? TODO: delete commented code when sure /*Sequence query_right = query.subseq(chain->anchors[extension.peakScoreAnchorIndex].i, chain->anchors[extension.peakScoreAnchorIndex - 1].i_start()); Sequence target_right = target.subseq(chain->anchors[extension.peakScoreAnchorIndex].j, chain->anchors[extension.peakScoreAnchorIndex - 1].j_start()); */ // if query or target overlap just align until end //if (query_right.length() < 1 || target_right.length() < 1) { const auto j_end = chain->anchors[extension.peakScoreAnchorIndex].j; Sequence query_right = query.subseq(chain->anchors[extension.peakScoreAnchorIndex].i, query.length()); Sequence target_right = target.subseq(j_end, std::min(target.length(), std::min(j_end + config.band_extension + (int) query_right.length(), j_end + (int) query_right.length() * 2))); //} config.dna_extension == DNAExtensionAlgo::WFA ? compute_wfa_cigar(cfg, query_right.to_string(), extension, false, false, target_right.to_string(), WFA_BAND_EXTENSION) : compute_ksw_cigar(target_right, query_right, cfg, KSW_FLAG_R, extension, config.zdrop_extension, config.band_extension); Hsp hsp = build_hsp_from_cigar(extension, cfg.target->seqs()[targetBlockId], query, start_i, start_j, chain->reverse, cfg); // TODO: return which anchor (as heuristic) for next extension? After peak or from now on? Save multiple peak scores? //return std::make_pair(hsp, extension.peakScoreAnchorIndex - 1); return std::make_pair(hsp, now_anchor_index); } std::pair extend_between_anchors(const Search::Config &cfg, const BlockId targetBlockId, const Chain *chain, const Sequence &query, const Sequence &target, int anchorIdx) { // start position of chain const int start_i = chain->anchors[anchorIdx].i_start(); const int start_j = chain->anchors[anchorIdx].j_start(); Cigar extension(anchorIdx * 3); if (start_i > 0 && start_j > 0) { int prev_anchor_i = 0; int prev_anchor_j = 0; // extend maximal to end anchor of last alignment if (anchorIdx != static_cast(chain->anchors.size()) - 1) { if (chain->anchors[anchorIdx + 1].i <= start_i && chain->anchors[anchorIdx + 1].j <= start_j) { prev_anchor_i = chain->anchors[anchorIdx + 1].i; prev_anchor_j = chain->anchors[anchorIdx + 1].j; } } // extend to the left at start (until previous anchor if dropped) std::vector query_left = query.subseq(prev_anchor_i, start_i).reverse(); std::vector target_left = target.subseq(std::max(prev_anchor_j, std::max(start_j - (int)query_left.size() - config.band_extension, start_j - ((int)query_left.size() * 2))), start_j).reverse(); config.dna_extension == DNAExtensionAlgo::WFA ? compute_wfa_cigar(cfg, ((Sequence) query_left).to_string(), extension, true, false, ((Sequence) target_left).to_string(), WFA_BAND_EXTENSION) : compute_ksw_cigar(target_left, query_left, cfg, KSW_FLAG_L, extension, config.zdrop_extension, config.band_extension); } else { extension.setMaxValues(-1, -1); } int anchor_distance_query= INT_MAX; int anchor_distance_target = INT_MAX; // iterate anchors from start to end (reverse ordered) for (; anchorIdx > 0; --anchorIdx) { const auto span_current_anchor = chain->anchors[anchorIdx].span; const auto span_next_anchor = chain->anchors[anchorIdx - 1].span; // anchor no overlap with previous anchor if (anchor_distance_query > span_current_anchor && anchor_distance_target > span_current_anchor) { extension.extendCigar(span_current_anchor, 'M'); extension.score += span_current_anchor * cfg.score_builder->reward(); } if (extension.score > extension.peakScore) { extension.peakScore = extension.score; extension.peakScoreCigarIndex = extension.getCigarDataConst().size(); extension.peakScoreAnchorIndex = anchorIdx; } anchor_distance_query = chain->anchors[anchorIdx - 1].i - chain->anchors[anchorIdx].i; anchor_distance_target = chain->anchors[anchorIdx - 1].j - chain->anchors[anchorIdx].j; // Case 1: Anchors don't overlap in Query and Target if (anchor_distance_query > span_next_anchor && anchor_distance_target > span_next_anchor) { // extend to the right between anchors Sequence query_right = query.subseq(chain->anchors[anchorIdx].i, chain->anchors[anchorIdx - 1].i_start()); Sequence target_right = target.subseq(chain->anchors[anchorIdx].j, chain->anchors[anchorIdx - 1].j_start()); const int alignment_band = std::abs(query_right.length() - target_right.length()) + std::min(config.band_global, (std::min(query_right.length(), target_right.length())) / 2); auto z_dropped = (config.dna_extension == DNAExtensionAlgo::WFA ? compute_wfa_cigar(cfg, query_right.to_string(), extension, false, true, target_right.to_string(), alignment_band) : compute_ksw_cigar(target_right, query_right, cfg, KSW_FLAG_G, extension, config.zdrop_global, alignment_band)); // finish alignment and start new one if (z_dropped == DROPPED || z_dropped == NEGATIVE_SCORE) { if (extension.score >= extension.peakScore) { Hsp hsp = build_hsp_from_cigar(extension, cfg.target->seqs()[targetBlockId], query, start_i, start_j, chain->reverse, cfg); return std::make_pair(hsp, anchorIdx - 1); } else { return extend_new_at_peak(cfg, extension, chain, query, target, targetBlockId, start_i, start_j, anchorIdx - 1); } } } // Case 2: Anchors overlap more in Query than in Target else if (anchor_distance_query <= span_next_anchor && anchor_distance_query < anchor_distance_target) { // push deletions const int number_of_gaps = anchor_distance_target - anchor_distance_query; extension.extendCigar(number_of_gaps, 'D'); extension.score -= (number_of_gaps * cfg.score_builder->gap_extend()) + cfg.score_builder->gap_open(); // push matches for last part of second anchor extension.extendCigar(anchor_distance_query, 'M'); extension.score += anchor_distance_query * cfg.score_builder->reward(); } // Case 3: Anchors overlap more in Target than in Query else if (anchor_distance_target <= span_next_anchor && anchor_distance_target < anchor_distance_query) { // push insertions const int number_of_gaps = anchor_distance_query - anchor_distance_target; extension.extendCigar(number_of_gaps, 'I'); extension.score -= (number_of_gaps * cfg.score_builder->gap_extend()) + cfg.score_builder->gap_open(); // push matches for last part of second anchor extension.extendCigar(anchor_distance_target, 'M'); extension.score += anchor_distance_target * cfg.score_builder->reward(); } else { throw std::runtime_error("Error in chaining extension: No anchor overlap case matched"); } } const auto span_last_anchor = chain->anchors.front().span; // no overlap with last anchor if (anchor_distance_query > span_last_anchor && anchor_distance_target > span_last_anchor) { extension.extendCigar(span_last_anchor, 'M'); extension.score += span_last_anchor * cfg.score_builder->reward(); } const auto j_end_last_anchor = chain->anchors.front().j; Sequence query_right = query.subseq(chain->anchors.front().i, query.length()); Sequence target_right = target.subseq(j_end_last_anchor, std::min(target.length(), std::min(j_end_last_anchor + config.band_extension + (int) query_right.length(), j_end_last_anchor + (int) query_right.length() * 2))); config.dna_extension == DNAExtensionAlgo::WFA ? compute_wfa_cigar(cfg, query_right.to_string(), extension, false, false, target_right.to_string(), WFA_BAND_EXTENSION) : compute_ksw_cigar(target_right, query_right, cfg, KSW_FLAG_R, extension, config.zdrop_extension, config.band_extension); if (extension.score >= extension.peakScore) { Hsp hsp = build_hsp_from_cigar(extension, cfg.target->seqs()[targetBlockId], query, start_i, start_j, chain->reverse, cfg); return std::make_pair(hsp, anchorIdx - 1); } else { return extend_new_at_peak(cfg, extension, chain, query, target, targetBlockId, start_i, start_j, anchorIdx - 1); } } Extension::Match extend_chains(const Search::Config &cfg, const BlockId targetBlockId, const Chain *beginChain, const Chain *endChain, const Sequence &query, const Sequence &query_reverse, ChainingParameters &chainingParameters) { Extension::Match match = Extension::Match(targetBlockId, cfg.target->seqs()[targetBlockId], ::Stats::TargetMatrix(), 0, 0); const Sequence &target = cfg.target->seqs()[targetBlockId]; ExtensionTimer timer; auto start_extend = std::chrono::high_resolution_clock::now(); std::vector> range_extended_chains; for (auto chain = beginChain; chain != endChain; ++chain) { // do not extend chains that overlap with percentage previous extensions const int query_range = chain->anchors[0].i - chain->anchors.back().i_start(); const int target_range = chain->anchors[0].j - chain->anchors.back().j_start(); bool do_not_extend = false; for (const auto& [extQueryStart, extQueryEnd, extTargetStart, extTargetEnd] : range_extended_chains) { const int query_overlap = std::min(chain->anchors[0].i, extQueryEnd) - std::max(chain->anchors.back().i_start(), extQueryStart); const int target_overlap = std::min(chain->anchors[0].j, extTargetEnd) - std::max(chain->anchors.back().j_start(), extTargetStart); // TODO: vielleicht im Verhältnis zur Länge der kleineren span? -> bereits alignierte chains hatten grÃļßeren Score, falls abgebrochen, dann trotzdem sonnvoll if (query_overlap > int(chainingParameters.MAX_OVERLAP_EXTENSION * query_range) && target_overlap > int(chainingParameters.MAX_OVERLAP_EXTENSION * target_range)) { do_not_extend = true; break; } } if (do_not_extend) { continue; } int anchor_idx = static_cast(chain->anchors.size()) - 1; do { auto [hsp_result, current_index] = chain->reverse ? extend_between_anchors(cfg, targetBlockId, chain, query_reverse, target, anchor_idx) : extend_between_anchors(cfg, targetBlockId, chain, query, target, anchor_idx); if (hsp_result.evalue < config.max_evalue) { // TODO: put this maybe in front of the condition? range_extended_chains.emplace_back(hsp_result.query_range.begin_, hsp_result.query_range.end_, hsp_result.subject_range.begin_, hsp_result.subject_range.end_); match.hsp.push_back(std::move(hsp_result)); } anchor_idx = current_index; } while (anchor_idx > -1); } auto end_extend = std::chrono::high_resolution_clock::now(); timer.update(4,end_extend-start_extend); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer; } if(config.best_hsp_only) { auto best_hsp_it = std::max_element(match.hsp.begin(), match.hsp.end(), [](const Hsp &a, const Hsp &b) { return a.score < b.score; }); if (best_hsp_it != match.hsp.end()) { Hsp best_hsp = std::move(*best_hsp_it); match.hsp.clear(); match.hsp.push_back(std::move(best_hsp)); } } return match; } std::vector compute_chains(const Search::Config &cfg, const Sequence &query, bool isReverse, const ChainingParameters &chainingParameters) { auto time_start_seed = std::chrono::high_resolution_clock::now(); auto seed_hits = seed_lookup(query, cfg.target->seqs(), cfg.dna_ref_index.get(), cfg.minimizer_window); auto time_end_seed = std::chrono::high_resolution_clock::now(); ExtensionTimer timer_seed; timer_seed.update(5, time_end_seed - time_start_seed); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_seed; } if (seed_hits.empty()) { return {}; } auto time_start_ungapped = std::chrono::high_resolution_clock::now(); seed_hits = merge_and_extend_seeds(seed_hits, query, cfg); auto time_end_ungapped = std::chrono::high_resolution_clock::now(); ExtensionTimer timer_ungapped; timer_seed.update(1, time_end_ungapped - time_start_ungapped); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_seed; } // Sort SeedMatch vector by BlockId and target location j std::sort(seed_hits.begin(), seed_hits.end(), [](const SeedMatch &a, const SeedMatch &b) { return a.id() < b.id() || (a.id() == b.id() && a.j() < b.j()); }); auto hits_it = merge_keys(seed_hits.begin(), seed_hits.end(), [](const SeedMatch &hit1) { return hit1.id(); }); auto time_start_chain = std::chrono::high_resolution_clock::now(); std::vector chains; // process subsets based on unique target id while (hits_it.good()) { auto new_chains = chaining_dynamic_program(chainingParameters, hits_it.begin().operator->(), hits_it.end().operator->(), isReverse); chains.insert(chains.end(), std::make_move_iterator(new_chains.begin()), std::make_move_iterator(new_chains.end())); ++hits_it; } auto time_end_chain = std::chrono::high_resolution_clock::now(); ExtensionTimer timer_chain; timer_chain.update(6, time_end_chain - time_start_chain); { std::lock_guard lock(cfg.timer->mtx); *(cfg.timer) += timer_chain; } return chains; } std::vector chaining_and_extension(const Search::Config &cfg, const Sequence &query, const Sequence &query_reverse) { std::vector matches; ChainingParameters chainingParameters(static_cast(cfg.chain_pen_gap), static_cast(cfg.chain_pen_skip), cfg.min_chain_score, static_cast(cfg.max_overlap_extension)); // static? auto chains = compute_chains(cfg, query, false, chainingParameters); auto chains_reverse = compute_chains(cfg, query_reverse, true, chainingParameters); if (chains.empty() && chains_reverse.empty()) { return matches; } chains.insert( chains.end(), std::make_move_iterator(chains_reverse.begin()), std::make_move_iterator(chains_reverse.end())); //if (config.best_hsp_only) { // only_keep_best_chains_per_target(chains, chainingParameters.MAP_PERCENTAGE_TARGET); //} // sort chains by score std::sort(chains.begin(), chains.end(), std::greater<>()); // compute chain quality if (config.chaining_out) detect_primary_chains(chains); // filter chains by score threshold // TODO: maybe remove from sensitivity modes and only filter when threshold was set (!= 0) const int map_score_threshold = chains[0].chain_score * cfg.chain_fraction_align; auto lower_bound = std::lower_bound(chains.begin(), chains.end(), map_score_threshold, [](const Chain& chain, int threshold) { return chain.chain_score >= threshold; }); chains.erase(lower_bound, chains.end()); std::sort(chains.begin(), chains.end(), [](const Chain &a, const Chain &b) { return (a.target_id == b.target_id) ? (a.chain_score > b.chain_score) : (a.target_id < b.target_id); }); auto iterator_chains_target = merge_keys(chains.begin(), chains.end(), [](const Chain &chain1) { return chain1.target_id; }); while (iterator_chains_target.good()) { Extension::Match match = config.chaining_out ? build_map_hsp(cfg, iterator_chains_target.key(), iterator_chains_target.begin().operator->(), iterator_chains_target.end().operator->()) : extend_chains(cfg, iterator_chains_target.key(), iterator_chains_target.begin().operator->(), iterator_chains_target.end().operator->(), query, query_reverse, chainingParameters); if (!match.hsp.empty()) { matches.push_back(std::move(match)); } ++iterator_chains_target; } return matches; } } bbuchfink-diamond-08b3cbc/src/contrib/dna/extension_chain.h000066400000000000000000000016401506104011400240550ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2023 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "extension.h" namespace Dna { std::vector chaining_and_extension(const Search::Config &cfg, const Sequence &query, const Sequence &query_reverse); } bbuchfink-diamond-08b3cbc/src/contrib/dna/extension_seed_matches.cpp000066400000000000000000000064201506104011400257530ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2024 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "extension_seed_matches.h" #include "../data/block/block.h" #include "../util/util.h" namespace Dna { std::vector extend_seeds_ungapped(const SeedMatch *seedMatchBegin, const SeedMatch *seedMatchEnd, const Sequence &query, const Search::Config &cfg) { const Sequence &target = cfg.target->seqs()[seedMatchBegin->id()]; const int kmer_size = shapes[0].length_; std::vector new_hits; new_hits.reserve(std::distance(seedMatchBegin, seedMatchEnd)); int prev_diagonal = std::numeric_limits::min(); const int query_length = query.length(); const int target_length = target.length(); for (auto hit = seedMatchBegin; hit != seedMatchEnd; ++hit) { const int diagonal = hit->i() - hit->j(); if (diagonal == prev_diagonal && hit->i() <= new_hits.back().i()) { continue; } int left_i = hit->i() - 1; int left_j = hit->j() - 1; while (query[left_i] == target[left_j] && left_i > -1 && left_j > -1) { left_i--; left_j--; } int right_i = hit->i() + kmer_size; int right_j = hit->j() + kmer_size; while (query[right_i] == target[right_j] && right_i < query_length && right_j < target_length) { right_i++; right_j++; } new_hits.emplace_back(right_i, hit->id(), right_j); new_hits.back().score(right_i - left_i - 1); prev_diagonal = diagonal; } return new_hits; } bool compare_by_target_and_diagonal(const SeedMatch& a, const SeedMatch& b) { if (a.id() != b.id()) { return a.id() < b.id(); } if ((a.i() - a.j()) != (b.i() - b.j())) { return (a.i() - a.j()) < (b.i() - b.j()); } return a.i() < b.i(); } std::vector merge_and_extend_seeds(std::vector &seed_hits, const Sequence &query, const Search::Config &cfg) { std::sort(seed_hits.begin(), seed_hits.end(), compare_by_target_and_diagonal); auto hits_it_target = merge_keys(seed_hits.begin(), seed_hits.end(), [](const SeedMatch &hit) { return hit.id(); }); std::vector new_seed_hits; new_seed_hits.reserve(seed_hits.size()); while (hits_it_target.good()) { auto new_hits = extend_seeds_ungapped(hits_it_target.begin().operator->(), hits_it_target.end().operator->(), query, cfg); new_seed_hits.insert(new_seed_hits.end(), std::make_move_iterator(new_hits.begin()), std::make_move_iterator(new_hits.end())); //move sinnvoll? ++hits_it_target; } return new_seed_hits; } } bbuchfink-diamond-08b3cbc/src/contrib/dna/extension_seed_matches.h000066400000000000000000000016421506104011400254210ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2024 Vincent Spath Code developed by Vincent Spath This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "seed_set_dna.h" namespace Dna { std::vector merge_and_extend_seeds(std::vector &seed_hits, const Sequence &query, const Search::Config &cfg); } bbuchfink-diamond-08b3cbc/src/contrib/dna/seed_set_dna.cpp000066400000000000000000000036111506104011400236470ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "seed_set_dna.h" #include #include "../basic/shape_config.h" #include "../basic/seed_iterator.h" #include "../data/block/block.h" #include "../data/sequence_file.h" using std::pair; namespace Dna { std::vector seed_lookup(const Sequence &query, SequenceSet& target_seqs, const Index *filter, Loc window_size){ std::vector seed_matches; std::vector query_sequence = query.copy(); const Shape &seed_shape = shapes[0]; MinimizerIterator it(query_sequence, seed_shape, window_size); while (it.good()) { uint64_t key = *it; pair ref_position = filter->contains(key); if (ref_position.first != nullptr){ for(auto pos = ref_position.first; pos != ref_position.second; pos++){ pair id_loc = target_seqs.local_position(pos->value); seed_matches.emplace_back(it.pos(), id_loc.first, id_loc.second); //ref_position)); } } ++it; } return seed_matches; } SeedMatch::SeedMatch(Loc i, BlockId id, Loc j): i_(i), target_id_(id), j_(j) {} } bbuchfink-diamond-08b3cbc/src/contrib/dna/seed_set_dna.h000066400000000000000000000031501506104011400233120ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "../data/flags.h" #include "dna_index.h" #include "../basic/shape_config.h" #pragma once namespace Dna{ struct SeedMatch{ SeedMatch(Loc i, BlockId id, Loc j); int ungapped_score()const{return score_;} void score(int scr){this->score_ = scr;} Loc i()const{return i_;} Loc j()const{return j_;} BlockId id()const{return target_id_;} int i_start() const { return i_ - score_; } int j_start() const { return j_ - score_; } bool operator>(const SeedMatch& hit)const {return this->id() < hit.id() || ((this->id() == hit.id()) && this->ungapped_score() > hit.ungapped_score());} private: Loc i_; Loc j_; BlockId target_id_; int score_ = shapes[0].length_; }; std::vector seed_lookup(const Sequence &query, SequenceSet& target_seqs, const Index *filter, Loc it_param); }; bbuchfink-diamond-08b3cbc/src/contrib/dna/setup.cpp000066400000000000000000000042621506104011400223750ustar00rootroot00000000000000namespace Dna { const map sensitivity_traits = { {{Sensitivity::FASTER, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 12, 0.0, 40, 0.1 }}, {Sensitivity::FAST, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 10, 0.0, 40, 0.5}}, {Sensitivity::DEFAULT, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 10, 0.0, 20, 0.5 }}, {Sensitivity::SENSITIVE, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 6, 0.0, 20, 0.5 }}, {Sensitivity::VERY_SENSITIVE, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 5, 0.0, 17, 0.5 }}, {Sensitivity::ULTRA_SENSITIVE, {true, false, 20.0, 9, 0, 0, 0, 1, 16, nullptr, 1.0, 2.0, dna, 4, 0.0, 15, 0.5 }}, } }; const map> shape_codes = { { Sensitivity::ULTRA_SENSITIVE, {"111111111111"} }, { Sensitivity::VERY_SENSITIVE, { "1111111111111"} }, { Sensitivity::SENSITIVE, { "11111111111111" } }, { Sensitivity::DEFAULT, { "111111111111111"} }, { Sensitivity::FAST, { "111111111111111" } }, { Sensitivity::FASTER, { "111111111111111111" } } }; void setup_search(Sensitivity sens, Search::Config& cfg) { const SensitivityTraits& traits = sensitivity_traits[(int)align_mode.sequence_type].at(sens); config.sensitivity = sens; ::Config::set_option(cfg.chain_fraction_align, config.chain_fraction_align_, 0.0, traits.chain_fraction_align); ::Config::set_option(cfg.min_chain_score, config.min_chain_score_, 0, traits.min_chain_score); ::Config::set_option(cfg.max_overlap_extension, config.max_overlap_extension_, 0.0, traits.max_overlap_extension); if(align_mode.mode == AlignMode::blastn) Reduction::reduction = dna; cfg.chain_pen_gap = config.chain_pen_gap_scale * 0.01 * (double)shapes[0].length_; cfg.chain_pen_skip = config.chain_pen_skip_scale * 0.01 * (double)shapes[0].length_; } }bbuchfink-diamond-08b3cbc/src/contrib/dna/smith_watermann.cpp000066400000000000000000000061271506104011400244370ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "smith_watermann.h" #include "../data/block/block.h" #include "../data/sequence_file.h" #include using std::vector; namespace SmithWaterman{ int scoringFunction(int match, int mismatch, Letter first,Letter second){ if(first == second) return match; else return mismatch; } int dynamic_programm(const Sequence &target, const Sequence &query, int match, int mismatch, int gapopen, int gapextend){ vector> dp_matrix(query.length()+1,vector(target.length()+1,0)); vector hgap(target.length()+1,0); int max = 0; for(int i = 1; i < (int)dp_matrix.size(); i++){ int vgap = 0; for (int j = 1; j<(int)dp_matrix[0].size(); j++){ int s = dp_matrix[i-1][j-1]+ scoringFunction(match,mismatch, query[i-1], target[j-1]); s = std::max({s,hgap[j],vgap,0},std::less()); dp_matrix[i][j] = s ; vgap -= gapextend; hgap[j] -= gapextend; int open = s - gapopen - gapextend; vgap = std::max(vgap, open); hgap[j] = std::max(hgap[j], open); if(dp_matrix[i][j] > max){ max = dp_matrix[i][j]; } } } return max; } std::pair, Extension::Stats> local_alignment(const Search::Config &cfg,BlockId query_id){ vector matches; SequenceSet& target_seqs = cfg.target->seqs(); Sequence query_sequence = cfg.query->seqs()[query_id]; for(int i = 0; i < target_seqs.size(); i ++){ Sequence target_sequence = target_seqs[i]; Extension::Match m = Extension::Match(query_id,target_sequence,::Stats::TargetMatrix(),0,0); int score = dynamic_programm(target_sequence, query_sequence,cfg.score_builder->reward(), cfg.score_builder->penalty(), cfg.score_builder->gap_open(), cfg.score_builder->gap_extend()) ; m.hsp.emplace_back(Hsp(false,score)); m.hsp.back().bit_score = cfg.score_builder->blast_bit_Score(score); m.hsp.back().evalue = cfg.score_builder->blast_eValue(score,query_sequence.length()); matches.emplace_back(m); } return { matches, Extension::Stats()}; } }bbuchfink-diamond-08b3cbc/src/contrib/dna/smith_watermann.h000066400000000000000000000017751506104011400241100ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "../basic/match.h" #include "../run/config.h" #include "../align/extend.h" namespace SmithWaterman { std::pair, Extension::Stats> local_alignment(const Search::Config &cfg, BlockId query_id); }bbuchfink-diamond-08b3cbc/src/contrib/dna/timer.h000066400000000000000000000076321506104011400220260ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2022 Dimitrios Koutsogiannis Code developed by Dimitrios Koutsogiannis This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "chrono" #include "mutex" #include "iostream" namespace Dna{ using Duration = std::chrono::duration>; struct ExtensionTimer { ExtensionTimer(): total_time(), preprocessing_time(), postprocessing_time(), extension(), next(), chaining(), extension_filter() {}; ExtensionTimer& operator+=(ExtensionTimer& other)noexcept{ this->total_time += (other.total_time); this->extension += (other.extension); this->preprocessing_time += (other.preprocessing_time); this->postprocessing_time += (other.postprocessing_time); this->next += (other.next); this->chaining += (other.chaining); this->extension_filter += (other.extension_filter); other.total_time = std::chrono::duration(0); other.extension = std::chrono::duration(0); other.preprocessing_time = std::chrono::duration(0); other.postprocessing_time = std::chrono::duration(0); other.next = std::chrono::duration(0); other.chaining = std::chrono::duration(0); other.extension_filter = std::chrono::duration(0); return *this; }; void update(int operation , std::chrono::duration> duration){ switch(operation){ case 0: total_time.operator+=(duration); break; case 1: preprocessing_time.operator+=(duration); break; case 2: postprocessing_time.operator+=(duration); break; case 3: extension_filter.operator+=(duration); break; case 4: extension.operator+=(duration); break; case 5: next.operator+=(duration); break; case 6: chaining.operator+=(duration); break; } }; Duration total_time; Duration preprocessing_time; Duration postprocessing_time; Duration extension; Duration next; Duration chaining; Duration extension_filter; std::mutex mtx; }; struct TotalTime: ExtensionTimer{ void print() { //std::cerr << "Total Time: " << total_time.count() / 1'000'000'000.0 << " seconds\n"; //std::cerr << "Pre-Processing: " << preprocessing_time.count() / 1'000'000'000.0 << " seconds\n"; std::cerr << "Chaining: " << chaining.count() / 1'000'000'000.0 << " seconds\n"; std::cerr << "Extension-Time: " << extension.count() / 1'000'000'000.0 << " seconds\n"; std::cerr << "seed-lookup: " << next.count() / 1'000'000'000.0 << " seconds\n"; std::cerr << "build Hsp from cigar (part of extension): " << postprocessing_time.count() / 1'000'000'000.0 << " seconds\n"; std::cerr << "ungapped: " << preprocessing_time.count() / 1'000'000'000.0 << " seconds\n"; //std::cerr << "extension_filter: " << extension_filter.count() / 1'000'000'000.0 << " seconds\n"; } ~TotalTime(){ print(); }; }; } bbuchfink-diamond-08b3cbc/src/contrib/mcl/000077500000000000000000000000001506104011400205365ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/contrib/mcl/clustering_format.cpp000066400000000000000000000035651506104011400250020ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "output_format.h" #include "../data/queries.h" #include "recursive_parser.h" using std::string; void Clustering_format::print_match(const HspContext& r, Output::Info& info) { info.out.write((uint32_t) r.query_oid); info.out.write((uint32_t) r.subject_oid); RecursiveParser rp(&r, format.c_str()); const double res = rp.evaluate(); info.out.write(res); } Clustering_format::Clustering_format(const string* const format): OutputFormat(bin1, HspValues::NONE), format(RecursiveParser::clean_expression(format)) { RecursiveParser rp(nullptr, format->c_str()); rp.evaluate(); const auto vars = rp.variables(); for (const Variable* v : vars) { this->hsp_values |= v->hsp_values; this->flags |= v->flags; } } void Bin1_format::print_query_intro(Output::Info& info) const { info.out.write(std::numeric_limits::max()); info.out.write((uint32_t)info.query.block_id); } void Bin1_format::print_match(const HspContext& r, Output::Info& info) { if (r.query_id < r.subject_oid) { info.out.write((uint32_t)r.subject_oid); info.out.write(r.bit_score() / std::max(r.query.source().length(), r.subject_len)); } }bbuchfink-diamond-08b3cbc/src/contrib/mcl/clustering_variables.cpp000066400000000000000000000015161506104011400254540ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "clustering_variables.h" StaticVariableRegistry VariableRegistry::vr; bbuchfink-diamond-08b3cbc/src/contrib/mcl/clustering_variables.h000066400000000000000000000214641506104011400251250ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "../stats/score_matrix.h" #include "../basic/match.h" #include "def.h" #include "../dp/flags.h" #include "def.h" class Variable{ public: Variable(const HspValues hsp_values = HspValues::NONE, const Output::Flags flags = Output::Flags::NONE): hsp_values(hsp_values), flags(flags) {} virtual double get(const HspContext& r) const = 0; virtual ~Variable(){}; const HspValues hsp_values; const Output::Flags flags; }; class QueryLength: public Variable{ public: static const std::string get_name(){ return "qlen"; } virtual double get(const HspContext& r) const override { return r.query.source().length(); } }; class SubjectLength: public Variable{ public: static const std::string get_name(){ return "slen"; } virtual double get(const HspContext& r) const override { return r.subject_len; } }; class QueryStart: public Variable{ public: QueryStart(): Variable(HspValues::QUERY_START) {} static const std::string get_name(){ return "qstart"; } virtual double get(const HspContext& r) const override { return r.oriented_query_range().begin_ + 1; } }; class QueryEnd: public Variable{ public: QueryEnd() : Variable(HspValues::QUERY_END) {} static const std::string get_name(){ return "qend"; } virtual double get(const HspContext& r) const override { return r.oriented_query_range().end_ + 1; } }; class SubjectStart: public Variable{ public: SubjectStart() : Variable(HspValues::TARGET_START) {} static const std::string get_name(){ return "sstart"; } virtual double get(const HspContext& r) const override { return r.subject_range().begin_ + 1; } }; class SubjectEnd: public Variable{ public: SubjectEnd() : Variable(HspValues::TARGET_END) {} static const std::string get_name(){ return "send"; } virtual double get(const HspContext& r) const override { return r.subject_range().end_; } }; class EValue: public Variable{ public: static const std::string get_name(){ return "evalue"; } virtual double get(const HspContext& r) const override { return r.evalue(); } }; class BitScore: public Variable{ public: static const std::string get_name(){ return "bitscore"; } virtual double get(const HspContext& r) const override { return r.bit_score(); } }; class RawScore: public Variable{ public: static const std::string get_name(){ return "score"; } virtual double get(const HspContext& r) const override { return r.score(); } }; class Length: public Variable{ public: Length(): Variable(HspValues::LENGTH) {} static const std::string get_name(){ return "length"; } virtual double get(const HspContext& r) const override { return r.length(); } }; class PercentIdenticalMatches: public Variable{ public: PercentIdenticalMatches(): Variable(HspValues::LENGTH | HspValues::IDENT) {} static const std::string get_name(){ return "pident"; } virtual double get(const HspContext& r) const override { return (double)r.identities() * 100 / r.length(); } }; class NumberIdenticalMatches: public Variable{ public: NumberIdenticalMatches() : Variable(HspValues::IDENT) {} static const std::string get_name(){ return "nident"; } virtual double get(const HspContext& r) const override { return r.identities(); } }; class NumberMismatches: public Variable{ public: NumberMismatches() : Variable(HspValues::MISMATCHES) {} static const std::string get_name(){ return "mismatch"; } virtual double get(const HspContext& r) const override { return r.mismatches(); } }; class NumberPositiveMatches: public Variable{ public: NumberPositiveMatches() : Variable(HspValues::TRANSCRIPT) {} static const std::string get_name(){ return "positive"; } virtual double get(const HspContext& r) const override { return r.positives(); } }; class NumberGapOpenings: public Variable{ public: NumberGapOpenings() : Variable(HspValues::GAP_OPENINGS) {} static const std::string get_name(){ return "gapopen"; } virtual double get(const HspContext& r) const override { return r.gap_openings(); } }; class NumberGaps: public Variable{ public: NumberGaps() : Variable(HspValues::GAPS) {} static const std::string get_name(){ return "gaps"; } virtual double get(const HspContext& r) const override { return r.gaps(); } }; class PercentagePositiveMatches: public Variable{ public: PercentagePositiveMatches() : Variable(HspValues::TRANSCRIPT) {} static const std::string get_name(){ return "ppos"; } virtual double get(const HspContext& r) const override { return (double)r.positives() * 100.0 / r.length(); } }; class QueryFrame: public Variable{ public: static const std::string get_name(){ return "qframe"; } virtual double get(const HspContext& r) const override { return r.blast_query_frame(); } }; class QueryCoveragePerHsp: public Variable{ public: QueryCoveragePerHsp() : Variable(HspValues::QUERY_COORDS) {} static const std::string get_name(){ return "qcovhsp"; } virtual double get(const HspContext& r) const override { return (double)r.query_source_range().length()*100.0 / r.query.source().length(); } }; class SubjectCoveragePerHsp: public Variable{ public: SubjectCoveragePerHsp() : Variable(HspValues::TARGET_COORDS) {} static const std::string get_name(){ return "scovhsp"; } virtual double get(const HspContext& r) const override { return (double)r.subject_range().length() * 100.0 / r.subject_len; } }; struct NormalizedBitScoreGlobal : public Variable { NormalizedBitScoreGlobal(): Variable(HspValues::NONE, Output::Flags::SELF_ALN_SCORES) {} static const std::string get_name() { return "normalized_bitscore_global"; } virtual double get(const HspContext& r) const override { return r.bit_score() / std::max(r.query_self_aln_score, r.target_self_aln_score) * 100; } }; class StaticVariableRegistry{ std::map regMap; public: StaticVariableRegistry(){ // To include new variables add the instantiation here and in the clustering_variable.cpp file. Then add it to the StaticConstructor below regMap[QueryLength::get_name()] = new QueryLength(); regMap[SubjectLength::get_name()] = new SubjectLength(); regMap[QueryStart::get_name()] = new QueryStart(); regMap[QueryEnd::get_name()] = new QueryEnd(); regMap[SubjectStart::get_name()] = new SubjectStart(); regMap[SubjectEnd::get_name()] = new SubjectEnd(); regMap[EValue::get_name()] = new EValue(); regMap[BitScore::get_name()] = new BitScore(); regMap[RawScore::get_name()] = new RawScore(); regMap[Length::get_name()] = new Length(); regMap[PercentIdenticalMatches::get_name()] = new PercentIdenticalMatches(); regMap[NumberIdenticalMatches::get_name()] = new NumberIdenticalMatches(); regMap[NumberMismatches::get_name()] = new NumberMismatches(); regMap[NumberPositiveMatches::get_name()] = new NumberPositiveMatches(); regMap[NumberGapOpenings::get_name()] = new NumberGapOpenings(); regMap[NumberGaps::get_name()] = new NumberGaps(); regMap[PercentagePositiveMatches::get_name()] = new PercentagePositiveMatches(); regMap[QueryFrame::get_name()] = new QueryFrame(); regMap[QueryCoveragePerHsp::get_name()] = new QueryCoveragePerHsp(); regMap[SubjectCoveragePerHsp::get_name()] = new SubjectCoveragePerHsp(); regMap[NormalizedBitScoreGlobal::get_name()] = new NormalizedBitScoreGlobal(); } ~StaticVariableRegistry(){ for(auto it = regMap.begin(); it != regMap.end(); it++){ delete it->second; it->second = nullptr; } } Variable* get(std::string key) const { auto ca = regMap.find(key); if(ca == regMap.end()){ throw std::runtime_error(std::string("Unknown variable: ")+ key); } return ca->second; } bool has(std::string key) const { return regMap.find(key) != regMap.end(); } std::vector getKeys() const { auto it = regMap.begin(); std::vector keys; while(it != regMap.end()){ keys.push_back(it->first); it++; } return keys; } }; class VariableRegistry{ static StaticVariableRegistry vr; public: static Variable* get(std::string key){ return vr.get(key); } static bool has(std::string key){ return vr.has(key); } static std::vector getKeys(){ return vr.getKeys(); } }; bbuchfink-diamond-08b3cbc/src/contrib/mcl/dense.h000066400000000000000000000103371506104011400220110ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once namespace Workflow { namespace Cluster{ void MCL::get_exp(Eigen::MatrixXf* in, Eigen::MatrixXf* out, float r){ // TODO: at some r it may be more beneficial to diagnoalize in and only take the exponents of the eigenvalues high_resolution_clock::time_point t = high_resolution_clock::now(); if(r - (int) r == 0){ *out = *in; for(uint32_t i=1; ipow(r) dense_int_exp_time += duration_cast(high_resolution_clock::now() - t).count(); } else{ // TODO: check whether the matrix is self-adjoint and use SelfAdjointEigenSolver instead // TODO: try and get out->noalias() = in->pow(r); to work (unsupported! http://eigen.tuxfamily.org/dox/unsupported/group__MatrixFunctions__Module.html). Eigen::EigenSolver solver(*in); Eigen::MatrixXcf d = solver.eigenvalues().asDiagonal(); for(uint32_t idiag = 0; idiag numeric_limits::epsilon() ){ out->noalias() = (V * d.real() * V.inverse()).real(); } dense_gen_exp_time += duration_cast(high_resolution_clock::now() - t).count(); } } void MCL::get_gamma(Eigen::SparseMatrix* in, Eigen::SparseMatrix* out, float r, uint32_t nThr) { high_resolution_clock::time_point t = high_resolution_clock::now(); vector> data; std::mutex m; auto mult = [&](const uint32_t iThr) { vector> t_data = sparse_matrix_get_gamma(in, r, iThr, nThr); m.lock(); data.insert(data.end(), t_data.begin(), t_data.end()); m.unlock(); }; vector threads; for (uint32_t iThread = 0; iThread < nThr; iThread++) { threads.emplace_back(mult, iThread); } for (uint32_t iThread = 0; iThread < nThr; iThread++) { threads[iThread].join(); } out->setZero(); out->setFromTriplets(data.begin(), data.end(), [](const float&, const float &b) { return b; }); *out = out->pruned(1.0, numeric_limits::epsilon()); sparse_gamma_time += duration_cast(high_resolution_clock::now() - t).count(); } void MCL::get_gamma(Eigen::MatrixXf* in, Eigen::MatrixXf* out, float r) { high_resolution_clock::time_point t = high_resolution_clock::now(); // Note that Eigen matrices are column-major, so this is the most efficient way for (uint32_t icol = 0; icol < in->cols(); ++icol) { float colSum = 0.0f; for (uint32_t irow = 0; irow < in->rows(); ++irow) { colSum += pow(in->coeffRef(irow, icol), r); } for (uint32_t irow = 0; irow < in->rows(); ++irow) { out->coeffRef(irow, icol) = pow(in->coeffRef(irow, icol), r) / colSum; } } dense_gamma_time += duration_cast(high_resolution_clock::now() - t).count(); } void MCL::markov_process(Eigen::MatrixXf* m, float inflation, float expansion, uint32_t max_iter) { uint32_t iteration = 0; float diff_norm = numeric_limits::max(); Eigen::MatrixXf msquared(m->rows(), m->cols()); Eigen::MatrixXf m_update(m->rows(), m->cols()); get_gamma(m, m, 1); // This is to get a matrix of random walks on the graph -> TODO: find out if something else is more suitable while (iteration < max_iter && diff_norm > numeric_limits::epsilon()) { get_exp(m, &msquared, expansion); get_gamma(&msquared, &m_update, inflation); *m -= m_update; diff_norm = m->norm(); *m = m_update; iteration++; } if (iteration == max_iter) { failed_to_converge++; } } }}bbuchfink-diamond-08b3cbc/src/contrib/mcl/lazy_disjoint_set.h000066400000000000000000000135031506104011400244460ustar00rootroot00000000000000/**** DIAMOND protein aligner - Markov Clustering Module Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include #include #pragma once template class Node { Node* parent = this; uint32_t r = 0; public: virtual ~Node(){}; virtual Node* getParent(){ return parent; } virtual void setParent(Node* p){ parent = p; } virtual const T* getValue() = 0; virtual uint32_t getCount(){ return r; } virtual void incrementCount(){ r++; } }; template class IntegralNode: public Node { private: T value; public: virtual ~IntegralNode(){}; IntegralNode(T v){ value = v; } virtual const T* getValue(){ return &value; } }; template class TypeNode: public Node { private: const T* value; uint32_t r; public: virtual ~TypeNode(){}; TypeNode(const T* v){ value = v; } virtual const T* getValue(){ return value; } }; template class LazyDisjointSet { private: virtual Node* get(const T i) = 0; virtual Node* get(const T* i) = 0; virtual uint64_t size() = 0; virtual std::vector*>* getNodes() = 0; public: virtual ~LazyDisjointSet(){}; virtual Node* getRoot(Node* x) { if (x->getParent() != x) { // flatten the tree while traversing x->setParent(getRoot(x->getParent())); } return x->getParent(); } virtual void merge(Node* x, Node* y) { if (x != y) { Node* rootX = getRoot(x); Node* rootY = getRoot(y); if (rootX != rootY) { if (rootX->getCount() < rootY->getCount()) { rootX->setParent(rootY); } else if (rootX->getCount() > rootY->getCount()) { rootY->setParent(rootX); } else { rootX->incrementCount(); rootY->setParent(rootX); } } } } virtual void merge(const T* x, const T* y) { merge(get(x), get(y)); } void merge(T x, T y) { merge(get(x), get(y)); } virtual std::vector> getListOfSets() { std::unordered_map map; uint32_t index = 0; for (Node* n : *(getNodes())) { if (n == nullptr) { continue; } const T* r = getRoot(n)->getValue(); if (map.find(r) == map.end()) { map.emplace(r, index++); } } std::vector> listOfSets(map.size()); for (Node* n : *(getNodes())) { if (n == nullptr) { continue; } listOfSets[map[getRoot(n)->getValue()]].insert(*(n->getValue())); } return listOfSets; } }; template class LazyDisjointIntegralSet : public LazyDisjointSet { private: std::vector*> nodes; virtual Node* get(T i){ assert(i >= 0 && nodes.size() > (size_t)i); if(nodes[i] == nullptr){ nodes[i] = new IntegralNode(i); } return nodes[i]; } virtual Node* get(const T* i) { return get(*i); } virtual uint64_t size(){ return nodes.size(); } virtual std::vector*>* getNodes(){ return &nodes; } public: static_assert(std::is_integral::value, "T needs to be an integral type"); LazyDisjointIntegralSet(T size) { nodes = std::vector*>(size, nullptr); } virtual ~LazyDisjointIntegralSet() { for(Node* n : nodes){ if (n != nullptr){ delete n; n = nullptr; } } nodes.clear(); } virtual std::vector> getListOfSets() { std::unordered_map map; uint32_t index = 0; for(T i = 0; i < (T)nodes.size(); i++){ const T* r = this->getRoot(get(i))->getValue(); if (map.find(r) == map.end()) { map.emplace(r, index++); } } std::vector> listOfSets(map.size()); for (Node* n : *(getNodes())) { if (n == nullptr) { throw new std::runtime_error("In an integral set, we expect all elements to be initialized, see loop beofre.\n"); } listOfSets[map[this->getRoot(n)->getValue()]].insert(*(n->getValue())); } return listOfSets; } }; template class LazyDisjointTypeSet : public LazyDisjointSet { private: std::unordered_set* elements; std::vector*> nodes; std::unordered_map mapping; bool isIntegralAndConsecutive; virtual Node* get(const T* i) { auto found = mapping.find(i); assert(found != mapping.end()); return nodes[found->second]; } virtual Node* get(T i) { auto found = elements->find(i); assert(found != elements->end()); return get(&(*found)); } virtual uint64_t size(){ return nodes.size(); } virtual std::vector*>* getNodes(){ return &nodes; } public: LazyDisjointTypeSet(std::unordered_set* s) { // note that the structure is backed by the set, so it should not be modified isIntegralAndConsecutive = false; elements = s; nodes = std::vector*>(elements->size()); mapping = std::unordered_map(elements->size()); for(auto e = elements->begin(); e != elements->end(); e++){ mapping[&(*e)] = nodes.size(); Node* n = new TypeNode(&(*e)); nodes.push_back(n); } } virtual ~LazyDisjointTypeSet() { mapping.clear(); for(Node* n : nodes){ if (n != nullptr){ delete n; n = nullptr; } } nodes.clear(); } }; bbuchfink-diamond-08b3cbc/src/contrib/mcl/mcl.cpp000066400000000000000000000605311506104011400220220ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "mcl.h" #include "sparse_matrix_stream.h" #include "../util/util.h" #include "../util/sequence/sequence.h" #define MASK_INVERSE 0xC000000000000000 #define MASK_NORMAL_NODE 0x4000000000000000 #define MASK_ATTRACTOR_NODE 0x8000000000000000 #define MASK_SINGLE_NODE 0xC000000000000000 const double DEFAULT_CLUSTERING_THRESHOLD = 50; using std::thread; using std::numeric_limits; using std::chrono::high_resolution_clock; using std::chrono::duration_cast; using std::chrono::milliseconds; using std::function; using std::setprecision; using std::endl; using std::setw; using std::atomic_uint; using std::right; using std::memory_order_relaxed; using std::shared_ptr; using std::fill; using std::cout; using std::ostream; using std::max; #include "sparse.h" #include "dense.h" namespace Workflow { namespace Cluster{ string MCL::get_description() { return "Markov clustering according to doi:10.1137/040608635"; } void MCL::print_stats(int64_t nElements, int64_t nComponents, int64_t nComponentsLt1, vector& sort_order, vector>& indices, SparseMatrixStream* ms){ task_timer timer; timer.go("Collecting stats"); const uint32_t chunk_size = config.cluster_mcl_chunk_size; const int nThreads = min(config.threads_, int(nComponents / chunk_size)); const float inflation = (float) config.cluster_mcl_inflation; const float expansion = (float) config.cluster_mcl_expansion; vector sparsities(nComponentsLt1); vector neighbors(nComponentsLt1); vector memories(nComponentsLt1); int64_t max_job_size = 0; for(uint32_t i=0; iallocate_read_buffer(1); while(my_counter < nComponentsLt1){ unordered_set all; Id upper_limit = min(my_counter+my_chunk_size, nComponentsLt1); vector*> loc_i; for (Id chunk_counter = my_counter; chunk_counter < upper_limit; chunk_counter++) { loc_i.push_back(&indices[sort_order[chunk_counter]]); } vector>> loc_c = ms->collect_components(&loc_i, 0); uint32_t ichunk = 0; generate(sparsities.begin()+my_counter, sparsities.begin()+upper_limit, [my_counter, ichunk, &sort_order, &indices, &loc_c]() mutable -> float { const uint32_t iComponent = sort_order[my_counter++]; const int64_t ssize = loc_c[ichunk++].size(); const uint64_t dsize = indices[iComponent].size() * indices[iComponent].size(); return 1.0f - (1.0f * ssize) / dsize; }); generate(neighbors.begin()+my_counter, neighbors.begin()+upper_limit, [my_counter, ichunk, &sort_order, &indices, &loc_c]() mutable -> float { uint32_t neighbors = 0; const uint32_t iComponent = sort_order[my_counter++]; for(auto t: loc_c[ichunk++]){ if(t.row() != t.col()) neighbors++; } return neighbors / ((float) indices[iComponent].size()); }); generate(memories.begin()+my_counter, memories.begin()+upper_limit, [my_counter, &sort_order, &indices, &neighbors, &sparsities, &expansion]() mutable -> float { const uint32_t iComponent = sort_order[my_counter++]; if(sparsities[my_counter- 1] >= config.cluster_mcl_sparsity_switch){ return (float)indices[iComponent].size() * (1+pow(neighbors[my_counter-1], expansion)) * (2 * sizeof(uint32_t) + sizeof(float)); } else{ return (float) sizeof(float) * indices[iComponent].size() * indices[iComponent].size(); } }); my_chunk_size = 0; for(auto const i : loc_i) my_chunk_size += i->size(); my_chunk_size = loc_i.size() * (max_job_size / my_chunk_size); my_counter = component_counter; component_counter += my_chunk_size; } sort(memories.rbegin(), memories.rend()); float mem_req = nElements * (2 * sizeof(uint32_t) + sizeof(float)); for(int iThr = 0; iThr < nThreads; iThr++){ mem_req += 3*memories[iThr]; // we need three matrices of this size } float neighbors_of_max = neighbors[0]; float neighbors_of_med = nComponentsLt1 > 0 && nComponentsLt1 % 2 == 0 ? (neighbors[nComponentsLt1/2] + neighbors[nComponentsLt1/2+1]) / 2.0f : neighbors[nComponentsLt1/2+1] ; float neighbors_of_min = neighbors[nComponentsLt1-1]; float sparsity_of_max = sparsities[0]; float sparsity_of_med = nComponentsLt1 > 0 && nComponentsLt1 % 2 == 0 ? (sparsities[nComponentsLt1/2] + sparsities[nComponentsLt1/2+1]) / 2.0f : sparsities[nComponentsLt1/2+1] ; float sparsity_of_min = sparsities[nComponentsLt1-1]; sort(sparsities.rbegin(), sparsities.rend()); sort(neighbors.rbegin(), neighbors.rend()); float med_sparsity = nComponentsLt1 > 0 && nComponentsLt1 % 2 == 0 ? (sparsities[nComponentsLt1/2] + sparsities[nComponentsLt1/2+1]) / 2.0f : sparsities[nComponentsLt1/2+1] ; float med_neighbors = nComponentsLt1 > 0 && nComponentsLt1 % 2 == 0 ? (neighbors[nComponentsLt1/2] + neighbors[nComponentsLt1/2+1]) / 2.0f : neighbors[nComponentsLt1/2+1] ; float median1 = nComponents > 0 && nComponents % 2 == 0 ? (indices[sort_order[nComponents/2]].size() + indices[sort_order[nComponents/2+1]].size()) / 2.0f : indices[sort_order[nComponents/2+1]].size(); float median2 = nComponentsLt1 > 0 && nComponentsLt1 % 2 == 0 ? (indices[sort_order[nComponentsLt1/2]].size() + indices[sort_order[nComponentsLt1/2+1]].size()) / 2.0f : indices[sort_order[nComponentsLt1/2+1]].size(); timer.finish(); message_stream << "Number of DIAMOND hits: " << nElements << endl; message_stream << "Number of independet components: " << nComponentsLt1 <<" ("<release_read_buffer(); } shared_ptr> get_graph_handle(shared_ptr& db){ const bool symmetric = !config.cluster_mcl_nonsymmetric; if(config.cluster_restart){ task_timer timer; timer.go("Reading cluster checkpoint file"); shared_ptr> ms(SparseMatrixStream::fromFile(symmetric, config.cluster_graph_file, (float)config.chunk_size)); timer.finish(); ms->done(); return ms; } config.command = Config::blastp; config.no_self_hits = false; config.max_target_seqs_.set_if_blank(INT64_MAX); string format = config.cluster_similarity; if (format.empty()) { format = "normalized_bitscore_global"; config.cluster_threshold.set_if_blank(DEFAULT_CLUSTERING_THRESHOLD); if (config.cluster_threshold == 0.0) config.cluster_threshold.unset(); } else if (config.cluster_threshold.blank()) std::cerr << "WARNING: It is recommended to set a threshold value for the clustering similarity measure (option `--cluster-threshold`)." << std::endl; config.output_format = {"clus", format}; shared_ptr> ms(new SparseMatrixStream(symmetric, db->sequence_count(), config.cluster_graph_file)); if(config.chunk_size > 0){ ms->set_max_mem((float)config.chunk_size); } Search::run(db, nullptr, ms); ms->done(); return ms; } Eigen::SparseMatrix MCL::get_sparse_matrix_and_clear(vector* order, vector>* m, bool symmetric){ Eigen::SparseMatrix m_sparse(order->size(), order->size()); if(symmetric){ uint64_t oSize = m->size(); for(uint64_t i = 0; i& t = m->at(i); if(t.col() != t.row()){ m->emplace_back(t.col(), t.row(), t.value()); } } } m_sparse.setFromTriplets(m->begin(), m->end()); m->clear(); return m_sparse; } Eigen::MatrixXf MCL::get_dense_matrix_and_clear(vector* order, vector>* m, bool symmetric){ Eigen::MatrixXf m_dense = Eigen::MatrixXf::Zero(order->size(), order->size()); for(Eigen::Triplet const & t : *m){ m_dense(t.row(), t.col()) = t.value(); if(symmetric && t.col() != t.row()) m_dense(t.col(), t.row()) = t.value(); } m->clear(); return m_dense; } void MCL::run(){ // testing // LazyDisjointIntegralSet test(5); // test.merge(1,3); // test.merge(3,4); // test.merge(0,2); // auto los = test.getListOfSets(); // for(auto& set: los){ // for(auto item:set){ // cout<< " " << item; // } // cout< s ( {"red","green","blue","rain", "sun", "snow"} ); // LazyDisjointTypeSet ts(&s); // ts.merge("red", "green"); // ts.merge("snow", "rain"); // ts.merge("sun", "rain"); // auto lo = ts.getListOfSets(); // for(auto& set: lo){ // cout<< "set :"; // for(auto item:set){ // cout<< " " << item; // } // cout< s ( {183, 239, 23834, 3399, 484, 2} ); // LazyDisjointTypeSet ts(&s); // ts.merge(183, 3399); // ts.merge(23834, 2); // ts.merge(183, 484); // auto lo = ts.getListOfSets(); // for(auto& set: lo){ // cout<< "set :"; // for(auto item:set){ // cout<< " " << item; // } // cout<> data; // data.emplace_back(0, 0, 0.2f); // data.emplace_back(0, 1, 0.25f); // data.emplace_back(0, 5, 0.333f); // data.emplace_back(0, 6, 0.25f); // data.emplace_back(0, 9, 0.25f); // data.emplace_back(1, 0, 0.20f); // data.emplace_back(1, 1, 0.25f); // data.emplace_back(1, 2, 0.25f); // data.emplace_back(1, 4, 0.20f); // data.emplace_back(2, 1, 0.25f); // data.emplace_back(2, 2, 0.25f); // data.emplace_back(2, 3, 0.20f); // data.emplace_back(2, 4, 0.20f); // data.emplace_back(3, 2, 0.25f); // data.emplace_back(3, 3, 0.20f); // data.emplace_back(3, 7, 0.20f); // data.emplace_back(3, 8, 0.20f); // data.emplace_back(3, 10, 0.20f); // data.emplace_back(4, 1, 0.25f); // data.emplace_back(4, 2, 0.25f); // data.emplace_back(4, 4, 0.20f); // data.emplace_back(4, 6, 0.25f); // data.emplace_back(4, 7, 0.20f); // data.emplace_back(5, 0, 0.20f); // data.emplace_back(5, 5, 0.333f); // data.emplace_back(5, 9, 0.25f); // data.emplace_back(6, 0, 0.20f); // data.emplace_back(6, 4, 0.20f); // data.emplace_back(6, 6, 0.25f); // data.emplace_back(6, 9, 0.25f); // data.emplace_back(7, 3, 0.20f); // data.emplace_back(7, 4, 0.20f); // data.emplace_back(7, 7, 0.20f); // data.emplace_back(7, 8, 0.20f); // data.emplace_back(7, 10, 0.20f); // data.emplace_back(8, 3, 0.20f); // data.emplace_back(8, 7, 0.20f); // data.emplace_back(8, 8, 0.20f); // data.emplace_back(8, 10, 0.20f); // data.emplace_back(8, 11, 0.333f); // data.emplace_back(9, 0, 0.20f); // data.emplace_back(9, 5, 0.333f); // data.emplace_back(9, 6, 0.25f); // data.emplace_back(9, 9, 0.25f); // data.emplace_back(10, 3, 0.20f); // data.emplace_back(10, 7, 0.20f); // data.emplace_back(10, 8, 0.20f); // data.emplace_back(10, 10, 0.20f); // data.emplace_back(10, 11, 0.333f); // data.emplace_back(11, 8, 0.20f); // data.emplace_back(11, 10, 0.20f); // data.emplace_back(11, 11, 0.333f); // vector> cr; // float inf = 2.0; // float exp = 2.0; // if(false){ // Eigen::SparseMatrix tmp(12,12); // tmp.setFromTriplets(data.begin(), data.end()); // printMatrix(&tmp); // cr = markov_process(&tmp, inf, exp); // printMatrix(&tmp); // } // else{ // Eigen::MatrixXf tmp = Eigen::MatrixXf::Zero(12,12); // for(Eigen::Triplet const & t : data){ // tmp(t.row(), t.col()) = t.value(); // } // printMatrix(&tmp); // cr = markov_process(&tmp, inf, exp); // printMatrix(&tmp); // } // cout << "Found "< db(SequenceFile::auto_create({ config.database })); statistics.reset(); shared_ptr> ms(get_graph_handle(db)); task_timer timer; timer.go("Computing independent components"); vector> indices = ms->get_indices(); ms->clear_disjoint_set(); uint64_t nElements = ms->getNumberOfElements(); uint32_t nComponents = count_if(indices.begin(), indices.end(), [](vector v){ return v.size() > 0;}); uint32_t nComponentsLt1 = count_if(indices.begin(), indices.end(), [](vector v){ return v.size() > 1;}); // Sort to get the largest chunks first vector sort_order(indices.size()); iota(sort_order.begin(), sort_order.end(), 0); sort(sort_order.begin(), sort_order.end(), [&](int64_t i, int64_t j){return indices[i].size() > indices[j].size();}); timer.finish(); if(config.cluster_mcl_stats){ print_stats(nElements, nComponents, nComponentsLt1, sort_order, indices, ms.get()); } timer.go("Clustering components"); // Note, we will access the clustering_result from several threads below and a vector does not guarantee thread-safety in these situations. // Note also, that the use of the disjoint_set structure guarantees that each thread will access a different part of the clustering_result uint64_t* clustering_result = new uint64_t[db->sequence_count()]; fill(clustering_result, clustering_result+db->sequence_count(), 0UL); // note that the disconnected components are sorted by size const uint32_t chunk_size = config.cluster_mcl_chunk_size; const int nThreads = min(config.threads_, int(nComponents / chunk_size)); const uint32_t exessThreads = config.threads_ - nThreads; ms->allocate_read_buffer(nThreads); const float inflation = (float) config.cluster_mcl_inflation; const float expansion = (float) config.cluster_mcl_expansion; const int64_t max_counter = nComponents; const uint32_t max_iter = config.cluster_mcl_max_iter; int64_t max_job_size = 0; for(uint32_t i=0; i all; uint32_t upper_limit = min(my_counter+my_chunk_size, max_counter); vector*> loc_i; for(uint32_t chunk_counter = my_counter; chunk_counter>> loc_c = ms->collect_components(&loc_i, iThr); uint32_t ichunk = 0; for(uint32_t chunk_counter = my_counter; chunk_counter* order = loc_i[ichunk]; if(order->size() > 1){ vector>* m = &loc_c[ichunk]; assert(m->size() <= order->size() * order->size()); // map back to original ids vector> list_of_sets; unordered_set attractors; const float sparsity = 1.0-(1.0 * m->size()) / (order->size()*order->size()); high_resolution_clock::time_point t = high_resolution_clock::now(); //TODO: a size limit for the dense matrix should control this as well if(sparsity >= config.cluster_mcl_sparsity_switch && expansion - (int) expansion == 0){ n_sparse++; Eigen::SparseMatrix m_sparse = get_sparse_matrix_and_clear(order, m, symmetric); sparse_create_time += duration_cast(high_resolution_clock::now() - t).count(); auto getThreads = [&threads_done, &nThreads, &exessThreads, &iThr](){ uint32_t td=threads_done.load(); uint32_t rt= nThreads - td; return 1 + (td+exessThreads) / rt + (iThr < ((td+exessThreads) % rt) ? 1 : 0); }; markov_process(&m_sparse, inflation, expansion, max_iter, getThreads); high_resolution_clock::time_point t = high_resolution_clock::now(); LazyDisjointIntegralSet disjointSet(m_sparse.cols()); for (uint32_t k=0; k::InnerIterator it(m_sparse, k); it; ++it){ assert(abs(it.value()) > numeric_limits::epsilon()); disjointSet.merge(it.row(), it.col()); if(it.row() == it.col()){ attractors.emplace(it.row()); } } } list_of_sets = disjointSet.getListOfSets(); sparse_list_time += duration_cast(high_resolution_clock::now() - t).count(); } else{ n_dense++; Eigen::MatrixXf m_dense = get_dense_matrix_and_clear(order, m, symmetric); dense_create_time += duration_cast(high_resolution_clock::now() - t).count(); markov_process(&m_dense, inflation, expansion, max_iter); high_resolution_clock::time_point t = high_resolution_clock::now(); LazyDisjointIntegralSet disjointSet(m_dense.cols()); for (uint32_t icol=0; icol numeric_limits::epsilon()){ disjointSet.merge(irow, icol); if(irow == icol){ attractors.emplace(irow); } } } } list_of_sets = disjointSet.getListOfSets(); dense_list_time += duration_cast(high_resolution_clock::now() - t).count(); } for(unordered_set subset : list_of_sets){ assert(cluster_id < 0x3fffffffffffffff); for(uint32_t el : subset){ const uint64_t mask = attractors.find(el) == attractors.end() ? MASK_NORMAL_NODE : MASK_ATTRACTOR_NODE; clustering_result[(*order)[el]] = mask | cluster_id; } if(subset.size() == 1) n_singletons++; cluster_id += nThreads; } } else if (order->size() == 1){ assert(cluster_id < 0x3fffffffffffffff); clustering_result[(*order)[0]] = MASK_SINGLE_NODE | cluster_id; cluster_id += nThreads; n_singletons++; } ichunk++; } my_chunk_size = 0; for(auto const i : loc_i) my_chunk_size += i->size(); my_chunk_size = loc_i.size() * (max_job_size / my_chunk_size); my_counter = component_counter.fetch_add(my_chunk_size, memory_order_relaxed); } n_clusters_found.fetch_add((cluster_id-iThr)/nThreads, memory_order_relaxed); n_dense_calculations.fetch_add(n_dense, memory_order_relaxed); n_sparse_calculations.fetch_add(n_sparse, memory_order_relaxed); nClustersEq1.fetch_add(n_singletons, memory_order_relaxed); jobs_per_thread[iThr] = n_jobs_done; threads_done.fetch_add(1, memory_order_relaxed); time_per_thread[iThr] = (duration_cast(high_resolution_clock::now() - thread_start).count()) / 1000.0; }; vector threads; for(int iThread = 0; iThread < nThreads ; iThread++) { threads.emplace_back(mcl_clustering, iThread); } for(int iThread = 0; iThread < nThreads ; iThread++) { threads[iThread].join(); } ms->release_read_buffer(); timer.finish(); // Output stats message_stream << "Jobs per thread: "; for(int iThread = 0; iThread < nThreads ; iThread++) { message_stream << " " << setw(8) << right << jobs_per_thread[iThread]; } message_stream << endl; message_stream << "Time per thread: "; for(int iThread = 0; iThread < nThreads ; iThread++) { message_stream << " " << setw(8) << right << time_per_thread[iThread]; } message_stream << endl; delete[] time_per_thread; delete[] jobs_per_thread; message_stream << "Clusters found " << n_clusters_found - nClustersEq1 << " ("<< n_clusters_found <<" incl. singletons)" << endl; message_stream << "\t number of failed calculations " << failed_to_converge.load() << endl; message_stream << "\t number of dense calculations " << n_dense_calculations << endl; message_stream << "\t number of sparse calculations " << n_sparse_calculations << endl; message_stream << "Time used for matrix creation: " << (sparse_create_time.load() + dense_create_time.load())/1000.0 <<" (sparse: " << sparse_create_time.load()/1000.0 << ", dense: " << dense_create_time.load()/1000.0 <<")" << endl; message_stream << "Time used for exp: " << (sparse_exp_time.load() + dense_int_exp_time.load() + dense_gen_exp_time.load())/1000.0 << " (sparse: " << sparse_exp_time.load()/1000.0 << ", dense int: " << dense_int_exp_time.load()/1000.0 << ", dense gen: " << dense_gen_exp_time.load()/1000.0 <<")" << endl; message_stream << "Time used for gamma: " << (sparse_gamma_time.load() + dense_gamma_time.load())/1000.0 << " (sparse: " << sparse_gamma_time.load()/1000.0 << ", dense: " << dense_gamma_time.load()/1000.0 <<")" << endl; message_stream << "Time used for listing: " << (sparse_list_time.load() + dense_list_time.load())/1000.0 << " (sparse: " << sparse_list_time.load()/1000.0 << ", dense: " << dense_list_time.load()/1000.0 <<")" << endl; timer.go("Cluster output"); ostream *out = config.output_file.empty() ? &cout : new ofstream(config.output_file.c_str()); vector seq; string id; db->init_seq_access(); //Hsp hsp; size_t n; out->precision(3); for (int i = 0; i < (int)db->sequence_count(); ++i) { db->read_seq(seq, id); const uint64_t cid = ((~MASK_INVERSE) & clustering_result[i]) + 1; const uint64_t lab = MASK_INVERSE & clustering_result[i]; (*out) << Util::Seq::seqid(id.c_str(), false) << '\t' ; switch(lab){ case MASK_SINGLE_NODE: (*out) << cid << '\t'<< 's'; break; case MASK_ATTRACTOR_NODE: (*out) << cid << '\t'<< 'a'; break; case MASK_NORMAL_NODE: (*out) << cid << '\t'<< 'n'; break; default: // Note that this is a sanity check that we have touched all elements in clustering_result (*out) << -1 << '\t' << 'u'; } (*out) << endl; id.clear(); seq.clear(); } if (out != &cout) delete out; db->close(); delete[] clustering_result; timer.finish(); } }} bbuchfink-diamond-08b3cbc/src/contrib/mcl/mcl.h000066400000000000000000000077441506104011400214760ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include #include #include #include #include #include "../util/system/system.h" #include "../basic/config.h" #include "../data/reference.h" #include "../run/workflow.h" #include "../util/io/consumer.h" #include "../util/algo/algo.h" #include "../basic/statistics.h" #include "../util/log_stream.h" #include "../dp/dp.h" #include "../../cluster/cluster.h" #include "sparse_matrix_stream.h" struct Bin1_format : public OutputFormat { Bin1_format() : OutputFormat(bin1) {} virtual void print_query_intro(Output::Info& info) const override; virtual void print_match(const HspContext& r, Output::Info& info) override; virtual ~Bin1_format() { } virtual OutputFormat* clone() const override { return new Bin1_format(*this); } }; struct Clustering_format : public OutputFormat { std::string format; Clustering_format(const std::string* const format); virtual void print_match(const HspContext& r, Output::Info& info) override; virtual ~Clustering_format() { } virtual OutputFormat* clone() const override { return new Clustering_format(*this); } }; namespace Workflow { namespace Cluster{ class MCL: public ClusteringAlgorithm { private: using Weight = float; using Id = SparseMatrixStream::Id; vector> sparse_matrix_multiply(Eigen::SparseMatrix* a, Eigen::SparseMatrix* b , uint32_t iThr, uint32_t nThr); vector> sparse_matrix_get_gamma(Eigen::SparseMatrix* in, float r, uint32_t iThr, uint32_t nThr); float sparse_matrix_get_norm(Eigen::SparseMatrix* in, uint32_t nThr); void print_stats(int64_t nElements, int64_t nComponents, int64_t nComponentsLt1, vector& sort_order, vector>& indices, SparseMatrixStream* ms); void get_exp(Eigen::SparseMatrix* in, Eigen::SparseMatrix* out, float r, uint32_t nThr); void get_exp(Eigen::MatrixXf* in, Eigen::MatrixXf* out, float r); void get_gamma(Eigen::SparseMatrix* in, Eigen::SparseMatrix* out, float r, uint32_t nThr); void get_gamma(Eigen::MatrixXf* in, Eigen::MatrixXf* out, float r); void markov_process(Eigen::SparseMatrix* m, float inflation, float expansion, uint32_t max_iter, std::function getThreads); void markov_process(Eigen::MatrixXf* m, float inflation, float expansion, uint32_t max_iter); Eigen::SparseMatrix get_sparse_matrix_and_clear(vector* order, vector>* m, bool symmetric); Eigen::MatrixXf get_dense_matrix_and_clear(vector* order, vector>* m, bool symmetric); std::atomic_ullong failed_to_converge = {0}; std::atomic_ullong sparse_create_time = {0}; std::atomic_ullong dense_create_time = {0}; std::atomic_ullong sparse_exp_time = {0}; std::atomic_ullong dense_int_exp_time = {0}; std::atomic_ullong dense_gen_exp_time = {0}; std::atomic_ullong sparse_gamma_time = {0}; std::atomic_ullong dense_gamma_time = {0}; std::atomic_ullong sparse_list_time = {0}; std::atomic_ullong dense_list_time = {0}; public: ~MCL(){}; void run(); string get_description(); static string get_key(){ return "mcl"; } }; }} bbuchfink-diamond-08b3cbc/src/contrib/mcl/recursive_parser.h000066400000000000000000000123261506104011400242760ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "clustering_variables.h" #include #include #include #include class RecursiveParser { const HspContext* r; const char * expression_to_parse; std::vector vars_; char peek() { return *expression_to_parse; } char peek(uint32_t ahead) { return *(expression_to_parse+ahead); } char get() { return *expression_to_parse++; } void advance(uint32_t ahead) { expression_to_parse+=ahead; } std::function relation(){ if(peek() == '>' && peek(1) == '='){ advance(2); return [](double a, double b){return a>=b;}; } else if(peek() == '<' && peek(1) == '='){ advance(2); return [](double a, double b){return a<=b;}; } else if(peek() == '=' && peek(1) == '='){ advance(2); return [](double a, double b){return a==b;}; } else if(peek() == '='){ advance(1); return [](double a, double b){return a==b;}; } else if(peek() == '>'){ advance(1); return [](double a, double b){return a>b;}; } else if(peek() == '<'){ advance(1); return [](double a, double b){return a v; while ( (peek() >= 'a' && peek() <= 'z') || (peek() >= 'A' && peek() <= 'Z') || peek() == '_') { v.push_back(get()); } return std::string(v.begin(), v.end()); } uint32_t integer() { uint32_t result = get() - '0'; while (peek() >= '0' && peek() <= '9') { result = 10*result + get() - '0'; } return result; } double number() { double result = integer(); if(peek() == '.'){ advance(1); // '.' const char *pos = expression_to_parse; double decimals = integer() * 1.0 / (expression_to_parse - pos); result += decimals; } return result; } double factor() { if (peek() >= '0' && peek() <= '9') { return number(); } else if (peek() == '(') { advance(1); // '(' double result = expression(); advance(1); // ')' return result; } else if (peek() == '-') { advance(1); return -factor(); } else if (peek() == 'm' && peek(1)=='a' && peek(2)=='x' && peek(3)=='('){ advance(4); // 'max(' double result1 = expression(); advance(1); // ',' double result2 = expression(); advance(1); // ')' return std::max(result1, result2); } else if (peek() == 'm' && peek(1)=='i' && peek(2)=='n' && peek(3)=='('){ advance(4); // 'min(' double result1 = expression(); advance(1); // ',' double result2 = expression(); advance(1); // ')' return std::min(result1, result2); } else if (peek() == 'e' && peek(1)=='x' && peek(2)=='p' && peek(3)=='('){ advance(4); // 'exp(' double result1 = expression(); advance(1); // ')' return std::exp(result1); } else if (peek() == 'l' && peek(1)=='o' && peek(2)=='g' && peek(3)=='('){ advance(4); // 'log(' double result1 = expression(); advance(1); // ')' return std::log(result1); } else if (peek() == 'I' && peek(1)=='('){ advance(2); // 'I(' double result1 = expression(); std::function rel = relation(); double result2 = expression(); advance(1); // ')' return rel(result1, result2); } else { auto v = VariableRegistry::get(variable()); if(!r) { vars_.push_back(v); return 4; } else { return v->get(*r); } } } double term() { double result = factor(); while (peek() == '*' || peek() == '/'){ if (get() == '*'){ result *= factor(); } else{ result /= factor(); } } return result; } double expression() { double result = term(); while (peek() == '+' || peek() == '-'){ if (get() == '+'){ result += term(); } else{ result -= term(); } } return result; } public: RecursiveParser(const HspContext* r, const char * c): r(r), expression_to_parse(c) {} double evaluate() { return expression(); } std::vector variables() const { return vars_; } const std::string static clean_expression(const std::string* const expression){ std::string cleanedExpression = std::string(*expression); cleanedExpression.erase(std::remove_if(cleanedExpression.begin(), cleanedExpression.end(), [](unsigned char c){return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f';}), cleanedExpression.end()); return cleanedExpression; } }; bbuchfink-diamond-08b3cbc/src/contrib/mcl/sparse.h000066400000000000000000000122611506104011400222060ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once using std::runtime_error; namespace Workflow { namespace Cluster{ vector> MCL::sparse_matrix_multiply(Eigen::SparseMatrix* a, Eigen::SparseMatrix* b , uint32_t iThr, uint32_t nThr){ int64_t n_cols = b->cols(); int64_t n_rows = a->rows(); std::vector result_col(n_rows, 0.0); vector> data; for (uint32_t j=0; j::InnerIterator rhsIt(*b, j); rhsIt; ++rhsIt) { const float y = rhsIt.value(); const int64_t k = rhsIt.row(); for (Eigen::SparseMatrix::InnerIterator lhsIt(*a, k); lhsIt; ++lhsIt) { const int64_t i = lhsIt.row(); const float x = lhsIt.value(); result_col[i] += x*y; } } for (int64_t i=0; i numeric_limits::epsilon()) { data.emplace_back(i, j, result_col[i]); } } } } return data; } void MCL::get_exp(Eigen::SparseMatrix* in, Eigen::SparseMatrix* out, float r, uint32_t nThr){ high_resolution_clock::time_point t = high_resolution_clock::now(); if( r - (int) r == 0 ){ // TODO: at some r it may be more beneficial to diagnoalize in and only take the exponents of the eigenvalues *out = *in; for(uint32_t i=1; i> data; std::mutex m; auto mult = [&](const uint32_t iThr){ vector> t_data = sparse_matrix_multiply(in, out, iThr, nThr); m.lock(); data.insert(data.end(), t_data.begin(), t_data.end()); m.unlock(); }; vector threads; for(uint32_t iThread = 0; iThread < nThr ; iThread++) { threads.emplace_back(mult, iThread); } for(uint32_t iThread = 0; iThread < nThr ; iThread++) { threads[iThread].join(); } out->setZero(); out->setFromTriplets(data.begin(), data.end(), [] (const float&, const float &b) { return b; }); *out = out->pruned(1.0, numeric_limits::epsilon()); //(*out) = (*out)*(*in); } } else{ throw runtime_error("Eigen does not provide an eigenvalue solver for sparse matrices"); } *out = out->pruned(); sparse_exp_time += duration_cast(high_resolution_clock::now() - t).count(); } vector> MCL::sparse_matrix_get_gamma(Eigen::SparseMatrix* in, float r, uint32_t iThr, uint32_t nThr) { vector> data; for (uint32_t k = 0; k < in->outerSize(); ++k) { if (k%nThr == iThr) { float colSum = 0.0f; for (Eigen::SparseMatrix::InnerIterator it(*in, k); it; ++it) { colSum += pow(it.value(), r); } for (Eigen::SparseMatrix::InnerIterator it(*in, k); it; ++it) { float val = pow(it.value(), r) / colSum; if (abs(val) > numeric_limits::epsilon()) { data.emplace_back(it.row(), it.col(), val); } } } } return data; } float MCL::sparse_matrix_get_norm(Eigen::SparseMatrix* in, uint32_t nThr) { vector data(nThr); fill(data.begin(), data.end(), 0.0); auto norm = [&](const uint32_t iThr) { for (uint32_t k = 0; k < in->outerSize(); ++k) { if (k%nThr == iThr) { for (Eigen::SparseMatrix::InnerIterator it(*in, k); it; ++it) { data[iThr] += pow(it.value(), 2.0f); } } } }; vector threads; for (uint32_t iThread = 0; iThread < nThr; iThread++) { threads.emplace_back(norm, iThread); } for (uint32_t iThread = 0; iThread < nThr; iThread++) { threads[iThread].join(); } return pow(accumulate(data.begin(), data.end(), 0.0f), 0.5f); } void MCL::markov_process(Eigen::SparseMatrix* m, float inflation, float expansion, uint32_t max_iter, function getThreads) { uint32_t iteration = 0; float diff_norm = numeric_limits::max(); Eigen::SparseMatrix msquared(m->rows(), m->cols()); Eigen::SparseMatrix m_update(m->rows(), m->cols()); get_gamma(m, m, 1, getThreads()); // This is to get a matrix of random walks on the graph -> TODO: find out if something else is more suitable while (iteration < max_iter && diff_norm > numeric_limits::epsilon()) { get_exp(m, &msquared, expansion, getThreads()); get_gamma(&msquared, &m_update, inflation, getThreads()); *m -= m_update; diff_norm = sparse_matrix_get_norm(m, getThreads()); *m = m_update; iteration++; } if (iteration == max_iter) { failed_to_converge++; } } }}bbuchfink-diamond-08b3cbc/src/contrib/mcl/sparse_matrix_stream.h000066400000000000000000000310061506104011400251430ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 QIAGEN A/S (Aarhus, Denmark) Code developed by Patrick Ettenhuber This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include #include #include // #include #include "../../util/data_structures/lazy_disjoint_set.h" #include "../util/io/consumer.h" #include "../../cluster/cluster.h" using std::vector; using std::map; using std::ofstream; using std::unordered_set; using std::ios; using std::ifstream; using std::min; using std::max; using std::runtime_error; using std::string; namespace Workflow { namespace Cluster{ template class SparseMatrixStream : public Consumer { public: using Id = OId; private: size_t n; uint32_t nThreads; const static size_t unit_size = 2*sizeof(uint32_t)+sizeof(double); const static unsigned long long read_buffer_size = 5ULL*1024*1024; // per thread 5MB buffer allowed const bool symmetric; bool in_memory, is_tmp_file, warned; float max_size; char* buffer; static bool cmp(const Eigen::Triplet& lhs, const Eigen::Triplet& rhs) { return lhs.row() == rhs.row() ? lhs.col() < rhs.col() : lhs.row() < rhs.row() ; }; static bool symmcmp(const Eigen::Triplet& lhs, const Eigen::Triplet& rhs) { auto maxL = max(lhs.row(), lhs.col()); auto minL = min(lhs.row(), lhs.col()); auto maxR = max(rhs.row(), rhs.col()); auto minR = min(rhs.row(), rhs.col()); return maxL == maxR ? minL < minR : maxL < maxR ; }; std::set, bool(*)(const Eigen::Triplet& lhs,const Eigen::Triplet& rhs)>* data; //set, decltype(cmp)> data; LazyDisjointSet* disjointSet; std::string file_name; std::ofstream* os; inline void write_triplet(const uint32_t* const query, const uint32_t* const subject, const T* const value){ if(os){ os->write((char*) query, sizeof(uint32_t)); os->write((char*) subject, sizeof(uint32_t)); double val = *value; os->write((char*) &val, sizeof(double)); } } vector>> split_data(map& indexToSetId, size_t size){ vector>> split(size); for(Eigen::Triplet t : *data){ Id iset = indexToSetId[t.row()]; assert( iset == indexToSetId[t.col()]); split[iset].emplace_back(t.row(), t.col(), t.value()); } return split; } void dump(){ if(os && data->size() > 0){ this->in_memory = false; vector> indices = get_indices(); map indexToSetId; for(Id iset = 0; iset < (Id)indices.size(); iset++){ for(Id index : indices.at(iset)){ indexToSetId.emplace(index, iset); } } vector>> components = split_data(indexToSetId, indices.size()); for(uint32_t iComponent = 0; iComponent < components.size(); iComponent++){ const int32_t size = (int32_t)components[iComponent].size(); if( size > 0 ){ const int64_t first_index = indices[iComponent][0]; os->write((char*) &first_index, sizeof(int64_t)); os->write((char*) &size, sizeof(int32_t)); for(auto& t : components[iComponent]){ const uint32_t irow = t.row(); const uint32_t icol = t.col(); const T val = t.value(); write_triplet(&irow, &icol, &val); } } } os->flush(); } } virtual void consume(const char *ptr, size_t n) override { const char *end = ptr + n; if (n >= unit_size) { while (ptr < end) { const uint32_t query = *(uint32_t*) ptr; ptr += sizeof(uint32_t); const uint32_t subject = *(uint32_t*) ptr; ptr += sizeof(uint32_t); const double value = *(double*) ptr; if(!warned && (value > std::numeric_limits::max() || value < std::numeric_limits::min())){ fprintf(stderr, "\n"); fprintf(stderr, "WARNING: The clustering similarity measure cannot be stored in a float, results may become unreliable\n"); fprintf(stderr, " Please modify --clustering-similarity accordingly.\n\n"); warned=true; } ptr += sizeof(double); Eigen::Triplet t(query, subject, (T)value); auto it = data->find(t); if(it == data->end()){ data->emplace(std::move(t)); disjointSet->merge(query, subject); } else if (t.value() > it->value()){ data->emplace_hint(data->erase(it), std::move(t)); } if(os && (data->size()*unit_size*1.0)/(1024ULL*1024*1024) > max_size){ dump(); data->clear(); } } } } void build_graph(const char *ptr, size_t n) { const char *end = ptr + n; if (n >= sizeof(uint32_t)) { while (ptr < end) { const uint32_t query = *(uint32_t*) ptr; ptr += sizeof(uint32_t); const uint32_t subject = *(uint32_t*) ptr; ptr += sizeof(uint32_t); ptr += sizeof(double); disjointSet->merge(query, subject); } } } ofstream* getStream(string graph_file_name){ ofstream* os = new ofstream(graph_file_name, ios::out | ios::binary); os->write((char*) &n, sizeof(size_t)); const uint32_t indexversion = 0; os->write((char*) &indexversion, sizeof(uint32_t)); return os; } vector> remap(vector>& split, map& index_map){ vector> remapped; for(Eigen::Triplet const & t : split){ remapped.emplace_back(index_map[t.row()], index_map[t.col()], t.value()); } remapped.shrink_to_fit(); return remapped; } vector>> getComponents(vector*>* indices){ vector>> split; { map indexToSetId; for(Id iset = 0; iset < (Id)indices->size(); iset++){ for(Id index : *(indices->at(iset))){ indexToSetId.emplace(index, iset); } } split = split_data(indexToSetId, indices->size()); } vector>> components; for(Id iset = 0; iset < (Id)indices->size(); iset++){ if(split[iset].size() > 0){ map index_map; Id iel = 0; for(Id const & el: *(indices->at(iset))){ index_map.emplace(el, iel++); } components.emplace_back(remap(split[iset], index_map)); } } return components; } SparseMatrixStream(const bool symmetric, int64_t n): n(n), nThreads(0), symmetric(symmetric), in_memory(false), is_tmp_file(false), warned(false), max_size(2.0), buffer(nullptr), os(nullptr){ bool(*function_pointer)(const Eigen::Triplet& lhs, const Eigen::Triplet& rhs) = symmetric ? symmcmp : cmp; data = new std::set, bool(*)(const Eigen::Triplet& lhs,const Eigen::Triplet& rhs)>(function_pointer); disjointSet = new LazyDisjointIntegralSet(n); } SparseMatrixStream(const bool symmetric, unordered_set* set) : nThreads(0), symmetric(symmetric), in_memory(true), is_tmp_file(false), warned(true), max_size(2.0), buffer(nullptr), os(nullptr){ bool(*function_pointer)(const Eigen::Triplet& lhs, const Eigen::Triplet& rhs) = symmetric ? symmcmp : cmp; data = new std::set, bool(*)(const Eigen::Triplet& lhs,const Eigen::Triplet& rhs)>(function_pointer); this->n = set->size(); disjointSet = new LazyDisjointTypeSet(set); } public: SparseMatrixStream(const bool symmetric, size_t n, string graph_file_name) : n(n), nThreads(0), symmetric(symmetric), in_memory(false), warned(false), max_size(2.0), buffer(nullptr) { bool(*function_pointer)(const Eigen::Triplet& lhs, const Eigen::Triplet& rhs) = symmetric ? symmcmp : cmp; data = new std::set, bool(*)(const Eigen::Triplet& lhs,const Eigen::Triplet& rhs)>(function_pointer); disjointSet = new LazyDisjointIntegralSet(n); if(graph_file_name.empty()){ this->is_tmp_file = true; file_name = "tmp.bin"; } else{ this->is_tmp_file = false; file_name = graph_file_name; } os = getStream(file_name); } ~SparseMatrixStream(){ clear_disjoint_set(); if(os){ os->close(); delete os; os = nullptr; } release_read_buffer(); if(is_tmp_file) remove(file_name.c_str()); } void done(){ if(!in_memory){ dump(); data->clear(); delete data; } if(os){ os->close(); delete os; os = nullptr; } } void set_max_mem(float max_size){ this->max_size = max_size; } void allocate_read_buffer(uint32_t nThreads){ if(!in_memory){ this->nThreads = nThreads; buffer = new char[nThreads * read_buffer_size]; } } void release_read_buffer(){ if(buffer){ delete[] buffer; buffer = nullptr; } } void clear_disjoint_set(){ if(disjointSet){ delete disjointSet; disjointSet = nullptr; } } static SparseMatrixStream* fromFile(bool read_symmetric, string graph_file_name, float max_size){ ifstream in(graph_file_name, ios::in | ios::binary); if(!in){ throw runtime_error("Cannot read the graph file"); } size_t n; in.read((char*) &n, sizeof(size_t)); uint32_t indexversion; in.read((char*) &indexversion, sizeof(uint32_t)); if(indexversion != 0){ throw runtime_error("This file cannot be read"); } SparseMatrixStream* sms = new SparseMatrixStream(read_symmetric, n); if(max_size>0) sms->set_max_mem(max_size); char* local_buffer = new char[read_buffer_size]; while(in.good()){ int64_t first_component; in.read((char*) &first_component, sizeof(int64_t)); uint32_t size; in.read((char*) &size, sizeof(uint32_t)); const unsigned long long block_size = size*unit_size; unsigned long long bytes_read = 0; for(uint32_t ichunk = 0; ichunk < ceil(block_size/(1.0 * read_buffer_size)); ichunk++){ const unsigned long long bytes = min(read_buffer_size - (read_buffer_size % unit_size), block_size - bytes_read); in.read(local_buffer, bytes); if((sms->data->size()*unit_size*1.0)/(1024ULL*1024*1024) < sms->max_size){ sms->consume(local_buffer, bytes); } else{ sms->build_graph(local_buffer, bytes); } bytes_read += bytes; } } in.close(); if((sms->data->size()*unit_size*1.0)/(1024ULL*1024*1024) >= sms->max_size){ sms->data->clear(); sms->in_memory = false; } delete[] local_buffer; sms->finalize(); sms->file_name=graph_file_name; return sms; } vector>> collect_components(vector*>* indices, uint32_t iThread){ if(in_memory){ return getComponents(indices); } else{ if(buffer == nullptr || nThreads == 0){ throw runtime_error("The global buffer needs to be allocated with allocate_read_buffer with at least one thread"); } ifstream in(file_name, ios::in | ios::binary); if(!in){ throw runtime_error("Cannot read the graph file"); } size_t n; in.read((char*) &n, sizeof(size_t)); uint32_t indexversion; in.read((char*) &indexversion, sizeof(uint32_t)); if(indexversion != 0){ throw runtime_error("This file cannot be read"); } unordered_set set; for(const vector* const idxs : *indices){ set.insert(idxs->begin(), idxs->end()); } SparseMatrixStream sms(this->symmetric, &set); while(in.good()){ Id first_component; in.read((char*) &first_component, sizeof(Id)); uint32_t size; in.read((char*) &size, sizeof(uint32_t)); const unsigned long long block_size = size*unit_size; if(set.count(first_component) == 1){ unsigned long long bytes_read = 0; for(uint32_t ichunk = 0; ichunk < ceil(block_size/(1.0 * read_buffer_size)); ichunk++){ const unsigned long long bytes = min(read_buffer_size - (read_buffer_size % unit_size), block_size - bytes_read); in.read(buffer+(iThread*read_buffer_size), bytes); sms.consume(buffer+(iThread*read_buffer_size), bytes); bytes_read += bytes; } } else{ in.seekg(block_size, ios::cur); } } in.close(); return sms.getComponents(indices); } } vector> get_indices(){ vector> sets = disjointSet->getListOfSets(); vector> indices; for(uint32_t iset = 0; iset < sets.size(); iset++){ indices.emplace_back(sets[iset].begin(), sets[iset].end()); } return indices; } uint64_t getNumberOfElements(){ return data->size(); } }; }} bbuchfink-diamond-08b3cbc/src/data/000077500000000000000000000000001506104011400172345ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/data/blastdb/000077500000000000000000000000001506104011400206475ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/data/blastdb/blastdb.cpp000066400000000000000000000272731506104011400230010ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include #include "util/io/text_input_file.h" #include "blastdb.h" #include "util/string/tokenizer.h" #include "util/system/system.h" #include "basic/config.h" #include "util/util.h" #include "util/log_stream.h" using std::cout; using std::endl; using std::vector; using std::runtime_error; using namespace ncbi; static string full_id(CBioseq& bioseq, CBioseq_Handle* bioseq_handle, bool long_ids, bool ctrl_a) { string id; if (long_ids) { CConstRef best_id = FindBestChoice(bioseq.GetId(), CSeq_id::FastaAARank); id = best_id->AsFastaString(); sequence::CDeflineGenerator gen; id += gen.GenerateDefline(*bioseq_handle, 0); } else { CBlastDeflineUtil::ProcessFastaDeflines(bioseq, id, ctrl_a); id.erase(0, 1); id.pop_back(); } return id; } template static void load_seq_data(CBioseq& bioseq, CBioseq_Handle bioseq_handle, It it) { ncbi::objects::CSeqVector v = bioseq_handle.GetSeqVector(CBioseq_Handle::eCoding_Iupac); if (v.GetCoding() != CSeq_data::e_Iupacaa) throw runtime_error("Invalid sequence coding in BLAST database."); for (ncbi::TSeqPos i = 0; i < v.size(); ++i) { const auto l = v[i] & 31; const Letter s = IUPACAA_TO_STD[l]; if (s == -1) throw runtime_error("Unrecognized sequence character in BLAST database letter=" + std::to_string(l) + " accession=" + bioseq.GetFirstId()->AsFastaString() + " position=" + std::to_string(i + 1)); *it = s; ++it; } } list>::const_iterator best_id(const list>& ids) { if (ids.empty()) throw runtime_error("Unable to retrieve sequence id from BLAST database."); auto min = ids.cbegin(), it = min; int min_score = (*min)->TextScore(), s; ++it; while (it != ids.cend()) { if ((s = (*it)->TextScore()) < min_score) { min_score = s; min = it; } ++it; } return min; } BlastDB::BlastDB(const std::string& file_name, Metadata metadata, Flags flags, const ValueTraits& value_traits) : SequenceFile(Type::BLAST, Alphabet::NCBI, flags, FormatFlags::TITLES_LAZY | FormatFlags::SEEKABLE | FormatFlags::LENGTH_LOOKUP | FormatFlags::DICT_LENGTHS | FormatFlags::DICT_SEQIDS, value_traits), file_name_(file_name), db_(new CSeqDB(file_name, CSeqDB::eProtein, nullptr, true)), oid_(0), long_seqids_(false), flags_(flags), sequence_count_(db_->GetNumOIDs()), sparse_sequence_count_(db_->GetNumSeqs()) { #ifndef EXTRA if (flag_any(metadata, Metadata::TAXON_NODES | Metadata::TAXON_MAPPING | Metadata::TAXON_SCIENTIFIC_NAMES | Metadata::TAXON_RANKS)) throw std::runtime_error("Taxonomy features are not supported for the BLAST database format."); #endif if (config.multiprocessing) throw std::runtime_error("Multiprocessing mode is not compatible with BLAST databases."); if (flag_any(metadata, Metadata::TAXON_NODES)) { const string path = extract_dir(SeqDB_ResolveDbPathNoExtension(db_->GetDBNameList(), 'p')); if (path.empty()) throw std::runtime_error("Could not find BLAST database path."); try { taxon_nodes_.reset(new TaxonomyNodes(path + dir_separator + "nodes.dmp", true)); } catch (FileOpenException&) { throw std::runtime_error("Taxonomy nodes file (nodes.dmp) was not found in the BLAST database directory."); } } } int64_t BlastDB::file_count() const { return 1; } void BlastDB::init_seqinfo_access() { } void BlastDB::init_seq_access() { oid_ = 0; } void BlastDB::seek_chunk(const Chunk& chunk) { throw OperationNotSupported(); } OId BlastDB::tell_seq() const { return oid_; } bool BlastDB::eof() const { return oid_ == sequence_count(); } SequenceFile::SeqInfo BlastDB::read_seqinfo() { if (oid_ >= db_->GetNumOIDs()) { ++oid_; return SeqInfo(0, 0); } const int l = db_->GetSeqLength(oid_); if (l == 0) throw std::runtime_error("Database with sequence length 0 is not supported"); return SeqInfo(oid_++, l); } void BlastDB::putback_seqinfo() { --oid_; } size_t BlastDB::id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) { if(flag_any(flags_, Flags::FULL_TITLES)) return full_id(*db_->GetBioseq((BlastOid)seq_info.pos), nullptr, long_seqids_, true).length(); else { return (*best_id(db_->GetSeqIDs((BlastOid)seq_info.pos)))->GetSeqIdString(true).length(); } } void BlastDB::seek_offset(size_t p) { } void BlastDB::read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) { *(dst - 1) = Sequence::DELIMITER; *(dst + len) = Sequence::DELIMITER; const char* buf; const int db_len = db_->GetSequence((int)pos, &buf); std::copy(buf, buf + len, dst); ++pos; db_->RetSequence(&buf); } void BlastDB::read_id_data(const int64_t oid, char* dst, size_t len) { if (flag_any(flags_, Flags::FULL_TITLES)) { const string id = full_id(*db_->GetBioseq((BlastOid)oid), nullptr, long_seqids_, true); std::copy(id.begin(), id.begin() + len, dst); } else { const string id = (*best_id(db_->GetSeqIDs((BlastOid)oid)))->GetSeqIdString(true); std::copy(id.begin(), id.end(), dst); } dst[len] = '\0'; } void BlastDB::skip_id_data() { //++oid_seqdata_; } string BlastDB::fetch_seqid(OId oid, bool all) const { if (flag_any(flags_, Flags::FULL_TITLES)) { return full_id(*db_->GetBioseqNoData((int)oid), nullptr, long_seqids_, true); } else { const list> ids = db_->GetSeqIDs(oid); if (ids.empty()) return "N/A"; if (all) { string r; for (list>::const_iterator i = ids.begin(); i != ids.end(); ++i) { if (i != ids.begin()) r += '\1'; r += (*i)->GetSeqIdString(true); } return r; } else return ids.front()->GetSeqIdString(true); } } string BlastDB::seqid(OId oid, bool all) const { return fetch_seqid(oid, all); } Loc BlastDB::dict_len(DictId dict_id, const size_t ref_block) const { if (dict_id >= (int64_t)dict_oid_[dict_block(ref_block)].size()) throw std::runtime_error("Dictionary not loaded."); return db_->GetSeqLength((int)dict_oid_[dict_block(ref_block)][dict_id]); } std::vector BlastDB::dict_seq(DictId dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (dict_id >= (DictId)dict_oid_[b].size()) throw std::runtime_error("Dictionary not loaded."); vector v; seq_data(dict_oid_[b][dict_id], v); alph_ncbi_to_std(v.begin(), v.end()); return v; } int64_t BlastDB::sequence_count() const { return sequence_count_; } int64_t BlastDB::sparse_sequence_count() const { return sparse_sequence_count_; } int64_t BlastDB::letters() const { return db_->GetTotalLength(); } int BlastDB::db_version() const { return (int)db_->GetBlastDbVersion(); } int BlastDB::program_build_version() const { return 0; } bool BlastDB::read_seq(std::vector& seq, std::string& id, std::vector* quals) { id.clear(); CRef bioseq = db_->GetBioseq(oid_); CScope scope(*CObjectManager::GetInstance()); CBioseq_Handle bioseq_handle = scope.AddBioseq(*bioseq); id = full_id(*bioseq, &bioseq_handle, long_seqids_, false); seq.clear(); load_seq_data(*bioseq, bioseq_handle, std::back_inserter(seq)); ++oid_; return true; } SequenceFile::Metadata BlastDB::metadata() const { return Metadata(); } int BlastDB::build_version() { return 0; } void BlastDB::create_partition_balanced(int64_t max_letters) { throw OperationNotSupported(); } void BlastDB::save_partition(const std::string& partition_file_name, const std::string& annotation) { throw OperationNotSupported(); } int BlastDB::get_n_partition_chunks() { throw OperationNotSupported(); } void BlastDB::set_seqinfo_ptr(int64_t i) { oid_ = (int)i; } void BlastDB::close() { db_.reset(); } BitVector* BlastDB::filter_by_accession(const std::string& file_name) { BitVector* v = new BitVector(sequence_count()); TextInputFile in(file_name); vector accs; while (in.getline(), (!in.line.empty() || !in.eof())) { accs.push_back(in.line); } in.close(); vector oids; try { db_->AccessionsToOids(accs, oids); } catch (CSeqDBException& e) { throw std::runtime_error(e.GetMsg()); } for (size_t i = 0; i < accs.size(); ++i) { if (oids[i] < 0) if (config.skip_missing_seqids) message_stream << "WARNING: Accession not found in database : " + accs[i] << endl; else throw std::runtime_error("Accession not found in database: " + accs[i] + ". Use --skip-missing-seqids to ignore."); else v->set(oids[i]); } return v; } std::string BlastDB::file_name() { return file_name_; } std::vector BlastDB::taxids(size_t oid) const { vector v; db_->GetTaxIDs((BlastOid)oid, v); return v; } string BlastDB::taxon_scientific_name(TaxId taxid) const { SSeqDBTaxInfo info; if(CSeqDBTaxInfo::GetTaxNames(taxid, info)) return info.scientific_name; else return std::to_string(taxid); } void BlastDB::seq_data(size_t oid, std::vector& dst) const { const char* buf; const int db_len = db_->GetSequence((int)oid, &buf); dst.clear(); dst.resize(db_len); std::copy(buf, buf + db_len, dst.data()); db_->RetSequence(&buf); } size_t BlastDB::seq_length(size_t oid) const { return db_->GetSeqLength((int)oid); } void BlastDB::end_random_access(bool dictionary) { if(dictionary) free_dictionary(); } std::vector BlastDB::accession_to_oid(const std::string& acc) const { vector r; db_->AccessionToOids(acc, r); if(r.empty()) throw runtime_error("Accession not found in database: " + acc); return vector(r.begin(), r.end()); } const BitVector* BlastDB::builtin_filter() { if (sequence_count() == sparse_sequence_count()) return nullptr; if (oid_filter_.empty()) { oid_filter_ = BitVector(sequence_count()); int oid = 0; while (db_->CheckOrFindOID(oid)) { oid_filter_.set(oid); ++oid; } } return &oid_filter_; } BlastDB::~BlastDB() { close(); } void BlastDB::prep_blast_db(const string& path) { vector paths; CSeqDB::FindVolumePaths(path, CSeqDB::eProtein, paths); for (const string& db : paths) { message_stream << "Processing volume: " << db << endl; CSeqDB volume(db, CSeqDB::eProtein, nullptr, false); const int n = volume.GetNumOIDs(); message_stream << "Number of sequences: " << n << endl; OutputFile out(db + ".acc", Compressor::ZSTD); TextBuffer buf; //buf << BlastDB::ACCESSION_FIELD << '\n'; size_t id_count = 0; for (int i = 0; i < n; ++i) { list> ids = volume.GetSeqIDs(i); if (!ids.empty()) { //auto best = best_id(ids); auto it = ids.cbegin(); buf << (*it)->GetSeqIdString(true); while (++it != ids.cend()) { //if (it != best) buf << '\t' << (*it)->GetSeqIdString(true); } id_count += ids.size(); } buf << '\n'; out.write(buf.data(), buf.size()); buf.clear(); } message_stream << "Number of accessions: " << id_count << endl; out.close(); } } void BlastDB::init_write() { throw OperationNotSupported(); } void BlastDB::write_seq(const Sequence& seq, const std::string& id) { throw OperationNotSupported(); }bbuchfink-diamond-08b3cbc/src/data/blastdb/blastdb.h000066400000000000000000000060371506104011400224410ustar00rootroot00000000000000#pragma once #include #include #include "../sequence_file.h" using BlastOid = int; struct BlastDB : public SequenceFile { BlastDB(const std::string& file_name, Metadata metadata, Flags flags, const ValueTraits& value_traits = amino_acid_traits); virtual int64_t file_count() const override; virtual void init_seqinfo_access() override; virtual void init_seq_access() override; virtual void seek_chunk(const Chunk& chunk) override; virtual OId tell_seq() const override; virtual bool eof() const override; virtual SeqInfo read_seqinfo() override; virtual void putback_seqinfo() override; virtual size_t id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) override; virtual void seek_offset(size_t p) override; virtual void read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) override; virtual void read_id_data(const int64_t oid, char* dst, size_t len) override; virtual void skip_id_data() override; virtual std::string seqid(OId oid, bool all = false) const override; virtual Loc dict_len(DictId dict_id, const size_t ref_block) const override; virtual std::vector dict_seq(DictId dict_id, const size_t ref_block) const override; virtual int64_t sequence_count() const override; virtual int64_t sparse_sequence_count() const override; virtual int64_t letters() const override; virtual int db_version() const override; virtual int program_build_version() const override; virtual bool read_seq(std::vector& seq, std::string& id, std::vector* quals = nullptr) override; virtual Metadata metadata() const override; virtual std::string taxon_scientific_name(TaxId taxid) const override; virtual int build_version() override; virtual void create_partition_balanced(int64_t max_letters) override; virtual void save_partition(const std::string& partition_file_name, const std::string& annotation = "") override; virtual int get_n_partition_chunks() override; virtual void set_seqinfo_ptr(OId i) override; virtual void close() override; virtual BitVector* filter_by_accession(const std::string& file_name) override; virtual const BitVector* builtin_filter() override; virtual std::string file_name() override; virtual std::vector taxids(size_t oid) const override; virtual void seq_data(size_t oid, std::vector& dst) const override; virtual size_t seq_length(size_t oid) const override; virtual void end_random_access(bool dictionary = true) override; virtual std::vector accession_to_oid(const std::string& acc) const override; virtual void init_write() override; virtual void write_seq(const Sequence& seq, const std::string& id) override; virtual ~BlastDB(); static void prep_blast_db(const std::string& path); private: std::string fetch_seqid(OId oid, bool all) const; const std::string file_name_; std::unique_ptr db_; int oid_; const bool long_seqids_; const Flags flags_; int64_t sequence_count_, sparse_sequence_count_; BitVector oid_filter_; friend void load_blast_seqid(); friend void load_blast_seqid_lin(); };bbuchfink-diamond-08b3cbc/src/data/block/000077500000000000000000000000001506104011400203265ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/data/block/block.cpp000066400000000000000000000201651506104011400221300ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2022 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include "../sequence_set.h" #include "block.h" #include "util/sequence/sequence.h" #include "../sequence_file.h" #include "basic/config.h" #include "dp/ungapped.h" #define _REENTRANT #include "ips4o/ips4o.hpp" using std::vector; using std::mutex; using std::lock_guard; using std::array; using std::pair; using std::greater; using std::string; using std::runtime_error; using std::numeric_limits; Block::Block(Alphabet alphabet): seqs_(alphabet), source_seqs_(Alphabet::STD), unmasked_seqs_(alphabet), soft_masked_(false) { } bool Block::empty() const { return seqs_.size() == 0; } void Block::convert_to_std_alph(size_t block_id) { throw std::runtime_error(""); } unsigned Block::source_len(unsigned block_id) const { return align_mode.query_translated ? (unsigned)seqs_.reverse_translated_len(block_id * align_mode.query_contexts) : (unsigned)seqs_.length(block_id); } TranslatedSequence Block::translated(size_t block_id) const { if (align_mode.query_translated) return seqs_.translated_seq(source_seqs_[block_id], block_id * align_mode.query_contexts); else return TranslatedSequence(seqs_[block_id]); } bool Block::long_offsets() const { return seqs_.raw_len() > (int64_t)std::numeric_limits::max(); } int64_t Block::push_back(const Sequence& seq, const char* id, const std::vector* quals, const OId oid, const SequenceType seq_type, const int frame_mask, const bool dna_translation) { static const char* const OVERFLOW_ERR = "Sequences in block exceed supported maximum."; if (block2oid_.size() == numeric_limits::max()) throw runtime_error(OVERFLOW_ERR); if (id) ids_.push_back(id, id + strlen(id)); if (quals) qual_.push_back(quals->cbegin(), quals->cend()); block2oid_.push_back(oid); if (seq_type == SequenceType::amino_acid || !dna_translation) { seqs_.push_back(seq.data(), seq.end()); return seq.length(); } if (seqs_.size() > numeric_limits::max() - 6) throw runtime_error(OVERFLOW_ERR); source_seqs_.push_back(seq.data(), seq.end()); auto t = Util::Seq::translate(seq); const Loc min_len = config.min_orf_len((Loc)t.front().size()); int64_t letters = 0; for (int j = 0; j < 6; ++j) { if (frame_mask & (1 << j)) { letters += Util::Seq::find_orfs(t[j], min_len); seqs_.push_back(t[j].cbegin(), t[j].cend()); } else seqs_.fill(t[j].size(), MASK_LETTER); } return letters; } void Block::append(const Block& b) { seqs_.append(b.seqs_); ids_.append(b.ids_); block2oid_.insert(block2oid_.end(), b.block2oid_.begin(), b.block2oid_.end()); } bool Block::fetch_seq_if_unmasked(size_t block_id, std::vector& seq) { if (masked_[block_id]) return false; { lock_guard lck(mask_lock_); if (masked_[block_id]) return false; seq.clear(); Sequence s = seqs_[block_id]; std::copy(s.data(), s.end(), std::back_inserter(seq)); return true; } } void Block::write_masked_seq(size_t block_id, const std::vector& seq) { lock_guard lck(mask_lock_); if (masked_[block_id]) return; std::copy(seq.begin(), seq.end(), seqs_.ptr(block_id)); masked_[block_id] = true; } DictId Block::dict_id(size_t block, BlockId block_id, SequenceFile& db, const OutputFormat& format) const { string t; const OId oid = block_id2oid(block_id); if (has_ids()) { const char* title = ids()[block_id]; if (config.salltitles) t = title; else if (config.sallseqid) t = Util::Seq::all_seqids(title); else t = Util::Seq::seqid(title); } else if (flag_any(format.flags, Output::Flags::SSEQID)) t = db.seqid(oid, config.sallseqid); const Letter* seq = unmasked_seqs().empty() ? nullptr : unmasked_seqs()[block_id].data(); double self_aln_score = 0.0; if (flag_any(db.flags(), SequenceFile::Flags::SELF_ALN_SCORES)) { if (!has_self_aln()) throw std::runtime_error("Missing self alignment scores in Block."); self_aln_score = this->self_aln_score(block_id); } return db.dict_id(block, block_id, oid, seqs().length(block_id), t.c_str(), seq, self_aln_score); } void Block::soft_mask(const MaskingAlgo algo) { if (soft_masked_) return; if (soft_masking_table_.blank()) mask_seqs(seqs_, Masking::get(), true, algo, &soft_masking_table_); else soft_masking_table_.apply(seqs_); soft_masked_ = true; } void Block::remove_soft_masking(const int template_len, const bool add_bit_mask) { if (!soft_masked_) return; soft_masking_table_.remove(seqs_, template_len, add_bit_mask); soft_masked_ = false; } bool Block::soft_masked() const { return soft_masked_; } size_t Block::soft_masked_letters() const { return soft_masking_table_.masked_letters(); } void Block::compute_self_aln() { self_aln_score_.resize(seqs_.size()); std::atomic_size_t next(0); auto worker = [this, &next] { const size_t n = this->seqs_.size(); size_t i; while ((i = next++) < n) { this->seqs().convert_to_std_alph(i); this->self_aln_score_[i] = score_matrix.bitscore(self_score(this->seqs_[i])); } }; vector t; for (int i = 0; i < config.threads_; ++i) t.emplace_back(worker); for (auto& i : t) i.join(); this->seqs().alphabet() = Alphabet::STD; } double Block::self_aln_score(const int64_t block_id) const { return self_aln_score_[block_id]; } BlockId Block::oid2block_id(OId i) const { if (block2oid_.back() - block2oid_.front() != seqs_.size() - 1) throw std::runtime_error("Block has a sparse OId range."); if (i < block2oid_.front() || i > block2oid_.back()) throw std::runtime_error("OId not contained in block."); return BlockId(i - block2oid_.front()); } SeqInfo Block::seq_info(const BlockId id) const { static const char* blank = ""; auto mate_id = (id % 2) == 0 ? id + 1 : id - 1; return { id, block_id2oid(id), ids_.empty() ? nullptr : ids_[id], qual_.empty() ? blank : qual_[id], align_mode.query_translated ? source_seqs_.length(id) : seqs_.length(id), align_mode.query_translated ? source_seqs_[id] : seqs_[id], align_mode.query_translated && mate_id < source_seqs_.size() ? source_seqs_[mate_id] : Sequence() }; } Block* Block::length_sorted(int threads) const { const BlockId n = seqs_.size(); vector> lengths = seqs_.lengths(); #if _MSC_FULL_VER == 191627045 || !defined(NDEBUG) std::sort(lengths.begin(), lengths.end(), greater>()); #else ips4o::parallel::sort(lengths.begin(), lengths.end(), greater>(), threads); #endif Block *b = new Block(); for (BlockId i = 0; i < n; ++i) { const BlockId j = lengths[i].second; b->seqs_.reserve(seqs_.length(j)); b->ids_.reserve(ids_.length(j)); } b->seqs_.finish_reserve(); b->ids_.finish_reserve(); b->block2oid_.reserve(n); for (BlockId i = 0; i < n; ++i) { const BlockId j = lengths[i].second; b->seqs_.assign(i, seqs_.ptr(j), seqs_.end(j)); b->ids_.assign(i, ids_.ptr(j), ids_.end(j)); b->block2oid_.push_back(block2oid_.at(j)); } if (masked_.size() > 0) b->masked_.resize(masked_.size(), false); return b; } bool Block::has_ids() const { return !ids_.empty(); } BlockId Block::source_seq_count() const { return source_seqs_.empty() ? seqs_.size() : source_seqs_.size(); } int64_t Block::mem_size() const { return seqs_.mem_size() + source_seqs_.mem_size() + unmasked_seqs_.mem_size() + ids_.mem_size() + qual_.mem_size() + block2oid_.size() * sizeof(OId) + soft_masking_table_.mem_size(); }bbuchfink-diamond-08b3cbc/src/data/block/block.h000066400000000000000000000066101506104011400215740ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "../sequence_set.h" #include "../seed_histogram.h" #include "masking/masking.h" #include "output/output_format.h" struct SequenceFile; struct Block { Block(Alphabet alphabet = Alphabet::STD); unsigned source_len(unsigned block_id) const; TranslatedSequence translated(size_t block_id) const; bool long_offsets() const; bool empty() const; void convert_to_std_alph(size_t i); SequenceSet& seqs() { return seqs_; } const SequenceSet& seqs() const { return seqs_; } const StringSet& ids() const { if (ids_.empty()) throw std::runtime_error("Block::ids()"); return ids_; } const SequenceSet& source_seqs() const { return source_seqs_; } SequenceSet& unmasked_seqs() { return unmasked_seqs_; } const SequenceSet& unmasked_seqs() const { return unmasked_seqs_; } const StringSet& qual() const { return qual_; } SeedHistogram& hst() { return hst_; } OId block_id2oid(BlockId i) const { return block2oid_[i]; } OId oid_begin() const { return *std::min_element(block2oid_.begin(), block2oid_.end()); //return block2oid_.front(); } OId oid_end() const { return *std::max_element(block2oid_.begin(), block2oid_.end()) + 1; //return block2oid_.back() + 1; } BlockId oid2block_id(OId i) const; Alphabet alphabet() const { return seqs_.alphabet(); } bool fetch_seq_if_unmasked(size_t block_id, std::vector& seq); void write_masked_seq(size_t block_id, const std::vector& seq); DictId dict_id(size_t block, BlockId block_id, SequenceFile& db, const OutputFormat& format) const; void soft_mask(const MaskingAlgo algo); void remove_soft_masking(const int template_len, const bool add_bit_mask); bool soft_masked() const; size_t soft_masked_letters() const; void compute_self_aln(); double self_aln_score(const int64_t block_id) const; bool has_self_aln() const { return (BlockId)self_aln_score_.size() == seqs_.size(); } int64_t push_back(const Sequence& seq, const char* id, const std::vector* quals, const OId oid, const SequenceType seq_type, const int frame_mask, const bool dna_translation = true); void append(const Block& b); SeqInfo seq_info(const BlockId id) const; Block* length_sorted(int threads) const; bool has_ids() const; BlockId source_seq_count() const; int64_t mem_size() const; private: SequenceSet seqs_, source_seqs_, unmasked_seqs_; StringSet ids_; StringSet qual_; SeedHistogram hst_; std::vector block2oid_; std::vector masked_; std::vector self_aln_score_; std::mutex mask_lock_; MaskingTable soft_masking_table_; bool soft_masked_; friend struct SequenceFile; };bbuchfink-diamond-08b3cbc/src/data/block/block_wrapper.cpp000066400000000000000000000104441506104011400236670ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "block_wrapper.h" using std::vector; using std::string; BlockWrapper::BlockWrapper(const Block& block, Metadata metadata, Flags flags, const ValueTraits& value_traits) : SequenceFile(SequenceFile::Type::BLOCK, Alphabet::STD, flags, FormatFlags::LENGTH_LOOKUP | FormatFlags::TITLES_LAZY | FormatFlags::SEEKABLE, value_traits), block_(block), oid_(0) { } int64_t BlockWrapper::file_count() const { return 1; } bool BlockWrapper::files_synced() { return true; } SequenceFile::SeqInfo BlockWrapper::read_seqinfo() { if (oid_ >= block_.seqs().size()) { ++oid_; return SeqInfo(0, 0); } const Loc l = block_.seqs().length(oid_); if (l == 0) throw std::runtime_error("Database with sequence length 0 is not supported"); return SeqInfo(oid_++, l); } void BlockWrapper::putback_seqinfo() { --oid_; } void BlockWrapper::close() { } void BlockWrapper::set_seqinfo_ptr(OId i) { oid_ = i; } OId BlockWrapper::tell_seq() const { return oid_; } bool BlockWrapper::eof() const { return oid_ >= block_.seqs().size(); } void BlockWrapper::init_seq_access() { set_seqinfo_ptr(0); } bool BlockWrapper::read_seq(vector& seq, string& id, std::vector* quals) { throw OperationNotSupported(); } void BlockWrapper::create_partition_balanced(int64_t max_letters) { throw OperationNotSupported(); } void BlockWrapper::save_partition(const string& partition_file_name, const string& annotation) { throw OperationNotSupported(); } int BlockWrapper::get_n_partition_chunks() { throw OperationNotSupported(); } void BlockWrapper::init_seqinfo_access() { } void BlockWrapper::seek_chunk(const Chunk& chunk) { throw OperationNotSupported(); } std::string BlockWrapper::seqid(OId oid, bool all) const { return block_.ids()[oid]; } size_t BlockWrapper::id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) { return block_.ids().length(seq_info.pos); } void BlockWrapper::seek_offset(size_t p) { } void BlockWrapper::read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) { *(dst - 1) = Sequence::DELIMITER; *(dst + len) = Sequence::DELIMITER; std::copy(block_.seqs().ptr(pos), block_.seqs().end(pos), dst); ++pos; } void BlockWrapper::read_id_data(const int64_t oid, char* dst, size_t len) { std::copy(block_.ids().ptr(oid), block_.ids().end(oid), dst); dst[len] = '\0'; } void BlockWrapper::skip_id_data() { } int64_t BlockWrapper::sequence_count() const { return block_.seqs().size(); } int64_t BlockWrapper::letters() const { return block_.seqs().letters(); } int BlockWrapper::db_version() const { throw OperationNotSupported(); } int BlockWrapper::program_build_version() const { throw OperationNotSupported(); } SequenceFile::Metadata BlockWrapper::metadata() const { return Metadata(); } int BlockWrapper::build_version() { throw OperationNotSupported(); } BlockWrapper::~BlockWrapper() { } BitVector* BlockWrapper::filter_by_accession(const std::string& file_name) { throw OperationNotSupported(); } const BitVector* BlockWrapper::builtin_filter() { return nullptr; } std::string BlockWrapper::file_name() { return {}; } int64_t BlockWrapper::sparse_sequence_count() const { throw OperationNotSupported(); } std::vector BlockWrapper::taxids(size_t oid) const { throw OperationNotSupported(); } void BlockWrapper::seq_data(size_t oid, std::vector& dst) const { throw OperationNotSupported(); } size_t BlockWrapper::seq_length(size_t oid) const { throw OperationNotSupported(); } void BlockWrapper::end_random_access(bool dictionary) { if (!dictionary) return; free_dictionary(); } bbuchfink-diamond-08b3cbc/src/data/block/block_wrapper.h000066400000000000000000000044071506104011400233360ustar00rootroot00000000000000#pragma once #include "../sequence_file.h" #include "block.h" struct BlockWrapper : public SequenceFile { BlockWrapper(const Block& block, Metadata metadata = Metadata(), Flags flags = Flags::NONE, const ValueTraits& value_traits = amino_acid_traits); virtual int64_t file_count() const override; virtual void create_partition_balanced(int64_t max_letters) override; virtual void save_partition(const std::string& partition_file_name, const std::string& annotation = "") override; virtual int get_n_partition_chunks() override; virtual void close() override; virtual void set_seqinfo_ptr(OId i) override; virtual OId tell_seq() const override; virtual bool eof() const override; virtual bool files_synced() override; virtual void init_seq_access() override; virtual void init_seqinfo_access() override; virtual void seek_chunk(const Chunk& chunk) override; virtual SeqInfo read_seqinfo() override; virtual void putback_seqinfo() override; virtual size_t id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) override; virtual void seek_offset(size_t p) override; virtual void read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) override; virtual void read_id_data(const int64_t oid, char* dst, size_t len) override; virtual void skip_id_data() override; virtual std::string seqid(OId oid, bool all) const override; virtual int64_t sequence_count() const override; virtual bool read_seq(std::vector& seq, std::string& id, std::vector* quals = nullptr) override; virtual int64_t letters() const override; virtual int db_version() const override; virtual int program_build_version() const override; virtual Metadata metadata() const override; virtual int build_version() override; virtual ~BlockWrapper(); virtual BitVector* filter_by_accession(const std::string& file_name) override; virtual const BitVector* builtin_filter() override; virtual std::string file_name() override; virtual int64_t sparse_sequence_count() const override; virtual std::vector taxids(size_t oid) const override; virtual void seq_data(size_t oid, std::vector& dst) const override; virtual size_t seq_length(size_t oid) const override; virtual void end_random_access(bool dictionary = true) override; private: const Block& block_; OId oid_; }; bbuchfink-diamond-08b3cbc/src/data/dmnd/000077500000000000000000000000001506104011400201565ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/data/dmnd/dmnd.cpp000066400000000000000000000450371506104011400216150ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "basic/config.h" #include "util/log_stream.h" #include "masking/masking.h" #include "../taxonomy.h" #include "../taxon_list.h" #include "../taxonomy_nodes.h" #include "murmurhash/MurmurHash3.h" #include "legacy/dmnd/record_reader.h" #include "util/parallel/multiprocessing.h" #include "dmnd.h" #include "util/system/system.h" #include "util/algo/external_sort.h" #include "util/util.h" #include "../fasta/fasta_file.h" #include "util/sequence/sequence.h" #include "legacy/dmnd/io.h" using std::tuple; using std::string; using std::list; using std::endl; using std::unique_ptr; using std::pair; using std::runtime_error; using std::vector; const char* DatabaseFile::FILE_EXTENSION = ".dmnd"; const uint32_t ReferenceHeader::current_db_version_prot = 3; const uint32_t ReferenceHeader::current_db_version_nucl = 4; Serializer& operator<<(Serializer &s, const ReferenceHeader2 &h) { s << sizeof(ReferenceHeader2); s.write(h.hash, sizeof(h.hash)); s << h.taxon_array_offset << h.taxon_array_size << h.taxon_nodes_offset << h.taxon_names_offset; #ifdef EXTRA s << (int32_t)h.db_type; #endif return s; } Deserializer& operator>>(Deserializer &d, ReferenceHeader2 &h) { #ifdef EXTRA int32_t db_type; #endif DynamicRecordReader(d).read(h.hash, sizeof(h.hash)) >> h.taxon_array_offset >> h.taxon_array_size >> h.taxon_nodes_offset >> h.taxon_names_offset #ifdef EXTRA >> db_type #endif >> Finish(); #ifdef EXTRA h.db_type = (SequenceType)db_type; #endif return d; } InputFile& operator>>(InputFile& file, ReferenceHeader& h) { file >> h.magic_number >> h.build >> h.db_version >> h.sequences >> h.letters >> h.pos_array_offset; return file; } Serializer& operator<<(Serializer& file, const ReferenceHeader& h) { file << h.magic_number << h.build << h.db_version << h.sequences << h.letters << h.pos_array_offset; return file; } InputFile& operator>>(InputFile& file, SequenceFile::SeqInfo& r) { uint32_t p; file >> r.pos >> r.seq_len >> p; return file; } Serializer& operator<<(Serializer& file, const SequenceFile::SeqInfo& r) { file << r.pos << r.seq_len << (uint32_t)0; return file; } SequenceFile::SeqInfo DatabaseFile::read_seqinfo() { SeqInfo r; (*this) >> r; pos_array_offset += SeqInfo::SIZE; return r; } void DatabaseFile::putback_seqinfo() { pos_array_offset -= SeqInfo::SIZE; } void DatabaseFile::init(Flags flags) { read_header(*this, ref_header); if (flag_any(flags, Flags::NO_COMPATIBILITY_CHECK)) return; if (ref_header.build < min_build_required || ref_header.db_version < MIN_DB_VERSION) throw std::runtime_error("Database was built with an older version of Diamond and is incompatible."); if (ref_header.db_version > std::max(ReferenceHeader::current_db_version_prot , ReferenceHeader::current_db_version_nucl)) throw std::runtime_error("Database was built with a newer version of Diamond and is incompatible."); if (ref_header.sequences == 0) throw std::runtime_error("Incomplete database file. Database building did not complete successfully."); *this >> header2; pos_array_offset = ref_header.pos_array_offset; } DatabaseFile::DatabaseFile(const string &input_file, Metadata metadata, Flags flags, const ValueTraits& value_traits): SequenceFile(SequenceFile::Type::DMND, Alphabet::STD, flags, FormatFlags::DICT_LENGTHS | FormatFlags::DICT_SEQIDS | FormatFlags::SEEKABLE | FormatFlags::LENGTH_LOOKUP, value_traits), InputFile(auto_append_extension_if_exists(input_file, FILE_EXTENSION), InputFile::BUFFERED), temporary(false) { init(flags); vector e; if (flag_any(metadata, Metadata::TAXON_MAPPING) && !has_taxon_id_lists()) e.push_back("taxonomy mapping information (--taxonmap option)"); if (flag_any(metadata, Metadata::TAXON_NODES) && !has_taxon_nodes()) e.push_back("taxonomy nodes information (--taxonnodes option)"); if (flag_any(metadata, Metadata::TAXON_SCIENTIFIC_NAMES) && !has_taxon_scientific_names()) e.push_back("taxonomy names information (--taxonnames option)"); if (flag_any(metadata, Metadata::TAXON_RANKS) && build_version() < 131) e.push_back("taxonomy ranks information (database needs to be built with diamond version >= 0.9.30"); if (!e.empty()) throw std::runtime_error("Options require taxonomy information included in the database. Please use the respective options to build this information into the database when running diamond makedb: " + join(", ", e)); if (flag_any(metadata, Metadata::TAXON_MAPPING)) taxon_list_.reset(new TaxonList(seek(header2.taxon_array_offset), ref_header.sequences, header2.taxon_array_size)); if (flag_any(metadata, Metadata::TAXON_SCIENTIFIC_NAMES)) { seek(header2.taxon_names_offset); deserialize(*this, taxon_scientific_names_); } if (flag_any(metadata, Metadata::TAXON_NODES)) taxon_nodes_.reset(new TaxonomyNodes(seek(header2.taxon_nodes_offset), ref_header.build)); if (flag_any(flags, Flags::ACC_TO_OID_MAPPING | Flags::OID_TO_ACC_MAPPING | Flags::NEED_LENGTH_LOOKUP)) read_seqid_list(); } DatabaseFile::DatabaseFile(TempFile &tmp_file, const ValueTraits& value_traits): SequenceFile(SequenceFile::Type::DMND, Alphabet::STD, Flags::NONE, FormatFlags::DICT_LENGTHS | FormatFlags::DICT_SEQIDS | FormatFlags::SEEKABLE | FormatFlags::LENGTH_LOOKUP, value_traits), InputFile(tmp_file, 0), temporary(true) { init(); } int64_t DatabaseFile::file_count() const { return 1; } void DatabaseFile::close() { if (temporary) InputFile::close_and_delete(); else InputFile::close(); } void DatabaseFile::read_header(InputFile &stream, ReferenceHeader &header) { stream >> header; if (header.magic_number != ReferenceHeader().magic_number) throw Database_format_exception(); } bool DatabaseFile::has_taxon_id_lists() const { return header2.taxon_array_offset != 0; } bool DatabaseFile::has_taxon_nodes() const { return header2.taxon_nodes_offset != 0; } bool DatabaseFile::has_taxon_scientific_names() const { return header2.taxon_names_offset != 0; } static void push_seq(const Sequence &seq, const char *id, size_t id_len, uint64_t &offset, vector &pos_array, OutputFile &out, size_t &letters, size_t &n_seqs) { pos_array.emplace_back(offset, seq.length()); out.write("\xff", 1); out.write(seq.data(), seq.length()); out.write("\xff", 1); out.write(id, id_len + 1); letters += seq.length(); ++n_seqs; offset += seq.length() + id_len + 3; } void DatabaseFile::make_db() { config.file_buffer_size = 4 * MEGABYTES; if (config.input_ref_file.size() > 1) throw runtime_error("Too many arguments provided for option --in."); const string input_file_name = config.input_ref_file.empty() ? string() : config.input_ref_file.front(); if (input_file_name.empty()) message_stream << "Input file parameter (--in) is missing. Input will be read from stdin." << endl; else message_stream << "Database input file: " << input_file_name << endl; TaskTimer total; TaskTimer timer("Opening the database file", true); value_traits = (config.dbtype == SequenceType::amino_acid) ? amino_acid_traits : nucleotide_traits; FastaFile db_file({ input_file_name }, Metadata (), Flags::NONE, value_traits); unique_ptr out(new OutputFile(config.database)); ReferenceHeader header; ReferenceHeader2 header2; *out << header; *out << header2; size_t letters = 0, n = 0, n_seqs = 0, total_seqs = 0; uint64_t offset = out->tell(); LoadFlags flags = SequenceFile::LoadFlags::ALL; if (config.dbtype == SequenceType::nucleotide){ header.db_version = ReferenceHeader::current_db_version_nucl; flags |= SequenceFile::LoadFlags::DNA_PRESERVATION; } Block* block; vector pos_array; ExternalSorter> accessions; Util::Seq::AccessionParsing acc_stats; try { while (true) { timer.go("Loading sequences"); block = db_file.load_seqs((int64_t)1e9, nullptr, flags); if (block->empty()) { delete block; break; } n = block->seqs().size(); if (config.dbtype == SequenceType::amino_acid && config.masking_ != "0") { timer.go("Masking sequences"); mask_seqs(block->seqs(), Masking::get(), false, MaskingAlgo::SEG); } timer.go("Writing sequences"); for (size_t i = 0; i < n; ++i) { Sequence seq = block->seqs()[i]; if (seq.length() == 0) throw std::runtime_error("File format error: sequence of length 0"); push_seq(seq, block->ids()[i], block->ids().length(i), offset, pos_array, *out, letters, n_seqs); } if (!config.prot_accession2taxid.empty()) { timer.go("Writing accessions"); for (size_t i = 0; i < n; ++i) { vector acc = Util::Seq::accession_from_title(block->ids()[i], !config.no_parse_seqids, acc_stats); for (const string& s : acc) accessions.push(std::make_pair(s, total_seqs + i)); } } timer.go("Hashing sequences"); for (size_t i = 0; i < n; ++i) { Sequence seq = block->seqs()[i]; MurmurHash3_x64_128(seq.data(), (int)seq.length(), header2.hash, header2.hash); MurmurHash3_x64_128(block->ids()[i], block->ids().length(i), header2.hash, header2.hash); } delete block; total_seqs += n; } } catch (std::exception&) { out->close(); out->remove(); throw; } timer.finish(); timer.go("Writing trailer"); header.pos_array_offset = offset; pos_array.emplace_back(offset, 0); for (const SeqInfo& r : pos_array) *out << r; pos_array.clear(); pos_array.shrink_to_fit(); timer.finish(); if (!config.prot_accession2taxid.empty() && !config.no_parse_seqids) message_stream << endl << "Accession parsing rules triggered for database seqids (use --no-parse-seqids to disable):" << endl << acc_stats << endl; Util::Table stats; stats("Database sequences", n_seqs); stats("Database letters", letters); taxonomy.init(); if (!config.prot_accession2taxid.empty()) { header2.taxon_array_offset = out->tell(); TaxonList::build(*out, accessions, n_seqs, stats); header2.taxon_array_size = out->tell() - header2.taxon_array_offset; } if (!config.nodesdmp.empty()) { TaxonomyNodes nodes(config.nodesdmp); header2.taxon_nodes_offset = out->tell(); nodes.save(*out); } if (!config.namesdmp.empty()) { header2.taxon_names_offset = out->tell(); serialize(*out, taxonomy.name_); } #ifdef EXTRA header2.db_type = config.dbtype; #endif timer.go("Closing the input file"); db_file.close(); timer.go("Closing the database file"); header.letters = letters; header.sequences = n_seqs; out->seek(0); *out << header; *out << header2; out->close(); timer.finish(); stats("Database hash", hex_print(header2.hash, 16)); stats("Total time", total.get(), "s"); message_stream << endl << stats; } void DatabaseFile::set_seqinfo_ptr(OId i) { pos_array_offset = ref_header.pos_array_offset + SeqInfo::SIZE * i; } OId DatabaseFile::tell_seq() const { return (pos_array_offset - ref_header.pos_array_offset) / SeqInfo::SIZE; } bool DatabaseFile::eof() const { return tell_seq() == sequence_count(); } void DatabaseFile::init_seq_access() { seek(sizeof(ReferenceHeader) + sizeof(ReferenceHeader2) + 8); } bool DatabaseFile::read_seq(vector& seq, string &id, std::vector* quals) { char c; read(&c, 1); seq.clear(); id.clear(); read_to(std::back_inserter(seq), '\xff'); read_to(std::back_inserter(id), '\0'); return false; } void DatabaseFile::skip_seq() { char c; if(read(&c, 1) != 1) throw std::runtime_error("Unexpected end of file."); if(!seek_forward('\xff')) throw std::runtime_error("Unexpected end of file."); if(!seek_forward('\0')) throw std::runtime_error("Unexpected end of file."); } bool DatabaseFile::is_diamond_db(const string &file_name) { if (file_name == "-" || file_name.empty()) return false; InputFile db_file(file_name); uint64_t magic_number = 0; try { db_file >> magic_number; } catch (EndOfStream&) {} bool r = (magic_number == ReferenceHeader::MAGIC_NUMBER); db_file.close(); return r; } void DatabaseFile::create_partition_fixednumber(size_t n) { size_t max_letters_balanced = static_cast(std::ceil(static_cast(ref_header.letters)/static_cast(n))); message_stream << "Fixed number partitioning using " << max_letters_balanced << " (" << n << ")" << endl; this->create_partition(max_letters_balanced); } void DatabaseFile::create_partition_balanced(int64_t max_letters) { //double n = std::ceil(static_cast(ref_header.letters) / static_cast(max_letters)); //size_t max_letters_balanced = static_cast(std::ceil(static_cast(ref_header.letters)/n)); //cout << "Balanced partitioning using " << max_letters_balanced << " (" << max_letters << ")" << endl; this->create_partition(max_letters); } void DatabaseFile::create_partition(size_t max_letters) { TaskTimer timer("Create partition of DatabaseFile"); size_t letters = 0, seqs = 0, total_seqs = 0; int i_chunk = 0; size_t oid = 0, oid_begin; set_seqinfo_ptr(oid); init_seqinfo_access(); SeqInfo r = read_seqinfo(); bool first = true; while (r.seq_len) { SeqInfo r_next = read_seqinfo(); if (first) { oid_begin = oid; first = false; } letters += r.seq_len; ++seqs; ++total_seqs; if ((letters > max_letters) || (r_next.seq_len == 0)) { partition.chunks.push_back(Chunk(i_chunk, oid_begin, seqs)); first = true; seqs = 0; letters = 0; ++i_chunk; } r = r_next; ++oid; } reverse(partition.chunks.begin(), partition.chunks.end()); partition.max_letters = max_letters; partition.n_seqs_total = total_seqs; } int DatabaseFile::get_n_partition_chunks() { return (int)partition.chunks.size(); } void DatabaseFile::save_partition(const string & partition_file_name, const string & annotation) { std::ofstream out(partition_file_name); // cout << "WRITING " << partition_file_name << endl; for (const auto& i : partition.chunks) { out << to_string(i); if (annotation.size() > 0) { out << " " << annotation; } out << endl; } } Chunk to_chunk(const string & line) { vector tokens = split(line, ' '); return Chunk((int)stoull(tokens[0]), stoull(tokens[1]), stoull(tokens[2])); } string to_string(const Chunk & c) { const string buf = std::to_string(c.i) + " " + std::to_string(c.offset) + " " + std::to_string(c.n_seqs); return buf; } void DatabaseFile::load_partition(const string & partition_file_name) { string line; std::ifstream in(partition_file_name); clear_partition(); while (getline(in, line)) { auto chunk = to_chunk(line); partition.chunks.push_back(chunk); } } void DatabaseFile::clear_partition() { partition.max_letters = 0; partition.n_seqs_total = 0; partition.chunks.clear(); } void DatabaseFile::init_seqinfo_access() { seek(pos_array_offset); } void DatabaseFile::seek_chunk(const Chunk& chunk) { set_seqinfo_ptr(chunk.offset); } size_t DatabaseFile::id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) { return seq_info_next.pos - seq_info.pos - seq_info.seq_len - 3; } void DatabaseFile::seek_offset(size_t p) { seek(p); } void DatabaseFile::read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) { if (seek) this->seek(pos); read(dst - 1, len + 2); *(dst - 1) = Sequence::DELIMITER; *(dst + len) = Sequence::DELIMITER; } void DatabaseFile::read_id_data(const int64_t oid, char* dst, size_t len) { read(dst, len + 1); } void DatabaseFile::skip_id_data() { if (!seek_forward('\0')) throw std::runtime_error("Unexpected end of file."); } int64_t DatabaseFile::sequence_count() const { return ref_header.sequences; } int64_t DatabaseFile::letters() const { return ref_header.letters; } int DatabaseFile::db_version() const { return ref_header.db_version; } int DatabaseFile::program_build_version() const { return ref_header.build; } SequenceFile::Metadata DatabaseFile::metadata() const { Metadata flags = Metadata(); if (has_taxon_id_lists()) flags |= Metadata::TAXON_MAPPING; if (has_taxon_nodes()) flags |= Metadata::TAXON_NODES; if (has_taxon_scientific_names()) flags |= Metadata::TAXON_SCIENTIFIC_NAMES; return flags; } int DatabaseFile::build_version() { return ref_header.build; } DatabaseFile::~DatabaseFile() { close(); } BitVector* DatabaseFile::filter_by_accession(const std::string& file_name) { throw std::runtime_error("The .dmnd database format does not support filtering by accession."); return nullptr; } const BitVector* DatabaseFile::builtin_filter() { return nullptr; } std::string DatabaseFile::file_name() { return InputFile::file_name; } int64_t DatabaseFile::sparse_sequence_count() const { return sequence_count(); } std::vector DatabaseFile::taxids(size_t oid) const { return (*taxon_list_)[oid]; } void DatabaseFile::seq_data(size_t oid, std::vector& dst) const { throw OperationNotSupported(); } size_t DatabaseFile::seq_length(size_t oid) const { if (oid < seq_length_.size()) return seq_length_[oid]; throw std::out_of_range("DatabaseFile::seq_length"); } void DatabaseFile::end_random_access(bool dictionary) { if (!dictionary) return; free_dictionary(); } void DatabaseFile::init_write() { throw OperationNotSupported(); } void DatabaseFile::write_seq(const Sequence& seq, const std::string& id) { throw OperationNotSupported(); } std::string DatabaseFile::taxon_scientific_name(TaxId taxid) const { return taxid < (TaxId)taxon_scientific_names_.size() && !taxon_scientific_names_[taxid].empty() ? taxon_scientific_names_[taxid] : std::to_string(taxid); } void DatabaseFile::read_seqid_list() { if (flag_any(flags_, Flags::ACC_TO_OID_MAPPING)) acc2oid_.reserve(sequence_count()); if (flag_any(flags_, Flags::NEED_LENGTH_LOOKUP)) seq_length_.reserve(sequence_count()); OId oid = 0; vector seq; string id; init_seq_access(); for (int64_t n = 0; n < sequence_count(); ++n) { read_seq(seq, id); const char* msg = Util::Seq::fix_title(id); if (msg) message_stream << "Warning: " << msg << std::endl; add_seqid_mapping(id, oid++); if (flag_any(flags_, Flags::NEED_LENGTH_LOOKUP)) seq_length_.push_back((Loc)seq.size()); } }bbuchfink-diamond-08b3cbc/src/data/dmnd/dmnd.h000066400000000000000000000132101506104011400212460ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "util/io/serializer.h" #include "util/io/input_file.h" #include "../sequence_file.h" #include "../taxon_list.h" struct ReferenceHeader { ReferenceHeader() : magic_number(MAGIC_NUMBER), build(Const::build_version), db_version(current_db_version_prot), sequences(0), letters(0) { } uint64_t magic_number; uint32_t build, db_version; uint64_t sequences, letters, pos_array_offset; static const uint32_t current_db_version_prot; static const uint32_t current_db_version_nucl; static constexpr uint64_t MAGIC_NUMBER = 0x24af8a415ee186dllu; friend InputFile& operator>>(InputFile& file, ReferenceHeader& h); }; struct ReferenceHeader2 { ReferenceHeader2(): taxon_array_offset(0), taxon_array_size(0), taxon_nodes_offset(0), taxon_names_offset(0) #ifdef EXTRA ,db_type(SequenceType::amino_acid) #endif { memset(hash, 0, sizeof(hash)); } char hash[16]; uint64_t taxon_array_offset, taxon_array_size, taxon_nodes_offset, taxon_names_offset; #ifdef EXTRA SequenceType db_type; #endif friend Serializer& operator<<(Serializer &s, const ReferenceHeader2 &h); friend Deserializer& operator>>(Deserializer &d, ReferenceHeader2 &h); }; struct Database_format_exception : public std::exception { virtual const char* what() const throw() { return "Database file is not a DIAMOND database."; } }; Chunk to_chunk(const std::string& line); std::string to_string(const Chunk& c); struct DatabaseFile : public SequenceFile, public InputFile { DatabaseFile(const std::string &file_name, Metadata metadata = Metadata(), Flags flags = Flags::NONE, const ValueTraits& value_traits = amino_acid_traits); DatabaseFile(TempFile &tmp_file, const ValueTraits& value_traits = amino_acid_traits); static void read_header(InputFile &stream, ReferenceHeader &header); static bool is_diamond_db(const std::string &file_name); void create_partition(size_t max_letters); virtual void create_partition_balanced(int64_t max_letters) override; void create_partition_fixednumber(size_t n); virtual void save_partition(const std::string& partition_file_name, const std::string& annotation = "") override; void load_partition(const std::string & partition_file_name); void clear_partition(); virtual int get_n_partition_chunks() override; void skip_seq(); bool has_taxon_id_lists() const; bool has_taxon_nodes() const; bool has_taxon_scientific_names() const; virtual void close() override; virtual void set_seqinfo_ptr(OId i) override; virtual OId tell_seq() const override; virtual bool eof() const override; virtual void init_seq_access() override; static void make_db(); enum { min_build_required = 74, MIN_DB_VERSION = 2 }; bool temporary; size_t pos_array_offset; ReferenceHeader ref_header; ReferenceHeader2 header2; struct Partition { Partition() : max_letters(0), n_seqs_total(0) {} size_t max_letters; size_t n_seqs_total; std::vector chunks; }; Partition partition; virtual int64_t file_count() const override; virtual void init_seqinfo_access() override; virtual void seek_chunk(const Chunk& chunk) override; virtual SeqInfo read_seqinfo() override; virtual void putback_seqinfo() override; virtual size_t id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) override; virtual void seek_offset(size_t p) override; virtual void read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) override; virtual void read_id_data(const int64_t oid, char* dst, size_t len) override; virtual void skip_id_data() override; virtual int64_t sequence_count() const override; virtual bool read_seq(std::vector& seq, std::string& id, std::vector* quals = nullptr) override; virtual int64_t letters() const override; virtual int db_version() const override; virtual int program_build_version() const override; virtual Metadata metadata() const override; virtual std::string taxon_scientific_name(TaxId taxid) const override; virtual int build_version() override; virtual ~DatabaseFile(); virtual BitVector* filter_by_accession(const std::string& file_name) override; virtual const BitVector* builtin_filter() override; virtual std::string file_name() override; virtual int64_t sparse_sequence_count() const override; virtual std::vector taxids(size_t oid) const override; virtual void seq_data(size_t oid, std::vector& dst) const override; virtual size_t seq_length(size_t oid) const override; virtual void end_random_access(bool dictionary = true) override; virtual void init_write() override; virtual void write_seq(const Sequence& seq, const std::string& id) override; static const char* FILE_EXTENSION; private: void init(Flags flags = Flags::NONE); void read_seqid_list(); std::unique_ptr taxon_list_; std::vector taxon_scientific_names_; };bbuchfink-diamond-08b3cbc/src/data/enum_seeds.h000066400000000000000000000153401506104011400215370ustar00rootroot00000000000000#pragma once #include #include "block/block.h" #include "search/seed_complexity.h" #include "util/ptr_vector.h" #include "basic/seed_iterator.h" #include "basic/shape_config.h" #include "flags.h" template Search::SeedStats enum_seeds(SequenceSet* seqs, F* f, unsigned begin, unsigned end, const Filter* filter, const EnumCfg& cfg) { std::vector buf(seqs->max_len(begin, end)); uint64_t key; Search::SeedStats stats; for (unsigned i = begin; i < end; ++i) { if (cfg.skip && (*cfg.skip)[i / align_mode.query_contexts]) continue; seqs->convert_to_std_alph(i); const Sequence seq = (*seqs)[i]; Reduction::reduce_seq(seq, buf); for (int shape_id = cfg.shape_begin; shape_id < cfg.shape_end; ++shape_id) { const Shape& sh = shapes[shape_id]; if (seq.length() < sh.length_) continue; SeedIterator it(buf, sh); Letter* ptr = seqs->ptr(i); Loc j = 0; while (it.good()) { if (it.get(key, sh)) if (filter->contains(key, shape_id)) (*f)(key, seqs->position(i, j), i, shape_id); ++j; } } } f->finish(); return stats; } template Search::SeedStats enum_seeds_minimizer(SequenceSet* seqs, F* f, unsigned begin, unsigned end, const Filter* filter, const EnumCfg& cfg, Loc it_param) { std::vector buf(seqs->max_len(begin, end)); Search::SeedStats stats; for (unsigned i = begin; i < end; ++i) { if (cfg.skip && (*cfg.skip)[i / align_mode.query_contexts]) continue; seqs->convert_to_std_alph(i); const Sequence seq = (*seqs)[i]; if (align_mode.mode != AlignMode::blastn) Reduction::reduce_seq(seq, buf); else buf = seq.copy(); for (int shape_id = cfg.shape_begin; shape_id < cfg.shape_end; ++shape_id) { const Shape& sh = shapes[shape_id]; if (seq.length() < sh.length_) continue; It it(buf, sh, it_param); while (it.good()) { const uint64_t key = *it; if (filter->contains(key, shape_id)) (*f)(key, seqs->position(i, it.pos()), i, shape_id); ++it; } } } f->finish(); return stats; } template void enum_seeds_hashed(SequenceSet* seqs, F* f, unsigned begin, unsigned end, const Filter* filter, const EnumCfg& cfg) { for (unsigned i = begin; i < end; ++i) { if (cfg.skip && (*cfg.skip)[i / align_mode.query_contexts]) continue; seqs->convert_to_std_alph(i); const Sequence seq = (*seqs)[i]; for (int shape_id = cfg.shape_begin; shape_id < cfg.shape_end; ++shape_id) { const Shape& sh = shapes[shape_id]; if (seq.length() < sh.length_) continue; //const __m128i shape_mask = sh.long_mask_sse_; HashedSeedIterator it(seqs->ptr(i), seqs->length(i), sh); while (it.good()) { const uint64_t key = *it; if (filter->contains(key, shape_id)) { if (!cfg.filter_low_complexity_seeds || Search::seed_is_complex(it.seq_ptr(sh), sh, cfg.seed_cut)) (*f)(key, seqs->position(i, Loc(it.seq_ptr(sh) - seq.data())), i, shape_id); else if (cfg.mask_low_complexity_seeds) *it.seq_ptr(sh) |= SEED_MASK; } ++it; } } } f->finish(); } template void enum_seeds_contiguous(SequenceSet* seqs, F* f, unsigned begin, unsigned end, const Filter* filter, const EnumCfg& cfg) { uint64_t key; for (unsigned i = begin; i < end; ++i) { if (cfg.skip && (*cfg.skip)[i / align_mode.query_contexts]) continue; seqs->convert_to_std_alph(i); const Sequence seq = (*seqs)[i]; if (seq.length() < It::length()) continue; It it(seq); Loc j = 0; while (it.good()) { if (it.get(key)) if (filter->contains(key, 0)) if ((*f)(key, seqs->position(i, j), i, 0) == false) return; ++j; } } f->finish(); } template static void enum_seeds_worker(F* f, SequenceSet* seqs, const unsigned begin, const unsigned end, const Filter* filter, Search::SeedStats* stats, const EnumCfg* cfg) { static const char* errmsg = "Unsupported contiguous seed."; if (cfg->code == SeedEncoding::CONTIGUOUS) { const uint64_t b = Reduction::get_reduction().bit_size(), l = shapes[cfg->shape_begin].length_; switch (l) { case 7: switch (b) { case 4: enum_seeds_contiguous, Filter>(seqs, f, begin, end, filter, *cfg); break; default: throw std::runtime_error(errmsg); } break; case 6: switch (b) { case 4: enum_seeds_contiguous, Filter>(seqs, f, begin, end, filter, *cfg); break; default: throw std::runtime_error(errmsg); } break; case 5: switch (b) { case 4: enum_seeds_contiguous, Filter>(seqs, f, begin, end, filter, *cfg); break; default: throw std::runtime_error(errmsg); } break; default: throw std::runtime_error(errmsg); } } else if (cfg->code == SeedEncoding::HASHED) { const uint64_t b = Reduction::get_reduction().bit_size(); switch (b) { case 4: enum_seeds_hashed(seqs, f, begin, end, filter, *cfg); break; default: throw std::runtime_error("Unsupported reduction."); } } else if(cfg->minimizer_window > 0) *stats = enum_seeds_minimizer(seqs, f, begin, end, filter, *cfg, cfg->minimizer_window); else if(cfg->sketch_size > 0) *stats = enum_seeds_minimizer(seqs, f, begin, end, filter, *cfg, cfg->sketch_size); else *stats = enum_seeds(seqs, f, begin, end, filter, *cfg); } template Search::SeedStats enum_seeds(Block& seqs, PtrVector& f, const Filter* filter, const EnumCfg& cfg) { if (cfg.soft_masking != MaskingAlgo::NONE) seqs.soft_mask(cfg.soft_masking); std::vector threads; std::vector stats(f.size()); for (unsigned i = 0; i < f.size(); ++i) { const unsigned begin = (unsigned)((*cfg.partition)[i]), end = (unsigned)((*cfg.partition)[i + 1]); if (cfg.filter_masked_seeds) threads.emplace_back(enum_seeds_worker, &f[i], &seqs.seqs(), begin, end, filter, &stats[i], &cfg); else threads.emplace_back(enum_seeds_worker, &f[i], &seqs.seqs(), begin, end, filter, &stats[i], &cfg); } for (auto& t : threads) t.join(); seqs.seqs().alphabet() = Alphabet::STD; for (size_t i = 1; i < f.size(); ++i) { stats[0].good_seed_positions += stats[i].good_seed_positions; stats[0].low_complexity_seeds += stats[i].low_complexity_seeds; } if (cfg.soft_masking != MaskingAlgo::NONE) { int l = 0; for (int i = cfg.shape_begin; i < cfg.shape_end; ++i) l = std::max(l, shapes[i].length_); seqs.remove_soft_masking((int)l, cfg.mask_seeds); } return stats[0]; }bbuchfink-diamond-08b3cbc/src/data/fasta/000077500000000000000000000000001506104011400203325ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/data/fasta/fasta_file.cpp000066400000000000000000000202401506104011400231310ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "fasta_file.h" #include "util/sequence/sequence.h" using std::vector; using std::string; using std::pair; using std::runtime_error; using std::unique_ptr; using std::tie; using std::next; using namespace Util::Tsv; using Util::String::TokenizerBase; using Util::String::FastaTokenizer; using Util::String::FastqTokenizer; static const Schema FASTA_SCHEMA { Type::STRING, Type::STRING }; static const Schema FASTQ_SCHEMA{ Type::STRING, Type::STRING, Type::STRING }; //const char* FASTA_SEP = "\n>", * FASTQ_SEP = "\n@"; SeqFileFormat guess_format(TextInputFile& file) { string r = file.peek(1); if (r.empty()) throw std::runtime_error("Error detecting input file format. Input file seems to be empty."); switch (r.front()) { case '>': return SeqFileFormat::FASTA; case '@': return SeqFileFormat::FASTQ; default: throw std::runtime_error("Error detecting input file format. First line must begin with '>' (FASTA) or '@' (FASTQ)."); } } FastaFile::FastaFile(const std::vector& file_name, Metadata metadata, Flags flags, const ValueTraits& value_traits): SequenceFile(SequenceFile::Type::FASTA, Alphabet::STD, flags, FormatFlags::DICT_LENGTHS | FormatFlags::DICT_SEQIDS, value_traits), oid_(0) { if (file_name.size() > 2) throw OperationNotSupported(); unique_ptr input_file(new TextInputFile(file_name.front())); format_ = guess_format(*input_file); //Util::Tsv::Config config(format_ == SeqFileFormat::FASTA ? FASTA_SEP : FASTQ_SEP, format_ == SeqFileFormat::FASTA ? (TokenizerBase*)(new FastaTokenizer()) : new FastqTokenizer); Util::Tsv::Config config(format_ == SeqFileFormat::FASTA ? (TokenizerBase*)(new FastaTokenizer()) : new FastqTokenizer); const auto schema = format_ == SeqFileFormat::FASTA ? FASTA_SCHEMA : FASTQ_SCHEMA; file_.emplace_back(schema, std::move(input_file), Util::Tsv::Flags(), config); if (file_name.size() > 1) file_.emplace_back(schema, file_name[1], Util::Tsv::Flags(), config); file_ptr_ = file_.begin(); if (!flag_any(flags, Flags::NEED_LETTER_COUNT)) return; tie(seqs_, letters_) = init_read(); set_seqinfo_ptr(0); } FastaFile::FastaFile(const string& file_name, bool overwrite, const WriteAccess&, Flags flags, const ValueTraits& value_traits): SequenceFile(SequenceFile::Type::FASTA, Alphabet::STD, flags, FormatFlags::DICT_LENGTHS | FormatFlags::DICT_SEQIDS, value_traits), out_file_(file_name.empty() ? new TempFile : new OutputFile(file_name, Compressor::NONE, overwrite ? "w+b" : "r+b")), format_(SeqFileFormat::FASTA), oid_(0), seqs_(0), letters_(0) { unique_ptr in(new TextInputFile(*out_file_)); //Util::Tsv::Config config(FASTA_SEP, new FastaTokenizer()); Util::Tsv::Config config(new FastaTokenizer()); file_.emplace_back(FASTA_SCHEMA, std::move(in), Util::Tsv::Flags(), config); //file_.emplace_back(*out_file_); file_ptr_ = file_.begin(); if (!overwrite) { vector seq; string id; while (read_seq(seq, id, nullptr)) { ++seqs_; letters_ += seq.size(); } } } int64_t FastaFile::file_count() const { return file_.size(); } bool FastaFile::files_synced() { if (file_ptr_ != file_.begin()) return false; if (file_ptr_->eof()) { string id; vector seq; if (next(file_ptr_) != file_.end() && !next(file_ptr_)->read_record().empty()) return false; } return true; } SequenceFile::SeqInfo FastaFile::read_seqinfo() { throw OperationNotSupported(); } void FastaFile::putback_seqinfo() { throw OperationNotSupported(); } void FastaFile::close() { if (out_file_) file_.front().close(); else for (auto& f : file_) f.close(); } void FastaFile::set_seqinfo_ptr(OId i) { if (out_file_) out_file_->rewind(); for (auto& f : file_) f.rewind(); oid_ = 0; vector seq; string id; while (oid_ != i) { read_seq(seq, id, nullptr); } } OId FastaFile::tell_seq() const { return oid_; } bool FastaFile::eof() const { return file_.back().eof(); } void FastaFile::init_seq_access() { set_seqinfo_ptr(0); } bool FastaFile::read_seq(vector& seq, string &id, std::vector* quals) { oid_++; Table t = file_ptr_->read_record(); if (!t.empty()) { id = t.front().get(0); Util::Seq::from_string(t.front().get(1), seq, value_traits_, 0); if (format_ == SeqFileFormat::FASTQ && quals) { const string q = t.front().get(2); quals->assign(q.begin(), q.end()); } if (++file_ptr_ == file_.end()) file_ptr_ = file_.begin(); } return !t.empty(); } void FastaFile::create_partition_balanced(int64_t max_letters) { throw OperationNotSupported(); } void FastaFile::save_partition(const string & partition_file_name, const string & annotation) { throw OperationNotSupported(); } int FastaFile::get_n_partition_chunks() { throw OperationNotSupported(); } void FastaFile::init_seqinfo_access() { throw OperationNotSupported(); } void FastaFile::seek_chunk(const Chunk& chunk) { throw OperationNotSupported(); } size_t FastaFile::id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) { throw OperationNotSupported(); } void FastaFile::seek_offset(size_t p) { } void FastaFile::read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) { throw OperationNotSupported(); } void FastaFile::read_id_data(const int64_t oid, char* dst, size_t len) { throw OperationNotSupported(); } void FastaFile::skip_id_data() { throw OperationNotSupported(); } int64_t FastaFile::sequence_count() const { return seqs_; } int64_t FastaFile::letters() const { return letters_; } int FastaFile::db_version() const { throw OperationNotSupported(); } int FastaFile::program_build_version() const { throw OperationNotSupported(); } SequenceFile::Metadata FastaFile::metadata() const { return Metadata(); } int FastaFile::build_version() { throw OperationNotSupported(); } FastaFile::~FastaFile() { close(); } BitVector* FastaFile::filter_by_accession(const std::string& file_name) { throw std::runtime_error("The FASTA database format does not support filtering by accession."); } const BitVector* FastaFile::builtin_filter() { return nullptr; } std::string FastaFile::file_name() { return file_.front().file_name(); } int64_t FastaFile::sparse_sequence_count() const { throw OperationNotSupported(); } std::vector FastaFile::taxids(size_t oid) const { throw OperationNotSupported(); } void FastaFile::seq_data(size_t oid, std::vector& dst) const { throw OperationNotSupported(); } size_t FastaFile::seq_length(size_t oid) const { if (oid < seq_length_.size()) return seq_length_[oid]; throw OperationNotSupported(); } void FastaFile::end_random_access(bool dictionary) { if (!dictionary) return; free_dictionary(); } void FastaFile::init_write() { out_file_->seek(0, SEEK_END); } void FastaFile::write_seq(const Sequence& seq, const std::string& id) { static TextBuffer buf; Util::Seq::format(seq, id.c_str(), nullptr, buf, "fasta", value_traits_); out_file_->write(buf.data(), buf.size()); buf.clear(); ++seqs_; letters_ += seq.length(); if (flag_any(flags_, Flags::NEED_LENGTH_LOOKUP)) seq_length_.push_back(seq.length()); } std::pair FastaFile::init_read() { vector seq; string id; int64_t seqs = 0, letters = 0; while (read_seq(seq, id)) { if (flag_any(flags_, Flags::ACC_TO_OID_MAPPING | Flags::OID_TO_ACC_MAPPING)) add_seqid_mapping(id, seqs); if (flag_any(flags_, Flags::NEED_LENGTH_LOOKUP)) seq_length_.push_back((Loc)seq.size()); ++seqs; letters += seq.size(); } return { seqs, letters }; }bbuchfink-diamond-08b3cbc/src/data/fasta/fasta_file.h000066400000000000000000000054141506104011400226040ustar00rootroot00000000000000#include #include #include "../sequence_file.h" #include "util/tsv/tsv.h" enum class SeqFileFormat { FASTA, FASTQ }; struct FastaFile : public SequenceFile { struct WriteAccess {}; FastaFile(const std::vector &file_name, Metadata metadata = Metadata(), Flags flags = Flags::NONE, const ValueTraits& value_traits = amino_acid_traits); FastaFile(const std::string& file_name, bool overwrite, const WriteAccess&, Flags flags = Flags::NONE, const ValueTraits& value_traits = amino_acid_traits); virtual int64_t file_count() const override; virtual void create_partition_balanced(int64_t max_letters) override; virtual void save_partition(const std::string& partition_file_name, const std::string& annotation = "") override; virtual int get_n_partition_chunks() override; virtual void close() override; virtual void set_seqinfo_ptr(OId i) override; virtual OId tell_seq() const override; virtual bool eof() const override; virtual bool files_synced() override; virtual void init_seq_access() override; virtual void init_seqinfo_access() override; virtual void seek_chunk(const Chunk& chunk) override; virtual SeqInfo read_seqinfo() override; virtual void putback_seqinfo() override; virtual size_t id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) override; virtual void seek_offset(size_t p) override; virtual void read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) override; virtual void read_id_data(const int64_t oid, char* dst, size_t len) override; virtual void skip_id_data() override; virtual int64_t sequence_count() const override; virtual bool read_seq(std::vector& seq, std::string& id, std::vector* quals = nullptr) override; virtual int64_t letters() const override; virtual int db_version() const override; virtual int program_build_version() const override; virtual Metadata metadata() const override; virtual int build_version() override; virtual ~FastaFile(); virtual BitVector* filter_by_accession(const std::string& file_name) override; virtual const BitVector* builtin_filter() override; virtual std::string file_name() override; virtual int64_t sparse_sequence_count() const override; virtual std::vector taxids(size_t oid) const override; virtual void seq_data(size_t oid, std::vector& dst) const override; virtual size_t seq_length(size_t oid) const override; virtual void end_random_access(bool dictionary = true) override; virtual void init_write() override; virtual void write_seq(const Sequence& seq, const std::string& id) override; private: std::pair init_read(); std::list file_; std::list::iterator file_ptr_; std::unique_ptr out_file_; SeqFileFormat format_; OId oid_; int64_t seqs_, letters_; }; bbuchfink-diamond-08b3cbc/src/data/flags.h000066400000000000000000000024561506104011400205100ustar00rootroot00000000000000#pragma once #include #include #include "../basic/packed_loc.h" #include "../masking/def.h" #include "basic/sequence.h" enum class SeedEncoding { SPACED_FACTOR, HASHED, CONTIGUOUS }; struct NoFilter { bool contains(uint64_t seed, uint64_t shape) const { return true; } }; extern NoFilter no_filter; #ifndef __sparc__ #pragma pack(1) #endif struct PackedLocId { PackedLocId() {} PackedLocId(PackedLoc pos) : pos(pos) {} PackedLocId(PackedLoc pos, uint32_t block_id) : pos(pos), block_id(block_id) {} operator uint64_t() const { return (uint64_t)pos; } PackedLoc pos; uint32_t block_id; } PACKED_ATTRIBUTE; #pragma pack() static inline uint32_t block_id(PackedLocId i) { return i.block_id; } static inline uint32_t block_id(PackedLoc i) { throw std::runtime_error("Unsupported"); } struct EnumCfg { const std::vector* partition; int shape_begin, shape_end; const SeedEncoding code; const std::vector* const skip; const bool filter_masked_seeds, mask_seeds; const double seed_cut; const MaskingAlgo soft_masking; const Loc minimizer_window; const bool filter_low_complexity_seeds, mask_low_complexity_seeds; const Loc sketch_size; }; struct SeqInfo { BlockId block_id; OId oid; const char* title, * qual; Loc len; Sequence source_seq, mate_seq; };bbuchfink-diamond-08b3cbc/src/data/frequent_seeds.cpp000066400000000000000000000112111506104011400227500ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "frequent_seeds.h" #include "util/parallel/thread_pool.h" #include "util/util.h" #include "basic/config.h" #include "basic/seed.h" #include "sequence_set.h" #include "block/block.h" #include "util/algo/join_result.h" using std::endl; using std::atomic; using std::vector; const double FrequentSeeds::hash_table_factor = 1.3; FrequentSeeds frequent_seeds; template static void compute_sd(atomic *seedp, SeedPartition partition_count, DoubleArray *query_seed_hits, DoubleArray *ref_seed_hits, vector *ref_out, vector *query_out) { SeedPartition p; while ((p = seedp->fetch_add(1, std::memory_order_relaxed)) < partition_count) { Sd ref_sd, query_sd; for (auto it = JoinIterator(query_seed_hits[p].begin(), ref_seed_hits[p].begin()); it; ++it) { query_sd.add((double)it.r->size()); ref_sd.add((double)it.s->size()); } (*ref_out)[p] = ref_sd; (*query_out)[p] = query_sd; } } template void FrequentSeeds::build_worker( size_t rel_seedp, size_t thread_id, DoubleArray *query_seed_hits, DoubleArray *ref_seed_hits, const SeedPartitionRange *range, unsigned sid, unsigned ref_max_n, unsigned query_max_n, vector *counts, Search::Config* cfg) { SequenceSet& query_seqs = cfg->query->seqs(); vector buf; size_t n = 0; for (auto it = JoinIterator(query_seed_hits[rel_seedp].begin(), ref_seed_hits[rel_seedp].begin()); it;) { if (it.s->size() > ref_max_n || it.r->size() > query_max_n) { n += (unsigned)it.s->size(); //Packed_seed s; //shapes[sid].set_seed(s, query_seqs::get().data(*it.r->begin())); //buf.push_back(seed_partition_offset(s)); Range query_hits = *it.r; for (SeedLoc* i = query_hits.begin(); i < query_hits.end(); ++i) { Letter* p = query_seqs.data(*i); *p |= SEED_MASK; } it.erase(); } else ++it; } (*counts)[rel_seedp] = (unsigned)n; } template void FrequentSeeds::build(unsigned sid, const SeedPartitionRange &range, DoubleArray *query_seed_hits, DoubleArray *ref_seed_hits, Search::Config& cfg) { vector ref_sds(range.size()), query_sds(range.size()); atomic rel_seedp(0); vector threads; for (int i = 0; i < config.threads_; ++i) threads.emplace_back(compute_sd, &rel_seedp, range.size(), query_seed_hits, ref_seed_hits, &ref_sds, &query_sds); for (auto &t : threads) t.join(); Sd ref_sd(ref_sds), query_sd(query_sds); const unsigned ref_max_n = (unsigned)(ref_sd.mean() + cfg.freq_sd*ref_sd.sd()), query_max_n = (unsigned)(query_sd.mean() + cfg.freq_sd*query_sd.sd()); log_stream << "Seed frequency mean (reference) = " << ref_sd.mean() << ", SD = " << ref_sd.sd() << endl; log_stream << "Seed frequency mean (query) = " << query_sd.mean() << ", SD = " << query_sd.sd() << endl; log_stream << "Seed frequency cap query: " << query_max_n << ", reference: " << ref_max_n << endl; vector counts(range.size()); Util::Parallel::scheduled_thread_pool_auto(config.threads_, range.size(), build_worker, query_seed_hits, ref_seed_hits, &range, sid, ref_max_n, query_max_n, &counts, &cfg); log_stream << "Masked positions = " << std::accumulate(counts.begin(), counts.end(), 0) << std::endl; } template void FrequentSeeds::build(unsigned, const SeedPartitionRange&, DoubleArray*, DoubleArray*, Search::Config&); template void FrequentSeeds::build(unsigned, const SeedPartitionRange&, DoubleArray*, DoubleArray*, Search::Config&); void FrequentSeeds::clear_masking(SequenceSet& seqs) { for (BlockId i = 0; i < seqs.size(); ++i) { const size_t len = seqs.length(i); Letter* p = seqs.ptr(i), *end = p + len; for (; p < end; ++p) *p = letter_mask(*p); } }bbuchfink-diamond-08b3cbc/src/data/frequent_seeds.h000066400000000000000000000031701506104011400224220ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "run/config.h" #include "util/data_structures/double_array.h" #include "seed_histogram.h" struct SequenceSet; struct FrequentSeeds { template void build(unsigned sid, const SeedPartitionRange &range, DoubleArray *query_seed_hits, DoubleArray *ref_seed_hits, Search::Config& cfg); static void clear_masking(SequenceSet& seqs); private: static const double hash_table_factor; template static void build_worker( size_t seedp, size_t thread_id, DoubleArray *query_seed_hits, DoubleArray *ref_seed_hits, const SeedPartitionRange *range, unsigned sid, unsigned ref_max_n, unsigned query_max_n, std::vector *counts, Search::Config* cfg); }; extern FrequentSeeds frequent_seeds;bbuchfink-diamond-08b3cbc/src/data/index.cpp000066400000000000000000000025601506104011400210520ustar00rootroot00000000000000#include #include "basic/config.h" #include "search/search.h" #include "seed_set.h" #include "dmnd/dmnd.h" #include "basic/shape_config.h" #include "util/log_stream.h" void makeindex() { static const size_t MAX_LETTERS = 100000000; if (config.database.empty()) throw std::runtime_error("Missing parameter: database file (--db/-d)."); DatabaseFile db(config.database); if (db.ref_header.letters > MAX_LETTERS) throw std::runtime_error("Indexing is only supported for databases of < 100000000 letters."); ::shapes = ShapeConfig(config.shape_mask.empty() ? Search::shape_codes.at(config.sensitivity) : config.shape_mask, config.shapes); config.algo = Config::Algo::DOUBLE_INDEXED; Block* block = db.load_seqs(MAX_LETTERS, nullptr, SequenceFile::LoadFlags::SEQS); TaskTimer timer("Building index"); HashedSeedSet index(*block, nullptr, 0.0, Search::soft_masking_algo(Search::sensitivity_traits.at(config.sensitivity))); timer.go("Writing to disk"); OutputFile out(db.file_name() + ".seed_idx"); out.write(SEED_INDEX_MAGIC_NUMBER); out.write(SEED_INDEX_VERSION); out.write((uint32_t)shapes.count()); for (int i = 0; i < shapes.count(); ++i) out.write(index.table(i).size()); for (int i = 0; i < shapes.count(); ++i) { out.write(index.table(i).data(), index.table(i).size() + HashedSeedSet::Table::PADDING); } out.close(); db.close(); delete block; }bbuchfink-diamond-08b3cbc/src/data/queries.cpp000066400000000000000000000035701506104011400214220ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2018 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "queries.h" #include "util/sequence/sequence.h" #include "basic/config.h" #include "seed_set.h" using std::unique_ptr; std::vector query_aligned; std::mutex query_aligned_mtx; unique_ptr query_seeds_hashed; unique_ptr query_seeds_bitset; void write_unaligned(const Block& query, OutputFile *file) { const size_t n = query.ids().size(); TextBuffer buf; for (size_t i = 0; i < n; ++i) { if (!query_aligned[i]) { Util::Seq::format(align_mode.query_translated ? query.source_seqs()[i] : query.seqs()[i], query.ids()[i], query.qual().empty() ? nullptr : query.qual()[i], buf, config.unfmt, input_value_traits); file->write(buf.data(), buf.size()); buf.clear(); } } } void write_aligned(const Block& query, OutputFile *file) { const size_t n = query.ids().size(); TextBuffer buf; for (size_t i = 0; i < n; ++i) { if (query_aligned[i]) { Util::Seq::format(align_mode.query_translated ? query.source_seqs()[i] : query.seqs()[i], query.ids()[i], query.qual().empty() ? nullptr : query.qual()[i], buf, config.alfmt, input_value_traits); file->write(buf.data(), buf.size()); buf.clear(); } } }bbuchfink-diamond-08b3cbc/src/data/queries.h000066400000000000000000000025401506104011400210630ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include "util/io/output_file.h" #include "block/block.h" extern std::mutex query_aligned_mtx; extern std::vector query_aligned; void write_unaligned(const Block& query, OutputFile *file); void write_aligned(const Block& query, OutputFile *file); struct HashedSeedSet; struct SeedSet; extern std::unique_ptr query_seeds_hashed; extern std::unique_ptr query_seeds_bitset;bbuchfink-diamond-08b3cbc/src/data/seed_array.cpp000066400000000000000000000214501506104011400220600ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2024 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "seed_array.h" #include "seed_set.h" #include "enum_seeds.h" #include "util/data_structures/deque.h" #include "util/memory/alignment.h" using std::vector; using std::fill; using std::array; template using PtrSet = vector::Entry*>>; template char* SeedArray::alloc_buffer(const SeedHistogram &hst, int index_chunks) { return (char*)Util::Memory::aligned_malloc(sizeof(Entry) * hst.max_chunk_size(index_chunks), 32); //return new char[sizeof(Entry) * hst.max_chunk_size(index_chunks)]; } template char* SeedArray::alloc_buffer(const SeedHistogram&, int); template char* SeedArray::alloc_buffer(const SeedHistogram&, int); static int seed_bits(const SeedEncoding code, int seedp_bits) { switch (code) { case SeedEncoding::HASHED: return int(sizeof(SeedOffset) * 8); case SeedEncoding::SPACED_FACTOR: return int(ceil(shapes[0].weight_ * Reduction::get_reduction().bit_size_exact()) - seedp_bits); case SeedEncoding::CONTIGUOUS: return shapes[0].length_ * Reduction::get_reduction().bit_size() - seedp_bits; default: break; } throw std::runtime_error("Unknown seed encoding."); } template struct BufferedWriter { using Entry = typename SeedArray::Entry; static const unsigned BUFFER_SIZE = 16; BufferedWriter(Entry* const* ptr, int seedp_bits, SeedPartitionRange seedp_range): seedp_mask(::seedp_mask(seedp_bits)), seedp_bits(seedp_bits), ptr(ptr, ptr + seedp_range.size()), buf(seedp_range.size()), n(seedp_range.size(), 0) {} void push(PackedSeed key, int64_t value, uint32_t block_id, const SeedPartitionRange &range) { const SeedPartition p = seed_partition(key, seedp_mask); if (range.contains(p)) { const SeedPartition d = p - range.begin(); assert(n[d] < BUFFER_SIZE); buf[d][n[d]++] = Entry(seed_partition_offset(key, seedp_bits), value, block_id); if (n[d] == BUFFER_SIZE) flush(d); } } NO_INLINE void flush(SeedPartition p) { memcpy(ptr[p], buf[p].data(), (size_t)n[p] * sizeof(Entry)); ptr[p] += n[p]; n[p] = 0; } void flush() { for (SeedPartition p = 0; p < (SeedPartition)n.size(); ++p) if (n[p] > 0) flush(p); } const PackedSeed seedp_mask, seedp_bits; vector ptr; vector> buf; vector n; }; template static PtrSet build_iterators(SeedArray &sa, const ShapeHistogram &hst, SeedPartitionRange range) { PtrSet iterators(hst.size()); for (auto& v : iterators) v.reserve(range.size()); for (SeedPartition i = 0; i < range.size(); ++i) iterators[0].push_back(sa.begin(i)); for (unsigned i = 1; i < hst.size(); ++i) for (SeedPartition j = range.begin(); j < range.end(); ++j) iterators[i].push_back(iterators[i - 1][j - range.begin()] + hst[i - 1][j]); return iterators; } template struct BuildCallback { BuildCallback(const SeedPartitionRange &range, typename SeedArray::Entry* const* ptr, int seedp_bits) : range(range), it(new BufferedWriter(ptr, seedp_bits, range)) { } bool operator()(uint64_t seed, uint64_t pos, uint32_t block_id, size_t shape) { it->push(seed, pos, block_id, range); return true; } void finish() { it->flush(); } ~BuildCallback() { delete it; } const SeedPartitionRange range; BufferedWriter *it; }; template template SeedArray::SeedArray(Block &seqs, const ShapeHistogram &hst, const SeedPartitionRange &range, int seedp_bits, char *buffer, const Filter *filter, const EnumCfg& enum_cfg) : key_bits(seed_bits(enum_cfg.code, seedp_bits)), data_((Entry*)buffer) { if (enum_cfg.shape_end - enum_cfg.shape_begin > 1) throw std::runtime_error("SeedArray construction for >1 shape."); begin_.reserve(range.size() + 1); begin_.push_back(0); for (SeedPartition i = range.begin(); i < range.end(); ++i) begin_.push_back(begin_.back() + partition_size(hst, i)); PtrSet iterators(build_iterators(*this, hst, range)); PtrVector> cb; for (size_t i = 0; i < enum_cfg.partition->size() - 1; ++i) cb.push_back(new BuildCallback(range, iterators[i].data(), seedp_bits)); stats_ = enum_seeds(seqs, cb, filter, enum_cfg); } template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const NoFilter*, const EnumCfg&); template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const SeedSet*, const EnumCfg&); template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const HashedSeedSet*, const EnumCfg&); template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const NoFilter*, const EnumCfg&); template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const SeedSet*, const EnumCfg&); template SeedArray::SeedArray(Block&, const ShapeHistogram&, const SeedPartitionRange&, int, char* buffer, const HashedSeedSet*, const EnumCfg&); template struct OnePassBufferedWriter { using Entry = typename SeedArray::Entry; static const unsigned BUFFER_SIZE = 16; OnePassBufferedWriter(SeedPartitionRange range, int seedp_bits) : seedp_bits(seedp_bits), out(range.size()), buf(range.size()), n(range.size(), 0) {} void push(PackedSeed key, int64_t value, const SeedPartitionRange& range) { const SeedPartition p = seed_partition(key, seedp_mask(seedp_bits)); if (range.contains(p)) { const SeedPartition d = p - range.begin(); assert(n[d] < BUFFER_SIZE); buf[d][n[d]++] = Entry(seed_partition_offset(key, seedp_bits), value); if (n[d] == BUFFER_SIZE) flush(d); } } NO_INLINE void flush(unsigned p) { out[p].push_back(buf[p].data(), n[p]); n[p] = 0; } void flush() { for (SeedPartition p = 0; p < (SeedPartition)n.size(); ++p) if (n[p] > 0) flush(p); } const int seedp_bits; vector> out; vector> buf; vector n; }; template struct OnePassBuildCallback { OnePassBuildCallback(const SeedPartitionRange& range, int seedp_bits) : range(range), it(new OnePassBufferedWriter(range, seedp_bits)) { } bool operator()(uint64_t seed, uint64_t pos, uint32_t block_id, size_t shape) { it->push(seed, pos, range); return true; } void finish() { it->flush(); } ~OnePassBuildCallback() { delete it; } SeedPartitionRange range; OnePassBufferedWriter* it; }; template template SeedArray::SeedArray(Block& seqs, const SeedPartitionRange& range, int seedp_bits, const Filter* filter, EnumCfg& enum_cfg) : key_bits(seed_bits(enum_cfg.code, seedp_bits)), data_(nullptr), entries_(range.size()) { if (enum_cfg.shape_end - enum_cfg.shape_begin > 1) throw std::runtime_error("SeedArray construction for >1 shape."); const auto seq_partition = seqs.seqs().partition(config.threads_); PtrVector> cb; for (size_t i = 0; i < seq_partition.size() - 1; ++i) cb.push_back(new OnePassBuildCallback(range, seedp_bits)); enum_cfg.partition = &seq_partition; stats_ = enum_seeds(seqs, cb, filter, enum_cfg); vector counts(range.size(), 0); for (OnePassBuildCallback* p : cb) for (SeedPartition i = 0; i < range.size(); ++i) counts[i] += p->it->out[i].size(); for (SeedPartition i = 0; i < range.size(); ++i) { entries_[i].reserve(counts[i]); for (OnePassBuildCallback* p : cb) p->it->out[i].move(entries_[i]); } } template SeedArray::SeedArray(Block&, const SeedPartitionRange&, int, const HashedSeedSet*, EnumCfg&); template SeedArray::SeedArray(Block&, const SeedPartitionRange&, int, const HashedSeedSet*, EnumCfg&); bbuchfink-diamond-08b3cbc/src/data/seed_array.h000066400000000000000000000057011506104011400215260ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2018 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "seed_histogram.h" #include "search/seed_complexity.h" #include "flags.h" #ifndef __sparc__ #pragma pack(1) #endif struct Block; template struct SeedArray { static PackedLoc make_seed_loc(PackedLoc pos, uint32_t block_id, PackedLoc) { return pos; } static PackedLocId make_seed_loc(PackedLoc pos, uint32_t block_id, PackedLocId) { return PackedLocId(pos, block_id); } struct Entry { Entry() : key(), value() { } Entry(SeedOffset key, PackedLoc value) : key(key), value(value) { } Entry(SeedOffset key, PackedLoc pos, uint32_t block_id) : key(key), value(make_seed_loc(pos, block_id, SeedLoc())) {} bool operator<(const Entry& entry)const { return this->key < entry.key; } bool operator==(const Entry& entry)const { return this->key == entry.key && this->value == entry.value; } SeedOffset key; struct GetKey { uint32_t operator()(const Entry& e) const { return e.key; } }; SeedLoc value; using Key = decltype(key); using Value = decltype(value); using value_type = Entry; } PACKED_ATTRIBUTE; template SeedArray(Block &seqs, const ShapeHistogram &hst, const SeedPartitionRange &range, int seedp_bits, char *buffer, const Filter* filter, const EnumCfg& enum_cfg); template SeedArray(Block& seqs, const SeedPartitionRange& range, int seedp_bits, const Filter* filter, EnumCfg& cfg); Entry* begin(unsigned i) { if (data_) return &data_[begin_[i]]; else return entries_[i].data(); } const Entry* begin(unsigned i) const { if (data_) return &data_[begin_[i]]; else return entries_[i].data(); } size_t size(size_t i) const { if (data_) return begin_[i + 1] - begin_[i]; else { return entries_[i].size(); } } size_t size() const { if (data_) return begin_.back(); else { size_t n = 0; for (const auto& v : entries_) n += v.size(); return n; } } const Search::SeedStats& stats() const { return stats_; } static char *alloc_buffer(const SeedHistogram &hst, int index_chunks); const int key_bits; private: Entry *data_; std::vector begin_; std::vector> entries_; Search::SeedStats stats_; }; #pragma pack()bbuchfink-diamond-08b3cbc/src/data/seed_histogram.cpp000066400000000000000000000056631506104011400227470ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "seed_histogram.h" #include "util/algo/partition.h" #include "basic/shape_config.h" #include "block/block.h" #include "util/ptr_vector.h" #include "seed_set.h" #include "data/enum_seeds.h" using std::vector; SeedPartitionRange current_range; SeedHistogram::SeedHistogram() { } size_t SeedHistogram::max_chunk_size(const int index_chunks) const { size_t max = 0; ::Partition p(seedp(), index_chunks); for (int shape = 0; shape < shapes.count(); ++shape) for (int chunk = 0; chunk < p.parts; ++chunk) max = std::max(max, hst_size(data_[shape], SeedPartitionRange(p.begin(chunk), p.end(chunk)))); return max; } template SeedHistogram::SeedHistogram(Block& seqs, bool serial, const Filter* filter, EnumCfg& enum_cfg, int seedp_bits) : p_(seqs.seqs().partition(config.threads_)), data_(shapes.count(), ShapeHistogram(p_.size() - 1, vector(seedp_count(seedp_bits), 0))) { struct Callback { Callback(size_t seqp, int seedp_bits, vector& data): seedp_mask(::seedp_mask(seedp_bits)) { for (int s = 0; s < shapes.count(); ++s) ptr.push_back(data[s][seqp].data()); } bool operator()(PackedSeed seed, uint64_t pos, uint32_t block_id, size_t shape) { ++ptr[shape][seed_partition(seed, seedp_mask)]; return true; } void finish() const { } const PackedSeed seedp_mask; vector ptr; }; PtrVector cb; for (size_t i = 0; i < p_.size() - 1; ++i) cb.push_back(new Callback(i, seedp_bits, data_)); enum_cfg.partition = &p_; if (serial) for (int s = 0; s < shapes.count(); ++s) { enum_cfg.shape_begin = s; enum_cfg.shape_end = s + 1; enum_seeds(seqs, cb, filter, enum_cfg); } else { enum_cfg.shape_begin = 0; enum_cfg.shape_end = shapes.count(); enum_seeds(seqs, cb, filter, enum_cfg); } } template SeedHistogram::SeedHistogram(Block&, bool, const NoFilter*, EnumCfg&, int); template SeedHistogram::SeedHistogram(Block&, bool, const SeedSet*, EnumCfg&, int); template SeedHistogram::SeedHistogram(Block&, bool, const HashedSeedSet*, EnumCfg&, int);bbuchfink-diamond-08b3cbc/src/data/seed_histogram.h000066400000000000000000000047621506104011400224130ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "flags.h" #include "basic/seed.h" using ShapeHistogram = std::vector>; struct SeedPartitionRange { SeedPartitionRange(): begin_ (0), end_ (0) { } SeedPartitionRange(SeedPartition begin, SeedPartition end): begin_ (begin), end_ (end) { } bool contains(SeedPartition i) const { return i >= begin_ && i < end_; } SeedPartition begin() const { return begin_; } SeedPartition end() const { return end_; } bool lower(SeedPartition i) const { return i < begin_; } bool lower_or_equal(SeedPartition i) const { return i < end_; } SeedPartition size() const { return end_ - begin_; } private: SeedPartition begin_, end_; }; extern SeedPartitionRange current_range; inline size_t partition_size(const ShapeHistogram &hst, size_t p) { size_t s = 0; for (unsigned i = 0; i < hst.size(); ++i) s += hst[i][p]; return s; } inline size_t hst_size(const ShapeHistogram &hst, const SeedPartitionRange &range) { size_t s = 0; for (SeedPartition i = range.begin(); i < range.end(); ++i) s += partition_size(hst, i); return s; } struct Block; struct SeedHistogram { SeedHistogram(); template SeedHistogram(Block& seqs, bool serial, const Filter* filter, EnumCfg& enum_cfg, int seedp_bits); const ShapeHistogram& get(unsigned sid) const { return data_[sid]; } size_t max_chunk_size(const int index_chunks) const; const std::vector& partition() const { return p_; } int seedp() const { return (int)data_.front().front().size(); } private: std::vector p_; std::vector data_; };bbuchfink-diamond-08b3cbc/src/data/seed_set.cpp000066400000000000000000000117621506104011400215420ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #define NOMINMAX #include "mio/mmap.hpp" #include "seed_set.h" #include "util/ptr_vector.h" #include "util/math/integer.h" #include "enum_seeds.h" #include "basic/shape_config.h" #include "util/log_stream.h" static const size_t PADDING = 32; static const double HASH_TABLE_FACTOR = 1.25; using std::vector; using std::endl; using std::get; using std::runtime_error; using std::string; NoFilter no_filter; struct SeedSetCallback { SeedSetCallback(vector &data, size_t max_coverage): coverage(0), max_coverage(max_coverage), data(&data) {} bool operator()(uint64_t seed, uint64_t pos, uint32_t block_id, uint64_t shape) { if ((*data)[seed] == false) { (*data)[seed] = true; ++coverage; if (coverage > max_coverage) return false; } return true; } void finish() {} size_t coverage, max_coverage; vector *data; }; SeedSet::SeedSet(Block &seqs, double max_coverage, const std::vector* skip, const double seed_cut, const MaskingAlgo soft_masking): data_((size_t)pow(1llu< v; v.push_back(new SeedSetCallback(data_, size_t(max_coverage*pow(Reduction::get_reduction().size(), shapes[0].length_)))); const auto p = seqs.seqs().partition(1); const EnumCfg cfg{ &p, 0, 1, SeedEncoding::CONTIGUOUS, skip, true, false, seed_cut, soft_masking, 0, false, false, 0 }; enum_seeds(seqs, v, &no_filter, cfg); coverage_ = (double)v.back().coverage / pow(Reduction::get_reduction().size(), shapes[0].length_); } struct HashedSeedSetCallback { HashedSeedSetCallback(PtrVector> &dst): dst(dst) {} bool operator()(uint64_t seed, uint64_t pos, uint32_t block_id, uint64_t shape) { dst[shape].insert(seed); return true; } void finish() {} PtrVector > &dst; }; HashedSeedSet::HashedSeedSet(Block &seqs, const std::vector* skip, const double seed_cut, const MaskingAlgo soft_masking) { for (int i = 0; i < shapes.count(); ++i) data_.push_back(new Table(next_power_of_2(seqs.seqs().letters() * HASH_TABLE_FACTOR))); PtrVector v; v.push_back(new HashedSeedSetCallback(data_)); const auto p = seqs.seqs().partition(1); const EnumCfg cfg{ &p, 0, shapes.count(), SeedEncoding::HASHED, skip, false, false, seed_cut, soft_masking, 0, false, false, 0 }; enum_seeds(seqs, v, &no_filter, cfg); vector sizes; for (int i = 0; i < shapes.count(); ++i) sizes.push_back(data_[i].load()); data_.clear(); for (int i = 0; i < shapes.count(); ++i) data_.push_back(new Table(next_power_of_2(sizes[i] * HASH_TABLE_FACTOR))); enum_seeds(seqs, v, &no_filter, cfg); for (int i = 0; i < shapes.count(); ++i) { data_[i].finish(); log_stream << "Shape=" << i << " Hash_table_size=" << data_[i].size() << " load=" << (double)data_[i].load() / data_[i].size() << endl; } } HashedSeedSet::HashedSeedSet(const string& index_file): mmap_(new mio::mmap_source(index_file)) { if (mmap_->length() < SEED_INDEX_HEADER_SIZE) throw runtime_error("Invalid seed index file."); const char* buf = mmap_->data(); if (*(uint64_t*)buf != SEED_INDEX_MAGIC_NUMBER) throw runtime_error("Invalid seed index file."); if (*(uint32_t*)(buf + 8) != SEED_INDEX_VERSION) throw runtime_error("Invalid seed index file version."); const int32_t shape_count = *(int32_t*)(buf + 12); if (shape_count != shapes.count()) throw runtime_error("Index has a different number of shapes."); const size_t* size_ptr = (const size_t*)(buf + SEED_INDEX_HEADER_SIZE); uint8_t* data_ptr = (uint8_t*)(buf + SEED_INDEX_HEADER_SIZE + sizeof(size_t) * shape_count); for (int i = 0; i < shapes.count(); ++i) { data_.push_back(new Table(data_ptr, *size_ptr)); log_stream << "MMAPED Shape=" << i << " Hash_table_size=" << data_[i].size() << " load=" << (double)data_[i].load() / data_[i].size() << endl; data_ptr += *size_ptr + Table::PADDING; ++size_ptr; } } HashedSeedSet::~HashedSeedSet() { } size_t HashedSeedSet::max_table_size() const { return (*std::max_element(data_.begin(), data_.end(), [](Table* a, Table* b) { return a->size() < b->size(); }))->size(); } bbuchfink-diamond-08b3cbc/src/data/seed_set.h000066400000000000000000000037451506104011400212110ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "util/ptr_vector.h" #include "util/data_structures/hash_set.h" #include "mio/forward.h" #include "masking/def.h" const uint64_t SEED_INDEX_MAGIC_NUMBER = 0x2d6ba306ecbf6aba; const uint32_t SEED_INDEX_VERSION = 0; const size_t SEED_INDEX_HEADER_SIZE = 16; struct Block; struct SeedSet { SeedSet(Block &seqs, double max_coverage, const std::vector* skip, const double seed_cut, const MaskingAlgo soft_masking); bool contains(uint64_t key, uint64_t shape) const { return data_[key]; } double coverage() const { return coverage_; } private: std::vector data_; double coverage_; }; struct HashedSeedSet { typedef HashSet Table; HashedSeedSet(Block &seqs, const std::vector* skip, const double seed_cut, const MaskingAlgo soft_masking); HashedSeedSet(const std::string& index_file); ~HashedSeedSet(); bool contains(uint64_t key, uint64_t shape) const { return data_[shape].contains(key); } const Table& table(size_t i) const { return data_[i]; } size_t max_table_size() const; private: PtrVector data_; std::unique_ptr mmap_; }; bbuchfink-diamond-08b3cbc/src/data/sequence_file.cpp000066400000000000000000000706201506104011400225540ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2022 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #define _REENTRANT #include "ips4o/ips4o.hpp" #ifdef WITH_BLASTDB #include "blastdb/blastdb.h" #endif #include "sequence_file.h" #include "masking/masking.h" #include "dmnd/dmnd.h" #include "util/system/system.h" #include "util/sequence/sequence.h" #include "util/parallel/multiprocessing.h" #include "basic/config.h" #include "fasta/fasta_file.h" #include "util/string/tokenizer.h" #include "util/tsv/tsv.h" #include "util/log_stream.h" using std::string; using std::endl; using std::setw; using std::thread; using std::pair; using std::tie; using std::runtime_error; using std::ofstream; using std::greater; using std::numeric_limits; using std::tuple; using std::get; using std::unique_ptr; using std::function; using std::vector; using namespace Util::Tsv; static constexpr int64_t CHECK_FOR_DNA_COUNT = 10; const char* const SequenceFile::SEQID_HDR = "seqid"; const DictId SequenceFile::DICT_EMPTY = std::numeric_limits::max(); const EMap EnumTraits::to_string = { {SequenceFile::Type::DMND, "Diamond database" }, {SequenceFile::Type::BLAST, "BLAST database"}, {SequenceFile::Type::FASTA, "FASTA file"}, {SequenceFile::Type::BLOCK, ""} }; static string dict_file_name(const size_t query_block, const size_t target_block) { const string file_name = append_label("ref_dict_", query_block) + append_label("_", target_block); return join_path(config.parallel_tmpdir, file_name); } static size_t single_oid(const SequenceFile* f, const string& acc) { const vector oid = f->accession_to_oid(acc); if (oid.empty()) throw AccessionNotFound(); if (oid.size() > 1) throw std::runtime_error("Multiple oids for target accession: " + acc); return oid.front(); } bool SequenceFile::files_synced() { throw OperationNotSupported(); } void SequenceFile::init_write() { throw OperationNotSupported(); } void SequenceFile::write_seq(const Sequence& seq, const std::string& id) { throw OperationNotSupported(); } std::string SequenceFile::taxon_scientific_name(TaxId taxid) const { throw OperationNotSupported(); } pair SequenceFile::load_twopass(const int64_t max_letters, const BitVector* filter, LoadFlags flags, const Chunk& chunk) { init_seqinfo_access(); OId database_id = tell_seq(); int64_t letters = 0, seqs = 0, id_letters = 0, seqs_processed = 0, filtered_seq_count = 0; vector filtered_pos; Block* block = new Block(alphabet_); SeqInfo r = read_seqinfo(); size_t offset = r.pos; bool last = false; if (type() == Type::BLAST && sequence_count() != sparse_sequence_count()) { if (filter) throw std::runtime_error("Database filtering is not compatible with a BLAST alias database."); filter = builtin_filter(); } const bool use_filter = filter && !filter->empty(); auto goon = [&]() { if (max_letters > 0) return (r.seq_len > 0 && letters < max_letters); else return (seqs < chunk.n_seqs); }; while (goon()) { SeqInfo r_next = read_seqinfo(); if (!use_filter || filter->get(database_id)) { letters += r.seq_len; if (flag_any(flags, LoadFlags::SEQS)) { block->seqs_.reserve(r.seq_len); } if (flag_any(flags, LoadFlags::TITLES)) { const size_t id_len = this->id_len(r, r_next); id_letters += id_len; if (flag_any(flags, LoadFlags::SEQS)) block->ids_.reserve(id_len); } ++filtered_seq_count; block->block2oid_.push_back(database_id); if (use_filter) { filtered_pos.push_back(last ? 0 : r.pos); } last = true; } else { last = false; } ++database_id; ++seqs_processed; r = r_next; ++seqs; } putback_seqinfo(); if (seqs == 0 || filtered_seq_count == 0) return { block, seqs_processed }; if (flag_any(flags, LoadFlags::SEQS)) { block->seqs_.finish_reserve(); if (flag_any(flags, LoadFlags::TITLES)) block->ids_.finish_reserve(); static const size_t MAX_LOAD_SIZE = 2 * GIGABYTES; if (use_filter && !flag_all(format_flags_, FormatFlags::SEEKABLE)) throw OperationNotSupported(); seek_offset(offset); for (BlockId i = 0; i < filtered_seq_count; ++i) { bool seek = false; if (use_filter && filtered_pos[i]) { offset = filtered_pos[i]; seek = true; } const size_t l = block->seqs_.length(i); read_seq_data(block->seqs_.ptr(i), l, offset, seek); if (flag_any(flags, LoadFlags::TITLES)) read_id_data(block->block2oid_[i], block->ids_.ptr(i), block->ids_.length(i)); else skip_id_data(); if (type_ == Type::DMND) Masking::get().remove_bit_mask(block->seqs_.ptr(i), block->seqs_.length(i)); } } return { block, seqs_processed }; } static int frame_mask() { if (config.query_strands == "both") return (1 << 6) - 1; else if (config.query_strands == "plus") return (1 << 3) - 1; else if (config.query_strands == "minus") return ((1 << 3) - 1) << 3; throw std::runtime_error("frame_mask"); } std::pair SequenceFile::load_onepass(const int64_t max_letters, const BitVector* filter, LoadFlags flags) { static const char* DNA_ERR = "The sequences are expected to be proteins but only contain DNA letters. Use the option --ignore-warnings to proceed."; vector seq; string id; vector qual; int64_t letters = 0, seq_count = 0; Block* block = new Block(alphabet_); const bool load_seqs = flag_any(flags, LoadFlags::SEQS), load_titles = flag_any(flags, LoadFlags::TITLES), preserve_dna = flag_any(flags,LoadFlags::DNA_PRESERVATION); vector* q = flag_any(flags, LoadFlags::QUALITY) ? &qual : nullptr; OId oid = tell_seq(); const bool first_block = oid == 0; const int frame_mask = ::frame_mask(); const int64_t modulo = file_count(); int looks_like_dna = 0; do { if (!read_seq(seq, id, q)) break; if (seq.size() == 0) continue; if (filter && !filter->get(oid)) { ++oid; continue; } letters += block->push_back(Sequence(seq), load_titles ? id.c_str() : nullptr, q, oid++, this->value_traits_.seq_type, frame_mask, !preserve_dna); ++seq_count; if (first_block && seq_count <= CHECK_FOR_DNA_COUNT && value_traits_.seq_type == SequenceType::amino_acid && Util::Seq::looks_like_dna(Sequence(seq)) && !config.ignore_warnings) { ++looks_like_dna; if (looks_like_dna >= CHECK_FOR_DNA_COUNT) throw std::runtime_error(DNA_ERR); } } while (letters < max_letters || seq_count % modulo != 0); if (seq_count > 0 && looks_like_dna == seq_count) throw std::runtime_error(DNA_ERR); if (file_count() == 2 && !files_synced()) throw std::runtime_error("Unequal number of sequences in paired read files."); block->seqs_.finish_reserve(); if (value_traits_.seq_type == SequenceType::nucleotide) block->source_seqs_.finish_reserve(); if (load_titles) block->ids_.finish_reserve(); if (q) block->qual_.finish_reserve(); return { block, seq_count }; } size_t SequenceFile::dict_block(const size_t ref_block) { return config.multiprocessing ? ref_block : 0; } Block* SequenceFile::load_seqs(const int64_t max_letters, const BitVector* filter, LoadFlags flags, const Chunk& chunk) { if(max_letters == 0) seek_chunk(chunk); Block* block; int64_t seqs_processed; if(flag_any(format_flags_, FormatFlags::LENGTH_LOOKUP)) tie(block, seqs_processed) = load_twopass(max_letters, filter, flags, chunk); else { if (chunk.n_seqs) throw OperationNotSupported(); tie(block, seqs_processed) = load_onepass(max_letters, filter, flags); } if (block->empty()) return block; if (flag_any(flags, LoadFlags::LAZY_MASKING)) block->masked_.resize(block->seqs_.size(), false); if (flag_any(flags, LoadFlags::CONVERT_ALPHABET)) block->seqs_.convert_all_to_std_alph(config.threads_); //block->seqs_.print_stats(); return block; } void SequenceFile::get_seq() { std::map seq_titles; if (!config.query_file.empty()) { TextInputFile list(config.single_query_file()); while (list.getline(), !list.eof()) { const vector t(Util::String::tokenize(list.line.c_str(), "\t")); if (t.size() != 2) throw std::runtime_error("Query file format error."); seq_titles[t[0]] = t[1]; } list.close(); } vector seq; string id; bool all = config.seq_no.size() == 0 && seq_titles.empty() && config.oid_list.empty(); std::set seqs; if (!all) for (vector::const_iterator i = config.seq_no.begin(); i != config.seq_no.end(); ++i) seqs.insert(atoi(i->c_str()) - 1); if (!config.oid_list.empty()) { TextInputFile f(config.oid_list); OId oid; while (f.getline(), !f.line.empty() || !f.eof()) { Util::String::Tokenizer(f.line, Util::String::CharDelimiter('\t')) >> oid; seqs.insert(oid); } f.close(); } if (!seqs.empty()) message_stream << "#Selected sequences: " << seqs.size() << endl; const size_t max_letters = config.chunk_size == 0.0 ? std::numeric_limits::max() : (size_t)(config.chunk_size * 1e9); size_t letters = 0; TextBuffer buf; OutputFile out(config.output_file); for (int64_t n = 0; n < sequence_count(); ++n) { read_seq(seq, id); std::map::const_iterator mapped_title = seq_titles.find(Util::Seq::seqid(id.c_str())); if (all || seqs.find(n) != seqs.end() || mapped_title != seq_titles.end()) { buf << '>' << (mapped_title != seq_titles.end() ? mapped_title->second : id) << '\n'; if (config.reverse) { Sequence(seq).print(buf, value_traits, Sequence::Reversed()); buf << '\n'; } else if (config.hardmasked) { Sequence(seq).print(buf, value_traits, Sequence::Hardmasked()); buf << '\n'; } else buf << Sequence(seq) << '\n'; } out.write(buf.data(), buf.size()); letters += seq.size(); if (letters >= max_letters) break; seq.clear(); id.clear(); buf.clear(); } out.close(); } Util::Tsv::File* SequenceFile::make_seqid_list() { Util::Tsv::File* f = new Util::Tsv::File(Util::Tsv::Schema{ Util::Tsv::Type::STRING }, "", Util::Tsv::Flags::TEMP); vector seq; string id; init_seq_access(); for (int64_t n = 0; n < sequence_count(); ++n) { read_seq(seq, id); f->write_record(Util::Seq::seqid(id.c_str())); } return f; } SequenceFile::~SequenceFile() { if (dict_file_) { dict_file_->close(); dict_file_.reset(); } } static bool is_blast_db(const string& path) { if (exists(path + ".pin") || exists(path + ".pal")) { #ifdef WITH_BLASTDB if (config.multiprocessing) throw std::runtime_error("--multiprocessing is not compatible with BLAST databases."); if (config.target_indexed) throw std::runtime_error("--target-indexed is not compatible with BLAST databases."); return true; #else throw std::runtime_error("This executable was not compiled with support for BLAST databases."); #endif } return false; } SequenceFile* SequenceFile::auto_create(const vector& path, Flags flags, Metadata metadata, const ValueTraits& value_traits) { if (path.size() == 1) { if (is_blast_db(path.front())) #ifdef WITH_BLASTDB return new BlastDB(path.front(), metadata, flags, value_traits); #else return nullptr; #endif const string a = auto_append_extension_if_exists(path.front(), DatabaseFile::FILE_EXTENSION); if (DatabaseFile::is_diamond_db(a)) return new DatabaseFile(a, metadata, flags, value_traits); } if (!flag_any(flags, Flags::NO_FASTA)) { //message_stream << "Database file is not a DIAMOND or BLAST database, treating as FASTA." << std::endl; return new FastaFile(path, metadata, flags, value_traits); } throw std::runtime_error("Sequence file does not have a supported format."); } void SequenceFile::load_dict_block(InputFile* f, const size_t ref_block) { while (load_dict_entry(*f, ref_block)); } void SequenceFile::load_dictionary(const size_t query_block, const size_t ref_blocks) { if (!dict_file_ && !config.multiprocessing) return; TaskTimer timer("Loading dictionary", 3); if (config.multiprocessing) { dict_oid_ = vector>(ref_blocks); if (flag_any(flags_, Flags::SELF_ALN_SCORES)) dict_self_aln_score_ = vector>(ref_blocks); reserve_dict(ref_blocks); for (size_t i = 0; i < ref_blocks; ++i) { InputFile f(dict_file_name(query_block, i), InputFile::NO_AUTODETECT); load_dict_block(&f, i); f.close_and_delete(); } } else { TempFile* t = dynamic_cast(dict_file_.get()); if (!t) throw std::runtime_error("Failed to load dictionary file."); dict_oid_ = { {} }; dict_oid_.front().reserve(next_dict_id_); if (flag_any(flags_, Flags::SELF_ALN_SCORES)) { dict_self_aln_score_ = { {} }; dict_self_aln_score_.front().reserve(next_dict_id_); } reserve_dict(0); InputFile f(*t); load_dict_block(&f, 0); if ((DictId)dict_oid_.front().size() != next_dict_id_) throw std::runtime_error("Dictionary corrupted."); f.close_and_delete(); dict_file_.reset(); } } void SequenceFile::free_dictionary() { dict_oid_.clear(); dict_oid_.shrink_to_fit(); dict_len_.clear(); dict_len_.shrink_to_fit(); dict_title_.clear(); dict_title_.shrink_to_fit(); dict_seq_.clear(); dict_seq_.shrink_to_fit(); dict_self_aln_score_.clear(); dict_self_aln_score_.shrink_to_fit(); block_to_dict_id_.clear(); } size_t SequenceFile::total_blocks() const { const size_t c = (size_t)(config.chunk_size * 1e9); return (this->letters() + c - 1) / c; } SequenceSet SequenceFile::seqs_by_accession(const std::vector::const_iterator begin, const std::vector::const_iterator end) const { SequenceSet out(Alphabet::NCBI); vector oids; oids.reserve(end - begin); for (auto it = begin; it != end; ++it) { try { const size_t oid = single_oid(this, *it); oids.push_back(oid); out.reserve(seq_length(oid)); } catch (AccessionNotFound&) { out.reserve(0); oids.push_back(SIZE_MAX); } } out.finish_reserve(); vector seq; for (size_t i = 0; i < oids.size(); ++i) { if (oids[i] == SIZE_MAX) continue; seq_data(oids[i], seq); out.assign(i, seq.begin(), seq.end()); out.convert_to_std_alph(i); } out.alphabet() = Alphabet::STD; return out; } std::vector SequenceFile::seq_by_accession(const std::string& acc) const { const size_t oid = single_oid(this, acc); vector seq; seq_data(oid, seq); alph_ncbi_to_std(seq.begin(), seq.end()); return seq; } void SequenceFile::init_dict(const size_t query_block, const size_t target_block) { if (dict_file_) dict_file_->close(); dict_file_.reset(config.multiprocessing ? new OutputFile(dict_file_name(query_block, target_block)) : new TempFile()); next_dict_id_ = 0; dict_alloc_size_ = 0; block_to_dict_id_.clear(); } void SequenceFile::init_dict_block(size_t block, size_t seq_count, bool persist) { if(!persist) block_to_dict_id_.clear(); if(block_to_dict_id_.find(block) == block_to_dict_id_.end()) block_to_dict_id_[block] = vector(seq_count, DICT_EMPTY); } void SequenceFile::close_dict_block(bool persist) { if (config.multiprocessing) { dict_file_->close(); dict_file_.reset(); } if (!persist) block_to_dict_id_.clear(); } DictId SequenceFile::dict_id(size_t block, size_t block_id, size_t oid, size_t len, const char* id, const Letter* seq, const double self_aln_score) { auto it = block_to_dict_id_.find(block); if (it == block_to_dict_id_.end() || block_id >= it->second.size()) throw std::runtime_error("Dictionary not initialized."); vector& v = it->second; DictId n = v[block_id]; if (n != DICT_EMPTY) return n; { std::lock_guard lock(dict_mtx_); n = v[block_id]; if (n != DICT_EMPTY) return n; n = next_dict_id_++; v[block_id] = n; write_dict_entry(block, oid, len, id, seq, self_aln_score); return n; } } size_t SequenceFile::oid(DictId dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (b >= dict_oid_.size() || dict_id >= (DictId)dict_oid_[b].size()) throw std::runtime_error("Dictionary not loaded."); return dict_oid_[b][dict_id]; } double SequenceFile::dict_self_aln_score(const size_t dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (b >= dict_self_aln_score_.size() || dict_id >= dict_self_aln_score_[b].size()) throw std::runtime_error("Dictionary not loaded."); return dict_self_aln_score_[b][dict_id]; } SequenceFile::SequenceFile(Type type, Alphabet alphabet, Flags flags, FormatFlags format_flags, const ValueTraits& value_traits): flags_(flags), format_flags_(format_flags), value_traits_(value_traits), type_(type), alphabet_(alphabet) { if (flag_any(flags_, Flags::OID_TO_ACC_MAPPING)) //seqid_file_.reset(new File(Schema{ ::Type::INT64, ::Type::STRING }, "", ::Flags::TEMP)); // | ::Flags::RECORD_ID_COLUMN)); seqid_file_.reset(new File(Schema{ ::Type::STRING }, "", ::Flags::TEMP)); } void SequenceFile::write_dict_entry(size_t block, size_t oid, size_t len, const char* id, const Letter* seq, const double self_aln_score) { OutputFile& f = *dict_file_; f.write((uint32_t)oid); if (flag_any(format_flags_, FormatFlags::DICT_LENGTHS)) f.write((uint32_t)len); if (flag_any(format_flags_, FormatFlags::DICT_SEQIDS)) { f << id; dict_alloc_size_ += strlen(id); } if (flag_any(flags_, Flags::TARGET_SEQS)) f.write(seq, len); if (flag_any(flags_, Flags::SELF_ALN_SCORES)) f.write(self_aln_score); } bool SequenceFile::load_dict_entry(InputFile& f, size_t ref_block) { const size_t b = dict_block(ref_block); uint32_t oid, len; string title; if(f.read(&oid, 1) == 0) return false; dict_oid_[b].push_back(oid); if (flag_any(format_flags_, FormatFlags::DICT_LENGTHS)) { f.read(len); dict_len_[b].push_back(len); } if (flag_any(format_flags_, FormatFlags::DICT_SEQIDS)) { f >> title; dict_title_[b].push_back(title.begin(), title.end()); } if (flag_any(flags_, Flags::TARGET_SEQS)) { vector v(len); f.read(v.data(), len); dict_seq_[b].push_back(v.begin(), v.end()); } if (flag_any(flags_, Flags::SELF_ALN_SCORES)) { double self_aln_score; f.read(self_aln_score); dict_self_aln_score_[b].push_back(self_aln_score); } return true; } void SequenceFile::reserve_dict(const size_t ref_blocks) { if (config.multiprocessing) { if (flag_any(format_flags_, FormatFlags::DICT_LENGTHS)) dict_len_ = std::vector>(ref_blocks); if (flag_any(format_flags_, FormatFlags::DICT_SEQIDS)) dict_title_ = std::vector(ref_blocks); if (flag_any(flags_, Flags::TARGET_SEQS)) dict_seq_ = std::vector(ref_blocks); } else { if (flag_any(format_flags_, FormatFlags::DICT_LENGTHS)) { dict_len_ = { {} }; dict_len_[0].reserve(next_dict_id_); } if (flag_any(format_flags_, FormatFlags::DICT_SEQIDS)) { dict_title_ = { {} }; dict_title_[0].reserve(next_dict_id_, dict_alloc_size_); } if (flag_any(flags_, Flags::TARGET_SEQS)) { dict_seq_ = { {} }; dict_seq_[0].reserve(next_dict_id_, 0); } } } std::string SequenceFile::dict_title(DictId dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (b >= dict_title_.size() || dict_id >= (DictId)dict_title_[b].size()) throw std::runtime_error("Dictionary not loaded."); return dict_title_[b][dict_id]; } Loc SequenceFile::dict_len(DictId dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (b >= dict_len_.size() || dict_id >= (DictId)dict_len_[b].size()) throw std::runtime_error("Dictionary not loaded."); return dict_len_[b][dict_id]; } std::vector SequenceFile::dict_seq(DictId dict_id, const size_t ref_block) const { const size_t b = dict_block(ref_block); if (b >= dict_seq_.size() || dict_id >= (DictId)dict_seq_[b].size()) throw std::runtime_error("Dictionary not loaded."); Sequence s = dict_seq_[b][dict_id]; return vector(s.data(), s.end()); } BitVector* SequenceFile::filter_by_taxonomy(const std::string& include, const std::string& exclude) const { BitVector* v = new BitVector(sequence_count()); if (!include.empty() && !exclude.empty()) throw std::runtime_error("Options --taxonlist and --taxon-exclude are mutually exclusive."); const bool e = !exclude.empty(); const std::set taxon_filter_list(Util::String::parse_csv(e ? exclude : include)); if (taxon_filter_list.empty()) throw std::runtime_error("Option --taxonlist/--taxon-exclude used with empty list."); if (taxon_filter_list.find(1) != taxon_filter_list.end() || taxon_filter_list.find(0) != taxon_filter_list.end()) throw std::runtime_error("Option --taxonlist/--taxon-exclude used with invalid argument (0 or 1)."); for (OId i = 0; i < sequence_count(); ++i) if (taxon_nodes_->contained(taxids(i), taxon_filter_list) ^ e) v->set(i); return v; } void SequenceFile::build_acc_to_oid() { acc2oid_.reserve(sequence_count()); set_seqinfo_ptr(0); vector seq; string id; for (OId i = 0; i < sequence_count(); ++i) { read_seq(seq, id); acc2oid_[Util::Seq::seqid(id.c_str())] = i; } } vector SequenceFile::accession_to_oid(const string& accession) const { try { return { acc2oid_.at(accession) }; } catch (std::out_of_range&) { throw runtime_error("Accession not found in database: " + accession); } } void SequenceFile::init_random_access(const size_t query_block, const size_t ref_blocks, bool dictionary) { if (dictionary) load_dictionary(query_block, ref_blocks); } std::string SequenceFile::seqid(OId oid, bool all) const { throw std::runtime_error("seqid"); //if (oid >= acc_.size()) //throw std::runtime_error("OId to accession mapping not available."); //return acc_[oid]; } void SequenceFile::write_accession_list(const std::vector& oids, std::string& file_name) { ofstream f(file_name); const Util::Tsv::Table acc = seqid_file().read(config.threads_); for (OId i = 0; i < sequence_count(); ++i) if (!oids[i]) f << acc[i].get(0) << endl; } template std::vector SequenceFile::seq_offsets(It begin, It end) { assert(std::is_sorted(begin, end)); vector r; if (end <= begin) return r; r.reserve(end - begin); set_seqinfo_ptr(0); init_seqinfo_access(); const OId end_oid = *(end - 1) + 1; if (end_oid > sequence_count()) throw runtime_error("OId out of bounds."); It it = begin; for (OId i = 0; i < end_oid; ++i) { SeqInfo info = read_seqinfo(); if (i == *it) { if (it != begin && i - 1 == *(it - 1)) r.push_back(-1); else r.push_back(info.pos); ++it; } } return r; } template void SequenceFile::sub_db(It begin, It end, FastaFile* out) { vector seq; string id; out->init_write(); if (end <= begin) return; if (flag_any(format_flags_, FormatFlags::LENGTH_LOOKUP)) { const vector pos = seq_offsets(begin, end); for (int64_t p : pos) { if (p >= 0) seek_offset(p); read_seq(seq, id); out->write_seq(Sequence(seq), id); } } else { assert(std::is_sorted(begin, end)); set_seqinfo_ptr(0); for (OId i = 0; i <= *(end - 1); ++i) { read_seq(seq, id); if (*begin == i) { out->write_seq(Sequence(seq), id); ++begin; } } } } template void SequenceFile::sub_db::const_iterator>(vector::const_iterator, vector::const_iterator, FastaFile*); template FastaFile* SequenceFile::sub_db(It begin, It end, const string& file_name) { FastaFile* f = new FastaFile(file_name, true, FastaFile::WriteAccess(), Flags::NEED_LENGTH_LOOKUP); sub_db(begin, end, f); return f; } template FastaFile* SequenceFile::sub_db::const_iterator>(vector::const_iterator, vector::const_iterator, const string&); template FastaFile* SequenceFile::sub_db::const_iterator>(vector::const_iterator, vector::const_iterator, const string&); pair SequenceFile::read_fai_file(const string& file_name, int64_t seqs, int64_t letters) { string acc; Loc len; TextInputFile fai(file_name); while (fai.getline(), !fai.line.empty() || !fai.eof()) { Util::String::Tokenizer(fai.line, Util::String::CharDelimiter('\t')) >> acc >> len; if (flag_any(flags_, Flags::ACC_TO_OID_MAPPING)) acc2oid_[acc] = seqs; //if (flag_any(flags_, Flags::OID_TO_ACC_MAPPING)) // acc_.push_back(acc.begin(), acc.end()); ++seqs; letters += len; } fai.close(); return { seqs, letters }; } void db_info() { using std::cout; if (config.database.empty()) throw std::runtime_error("Missing option for database file: --db/-d."); SequenceFile* db = SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NO_FASTA | SequenceFile::Flags::NO_COMPATIBILITY_CHECK); const std::streamsize w = 25; cout << setw(w) << "Database type " << to_string(db->type()) << endl; cout << setw(w) << "Database format version " << db->db_version() << endl; if(db->type() == SequenceFile::Type::DMND) cout << setw(w) << "Diamond build " << db->program_build_version() << endl; cout << setw(w) << "Sequences " << db->sequence_count() << endl; if (db->type() == SequenceFile::Type::BLAST && db->sequence_count() != db->sparse_sequence_count()) cout << setw(w) << "Sequences (filtered) " << db->sparse_sequence_count() << endl; cout << setw(w) << "Letters " << db->letters() << endl; db->close(); delete db; } void SequenceFile::add_seqid_mapping(const std::string& id, OId oid) { const string acc = Util::Seq::seqid(id.c_str()); if (flag_any(flags_, Flags::ACC_TO_OID_MAPPING)) { if (oid != (OId)acc2oid_.size()) throw runtime_error("add_seqid_mapping"); auto r = acc2oid_.emplace(acc, oid); if (!r.second) throw runtime_error("Accession is not unique in database file: " + acc); } if (flag_any(flags_, Flags::OID_TO_ACC_MAPPING)) { seqid_file_->write_record(acc); } } vector, File*>> SequenceFile::length_sort(int64_t block_size, function& seq_size) { static const int64_t MIN_BLOCK_SIZE = 1; vector, File*>> files; init_seq_access(); vector seq; string id; vector> lengths; lengths.reserve(sequence_count()); for (OId i = 0; i < sequence_count(); ++i) { read_seq(seq, id); lengths.emplace_back((Loc)seq.size(), i); } ips4o::parallel::sort(lengths.begin(), lengths.end(), greater>(), config.threads_); int64_t size = 0, seqs = 0, letters = 0; int block = 0; for (auto i = lengths.begin(); i != lengths.end(); ++i) { size += seq_size(i->first); letters += i->first; ++seqs; i->first = block; if ((size >= block_size && letters >= MIN_BLOCK_SIZE) || seqs >= numeric_limits::max()) { log_stream << "Super block " << block << " seqs=" << seqs << " letters=" << letters << endl; ++block; size = 0; seqs = 0; letters = 0; } } if (size > 0) { log_stream << "Super block " << block << " seqs=" << seqs << " letters=" << letters << endl; ++block; } ips4o::parallel::sort(lengths.begin(), lengths.end(), [](const pair& p1, const pair& p2) { return p1.second < p2.second; }, config.threads_); files.reserve(block); for (int i = 0; i < block; ++i) { //files.emplace_back(new FastaFile("", true, FastaFile::WriteAccess()), vector(), files.emplace_back(new FastaFile("", true, FastaFile::WriteAccess(), Flags::NEED_LENGTH_LOOKUP), vector(), new File(Schema{ ::Type::INT64 }, "", ::Flags::TEMP)); get<0>(files.back())->init_write(); } init_seq_access(); //Util::Tsv::File map_file(Util::Tsv::Schema{ Util::Tsv::Type::INT64 }, "", Util::Tsv::Flags::WRITE_ACCESS); const string placeholer("X"); for (OId i = 0; i < sequence_count(); ++i) { read_seq(seq, id); auto& f = files[lengths[i].first]; get<0>(f)->write_seq(seq, placeholer); get<2>(f)->write_record(i); } for (auto f : files) get<0>(f)->set_seqinfo_ptr(0); return files; } Util::Tsv::File& SequenceFile::seqid_file() { seqid_file_->rewind(); return *seqid_file_; } size_t SequenceFile::letters_filtered(const BitVector& v) const { size_t n = 0; for (OId i = 0; i < v.size(); ++i) if (v.get(i)) n += seq_length(i); return n; }bbuchfink-diamond-08b3cbc/src/data/sequence_file.h000066400000000000000000000223251506104011400222200ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "util/io/input_file.h" #include "sequence_set.h" #include "util/data_structures/bit_vector.h" #include "taxonomy_nodes.h" #include "util/enum.h" #include "block/block.h" #include "util/tsv/tsv.h" struct Chunk { Chunk() : i(0), offset(0), n_seqs(0) {} Chunk(int i_, size_t offset_, size_t n_seqs_) : i(i_), offset(offset_), n_seqs(n_seqs_) {} int i; size_t offset; int64_t n_seqs; }; struct AccessionNotFound : public std::exception { }; struct OperationNotSupported : public std::exception { }; struct FastaFile; struct SequenceFile { enum class Type { DMND = 0, BLAST = 1, FASTA = 2, BLOCK = 3 }; enum class Metadata : int { TAXON_MAPPING = 1, TAXON_NODES = 1 << 1, TAXON_SCIENTIFIC_NAMES = 1 << 2, TAXON_RANKS = 1 << 3 }; enum class Flags : int { NONE = 0, NO_COMPATIBILITY_CHECK = 1, NO_FASTA = 1 << 1, ALL_SEQIDS = 1 << 2, FULL_TITLES = 1 << 3, TARGET_SEQS = 1 << 4, SELF_ALN_SCORES = 1 << 5, NEED_LETTER_COUNT = 1 << 6, ACC_TO_OID_MAPPING = 1 << 7, OID_TO_ACC_MAPPING = 1 << 8, NEED_LENGTH_LOOKUP = 1 << 9 }; enum class FormatFlags { TITLES_LAZY = 1, DICT_LENGTHS = 1 << 1, DICT_SEQIDS = 1 << 2, LENGTH_LOOKUP = 1 << 3, SEEKABLE = 1 << 4 }; enum class LoadFlags { SEQS = 1, TITLES = 1 << 1, QUALITY = 1 << 2, LAZY_MASKING = 1 << 3, CONVERT_ALPHABET = 1 << 4, DNA_PRESERVATION = 1 << 5, ALL = SEQS | TITLES }; struct SeqInfo { SeqInfo() {} SeqInfo(uint64_t pos, size_t len) : pos(pos), seq_len(uint32_t(len)) {} uint64_t pos; uint32_t seq_len; enum { SIZE = 16 }; }; SequenceFile(Type type, Alphabet alphabet, Flags flags, FormatFlags format_flags, const ValueTraits& value_traits = amino_acid_traits); virtual int64_t file_count() const = 0; virtual void init_seqinfo_access() = 0; virtual void init_seq_access() = 0; virtual void seek_chunk(const Chunk& chunk) = 0; virtual OId tell_seq() const = 0; virtual bool eof() const = 0; virtual bool files_synced(); virtual SeqInfo read_seqinfo() = 0; virtual void putback_seqinfo() = 0; virtual size_t id_len(const SeqInfo& seq_info, const SeqInfo& seq_info_next) = 0; virtual void seek_offset(size_t p) = 0; virtual void read_seq_data(Letter* dst, size_t len, size_t& pos, bool seek) = 0; virtual void read_id_data(const int64_t oid, char* dst, size_t len) = 0; virtual void skip_id_data() = 0; virtual std::string seqid(OId oid, bool all = false) const; virtual std::string dict_title(DictId dict_id, const size_t ref_block) const final; virtual Loc dict_len(DictId dict_id, const size_t ref_block) const; virtual std::vector dict_seq(DictId dict_id, const size_t ref_block) const; virtual int64_t sequence_count() const = 0; virtual int64_t sparse_sequence_count() const = 0; virtual int64_t letters() const = 0; virtual size_t letters_filtered(const BitVector& v) const; virtual int db_version() const = 0; virtual int program_build_version() const = 0; virtual bool read_seq(std::vector& seq, std::string& id, std::vector* quals = nullptr) = 0; virtual Metadata metadata() const = 0; virtual std::string taxon_scientific_name(TaxId taxid) const; virtual int build_version() = 0; virtual void create_partition_balanced(int64_t max_letters) = 0; virtual void save_partition(const std::string& partition_file_name, const std::string& annotation = "") = 0; virtual int get_n_partition_chunks() = 0; virtual void set_seqinfo_ptr(OId i) = 0; virtual void close() = 0; virtual BitVector* filter_by_accession(const std::string& file_name) = 0; virtual std::vector taxids(size_t oid) const = 0; virtual const BitVector* builtin_filter() = 0; virtual std::string file_name() = 0; virtual void seq_data(size_t oid, std::vector& dst) const = 0; virtual size_t seq_length(size_t oid) const = 0; void init_random_access(const size_t query_block, const size_t ref_blocks, bool dictionary = true); virtual void end_random_access(bool dictionary = true) = 0; virtual std::vector accession_to_oid(const std::string& acc) const; virtual void init_write(); virtual void write_seq(const Sequence& seq, const std::string& id); virtual ~SequenceFile(); Type type() const { return type_; } Block* load_seqs(const int64_t max_letters, const BitVector* filter = nullptr, LoadFlags flags = LoadFlags(3), const Chunk& chunk = Chunk()); void get_seq(); Util::Tsv::File* make_seqid_list(); size_t total_blocks() const; SequenceSet seqs_by_accession(const std::vector::const_iterator begin, const std::vector::const_iterator end) const; std::vector seq_by_accession(const std::string& acc) const; BitVector* filter_by_taxonomy(const std::string& include, const std::string& exclude) const; void write_accession_list(const std::vector& oids, std::string& file_name); template std::vector seq_offsets(It begin, It end); template FastaFile* sub_db(It begin, It end, const std::string& file_name = std::string()); template void sub_db(It begin, It end, FastaFile* out); std::vector, Util::Tsv::File*>> length_sort(int64_t block_size, std::function& seq_size); Util::Tsv::File& seqid_file(); void init_dict(const size_t query_block, const size_t target_block); void init_dict_block(size_t block, size_t seq_count, bool persist); void close_dict_block(bool persist); DictId dict_id(size_t block, size_t block_id, size_t oid, size_t len, const char* id, const Letter* seq, const double self_aln_score); size_t oid(DictId dict_id, const size_t ref_block) const; double dict_self_aln_score(const size_t dict_size, const size_t ref_block) const; size_t dict_size() const { return next_dict_id_; } Flags flags() const { return flags_; } FormatFlags format_flags() const { return format_flags_; } const TaxonomyNodes& taxon_nodes() const { return *taxon_nodes_; } static SequenceFile* auto_create(const std::vector& path, Flags flags = Flags::NONE, Metadata metadata = Metadata(), const ValueTraits& value_traits = amino_acid_traits); size_t mem_size() const { size_t n = 0; for (auto& v : dict_oid_) n += v.size() * sizeof(OId); for (auto& v : dict_len_) n += v.size() * sizeof(uint32_t); for (auto& v : dict_title_) n += v.raw_len(); for (auto& v : dict_seq_) n += v.raw_len(); for (auto& v : dict_self_aln_score_) n += v.size() * sizeof(double); if (!acc2oid_.empty() || !block_to_dict_id_.empty()) std::terminate(); return n; } protected: static const char* const SEQID_HDR; void load_dictionary(const size_t query_block, const size_t ref_blocks); void free_dictionary(); static size_t dict_block(const size_t ref_block); void build_acc_to_oid(); std::pair read_fai_file(const std::string& file_name, int64_t seqs, int64_t letters); void add_seqid_mapping(const std::string& id, OId oid); const Flags flags_; const FormatFlags format_flags_; const ValueTraits& value_traits_; std::unique_ptr dict_file_; DictId next_dict_id_; size_t dict_alloc_size_; std::vector> dict_oid_; std::vector> dict_len_; std::vector dict_title_; std::vector dict_seq_; std::vector> dict_self_aln_score_; std::unique_ptr taxon_nodes_; std::unordered_map acc2oid_; std::unique_ptr seqid_file_; std::vector seq_length_; private: static const DictId DICT_EMPTY; void write_dict_entry(size_t block, size_t oid, size_t len, const char* id, const Letter* seq, const double self_aln_score); bool load_dict_entry(InputFile& f, const size_t ref_block); void reserve_dict(const size_t ref_blocks); std::pair load_twopass(const int64_t max_letters, const BitVector* filter, LoadFlags flags, const Chunk& chunk); std::pair load_onepass(const int64_t max_letters, const BitVector* filter, LoadFlags flags); void load_dict_block(InputFile* f, const size_t ref_block); const Type type_; const Alphabet alphabet_; std::map> block_to_dict_id_; std::mutex dict_mtx_; }; template<> struct EnumTraits { static const EMap to_string; }; DEFINE_ENUM_FLAG_OPERATORS(SequenceFile::Flags) DEFINE_ENUM_FLAG_OPERATORS(SequenceFile::Metadata) DEFINE_ENUM_FLAG_OPERATORS(SequenceFile::FormatFlags) DEFINE_ENUM_FLAG_OPERATORS(SequenceFile::LoadFlags) bbuchfink-diamond-08b3cbc/src/data/sequence_set.cpp000066400000000000000000000101171506104011400224230ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "sequence_set.h" #include "util/sequence/sequence.h" #include "util/log_stream.h" using std::vector; using std::pair; using std::string; SequenceSet::SequenceSet(Alphabet alphabet) : alphabet_(alphabet) { } void SequenceSet::print_stats() const { verbose_stream << "Sequences = " << this->size() << ", letters = " << this->letters() << ", average length = " << this->avg_len() << std::endl; } std::pair SequenceSet::len_bounds(Length min_len) const { const size_t l(this->size()); Length max = 0, min = std::numeric_limits::max(); for (size_t i = 0; i < l; ++i) { max = std::max(this->length(i), max); min = this->length(i) >= min_len ? std::min(this->length(i), min) : min; } return std::pair(min, max); } SequenceSet::Length SequenceSet::max_len(size_t begin, size_t end) const { Length max = 0; for (size_t i = begin; i < end; ++i) max = std::max(this->length(i), max); return max; } std::vector SequenceSet::partition(unsigned n_part, bool shortened, bool context_reduced) const { std::vector v; const size_t l = (this->letters() + n_part - 1) / n_part; const Id c = context_reduced ? align_mode.query_contexts : 1; if(!shortened) v.push_back(0); for (Id i = 0; i < this->size();) { size_t n = 0; while (i < this->size() && n < l) { for (Id j = 0; j < c; ++j) n += this->length(i++); } v.push_back(i / c); } for (size_t i = v.size(); i < n_part + (shortened ? 0 : 1); ++i) v.push_back(this->size() / c); return v; } size_t SequenceSet::reverse_translated_len(size_t i) const { const size_t j(i - i % 6); const Loc l(this->length(j)); if (this->length(j + 2) == l) return l * 3 + 2; else if (this->length(j + 1) == l) return l * 3 + 1; else return l * 3; } TranslatedSequence SequenceSet::translated_seq(const Sequence& source, size_t i) const { if (!align_mode.query_translated) return TranslatedSequence((*this)[i]); return TranslatedSequence(source, (*this)[i], (*this)[i + 1], (*this)[i + 2], (*this)[i + 3], (*this)[i + 4], (*this)[i + 5]); } size_t SequenceSet::avg_len() const { return this->letters() / this->size(); } SequenceSet::~SequenceSet() { } void SequenceSet::convert_to_std_alph(size_t id) { if (alphabet_ == Alphabet::STD) return; Letter* ptr = this->ptr(id); const size_t len = length(id); alph_ncbi_to_std(ptr, ptr + len); } void SequenceSet::convert_all_to_std_alph(size_t threads) { if (alphabet_ == Alphabet::STD) return; std::atomic_size_t next(0); auto worker = [this, &next] { const size_t n = this->size(); size_t i; while ((i = next++) < n) this->convert_to_std_alph(i); }; vector t; for (size_t i = 0; i < threads; ++i) t.emplace_back(worker); for (auto& i : t) i.join(); alphabet_ = Alphabet::STD; } size_t max_id_len(const StringSet& ids) { size_t max(0); for (BlockId i = 0; i < ids.size(); ++i) max = std::max(max, find_first_of(ids[i], Util::Seq::id_delimiters)); return max; } std::vector> SequenceSet::lengths() const { vector> l; l.reserve(size()); for (BlockId i = 0; i < size(); ++i) l.emplace_back(length(i), i); return l; }bbuchfink-diamond-08b3cbc/src/data/sequence_set.h000066400000000000000000000040201506104011400220640ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "basic/sequence.h" #include "string_set.h" #include "basic/value.h" struct SequenceSet : public StringSetBase { SequenceSet(Alphabet alphabet = Alphabet::STD); SequenceSet(StringSetBase&& string_set): StringSetBase(string_set), alphabet_(Alphabet::STD) {} void print_stats() const; Sequence operator[](size_t i) const { return Sequence(ptr(i), (Loc)length(i)); } std::pair len_bounds(Length min_len) const; Length max_len(size_t begin, size_t end) const; std::vector partition(unsigned n_part, bool shortened = false, bool context_reduced = false) const; size_t reverse_translated_len(size_t i) const; TranslatedSequence translated_seq(const Sequence& source, size_t i) const; size_t avg_len() const; virtual ~SequenceSet(); Alphabet alphabet() const { return alphabet_; } Alphabet& alphabet() { return alphabet_; } void convert_to_std_alph(size_t id); void convert_all_to_std_alph(size_t threads); std::vector> lengths() const; private: Alphabet alphabet_; }; size_t max_id_len(const StringSet& ids);bbuchfink-diamond-08b3cbc/src/data/string_set.h000066400000000000000000000142471506104011400215760ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include template struct StringSetBase { using Length = Loc; using Id = BlockId; using Pos = int64_t; enum { PERIMETER_PADDING = 256 }; static const char DELIMITER = padding_char; StringSetBase(): data_ (PERIMETER_PADDING, padding_char) { limits_.push_back(PERIMETER_PADDING); } void finish_reserve() { data_.resize(raw_len() + PERIMETER_PADDING); std::fill(data_.begin() + raw_len(), data_.end(), padding_char); } void reserve(size_t n) { limits_.push_back(raw_len() + n + padding_len); } void reserve(size_t entries, size_t length) { limits_.reserve(entries + 1); data_.reserve(length + 2 * PERIMETER_PADDING + entries * padding_len); } void clear() { limits_.resize(1); data_.resize(PERIMETER_PADDING); } void shrink_to_fit() { limits_.shrink_to_fit(); data_.shrink_to_fit(); } template void push_back(_it begin, _it end) { assert(begin <= end); limits_.push_back(raw_len() + (end - begin) + padding_len); data_.insert(data_.end(), begin, end); data_.insert(data_.end(), padding_len, padding_char); } void append(const StringSetBase& s) { reserve(size() + s.size(), letters() + s.letters()); for (Id i = 0; i < s.size(); ++i) push_back(s.ptr(i), s.end(i)); } template void assign(const size_t i, const It begin, const It end) { std::copy(begin, end, ptr(i)); std::fill(ptr(i) + (end - begin), ptr(i) + (end - begin) + padding_len, padding_char); } void fill(size_t n, T v) { limits_.push_back(raw_len() + n + padding_len); data_.insert(data_.end(), n, v); data_.insert(data_.end(), padding_len, padding_char); } T* ptr(size_t i) { return &data_[limits_[i]]; } const T* ptr(size_t i) const { return &data_[limits_[i]]; } const T* end(size_t i) const { return &data_[limits_[i + 1] - padding_len]; } size_t check_idx(size_t i) const { if (limits_.size() < i + 2) throw std::runtime_error("Sequence set index out of bounds."); return i; } Length length(size_t i) const { return Length(limits_[i + 1] - limits_[i] - padding_len); } Id size() const { return Id(limits_.size() - 1); } bool empty() const { return limits_.size() <= 1; } int64_t raw_len() const { return limits_.back(); } int64_t mem_size() const { return data_.size() * sizeof(T) + limits_.size() * sizeof(int64_t); } int64_t letters() const { return raw_len() - size() - PERIMETER_PADDING; } T* data(uint64_t p = 0) { return &data_[p]; } const T* data(uint64_t p = 0) const { return &data_[p]; } size_t position(const T* p) const { return p - data(); } Pos position(Id i, Length j) const { return limits_[i] + j; } std::pair local_position(int64_t p) const { auto i = std::upper_bound(limits_.begin(), limits_.end(), p) - limits_.begin() - 1; return std::pair(Id(i), Length(p - limits_[i])); } template void local_position_batch(It begin, It end, Out out, Cmp cmp) const { batch_binary_search(begin, end, limits_.begin(), limits_.end(), out, cmp); } const T* operator[](size_t i) const { return ptr(i); } const T* back() const { return ptr(limits_.size() - 2); } typename std::vector::const_iterator limits_begin() const { return limits_.begin(); } typename std::vector::const_iterator limits_end() const { return limits_.end(); } struct ConstIterator { ConstIterator(const T* data, const int64_t* limits): data_(data), limits_(limits) {} using iterator_category = std::random_access_iterator_tag; using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using reference = T&; ptrdiff_t operator-(const ConstIterator& it) const { return limits_ - it.limits_; } bool operator==(const ConstIterator& it) const { return limits_ == it.limits_; } bool operator!=(const ConstIterator& it) const { return limits_ != it.limits_; } ConstIterator operator+(ptrdiff_t d) const { return { data_ + *(limits_ + d) - *limits_, limits_ + d }; } bool operator<(const ConstIterator& it) const { return limits_ < it.limits_; } ConstIterator& operator+=(ptrdiff_t d) { data_ += *(limits_ + d) - *limits_; limits_ += d; return *this; } ConstIterator& operator++() { this->operator+=(1); return *this; } std::pair operator[](const ptrdiff_t i) const { return { data_ + limits_[i] - limits_[0], limits_[i + 1] - limits_[i] - padding_len }; } std::pair operator*() const { return this->operator[](0); } private: const T* data_; const int64_t* limits_; }; ConstIterator cbegin() const { return ConstIterator(ptr(0), limits_.data()); } ConstIterator cend() const { return ConstIterator(nullptr, &limits_[size()]); } template StringSetBase subset(It begin, It end) const { StringSetBase r; r.limits_.reserve(end - begin); for (It i = begin; i != end; ++i) r.reserve(length(*i)); r.finish_reserve(); Id n = 0; for (It i = begin; i != end; ++i, ++n) { r.assign(n, ptr(*i), this->end(*i)); } return r; } private: std::vector data_; std::vector limits_; }; using StringSet = StringSetBase;bbuchfink-diamond-08b3cbc/src/data/taxon_list.cpp000066400000000000000000000114211506104011400221230ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "taxon_list.h" #include "util/log_stream.h" #include "util/io/text_input_file.h" #include "basic/config.h" #include "util/string/tokenizer.h" #include "util/algo/external_sort.h" #include "util/algo/sort_helper.h" #include "legacy/dmnd/io.h" #include "util/sequence/sequence.h" using std::set; using std::endl; using std::make_pair; using std::vector; using std::pair; using std::string; TaxonList::TaxonList(Deserializer &in, size_t size, size_t data_size): CompactArray(in, size, data_size) {} static int mapping_file_format(const string& header) { string field1, field2; Util::String::Tokenizer tok(header, Util::String::CharDelimiter('\t')); tok >> field1 >> field2; if (field1 == "accession" && field2 == "accession.version") { tok >> field1 >> field2; if (field1 == "taxid" && field2 == "gi" && !tok.good()) return 0; } else if (field1 == "accession.version" && field2 == "taxid" && !tok.good()) return 1; throw std::runtime_error("Accession mapping file header has to be in one of these formats:\naccession\taccession.version\ttaxid\tgi\naccession.version\ttaxid"); } static Util::Seq::AccessionParsing load_mapping_file(ExternalSorter>& sorter) { TaxId taxid; TextInputFile f(config.prot_accession2taxid); f.getline(); int format = mapping_file_format(f.line); string accession, last; Util::Seq::AccessionParsing stats; while (!f.eof() && (f.getline(), !f.line.empty())) { try { if (format == 0) Util::String::Tokenizer(f.line, Util::String::CharDelimiter('\t')) >> Util::String::Skip() >> accession >> taxid; else Util::String::Tokenizer(f.line, Util::String::CharDelimiter('\t')) >> accession >> taxid; } catch (Util::String::TokenizerException&) { throw std::runtime_error("Malformed input in line " + std::to_string(f.line_count)); } if (accession.empty()) throw std::runtime_error("Empty accession field in line " + std::to_string(f.line_count)); if (!config.no_parse_seqids) { size_t i = accession.find(":PDB="); if (i != string::npos) { accession.erase(i); ++stats.pdb_suffix; } accession = Util::Seq::get_accession(accession, stats); } if (accession != last) sorter.push(make_pair(accession, taxid)); last = accession; } f.close(); return stats; } void TaxonList::build(OutputFile &db, ExternalSorter>& acc2oid, OId seqs, Util::Table& stats) { TaskTimer timer("Loading taxonomy mapping file"); ExternalSorter> acc2taxid; const Util::Seq::AccessionParsing acc_stats = load_mapping_file(acc2taxid); timer.go("Joining accession mapping"); acc2taxid.init_read(); acc2oid.init_read(); const auto cmp = [](const pair& x, const pair& y) { return x.first < y.first; }; const auto value = [](const pair& x, const pair& y) { return make_pair(x.second, y.second); }; auto it = join_sorted_lists(acc2oid, acc2taxid, First(), First(), value); ExternalSorter> oid2taxid; size_t acc_matched = 0; while (it.good()) { oid2taxid.push(*it); ++it; ++acc_matched; } timer.go("Writing taxon id list"); oid2taxid.init_read(); auto taxid_it = merge_keys(oid2taxid, First(), Second(), 0); size_t mapped_seqs = 0; while (taxid_it.key() < seqs) { set tax_ids = *taxid_it; tax_ids.erase(0); serialize(db, tax_ids); ++taxid_it; if (!tax_ids.empty()) ++mapped_seqs; } timer.finish(); stats("Accessions in database", acc2oid.count()); stats("Entries in accession to taxid file", acc2taxid.count()); stats("Database accessions mapped to taxid" , acc_matched); stats("Database sequences mapped to taxid", mapped_seqs); if (!config.no_parse_seqids) message_stream << endl << "Accession parsing rules triggered for mapping file seqids (use --no-parse-seqids to disable):" << endl << acc_stats << endl; } bbuchfink-diamond-08b3cbc/src/data/taxon_list.h000066400000000000000000000024211506104011400215700ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "util/io/output_file.h" #include "legacy/dmnd/compact_array.h" #include "util/table.h" #include "basic/value.h" template struct ExternalSorter; struct TaxonList : public CompactArray { typedef std::pair T; TaxonList(Deserializer &in, size_t size, size_t data_size); static void build(OutputFile &db, ExternalSorter>& accessions, OId seqs, Util::Table& stats); };bbuchfink-diamond-08b3cbc/src/data/taxonomy.cpp000066400000000000000000000056071506104011400216260ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "taxonomy.h" #include "util/io/text_input_file.h" #include "basic/config.h" #include "util/log_stream.h" #include "util/string/string.h" #include "util/string/tokenizer.h" #include "taxonomy_nodes.h" using std::string; using std::map; using std::endl; using std::set; using std::vector; const char* Rank::names[] = { "no rank", "superkingdom", "cellular root", "acellular root", "domain", "realm", "kingdom", "subkingdom", "superphylum", "phylum", "subphylum", "superclass", "class", "subclass", "infraclass", "cohort", "subcohort", "superorder", "order", "suborder", "infraorder", "parvorder", "superfamily", "family", "subfamily", "tribe", "subtribe", "genus", "subgenus", "section", "subsection", "series", "species group", "species subgroup", "species", "subspecies", "varietas", "forma", "strain", "biotype", "clade", "forma specialis", "genotype", "isolate", "morph", "pathogroup", "serogroup", "serotype", "subvariety" }; map Rank::init_map() { map r; for (size_t i = 0; i < count; ++i) r[names[i]] = Rank(i); return r; } const map Rank::rank_map = Rank::init_map(); Rank::Rank(const char *s) { if (rank_map.find(s) == rank_map.end()) throw std::runtime_error("Invalid taxonomic rank: " + string(s)); r = rank_map.find(s)->second.r; } Taxonomy taxonomy; size_t Taxonomy::load_names() { TextInputFile in(config.namesdmp); string name, type; int64_t id; size_t n = 0; while (in.getline(), !in.eof()) { if (in.line.empty()) continue; Util::String::Tokenizer(in.line, Util::String::StringDelimiter("\t|\t")) >> id >> name >> Util::String::Skip() >> type; type = rstrip(type, "\t|"); if (type == "scientific name") { name_.resize(id + 1); name_[id] = name; ++n; } } in.close(); return n; } void Taxonomy::init() { TaskTimer timer; if (!config.namesdmp.empty()) { timer.go("Loading taxonomy names"); size_t n = load_names(); timer.finish(); message_stream << "Loaded taxonomy names for " << n << " taxon ids." << endl; } }bbuchfink-diamond-08b3cbc/src/data/taxonomy.h000066400000000000000000000020251506104011400212620ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include struct Taxonomy { void init(); size_t load_names(); std::vector name_; friend struct TaxonomyNodes; }; extern Taxonomy taxonomy;bbuchfink-diamond-08b3cbc/src/data/taxonomy_nodes.cpp000066400000000000000000000120621506104011400230070ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2019 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include "taxonomy_nodes.h" #include "util/log_stream.h" #include "util/string/string.h" #include "util/io/text_input_file.h" #include "util/string/tokenizer.h" #include "legacy/dmnd/io.h" using std::string; using std::reverse; using std::vector; using std::set; using std::endl; using std::to_string; using std::runtime_error; TaxonomyNodes::TaxonomyNodes(const string& file_name, const bool init_cache) { TextInputFile f(file_name); TaxId taxid, parent; string rank; while (!f.eof() && (f.getline(), !f.line.empty())) { Util::String::Tokenizer(f.line, Util::String::StringDelimiter("\t|\t")) >> taxid >> parent >> rank; parent_.resize(taxid + 1, 0); parent_[taxid] = parent; rank_.resize(taxid + 1, Rank::none); rank_[taxid] = Rank(rank.c_str()); } f.close(); if (init_cache) this->init_cache(); } void TaxonomyNodes::save(Serializer &out) { TaskTimer timer("Building taxonomy nodes"); serialize(out, parent_); out.write(rank_.data(), rank_.size()); timer.finish(); message_stream << parent_.size() << " taxonomy nodes processed." << endl; size_t rank_count[Rank::count]; std::fill(rank_count, rank_count + Rank::count, 0); for (const Rank r : rank_) { ++rank_count[r]; } const size_t w = MAX_LEN(Rank::names) + 2; message_stream << "Number of nodes assigned to rank:" << endl; for (size_t i = 0; i < Rank::count; ++i) message_stream << std::left << std::setw(w) << Rank::names[i] << rank_count[i] << endl; message_stream << endl; } TaxonomyNodes::TaxonomyNodes(Deserializer &in, uint32_t db_build) { deserialize(in, parent_); if (db_build >= 131) { rank_.resize(parent_.size()); in.read(rank_.data(), rank_.size()); } init_cache(); } void TaxonomyNodes::init_cache() { cached_.insert(cached_.end(), parent_.size(), false); contained_.insert(contained_.end(), parent_.size(), false); } unsigned TaxonomyNodes::get_lca(unsigned t1, unsigned t2) const { static const int max = 64; if (t1 == t2 || t2 == 0) return t1; if (t1 == 0) return t2; unsigned p = t2; set l; l.insert(p); int n = 0; do { p = get_parent(p); if (p == 0) return t1; l.insert(p); if (++n > max) throw std::runtime_error("Path in taxonomy too long (1)."); } while (p != t1 && p != 1); if (p == t1) return p; p = t1; n = 0; while (l.find(p) == l.end()) { p = get_parent(p); if (p == 0) return t2; if (++n > max) throw std::runtime_error("Path in taxonomy too long (2)."); } return p; } bool TaxonomyNodes::contained(TaxId query, const set &filter) { static const int max = 64; if (query >= (TaxId)parent_.size()) throw runtime_error(string("No taxonomy node found for taxon id ") + to_string(query)); if (cached_[query]) return contained_[query]; if (filter.find(1) != filter.end()) return true; int n = 0; unsigned p = query; while (p > 1 && filter.find(p) == filter.end()) { p = get_parent(p); if (++n > max) throw std::runtime_error("Path in taxonomy too long (3)."); } const bool contained = p > 1; unsigned q = query; while (set_cached(q, contained), q != p) q = get_parent(q); return contained; } bool TaxonomyNodes::contained(const vector& query, const set &filter) { static const int max = 64; if (filter.find(1) != filter.end()) return true; for (vector::const_iterator i = query.begin(); i != query.end(); ++i) if (contained(*i, filter)) return true; return false; } unsigned TaxonomyNodes::rank_taxid(unsigned taxid, Rank rank) const { static const int max = 64; int n = 0; while (true) { if (taxid >= rank_.size()) return 0; if (rank_[taxid] == rank) return taxid; if (taxid == 0 || taxid == 1) return 0; if (++n > max) throw std::runtime_error("Path in taxonomy too long (4)."); taxid = get_parent(taxid); } return 0; } std::set TaxonomyNodes::rank_taxid(const std::vector &taxid, Rank rank) const { set r; for (unsigned i : taxid) r.insert(rank_taxid(i, rank)); return r; } vector TaxonomyNodes::lineage(TaxId taxid) const { static const int MAX = 64; vector out; int n = 0; while (true) { if (taxid == 0 || taxid == 1) break; if (++n > MAX) throw std::runtime_error("Path in taxonomy too long (TaxonomyNodes::lineage)."); out.push_back(taxid); taxid = get_parent(taxid); } reverse(out.begin(), out.end()); return out; }bbuchfink-diamond-08b3cbc/src/data/taxonomy_nodes.h000066400000000000000000000062321506104011400224560ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2020 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include "util/io/serializer.h" #include "util/io/deserializer.h" #include "basic/value.h" struct Rank { Rank() : r(none) {} Rank(size_t i) : r((char)i) {} Rank(const char *s); enum { count = 49, strain = 38, biotype = 39, clade = 40, forma_specialis = 41, genotype = 42, isolate = 43, morph = 44, pathogroup = 45, serogroup = 46, serotype = 47, subvariety = 48, forma = 37, varietas = 36, subspecies = 35, species = 34, species_subgroup = 33, species_group = 32, series = 31, subsection = 30, section = 29, subgenus = 28, genus = 27, subtribe = 26, tribe = 25, subfamily = 24, family = 23, superfamily = 22, parvorder = 21, infraorder = 20, suborder = 19, order = 18, superorder = 17, subcohort = 16, cohort = 15, infraclass = 14, subclass = 13, class_rank = 12, superclass = 11, subphylum = 10, phylum = 9, superphylum = 8, subkingdom = 7, kingdom = 6, realm = 5, domain = 4, acellular_root = 3, cellular_root = 2, superkingdom = 1, none = 0 }; operator int() const { return (int)r; } friend std::ostream& operator<<(std::ostream &s, Rank &r) { s << std::string(names[(int)r.r]); return s; } static const char* names[count]; private: char r; static const std::map rank_map; static std::map init_map(); }; struct TaxonomyNodes { TaxonomyNodes(const std::string& file_name, const bool init_cache = false); TaxonomyNodes(Deserializer &in, uint32_t db_build); void save(Serializer &out); unsigned get_parent(unsigned taxid) const { if (taxid >= parent_.size()) throw std::runtime_error(std::string("No taxonomy node found for taxon id ") + std::to_string(taxid)); return parent_[taxid]; } unsigned rank_taxid(unsigned taxid, Rank rank) const; std::set rank_taxid(const std::vector &taxid, Rank rank) const; unsigned get_lca(unsigned t1, unsigned t2) const; bool contained(TaxId query, const std::set &filter); bool contained(const std::vector& query, const std::set &filter); std::vector lineage(TaxId taxid) const; private: void set_cached(unsigned taxon_id, bool contained) { cached_[taxon_id] = true; contained_[taxon_id] = contained; } void init_cache(); std::vector parent_; std::vector rank_; std::vector cached_, contained_; }; bbuchfink-diamond-08b3cbc/src/dp/000077500000000000000000000000001506104011400167265ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/dp/dp.h000066400000000000000000000203221506104011400175010ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "basic/sequence.h" #include "basic/match.h" #include "basic/statistics.h" #include "basic/config.h" #include "data/sequence_set.h" #include "stats/cbs.h" #include "flags.h" #include "util/parallel/thread_pool.h" #include "align/def.h" #include "dp/score_profile.h" struct DpTarget { struct CarryOver { CarryOver() : i1(0), j1(0), ident(0), len(0) {} CarryOver(int i1, int j1, int ident, int len) : i1(i1), j1(j1), ident(ident), len(len) {} int i1, j1, ident, len; }; enum { BLANK = -1, MIN_LETTERS = 3 }; static Loc banded_cols(const Loc qlen, const Loc tlen, const Loc d_begin, const Loc d_end) { const Loc pos = std::max(d_end - 1, 0) - (d_end - 1); const Loc d0 = d_begin; const Loc j1 = std::min(qlen - 1 - d0, tlen - 1) + 1; return j1 - pos; } DpTarget(): d_begin(), d_end(), cols(), target_idx(BLANK), matrix(nullptr) { } //DpTarget(const Sequence &seq, int true_target_len, int d_begin, int d_end, Interval chaining_target_range, Score chaining_score, BlockId target_idx, int qlen, const Stats::TargetMatrix* matrix = nullptr, const CarryOver& carry_over = CarryOver(), const Anchor& anchor = Anchor()) : DpTarget(const Sequence& seq, int true_target_len, int d_begin, int d_end, BlockId target_idx, int qlen, const Stats::TargetMatrix* matrix = nullptr, const CarryOver& carry_over = CarryOver(), const Anchor& anchor = Anchor()) : seq(seq), d_begin(d_begin), d_end(d_end), cols(banded_cols(qlen, seq.length(), d_begin, d_end)), true_target_len(true_target_len), //chaining_target_range(chaining_target_range), //chaining_score(chaining_score), target_idx(target_idx), carry_over(carry_over), matrix(matrix), anchor(anchor) { } DpTarget(const Sequence& seq, int true_target_len, BlockId target_idx, const Stats::TargetMatrix* matrix = nullptr, const CarryOver& carry_over = CarryOver()): seq(seq), d_begin(), d_end(), cols(), true_target_len(true_target_len), //chaining_score(0), target_idx(target_idx), carry_over(carry_over), matrix(matrix) { } DpTarget(const std::pair seq) : seq(seq.first, seq.second), d_begin(), d_end(), cols(), true_target_len((Loc)seq.second), target_idx(BLANK), matrix(nullptr) { } int left_i1() const { return std::max(d_end - 1, 0); } int band() const { return d_end - d_begin; } bool operator<(const DpTarget &x) const { const int i = left_i1(), j = x.left_i1(), b1 = band(), b2 = x.band(), bin_b1 = b1 / config.band_bin, bin_b2 = b2 / config.band_bin, t1 = cols, t2 = x.cols, bin_t1 = t1 / config.col_bin, bin_t2 = t2 / config.col_bin; return bin_b1 < bin_b2 || (bin_b1 == bin_b2 && (bin_t1 < bin_t2 || (bin_t1 == bin_t2 && i < j))); //return i < j || (i == j && (target_idx < x.target_idx || (target_idx == x.target_idx && d_begin < x.d_begin))); } bool blank() const { return target_idx == BLANK; } bool adjusted_matrix() const { return matrix != nullptr; } int matrix_scale() const { return adjusted_matrix() ? config.cbs_matrix_scale : 1; } int64_t cells(DP::Flags flags, Loc qlen) const { return flag_any(flags, DP::Flags::FULL_MATRIX) ? (int64_t)seq.length() * (int64_t)qlen : int64_t(d_end - d_begin) * (int64_t)cols; } bool extend_right(Loc qlen) const { //return anchor.query_end() < qlen && anchor.subject_end() < seq.length() return std::min(qlen - anchor.query_end(), seq.length() - anchor.subject_end()) >= MIN_LETTERS; } bool extend_left() const { //return anchor.query_begin() > 0 && anchor.subject_begin() > 0 return std::min(anchor.query_begin(), anchor.subject_begin()) >= MIN_LETTERS; } friend std::ostream& operator<<(std::ostream& s, const DpTarget& t) { s << t.seq << '\t' << t.d_begin << '\t' << t.d_end << '\t' << t.cols << '\t' << t.true_target_len << '\t' << t.target_idx; return s; } Sequence seq; Loc d_begin, d_end, cols, true_target_len; //Interval chaining_target_range; //Score chaining_score; BlockId target_idx; CarryOver carry_over; const Stats::TargetMatrix* matrix; Anchor anchor; const LongScoreProfile* prof, *prof_reverse; }; struct DpStat { DpStat(): gross_cells(0), net_cells(0) {} DpStat& operator+=(DpStat &x) { mtx_.lock(); gross_cells += x.gross_cells; net_cells += x.net_cells; mtx_.unlock(); return *this; } size_t gross_cells, net_cells; private: std::mutex mtx_; }; extern DpStat dp_stat; namespace DP { struct Params { const Sequence query; const char* query_id; const Frame frame; const int query_source_len; const int8_t* const composition_bias; const Flags flags; const bool reverse_targets; Loc target_max_len; int swipe_bin; HspValues v; Statistics& stat; ThreadPool* thread_pool; }; enum { BINS = 6, SCORE_BINS = 3, ALGO_BINS = 2 }; struct Traceback {}; struct ScoreOnly {}; struct TargetVec { using const_iterator = std::vector::const_iterator; using iterator = std::vector::iterator; TargetVec() : max_len_(0) {} iterator begin() { return targets_.begin(); } iterator end() { return targets_.end(); } const_iterator begin() const { return targets_.begin(); } const_iterator end() const { return targets_.end(); } DpTarget& operator[](int64_t i) { return targets_[i]; } const DpTarget& operator[](int64_t i) const { return targets_[i]; } DpTarget& front() { return targets_.front(); } const DpTarget& front() const { return targets_.front(); } DpTarget& back() { return targets_.back(); } int64_t size() const { return targets_.size(); } void reserve(int64_t size) { targets_.reserve(size); } void push_back(const DpTarget& t) { targets_.push_back(t); max_len_ = std::max(max_len_, t.seq.length()); } void push_back(const TargetVec& v) { targets_.insert(targets_.end(), v.targets_.begin(), v.targets_.end()); max_len_ = std::max(max_len_, v.max_len_); } bool empty() const { return targets_.empty(); } void clear() { targets_.clear(); max_len_ = 0; } Loc max_len() const { return max_len_; } template void emplace_back(T&&... args) { targets_.emplace_back(std::forward(args)...); max_len_ = std::max(max_len_, targets_.back().seq.length()); } private: std::vector targets_; Loc max_len_; }; using Targets = std::array; struct NoCBS { constexpr void* operator[](int i) const { return nullptr; } }; namespace AnchoredSwipe { struct Config { Sequence query; const int8_t* query_cbs; Score score_hint; Statistics& stats; ThreadPool* thread_pool; bool recompute_adjusted; Extension::Mode extension_mode; bool target_profiles; }; } namespace Swipe { //DECL_DISPATCH(std::list, swipe, (const sequence &query, const sequence *subject_begin, const sequence *subject_end, int score_cutoff)) } namespace BandedSwipe { std::list swipe(const Targets& targets, Params& params); std::list swipe_set(const SequenceSet::ConstIterator begin, const SequenceSet::ConstIterator end, Params& params); int bin(HspValues v, int query_len, int score, int ungapped_score, const int64_t dp_size, unsigned score_width, const Loc mismatch_est); std::list anchored_swipe(Targets& targets, const DP::AnchoredSwipe::Config& cfg, std::pmr::monotonic_buffer_resource& pool); } } std::list banded_3frame_swipe(const TranslatedSequence& query, Strand strand, std::vector::iterator target_begin, std::vector::iterator target_end, DpStat& stat, bool score_only, bool parallel);bbuchfink-diamond-08b3cbc/src/dp/flags.h000066400000000000000000000014061506104011400201740ustar00rootroot00000000000000#pragma once #include "util/enum.h" namespace DP { enum class Flags { NONE = 0, PARALLEL = 1, FULL_MATRIX = 2, SEMI_GLOBAL = 4 }; DEFINE_ENUM_FLAG_OPERATORS(Flags) } enum class HspValues : unsigned { NONE = 0, TRANSCRIPT = 1, QUERY_START = 1 << 1, QUERY_END = 1 << 2, TARGET_START = 1 << 3, TARGET_END = 1 << 4, IDENT = 1 << 5, LENGTH = 1 << 6, MISMATCHES = 1 << 7, GAP_OPENINGS = 1 << 8, GAPS = IDENT | LENGTH | MISMATCHES, QUERY_COORDS = QUERY_START | QUERY_END, TARGET_COORDS = TARGET_START | TARGET_END, COORDS = QUERY_COORDS | TARGET_COORDS }; DEFINE_ENUM_FLAG_OPERATORS(HspValues) static inline bool have_coords(const HspValues v) { return flag_any(v, HspValues::TRANSCRIPT) || flag_all(v, HspValues::QUERY_COORDS | HspValues::TARGET_COORDS); }bbuchfink-diamond-08b3cbc/src/dp/scalar/000077500000000000000000000000001506104011400201735ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/dp/scalar/double_buffer.h000066400000000000000000000024061506104011400231510ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once template struct DoubleBuffer { inline void init(size_t size, size_t padding, size_t padding_front, T init) { const size_t total = size + padding + padding_front; data_.clear(); data_.resize(total * 2); ptr1 = &data_[padding_front]; ptr2 = &data_[total + padding_front]; for (size_t i = 0; i < total * 2; ++i) data_[i] = init; } inline std::pair get(int) { std::swap(ptr1, ptr2); return std::pair(ptr2, ptr1); } inline T* last() { return ptr1; } private: T* ptr1, * ptr2; std::vector data_; }; bbuchfink-diamond-08b3cbc/src/dp/scalar/needleman_wunsch.h000066400000000000000000000020641506104011400236650ustar00rootroot00000000000000#pragma once #include "../basic/sequence.h" #include "../stats/score_matrix.h" #include "../util/util.h" inline int nw_semiglobal(Sequence query, Sequence target) { Matrix m(query.length() + 1, target.length() + 1); std::vector hgap(query.length() + 1); for (Loc i = 1; i <= query.length(); ++i) { hgap[i] = -score_matrix.gap_open() - i * score_matrix.gap_extend(); m[i][0] = hgap[i] - score_matrix.gap_open() - score_matrix.gap_extend(); } int score = INT_MIN; for (int j = 1; j <= target.length(); ++j) { int vgap = -score_matrix.gap_open() - score_matrix.gap_extend(); for (int i = 1; i <= query.length(); ++i) { int s = m[i - 1][j - 1] + score_matrix(query[i - 1], target[j - 1]); s = std::max(s, vgap); s = std::max(s, hgap[i]); m[i][j] = s; vgap -= score_matrix.gap_extend(); hgap[i] -= score_matrix.gap_extend(); int open = s - score_matrix.gap_open() - score_matrix.gap_extend(); vgap = std::max(vgap, open); hgap[i] = std::max(hgap[i], open); } score = std::max(score, m[query.length()][j]); } return score; }bbuchfink-diamond-08b3cbc/src/dp/scalar/scalar.h000066400000000000000000000001031506104011400216030ustar00rootroot00000000000000#pragma once void smith_waterman(Sequence q, Sequence s, Hsp& out);bbuchfink-diamond-08b3cbc/src/dp/scalar/smith_waterman.cpp000066400000000000000000000146321506104011400237270ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "../dp.h" #include "traceback.h" using std::vector; using std::pair; struct Local {}; struct Global {}; template Score saturate(Score x) { return x; } template<> int saturate(int x) { return std::max(x, 0); } template void set_max_score(Score s, Score& max_score) { } template<> void set_max_score(int s, int& max_score) { max_score = std::max(max_score, s); } template struct FixedScoreBuffer { inline void init(size_t col_size, size_t cols, T init) { col_size_ = col_size; data_.clear(); data_.reserve(col_size * cols); data_.resize(col_size); for (size_t i = 0; i < col_size; ++i) data_[i] = init; } std::pair find(T s) const { const int i = int(std::find(data_.begin(), data_.end(), s) - data_.begin()); return std::pair(int(i % col_size_), int(i / col_size_)); } inline std::pair get() { data_.resize(data_.size() + col_size_); T* ptr = last(); return std::pair(ptr - col_size_, ptr); } inline T* last() { return &*(data_.end() - col_size_); } const T* column(int col) const { return &data_[col_size_ * col]; } T operator()(int i, int j) const { return data_[j * col_size_ + i]; } friend std::ostream& operator<<(std::ostream& s, const FixedScoreBuffer& buf) { s << '\t'; for (int j = 0; j < int(buf.data_.size() / buf.col_size_); ++j) s << j << '\t'; s << std::endl; for (int i = 0; i < int(buf.col_size_); ++i) { s << i << '\t'; for (int j = 0; j < int(buf.data_.size() / buf.col_size_); ++j) s << buf(i, j) << '\t'; s << std::endl; } return s; } private: std::vector data_; size_t col_size_; }; template struct DpMatrix { struct Column_iterator { inline Column_iterator(const pair& score, Score* hgap, int query_len, int col) : score_(score), hgap_(hgap), end_(score_.second + query_len + 1), i_(0) { *score_.first = saturate(col == 0 ? 0 : -score_matrix.gap_open() - col * score_matrix.gap_extend()); ++score_.second; } inline int row() const { return i_; } inline bool valid() const { return score_.second < end_; } inline Score& score() { return *score_.second; } inline Score diag() const { return *score_.first; } inline Score& hgap() { return *hgap_; } inline void operator++() { ++i_; ++score_.first; ++score_.second; ++hgap_; } private: pair score_; Score* hgap_; const Score* const end_; int i_; }; inline Column_iterator column(int j) { return Column_iterator(score_.get(), hgap_.data(), query_len_, j); } inline DpMatrix(int query_len, int subject_len) : query_len_(query_len) { score_.init(query_len + 1, subject_len + 1, 0); hgap_.clear(); hgap_.insert(hgap_.end(), query_len, std::numeric_limits::min() + score_matrix.gap_extend()); int* score = score_.last(); int g = -score_matrix.gap_open() - score_matrix.gap_extend(); for (int i = 1; i <= query_len; ++i) score[i] = saturate(g--); } const FixedScoreBuffer& score_buffer() const { return score_; } private: const int query_len_; FixedScoreBuffer score_; vector hgap_; }; template FixedScoreBuffer needleman_wunsch(Sequence query, Sequence subject, int& max_score, const Mode&, const Score&) { using std::max; const int gap_open = score_matrix.gap_open() + score_matrix.gap_extend(), gap_extend = score_matrix.gap_extend(); int m = 0; DpMatrix mtx((unsigned)query.length(), (unsigned)subject.length()); for (int j = 0; j < (int)subject.length(); ++j) { typename DpMatrix::Column_iterator it = mtx.column(j); Score vgap = std::numeric_limits::min() + gap_extend; for (; it.valid(); ++it) { const Score match_score = score_matrix(subject[j], query[it.row()]); const Score s = saturate(max(max(it.diag() + match_score, vgap), it.hgap())); const Score open = s - gap_open; vgap = max(vgap - gap_extend, open); it.hgap() = max(it.hgap() - gap_extend, open); it.score() = s; set_max_score(s, m); } } max_score = m; return mtx.score_buffer(); } template FixedScoreBuffer needleman_wunsch(Sequence query, Sequence subject, int& max_score, const Local&, const int&); void smith_waterman(Sequence q, Sequence s, Hsp& out) { int max_score; const FixedScoreBuffer dp = needleman_wunsch(q, s, max_score, Local(), int()); pair max_pos = dp.find(max_score); const int gap_open = score_matrix.gap_open(), gap_extend = score_matrix.gap_extend(); int l, i = max_pos.first, j = max_pos.second, score; out.clear(); out.score = dp(i, j); out.query_range.end_ = i; out.subject_range.end_ = j; while ((score = dp(i, j)) > 0) { const int match_score = score_matrix(q[i - 1], s[j - 1]); if (score == match_score + dp(i - 1, j - 1)) { if (q[i - 1] == s[j - 1]) { out.transcript.push_back(op_match); ++out.identities; } else { out.transcript.push_back(op_substitution, s[j - 1]); } --i; --j; ++out.length; } else if (have_hgap(dp, i, j, gap_open, gap_extend, l)) { for (; l > 0; l--) { out.transcript.push_back(op_deletion, s[--j]); ++out.length; } } else if (have_vgap(dp, i, j, gap_open, gap_extend, l)) { out.transcript.push_back(op_insertion, (unsigned)l); out.length += l; i -= l; } else throw std::runtime_error("Traceback error."); } out.query_range.begin_ = i; out.subject_range.begin_ = j; out.query_source_range = out.query_range; out.transcript.reverse(); out.transcript.push_terminator(); }bbuchfink-diamond-08b3cbc/src/dp/scalar/traceback.h000066400000000000000000000034641506104011400222720ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "stats/score_matrix.h" template bool have_vgap(const Matrix& dp, int i, int j, int gap_open, int gap_extend, int& l) { int score = dp(i, j); l = 1; --i; while (i > 0) { if (score == dp(i, j) - gap_open - l * gap_extend) return true; --i; ++l; } return false; } template bool have_hgap(const Matrix& dp, int i, int j, int gap_open, int gap_extend, int& l) { int score = dp(i, j); l = 1; --j; while (j > 0) { if (score == dp(i, j) - gap_open - l * gap_extend) return true; --j; ++l; } return false; } template int have_diag(const Matrix& dp, int i, int j, const Sequence& query, const Sequence& subject, bool log) { int l = 0; while (i > 0 && j > 0) { const int match_score = score_matrix(query[i - 1], subject[j - 1]); if (dp(i, j) == match_score + dp(i - 1, j - 1)) { /*if (log) printf("i=%i j=%i score=%i subject=%c query=%c\n", i, j, dp(i, j), value_traits.alphabet[(int)subject[j - 1]], value_traits.alphabet[(int)query[i - 1]]);*/ ++l; --i; --j; } else break; } return l; } bbuchfink-diamond-08b3cbc/src/dp/scan_diags.cpp000066400000000000000000000200621506104011400215250ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "basic/config.h" #include "score_profile.h" #include "score_vector_int8.h" #include "util/simd/dispatch.h" #include "stats/score_matrix.h" using namespace DISPATCH_ARCH; namespace DP { namespace DISPATCH_ARCH { void scan_diags128(const LongScoreProfile& qp, Sequence s, int d_begin, int j_begin, int j_end, int *out) { #ifdef __AVX2__ using Sv = ScoreVector; const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 128 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2, v3, max3, v4, max4; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 32; v2 += Sv(q); max2.max(v2); q += 32; v3 += Sv(q); max3.max(v3); q += 32; v4 += Sv(q); max4.max(v4); } int8_t scores[128]; max1.store(scores); max2.store(scores + 32); max3.store(scores + 64); max4.store(scores + 96); for (int i = 0; i < 128; ++i) out[i] = ScoreTraits::int_score(scores[i]); #elif defined(__SSE4_1__) | defined(__ARM_NEON) using Sv = ScoreVector; const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 128 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2, v3, max3, v4, max4, v5, max5, v6, max6, v7, max7, v8, max8; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 16; v2 += Sv(q); max2.max(v2); q += 16; v3 += Sv(q); max3.max(v3); q += 16; v4 += Sv(q); max4.max(v4); q += 16; v5 += Sv(q); max5.max(v5); q += 16; v6 += Sv(q); max6.max(v6); q += 16; v7 += Sv(q); max7.max(v7); q += 16; v8 += Sv(q); max8.max(v8); } int8_t scores[128]; max1.store(scores); max2.store(scores + 16); max3.store(scores + 32); max4.store(scores + 48); max5.store(scores + 64); max6.store(scores + 80); max7.store(scores + 96); max8.store(scores + 112); for (int i = 0; i < 128; ++i) out[i] = ScoreTraits::int_score(scores[i]); #else const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 128 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); int v[8 * 16], max[8 * 16]; std::fill(v, v + 128, 0); std::fill(max, max + 128, 0); for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); for (int k = 0; k < 128; ++k) { v[k] += q[k]; v[k] = std::max(v[k], 0); max[k] = std::max(max[k], v[k]); } } for (int i = 0; i < 128; ++i) out[i] = max[i]; #endif } void scan_diags64(const LongScoreProfile& qp, Sequence s, int d_begin, int j_begin, int j_end, int* out) { #ifdef __AVX2__ using Sv = ScoreVector; const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 64 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 32; v2 += Sv(q); max2.max(v2); } int8_t scores[64]; max1.store(scores); max2.store(scores + 32); for (int i = 0; i < 64; ++i) out[i] = ScoreTraits::int_score(scores[i]); #elif defined(__SSE4_1__) | defined(__ARM_NEON) using Sv = ScoreVector; const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 64 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2, v3, max3, v4, max4; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 16; v2 += Sv(q); max2.max(v2); q += 16; v3 += Sv(q); max3.max(v3); q += 16; v4 += Sv(q); max4.max(v4); } int8_t scores[64]; max1.store(scores); max2.store(scores + 16); max3.store(scores + 32); max4.store(scores + 48); for (int i = 0; i < 64; ++i) out[i] = ScoreTraits::int_score(scores[i]); #else const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 64 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); int v[64], max[64]; std::fill(v, v + 64, 0); std::fill(max, max + 64, 0); for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); for (int k = 0; k < 64; ++k) { v[k] += q[k]; v[k] = std::max(v[k], 0); max[k] = std::max(max[k], v[k]); } } for (int i = 0; i < 64; ++i) out[i] = max[i]; #endif } void scan_diags(const LongScoreProfile& qp, Sequence s, int d_begin, int d_end, int j_begin, int j_end, int* out) { #ifdef __AVX2__ using Sv = ScoreVector; const int qlen = (int)qp.length(), band = d_end - d_begin; assert(band % 32 == 0); const int j0 = std::max(j_begin, -(d_end - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 32; v2 += Sv(q); max2.max(v2); } int8_t scores[64]; max1.store(scores); max2.store(scores + 32); for (int i = 0; i < 64; ++i) out[i] = ScoreTraits::int_score(scores[i]); #elif defined(__SSE4_1__) | defined(__ARM_NEON) using Sv = ScoreVector; const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 64 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); Sv v1, max1, v2, max2, v3, max3, v4, max4; for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); v1 += Sv(q); max1.max(v1); q += 16; v2 += Sv(q); max2.max(v2); q += 16; v3 += Sv(q); max3.max(v3); q += 16; v4 += Sv(q); max4.max(v4); } int8_t scores[64]; max1.store(scores); max2.store(scores + 16); max3.store(scores + 32); max4.store(scores + 48); for (int i = 0; i < 64; ++i) out[i] = ScoreTraits::int_score(scores[i]); #else const int qlen = (int)qp.length(); const int j0 = std::max(j_begin, -(d_begin + 64 - 1)), i0 = d_begin + j0, j1 = std::min(qlen - d_begin, j_end); int v[64], max[64]; std::fill(v, v + 64, 0); std::fill(max, max + 64, 0); for (int i = i0, j = j0; j < j1; ++j, ++i) { const int8_t* q = qp.get(s[j], i); for (int k = 0; k < 64; ++k) { v[k] += q[k]; v[k] = std::max(v[k], 0); max[k] = std::max(max[k], v[k]); } } for (int i = 0; i < 64; ++i) out[i] = max[i]; #endif } int diag_alignment(const int* s, int count) { int best = 0, best_gap = -score_matrix.gap_open(), d = -1; for (int i = 0; i < count; ++i) { if (s[i] < config.gapped_filter_diag_score) continue; const int gap_score = -score_matrix.gap_extend() * (i - d) + best_gap; int n = s[i]; if (gap_score + s[i] > best) { best = n = gap_score + s[i]; } if (s[i] > best) { best = n = s[i]; } const int open_score = -score_matrix.gap_open() + n; if (open_score > gap_score) { best_gap = open_score; d = i; } } return best; } } DISPATCH_6V(scan_diags128, const LongScoreProfile&, qp, Sequence, s, int, d_begin, int, j_begin, int, j_end, int*, out) DISPATCH_6V(scan_diags64, const LongScoreProfile&, qp, Sequence, s, int, d_begin, int, j_begin, int, j_end, int*, out) DISPATCH_7V(scan_diags, const LongScoreProfile&, qp, Sequence, s, int, d_begin, int, d_end, int, j_begin, int, j_end, int*, out) DISPATCH_2(int, diag_alignment, const int*, s, int, count) }bbuchfink-diamond-08b3cbc/src/dp/scan_diags.h000066400000000000000000000007101506104011400211700ustar00rootroot00000000000000#pragma once #include "score_profile.h" namespace DP { void scan_diags128(const LongScoreProfile& qp, Sequence s, int d_begin, int j_begin, int j_end, int* out); void scan_diags64(const LongScoreProfile& qp, Sequence s, int d_begin, int j_begin, int j_end, int* out); void scan_diags(const LongScoreProfile& qp, Sequence s, int d_begin, int d_end, int j_begin, int j_end, int* out); int diag_alignment(const int* s, int count); }bbuchfink-diamond-08b3cbc/src/dp/score_profile.cpp000066400000000000000000000073001506104011400222650ustar00rootroot00000000000000#include "score_profile.h" #include "score_vector.h" #include "score_vector_int8.h" #include "score_vector_int16.h" #include "util/util.h" #include "util/simd/dispatch.h" #include "stats/score_matrix.h" using std::array; namespace DP { namespace DISPATCH_ARCH { template LongScoreProfile make_profile(Sequence seq, const int8_t* cbs, int64_t padding, const ScoreMatrix& matrix) { LongScoreProfile p; p.padding = std::max(padding, (int64_t)LongScoreProfile::DEFAULT_PADDING); for (unsigned l = 0; l < AMINO_ACID_COUNT; ++l) { const int8_t* scores = &matrix.matrix8()[l << 5]; p.data[l].reserve(round_up(seq.length(), 32) + 2 * p.padding); p.data[l].insert(p.data[l].end(), p.padding, -1); #if ARCH_ID == 2 using Sv = ::DISPATCH_ARCH::ScoreVector; constexpr auto CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; alignas(32) array buf; for (Loc i = 0; i < seq.length(); i += CHANNELS) { __m256i s = _mm256_loadu_si256((const __m256i*)(seq.data() + i)); Sv scores(l, s, matrix.matrix8_low(), matrix.matrix8_high()); if (cbs && l < TRUE_AA) scores += Sv(cbs + i); store_expanded(scores, buf.data()); p.data[l].insert(p.data[l].end(), buf.begin(), buf.end()); } p.data[l].erase(p.data[l].end() - round_up(seq.length(), (Loc)CHANNELS) + seq.length(), p.data[l].end()); #else for (Loc i = 0; i < seq.length(); ++i) { int8_t score = scores[(int)seq[i]]; if (cbs) score += cbs[i]; p.data[l].push_back(score); } #endif p.data[l].insert(p.data[l].end(), p.padding, -1); } return p; } template LongScoreProfile make_profile(Sequence seq, const Stats::TargetMatrix& matrix, int64_t padding) { LongScoreProfile p; p.padding = std::max(padding, (int64_t)LongScoreProfile::DEFAULT_PADDING); for (int l = 0; l < AMINO_ACID_COUNT; ++l) { const int8_t* scores = &matrix.scores[l << 5]; p.data[l].reserve(round_up(seq.length(), 32) + 2 * p.padding); p.data[l].insert(p.data[l].end(), p.padding, -1); /*#if ARCH_ID == 2 using Sv = ::DISPATCH_ARCH::ScoreVector; constexpr auto CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; alignas(32) array buf; const int8_t* low = matrix.scores_low.data, * high = matrix.scores_high.data; for (Loc i = 0; i < seq.length(); i += CHANNELS) { __m256i s = _mm256_loadu_si256((const __m256i*)(seq.data() + i)); Sv scores(l, s, low, high); store_expanded(scores, buf.data()); p.data[l].insert(p.data[l].end(), buf.begin(), buf.end()); } p.data[l].erase(p.data[l].end() - round_up(seq.length(), (Loc)CHANNELS) + seq.length(), p.data[l].end()); #else*/ for (Loc i = 0; i < seq.length(); ++i) { int8_t score = scores[(int)seq[i]]; p.data[l].push_back(score); } //#endif p.data[l].insert(p.data[l].end(), p.padding, -1); } return p; } LongScoreProfile make_profile8(Sequence seq, const int8_t* cbs, int64_t padding) { return make_profile(seq, cbs, padding, score_matrix); } LongScoreProfile make_profile16(Sequence seq, const int8_t* cbs, int64_t padding, const ::ScoreMatrix* matrix) { return make_profile(seq, cbs, padding, *matrix); } LongScoreProfile make_profile16(Sequence seq, const Stats::TargetMatrix& matrix, int64_t padding) { return make_profile(seq, matrix, padding); } } DISPATCH_3(LongScoreProfile, make_profile8, Sequence, seq, const int8_t*, cbs, int64_t, padding); DISPATCH_4(LongScoreProfile, make_profile16, Sequence, seq, const int8_t*, cbs, int64_t, padding, const ::ScoreMatrix*, matrix); DISPATCH_3(LongScoreProfile, make_profile16, Sequence, seq, const Stats::TargetMatrix&, matrix, int64_t, padding); }bbuchfink-diamond-08b3cbc/src/dp/score_profile.h000066400000000000000000000041441506104011400217350ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "basic/sequence.h" #include "basic/value.h" #include "stats/cbs.h" #include "stats/score_matrix.h" template struct LongScoreProfile { enum { DEFAULT_PADDING = 128 }; LongScoreProfile(int64_t padding = DEFAULT_PADDING): padding(std::max(padding, (int64_t)DEFAULT_PADDING)) {} size_t length() const { return data[0].size() - 2 * padding; } const Score* get(Letter l, int i) const { return &data[(int)l][i + padding]; } std::vector pointers(int offset) const { std::vector v; v.reserve(AMINO_ACID_COUNT); for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) v.push_back(get(Letter(i), offset)); return v; } LongScoreProfile reverse() const { LongScoreProfile r(*this); for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) std::reverse(r.data[i].begin(), r.data[i].end()); return r; } std::vector data[AMINO_ACID_COUNT]; int64_t padding; }; namespace DP { LongScoreProfile make_profile16(Sequence seq, const Stats::TargetMatrix& matrix, int64_t padding); LongScoreProfile make_profile8(Sequence seq, const int8_t* cbs, int64_t padding); LongScoreProfile make_profile16(Sequence seq, const int8_t* cbs, int64_t padding, const ::ScoreMatrix* matrix); }bbuchfink-diamond-08b3cbc/src/dp/score_vector.h000066400000000000000000000113641506104011400216010ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include #include #include "util/simd.h" namespace DISPATCH_ARCH { template struct ScoreVector { }; template struct ScoreTraits { typedef void Score; enum { CHANNELS = 0 }; }; template<> struct ScoreTraits { enum { CHANNELS = 1, BITS = 32 }; typedef int32_t Score; struct TraceMask { static uint8_t make(int vmask, int hmask) { return vmask << 1 | hmask; } static uint8_t vmask(int channel) { return 2; } static uint8_t hmask(int channel) { return 1; } uint8_t gap; uint8_t open; }; static int32_t zero() { return 0; } static int32_t zero_score() { return 0; } static int int_score(Score s) { return s; } static int max_score() { return INT_MAX; } static constexpr int max_int_score() { return INT_MAX; } }; } static inline void store_sv(int32_t sv, int32_t *dst) { *dst = sv; } template static inline void store_aligned(Sv sv, typename DISPATCH_ARCH::ScoreTraits::Score* ptr) { sv.store_aligned(ptr); } template<> inline void store_aligned(int32_t sv, int32_t* ptr) { *ptr = sv; } template static inline Sv load_sv(const typename DISPATCH_ARCH::ScoreTraits::Score* ptr) { return Sv(ptr); } template<> inline int32_t load_sv(const int32_t* x) { return *x; } template static inline Sv load_sv_aligned(const typename DISPATCH_ARCH::ScoreTraits::Score* ptr) { return Sv::load_aligned(ptr); } template<> inline int32_t load_sv_aligned(const int32_t* ptr) { return *ptr; } template static inline int32_t extract(int32_t x) { return x; } static inline int32_t extract(int32_t x, int i) { return x; } template static inline typename DISPATCH_ARCH::ScoreTraits::Score extract(Sv sv, int i) { return sv[i]; } template static Sv blend_sv(const typename DISPATCH_ARCH::ScoreTraits::Score a, const typename DISPATCH_ARCH::ScoreTraits::Score b, const uint32_t mask) { const uint32_t CHANNELS = DISPATCH_ARCH::ScoreTraits::CHANNELS; alignas(32) typename DISPATCH_ARCH::ScoreTraits::Score s[CHANNELS]; for (uint32_t i = 0; i < CHANNELS; ++i) if (mask & (1 << i)) s[i] = b; else s[i] = a; return Sv(s); } template<> int32_t blend_sv(const int32_t a, const int32_t b, const uint32_t mask) { return mask ? b : a; } static inline int32_t blend(const int32_t a, const int32_t b, const uint32_t mask) { return mask ? b : a; } static inline std::pair max_entry(int32_t x) { return { x,0 }; } template static inline std::pair::Score, int> max_entry(Sv sv) { std::array::Score, DISPATCH_ARCH::ScoreTraits::CHANNELS> s; sv.store(s.data()); const auto i = std::max_element(s.begin(), s.end()); return { *i, int(i - s.begin()) }; } #ifdef __SSE2__ template static inline void store_sv(const DISPATCH_ARCH::ScoreVector<_t, DELTA> &sv, _p *dst) { #if ARCH_ID == 3 //_mm512_storeu_si512((__m512i*)dst, sv.data_); sv.store(dst); #elif ARCH_ID == 2 _mm256_storeu_si256((__m256i*)dst, sv.data_); #else _mm_storeu_si128((__m128i*)dst, sv.data_); #endif } #endif #ifdef __ARM_NEON template static inline void store_sv(const DISPATCH_ARCH::ScoreVector &sv, int8_t *dst) { vst1q_s8(dst, sv.data_); } template static inline void store_sv(const DISPATCH_ARCH::ScoreVector &sv, int16_t *dst) { vst1q_s16(dst, sv.data_); } #endif static inline int extract_channel(const int32_t v, const int i) { return v; } static inline void set_channel(int32_t& v, const int i, const int32_t x) { v = x; } template static inline void saturate(Sv& v) { } static inline void saturate(int32_t& v) { v = std::max(v, 0); } bbuchfink-diamond-08b3cbc/src/dp/score_vector_int16.h000066400000000000000000000356701506104011400226300ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2025 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink Arm NEON port contributed by Martin Larralde This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "score_vector.h" #include "util/simd.h" #include "stats/score_matrix.h" namespace DISPATCH_ARCH { #if ARCH_ID == 2 || ARCH_ID == 3 template struct ScoreVector { typedef __m256i Register; ScoreVector() : data_(_mm256_set1_epi16(DELTA)) {} explicit ScoreVector(int x) { data_ = _mm256_set1_epi16(x); } explicit ScoreVector(int16_t x) { data_ = _mm256_set1_epi16(x); } explicit ScoreVector(__m256i data) : data_(data) { } explicit ScoreVector(const int16_t* x) : data_(_mm256_loadu_si256((const __m256i*)x)) {} explicit ScoreVector(const uint16_t* x) : data_(_mm256_loadu_si256((const __m256i*)x)) {} ScoreVector(unsigned a, Register seq) { const __m256i* row_lo = reinterpret_cast(&score_matrix.matrix8u_low()[a << 5]); const __m256i* row_hi = reinterpret_cast(&score_matrix.matrix8u_high()[a << 5]); __m256i high_mask = _mm256_slli_epi16(_mm256_and_si256(seq, _mm256_set1_epi8('\x10')), 3); __m256i seq_low = _mm256_or_si256(seq, high_mask); __m256i seq_high = _mm256_or_si256(seq, _mm256_xor_si256(high_mask, _mm256_set1_epi8('\x80'))); __m256i r1 = _mm256_load_si256(row_lo); __m256i r2 = _mm256_load_si256(row_hi); __m256i s1 = _mm256_shuffle_epi8(r1, seq_low); __m256i s2 = _mm256_shuffle_epi8(r2, seq_high); data_ = _mm256_and_si256(_mm256_or_si256(s1, s2), _mm256_set1_epi16(255)); data_ = _mm256_subs_epi16(data_, _mm256_set1_epi16(score_matrix.bias())); } ScoreVector operator+(const ScoreVector& rhs) const { return ScoreVector(_mm256_adds_epi16(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector& rhs) const { return ScoreVector(_mm256_subs_epi16(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = _mm256_adds_epi16(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector& rhs) { data_ = _mm256_subs_epi16(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = _mm256_and_si256(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = _mm256_adds_epi16(data_, _mm256_set1_epi16(1)); return *this; } ScoreVector& max(const ScoreVector& rhs) { data_ = _mm256_max_epi16(data_, rhs.data_); return *this; } template ScoreVector shift_left() const { return ScoreVector(_mm256_slli_si256(data_, i)); } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(_mm256_cmpeq_epi16(data_, v.data_)); } ScoreVector operator>(const ScoreVector& v) const { return ScoreVector(_mm256_cmpgt_epi16(data_, v.data_)); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return _mm256_movemask_epi8(_mm256_cmpeq_epi16(v.data_, w.data_)); } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector& rhs) { return ScoreVector(_mm256_max_epi16(lhs.data_, rhs.data_)); } void store(int16_t* ptr) const { _mm256_storeu_si256((__m256i*)ptr, data_); } void store_aligned(int16_t* ptr) const { _mm256_store_si256((__m256i*)ptr, data_); } int16_t operator[](int i) const { int16_t d[16]; store(d); return d[i]; } ScoreVector& set(int i, int16_t x) { alignas(32) int16_t d[16]; store(d); d[i] = x; data_ = _mm256_load_si256((__m256i*)d); return *this; } void expand_from_8bit() { __m128i in = _mm256_extractf128_si256(data_, 0); __m128i mask = _mm_set1_epi8((char)0x80); __m128i sign = _mm_cmpeq_epi8(_mm_and_si128(in, mask), mask); __m128i low = _mm_unpacklo_epi8(in, sign); __m128i hi = _mm_unpackhi_epi8(in, sign); data_ = _mm256_set_m128i(hi, low); } friend std::ostream& operator<<(std::ostream& s, ScoreVector v) { int16_t x[16]; v.store(x); for (unsigned i = 0; i < 16; ++i) printf("%3i ", (int)x[i]); return s; } static ScoreVector load_aligned(const int16_t* x) { return ScoreVector(_mm256_load_si256((const __m256i*)x)); } __m256i data_; }; template static inline int16_t extract(ScoreVector sv) { return (int16_t)_mm256_extract_epi16(sv.data_, i); } template static inline ScoreVector blend(const ScoreVector& v, const ScoreVector& w, const ScoreVector& mask) { return ScoreVector(_mm256_blendv_epi8(v.data_, w.data_, mask.data_)); } #elif defined(__ARM_NEON) template struct ScoreVector { typedef int16x8_t Register; inline ScoreVector() : data_(vdupq_n_s16(DELTA)) {} explicit ScoreVector(int x) { data_ = vdupq_n_s16(x); } explicit ScoreVector(int16_t x) { data_ = vdupq_n_s16(x); } explicit ScoreVector(int16x8_t data) : data_(data) { } explicit ScoreVector(const int16_t *x): data_(vld1q_s16(x)) {} explicit ScoreVector(const uint16_t *x) : data_(vreinterpretq_s16_u16(vld1q_u16(x))) {} #ifdef __aarch64__ ScoreVector(unsigned a, Register seq) { const int8x16_t* row = reinterpret_cast(&score_matrix.matrix8()[a << 5]); int8x16_t high_mask = vreinterpretq_s8_s16(vshlq_n_s16(vreinterpretq_s16_s8(vandq_s8(vreinterpretq_s8_s16(seq), vdupq_n_s8('\x10'))), 3)); int8x16_t seq_low = vorrq_s8(vreinterpretq_s8_s16(seq), high_mask); int8x16_t seq_high = vorrq_s8(vreinterpretq_s8_s16(seq), veorq_s8(high_mask, vdupq_n_s8('\x80'))); int8x16_t r1 = vld1q_s8(reinterpret_cast(row)); int8x16_t r2 = vld1q_s8(reinterpret_cast(row + 1)); int8x16_t s1 = vqtbl1q_s8(r1, vandq_u8(vreinterpretq_u8_s8(seq_low), vdupq_n_u8(0x8F))); int8x16_t s2 = vqtbl1q_s8(r2, vandq_u8(vreinterpretq_u8_s8(seq_high), vdupq_n_u8(0x8F))); data_ = vorrq_s16(vreinterpretq_s16_s8(s1), vreinterpretq_s16_s8(s2)); data_ = vandq_s16(data_, vdupq_n_s16(255)); data_ = vqsubq_s16(data_, vdupq_n_s16(score_matrix.bias())); } #endif ScoreVector operator+(const ScoreVector&rhs) const { return ScoreVector(vqaddq_s16(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector&rhs) const { return ScoreVector(vqsubq_s16(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = vqaddq_s16(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector&rhs) { data_ = vqsubq_s16(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = vandq_s16(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = vqaddq_s16(data_, vdupq_n_s16(1)); return *this; } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(vreinterpretq_s16_u16(vceqq_s16(data_, v.data_))); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return vmaskq_s8(vreinterpretq_s8_u16(vceqq_s16(v.data_, w.data_))); } ScoreVector& max(const ScoreVector&rhs) { data_ = vmaxq_s16(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(vmaxq_s16(lhs.data_, rhs.data_)); } friend ScoreVector blend(const ScoreVector&v, const ScoreVector&w, const ScoreVector&mask) { /* Use a signed shift right to create a mask with the sign bit */ uint16x8_t mask_ = vreinterpretq_u16_s16(vshrq_n_s16(mask.data_, 7)); return ScoreVector(vbslq_s16(mask_, w.data_, v.data_)); } void store(int16_t *ptr) const { vst1q_s16(ptr, data_); } int16_t operator[](int i) const { // return vgetq_lane_s16(data_, i); int16_t tmp[8]; vst1q_s16(tmp, data_); return tmp[i]; } ScoreVector& set(int i, int16_t x) { // vsetq_lane_s16(x, data_, i); int16_t tmp[8]; vst1q_s16(tmp, data_); tmp[i] = x; data_ = vld1q_s16(tmp); return *this; } void expand_from_8bit() { int8x16_t mask = vdupq_n_s8(0x80); int8x16_t sign = vreinterpretq_s8_u8(vceqq_s8(vandq_s8(vreinterpretq_s8_s16(data_), mask), mask)); #ifdef __aarch64__ data_ = vreinterpretq_s16_s8(vzip1q_s8(vreinterpretq_s8_s16(data_), sign)); #else int8x16x2_t tmp = vzipq_s8(vreinterpretq_s8_s16(data_), sign); data_ = vreinterpretq_s16_s8(tmp.val[0]); #endif } friend std::ostream& operator<<(std::ostream& s, ScoreVector v) { int16_t x[8]; v.store(x); for (unsigned i = 0; i < 8; ++i) printf("%3i ", (int)x[i]); return s; } int16x8_t data_; }; #elif defined(__SSE2__) template struct ScoreVector { typedef __m128i Register; inline ScoreVector() : data_(_mm_set1_epi16(DELTA)) {} explicit ScoreVector(int x) { data_ = _mm_set1_epi16(x); } explicit ScoreVector(int16_t x) { data_ = _mm_set1_epi16(x); } explicit ScoreVector(__m128i data) : data_(data) { } explicit ScoreVector(const int16_t *x): data_(_mm_loadu_si128((const __m128i*)x)) {} explicit ScoreVector(const uint16_t *x) : data_(_mm_loadu_si128((const __m128i*)x)) {} #ifdef __SSSE3__ ScoreVector(unsigned a, Register seq) { const __m128i *row = reinterpret_cast(&score_matrix.matrix8u()[a << 5]); __m128i high_mask = _mm_slli_epi16(_mm_and_si128(seq, _mm_set1_epi8('\x10')), 3); __m128i seq_low = _mm_or_si128(seq, high_mask); __m128i seq_high = _mm_or_si128(seq, _mm_xor_si128(high_mask, _mm_set1_epi8('\x80'))); __m128i r1 = _mm_load_si128(row); __m128i r2 = _mm_load_si128(row + 1); __m128i s1 = _mm_shuffle_epi8(r1, seq_low); __m128i s2 = _mm_shuffle_epi8(r2, seq_high); data_ = _mm_and_si128(_mm_or_si128(s1, s2), _mm_set1_epi16(255)); data_ = _mm_subs_epi16(data_, _mm_set1_epi16(score_matrix.bias())); } #endif ScoreVector operator+(const ScoreVector&rhs) const { return ScoreVector(_mm_adds_epi16(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector&rhs) const { return ScoreVector(_mm_subs_epi16(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = _mm_adds_epi16(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector&rhs) { data_ = _mm_subs_epi16(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = _mm_and_si128(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = _mm_adds_epi16(data_, _mm_set1_epi16(1)); return *this; } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(_mm_cmpeq_epi16(data_, v.data_)); } ScoreVector operator>(const ScoreVector& v) const { return ScoreVector(_mm_cmpgt_epi16(data_, v.data_)); } template ScoreVector shift_left() const { return ScoreVector(_mm_slli_si128(data_, bytes)); } ScoreVector& max(const ScoreVector&rhs) { data_ = _mm_max_epi16(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(_mm_max_epi16(lhs.data_, rhs.data_)); } void store(int16_t *ptr) const { _mm_storeu_si128((__m128i*)ptr, data_); } void store_aligned(int16_t* ptr) const { _mm_store_si128((__m128i*)ptr, data_); } int16_t operator[](int i) const { int16_t d[8]; store(d); return d[i]; } ScoreVector& set(int i, int16_t x) { int16_t d[8]; store(d); d[i] = x; data_ = _mm_loadu_si128((__m128i*)d); return *this; } void expand_from_8bit() { __m128i mask = _mm_set1_epi8((char)0x80); __m128i sign = _mm_cmpeq_epi8(_mm_and_si128(data_, mask), mask); data_ = _mm_unpacklo_epi8(data_, sign); } friend std::ostream& operator<<(std::ostream& s, ScoreVector v) { int16_t x[8]; v.store(x); for (unsigned i = 0; i < 8; ++i) printf("%3i ", (int)x[i]); return s; } static ScoreVector load_aligned(const int16_t* x) { return ScoreVector(_mm_load_si128((const __m128i*)x)); } __m128i data_; }; template static inline uint32_t cmp_mask(const ScoreVector& v, const ScoreVector& w) { return (uint32_t)_mm_movemask_epi8(_mm_cmpeq_epi16(v.data_, w.data_)); } template static inline ScoreVector blend(const ScoreVector& v, const ScoreVector& w, const ScoreVector& mask) { #ifdef __SSE4_1__ return ScoreVector(_mm_blendv_epi8(v.data_, w.data_, mask.data_)); #else __m128i a = _mm_andnot_si128(mask.data_, v.data_); __m128i b = _mm_and_si128(mask.data_, w.data_); return ScoreVector(_mm_or_si128(a, b)); #endif } template static inline int16_t extract(ScoreVector sv) { return 0; } #endif #if defined(__SSE2__) | defined(__ARM_NEON) template struct ScoreTraits> { typedef ::DISPATCH_ARCH::SIMD::Vector Vector; #if ARCH_ID == 2 enum { CHANNELS = 16 }; typedef uint16_t Mask; struct TraceMask { uint32_t gap; uint32_t open; static uint32_t make(uint32_t vmask, uint32_t hmask) { return (vmask & VMASK) | (hmask & HMASK); } static uint32_t vmask(int channel) { return 2 << (2 * channel); } static uint32_t hmask(int channel) { return 1 << (2 * channel); } static const uint32_t VMASK = 0xAAAAAAAAu, HMASK = 0x55555555u; }; #else enum { CHANNELS = 8 }; typedef uint8_t Mask; struct TraceMask { static uint16_t make(uint16_t vmask, uint16_t hmask) { return (vmask & VMASK) | (hmask & HMASK); } static uint16_t vmask(int channel) { return 2 << (2 * channel); } static uint16_t hmask(int channel) { return 1 << (2 * channel); } uint16_t gap; uint16_t open; static const uint16_t VMASK = 0xAAAAu, HMASK = 0x5555u; }; #endif typedef int16_t Score; typedef uint16_t Unsigned; static ScoreVector zero() { return ScoreVector(); } static void saturate(ScoreVector &v) { } static constexpr int16_t zero_score() { return DELTA; } static int int_score(Score s) { return (int)s - DELTA; } static constexpr int16_t max_score() { return SHRT_MAX; } static constexpr int max_int_score() { return SHRT_MAX - DELTA; } }; #endif } #if defined(__SSE2__) | defined(__ARM_NEON) template static inline int16_t extract_channel(const DISPATCH_ARCH::ScoreVector& v, int i) { return v[i]; } template static inline void set_channel(DISPATCH_ARCH::ScoreVector& v, const int i, const int16_t x) { v.set(i, x); } #endifbbuchfink-diamond-08b3cbc/src/dp/score_vector_int8.h000066400000000000000000000500151506104011400225370ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2022 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink Arm NEON port contributed by Martin Larralde This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "score_vector.h" #include "stats/score_matrix.h" namespace DISPATCH_ARCH { #if ARCH_ID == 3 template struct ScoreVector { ScoreVector() : data_(_mm512_set1_epi8(DELTA)) {} explicit ScoreVector(__m512i data) : data_(data) {} explicit ScoreVector(int8_t x) : data_(_mm512_set1_epi8(x)) {} explicit ScoreVector(int x) : data_(_mm512_set1_epi8(x)) {} explicit ScoreVector(const int8_t* s) : data_(_mm512_loadu_si512(reinterpret_cast(s))) { } explicit ScoreVector(const uint8_t* s) : data_(_mm512_loadu_si512(reinterpret_cast(s))) { } ScoreVector(unsigned a, __m512i seq) { /*const __m256i* row_lo = reinterpret_cast(&score_matrix.matrix8_low()[a << 5]); const __m256i* row_hi = reinterpret_cast(&score_matrix.matrix8_high()[a << 5]); __m256i high_mask = _mm256_slli_epi16(_mm256_and_si256(seq, _mm256_set1_epi8('\x10')), 3); __m256i seq_low = _mm256_or_si256(seq, high_mask); __m256i seq_high = _mm256_or_si256(seq, _mm256_xor_si256(high_mask, _mm256_set1_epi8('\x80'))); __m256i r1 = _mm512_load_si512(row_lo); __m256i r2 = _mm512_load_si512(row_hi); __m256i s1 = _mm256_shuffle_epi8(r1, seq_low); __m256i s2 = _mm256_shuffle_epi8(r2, seq_high); data_ = _mm256_or_si256(s1, s2);*/ } ScoreVector operator+(const ScoreVector& rhs) const { return ScoreVector(_mm512_adds_epi8(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector& rhs) const { return ScoreVector(_mm512_subs_epi8(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = _mm512_adds_epi8(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector& rhs) { data_ = _mm512_subs_epi8(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = _mm512_and_si512(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = _mm512_adds_epi8(data_, _mm512_set1_epi8(1)); return *this; } friend ScoreVector blend(const ScoreVector&v, const ScoreVector&w, const ScoreVector&mask) { return ScoreVector(); // (_mm256_blendv_epi8(v.data_, w.data_, mask.data_)); } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(); // ScoreVector(_mm256_cmpeq_epi8(data_, v.data_)); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return 0; // (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(v.data_, w.data_)); } int operator [](unsigned i) const { return *(((uint8_t*)&data_) + i); } ScoreVector& set(unsigned i, uint8_t v) { *(((uint8_t*)&data_) + i) = v; return *this; } ScoreVector& max(const ScoreVector& rhs) { data_ = _mm512_max_epi8(data_, rhs.data_); return *this; } ScoreVector& min(const ScoreVector& rhs) { data_ = _mm512_min_epi8(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector& rhs) { return ScoreVector(_mm512_max_epi8(lhs.data_, rhs.data_)); } friend ScoreVector min(const ScoreVector& lhs, const ScoreVector& rhs) { return ScoreVector(_mm512_min_epi8(lhs.data_, rhs.data_)); } void store(int8_t* ptr) const { _mm512_storeu_si512((__m512i*)ptr, data_); } friend std::ostream& operator<<(std::ostream& s, ScoreVector v) { int8_t x[32]; v.store(x); for (unsigned i = 0; i < 32; ++i) printf("%3i ", (int)x[i]); return s; } void expand_from_8bit() {} __m512i data_; }; template struct ScoreTraits> { enum { CHANNELS = 64 }; typedef ::DISPATCH_ARCH::SIMD::Vector Vector; typedef int8_t Score; typedef uint8_t Unsigned; typedef uint32_t Mask; struct TraceMask { static uint64_t make(uint32_t vmask, uint32_t hmask) { return (uint64_t)vmask << 32 | (uint64_t)hmask; } static uint64_t vmask(int channel) { return (uint64_t)1 << (channel + 32); } static uint64_t hmask(int channel) { return (uint64_t)1 << channel; } uint64_t gap; uint64_t open; }; static ScoreVector zero() { return ScoreVector(); } static constexpr int8_t max_score() { return SCHAR_MAX; } static int int_score(int8_t s) { return (int)s - DELTA; } static constexpr int max_int_score() { return SCHAR_MAX - DELTA; } static constexpr int8_t zero_score() { return DELTA; } static void saturate(ScoreVector& v) {} }; #elif ARCH_ID == 2 template struct ScoreVector { ScoreVector() : data_(_mm256_set1_epi8(DELTA)) {} explicit ScoreVector(__m256i data) : data_(data) {} explicit ScoreVector(int8_t x) : data_(_mm256_set1_epi8(x)) {} explicit ScoreVector(int x) : data_(_mm256_set1_epi8(x)) {} explicit ScoreVector(const int8_t* s) : data_(_mm256_loadu_si256(reinterpret_cast(s))) { } explicit ScoreVector(const uint8_t* s) : data_(_mm256_loadu_si256(reinterpret_cast(s))) { } ScoreVector(unsigned a, __m256i seq, const int8_t* matrix_low, const int8_t* matrix_high) { const __m256i* row_lo = reinterpret_cast(&matrix_low[a << 5]); const __m256i* row_hi = reinterpret_cast(&matrix_high[a << 5]); seq = letter_mask(seq); __m256i high_mask = _mm256_slli_epi16(_mm256_and_si256(seq, _mm256_set1_epi8('\x10')), 3); __m256i seq_low = _mm256_or_si256(seq, high_mask); __m256i seq_high = _mm256_or_si256(seq, _mm256_xor_si256(high_mask, _mm256_set1_epi8('\x80'))); __m256i r1 = _mm256_load_si256(row_lo); __m256i r2 = _mm256_load_si256(row_hi); __m256i s1 = _mm256_shuffle_epi8(r1, seq_low); __m256i s2 = _mm256_shuffle_epi8(r2, seq_high); data_ = _mm256_or_si256(s1, s2); } ScoreVector(unsigned a, __m256i seq): ScoreVector(a, seq, score_matrix.matrix8_low(), score_matrix.matrix8_high()) {} ScoreVector operator+(const ScoreVector& rhs) const { return ScoreVector(_mm256_adds_epi8(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector& rhs) const { return ScoreVector(_mm256_subs_epi8(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = _mm256_adds_epi8(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector& rhs) { data_ = _mm256_subs_epi8(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = _mm256_and_si256(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = _mm256_adds_epi8(data_, _mm256_set1_epi8(1)); return *this; } friend ScoreVector blend(const ScoreVector&v, const ScoreVector&w, const ScoreVector&mask) { return ScoreVector(_mm256_blendv_epi8(v.data_, w.data_, mask.data_)); } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(_mm256_cmpeq_epi8(data_, v.data_)); } ScoreVector operator>(const ScoreVector& v) const { return ScoreVector(_mm256_cmpgt_epi8(data_, v.data_)); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(v.data_, w.data_)); } int operator [](unsigned i) const { return *(((int8_t*)&data_) + i); } ScoreVector& set(unsigned i, int8_t v) { //*(((uint8_t*)&data_) + i) = v; //data_ = _mm256_insert_epi8(data_, v, i); alignas(32) std::array s; _mm256_store_si256((__m256i *)s.data(), data_); s[i] = v; data_ = _mm256_load_si256((__m256i*)s.data()); return *this; } ScoreVector& max(const ScoreVector& rhs) { data_ = _mm256_max_epi8(data_, rhs.data_); return *this; } ScoreVector& min(const ScoreVector& rhs) { data_ = _mm256_min_epi8(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector& rhs) { return ScoreVector(_mm256_max_epi8(lhs.data_, rhs.data_)); } friend ScoreVector min(const ScoreVector& lhs, const ScoreVector& rhs) { return ScoreVector(_mm256_min_epi8(lhs.data_, rhs.data_)); } void store(int8_t* ptr) const { _mm256_storeu_si256((__m256i*)ptr, data_); } void store_aligned(int8_t* ptr) const { _mm256_store_si256((__m256i*)ptr, data_); } friend std::ostream& operator<<(std::ostream& s, ScoreVector v) { int8_t x[32]; v.store(x); for (unsigned i = 0; i < 32; ++i) printf("%3i ", (int)x[i]); return s; } static ScoreVector load_aligned(const int8_t* x) { return ScoreVector(_mm256_load_si256((const __m256i*)x)); } void expand_from_8bit() {} __m256i data_; }; template static inline int8_t extract(ScoreVector sv) { return (int8_t)_mm256_extract_epi8(sv.data_, i); } template static inline void store_expanded(ScoreVector sv, int16_t* dst) { const __m256i z = _mm256_setzero_si256(); const __m256i a = _mm256_permute4x64_epi64(sv.data_, 216); __m256i b = _mm256_unpacklo_epi8(a, z); __m256i c = _mm256_slli_si256(_mm256_cmpgt_epi8(z, b), 1); _mm256_store_si256((__m256i*)dst, _mm256_or_si256(b, c)); b = _mm256_unpackhi_epi8(a, z); c = _mm256_slli_si256(_mm256_cmpgt_epi8(z, b), 1); _mm256_store_si256((__m256i*)(dst + 16), _mm256_or_si256(b, c)); } template static inline void store_expanded(ScoreVector sv, int8_t* dst) { _mm256_store_si256((__m256i*)dst, sv.data_); } template struct ScoreTraits> { enum { CHANNELS = 32 }; typedef ::DISPATCH_ARCH::SIMD::Vector Vector; typedef int8_t Score; typedef uint8_t Unsigned; typedef uint32_t Mask; struct TraceMask { static uint64_t make(uint32_t vmask, uint32_t hmask) { return (uint64_t)vmask << 32 | (uint64_t)hmask; } static uint64_t vmask(int channel) { return (uint64_t)1 << (channel + 32); } static uint64_t hmask(int channel) { return (uint64_t)1 << channel; } uint64_t gap; uint64_t open; }; static ScoreVector zero() { return ScoreVector(); } static constexpr int8_t max_score() { return SCHAR_MAX; } static int int_score(int8_t s) { return (int)s - DELTA; } static constexpr int max_int_score() { return SCHAR_MAX - DELTA; } static constexpr int8_t zero_score() { return DELTA; } static void saturate(ScoreVector& v) {} }; #elif defined(__ARM_NEON) template struct ScoreVector { ScoreVector(): data_(vdupq_n_s8(DELTA)) {} explicit ScoreVector(int8x16_t data): data_(data) {} explicit ScoreVector(int8_t x): data_(vdupq_n_s8(x)) {} explicit ScoreVector(int x): data_(vdupq_n_s8(x)) {} explicit ScoreVector(const int8_t* s) : data_(vld1q_s8(s)) { } explicit ScoreVector(const uint8_t* s) : data_(vreinterpretq_s8_u8(vld1q_u8(s))) { } #ifdef __aarch64__ ScoreVector(unsigned a, int8x16_t seq) { const int8x16_t* row = reinterpret_cast(&score_matrix.matrix8()[a << 5]); int8x16_t high_mask = vreinterpretq_s8_s16(vshlq_n_s16(vreinterpretq_s16_s8(vandq_s8(seq, vdupq_n_s8('\x10'))), 3)); int8x16_t seq_low = vorrq_s8(seq, high_mask); int8x16_t seq_high = vorrq_s8(seq, veorq_s8(high_mask, vdupq_n_s8('\x80'))); int8x16_t r1 = vld1q_s8(reinterpret_cast(row)); int8x16_t r2 = vld1q_s8(reinterpret_cast(row + 1)); int8x16_t s1 = vqtbl1q_s8(r1, vandq_u8(vreinterpretq_u8_s8(seq_low), vdupq_n_u8(0x8F))); int8x16_t s2 = vqtbl1q_s8(r2, vandq_u8(vreinterpretq_u8_s8(seq_high), vdupq_n_u8(0x8F))); data_ = vorrq_s8(s1, s2); } #endif ScoreVector operator+(const ScoreVector&rhs) const { return ScoreVector(vqaddq_s8(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector&rhs) const { return ScoreVector(vqsubq_s8(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = vqaddq_s8(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector& rhs) { data_ = vqsubq_s8(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = vandq_s8(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = vqaddq_s8(data_, vdupq_n_s8(1)); return *this; } friend ScoreVector blend(const ScoreVector&v, const ScoreVector&w, const ScoreVector&mask) { /* Use a signed shift right to create a mask with the sign bit */ uint8x16_t mask_ = vreinterpretq_u8_s8(vshrq_n_s8(mask.data_, 7)); return ScoreVector(vbslq_s8(mask_, w.data_, v.data_)); } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(vreinterpretq_s8_u8(vceqq_s8(data_, v.data_))); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return vmaskq_s8(vreinterpretq_s8_u8(vceqq_s8(v.data_, w.data_))); } int operator [](unsigned i) const { int8_t x[16]; store(x); return x[i]; } ScoreVector& set(const unsigned i, uint8_t v) { int8_t x[16]; store(x); x[i] = v; data_ = vld1q_s8(x); return *this; } ScoreVector& max(const ScoreVector&rhs) { data_ = vmaxq_s8(data_, rhs.data_); return *this; } ScoreVector& min(const ScoreVector&rhs) { data_ = vminq_s8(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(vmaxq_s8(lhs.data_, rhs.data_)); } friend ScoreVector min(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(vminq_s8(lhs.data_, rhs.data_)); } void store(int8_t *ptr) const { vst1q_s8(ptr, data_); } friend std::ostream& operator<<(std::ostream &s, ScoreVector v) { int8_t x[16]; v.store(x); for (unsigned i = 0; i < 16; ++i) printf("%3i ", (int)x[i]); return s; } void expand_from_8bit() {} int8x16_t data_; }; template struct ScoreTraits> { enum { CHANNELS = 16 }; typedef ::DISPATCH_ARCH::SIMD::Vector Vector; typedef int8_t Score; typedef uint8_t Unsigned; typedef uint16_t Mask; struct TraceMask { static uint32_t make(uint32_t vmask, uint32_t hmask) { return vmask << 16 | hmask; } static uint32_t vmask(int channel) { return 1 << (channel + 16); } static uint32_t hmask(int channel) { return 1 << channel; } uint32_t gap; uint32_t open; }; static ScoreVector zero() { return ScoreVector(); } static constexpr int8_t max_score() { return SCHAR_MAX; } static int int_score(int8_t s) { return (int)s - DELTA; } static constexpr int max_int_score() { return SCHAR_MAX - DELTA; } static constexpr int8_t zero_score() { return DELTA; } static void saturate(ScoreVector& v) {} }; #elif defined(__SSE4_1__) template struct ScoreVector { ScoreVector(): data_(_mm_set1_epi8(DELTA)) {} explicit ScoreVector(__m128i data): data_(data) {} explicit ScoreVector(int8_t x): data_(_mm_set1_epi8(x)) {} explicit ScoreVector(int x): data_(_mm_set1_epi8(x)) {} explicit ScoreVector(const int8_t* s) : data_(_mm_loadu_si128(reinterpret_cast(s))) { } explicit ScoreVector(const uint8_t* s) : data_(_mm_loadu_si128(reinterpret_cast(s))) { } #ifdef __SSSE3__ ScoreVector(unsigned a, __m128i seq) { const __m128i* row = reinterpret_cast(&score_matrix.matrix8()[a << 5]); seq = letter_mask(seq); __m128i high_mask = _mm_slli_epi16(_mm_and_si128(seq, _mm_set1_epi8('\x10')), 3); __m128i seq_low = _mm_or_si128(seq, high_mask); __m128i seq_high = _mm_or_si128(seq, _mm_xor_si128(high_mask, _mm_set1_epi8('\x80'))); __m128i r1 = _mm_load_si128(row); __m128i r2 = _mm_load_si128(row + 1); __m128i s1 = _mm_shuffle_epi8(r1, seq_low); __m128i s2 = _mm_shuffle_epi8(r2, seq_high); data_ = _mm_or_si128(s1, s2); } #endif ScoreVector operator+(const ScoreVector&rhs) const { return ScoreVector(_mm_adds_epi8(data_, rhs.data_)); } ScoreVector operator-(const ScoreVector&rhs) const { return ScoreVector(_mm_subs_epi8(data_, rhs.data_)); } ScoreVector& operator+=(const ScoreVector& rhs) { data_ = _mm_adds_epi8(data_, rhs.data_); return *this; } ScoreVector& operator-=(const ScoreVector& rhs) { data_ = _mm_subs_epi8(data_, rhs.data_); return *this; } ScoreVector& operator &=(const ScoreVector& rhs) { data_ = _mm_and_si128(data_, rhs.data_); return *this; } ScoreVector& operator++() { data_ = _mm_adds_epi8(data_, _mm_set1_epi8(1)); return *this; } friend ScoreVector blend(const ScoreVector&v, const ScoreVector&w, const ScoreVector&mask) { return ScoreVector(_mm_blendv_epi8(v.data_, w.data_, mask.data_)); } ScoreVector operator==(const ScoreVector&v) const { return ScoreVector(_mm_cmpeq_epi8(data_, v.data_)); } ScoreVector operator>(const ScoreVector& v) const { return ScoreVector(_mm_cmpgt_epi8(data_, v.data_)); } friend uint32_t cmp_mask(const ScoreVector&v, const ScoreVector&w) { return _mm_movemask_epi8(_mm_cmpeq_epi8(v.data_, w.data_)); } int operator [](unsigned i) const { return *(((uint8_t*)&data_) + i); } ScoreVector& set(unsigned i, uint8_t v) { *(((uint8_t*)&data_) + i) = v; return *this; } ScoreVector& max(const ScoreVector&rhs) { data_ = _mm_max_epi8(data_, rhs.data_); return *this; } ScoreVector& min(const ScoreVector&rhs) { data_ = _mm_min_epi8(data_, rhs.data_); return *this; } friend ScoreVector max(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(_mm_max_epi8(lhs.data_, rhs.data_)); } friend ScoreVector min(const ScoreVector& lhs, const ScoreVector&rhs) { return ScoreVector(_mm_min_epi8(lhs.data_, rhs.data_)); } void store(int8_t *ptr) const { _mm_storeu_si128((__m128i*)ptr, data_); } void store_aligned(int8_t* ptr) const { _mm_store_si128((__m128i*)ptr, data_); } friend std::ostream& operator<<(std::ostream &s, ScoreVector v) { int8_t x[16]; v.store(x); for (unsigned i = 0; i < 16; ++i) printf("%3i ", (int)x[i]); return s; } static ScoreVector load_aligned(const int8_t* x) { return ScoreVector(_mm_load_si128((const __m128i*)x)); } void expand_from_8bit() {} __m128i data_; }; template static inline int8_t extract(ScoreVector sv) { return 0; } template struct ScoreTraits> { enum { CHANNELS = 16 }; typedef ::DISPATCH_ARCH::SIMD::Vector Vector; typedef int8_t Score; typedef uint8_t Unsigned; typedef uint16_t Mask; struct TraceMask { static uint32_t make(uint32_t vmask, uint32_t hmask) { return vmask << 16 | hmask; } static uint32_t vmask(int channel) { return 1 << (channel + 16); } static uint32_t hmask(int channel) { return 1 << channel; } uint32_t gap; uint32_t open; }; static ScoreVector zero() { return ScoreVector(); } static constexpr int8_t max_score() { return SCHAR_MAX; } static int int_score(int8_t s) { return (int)s - DELTA; } static constexpr int max_int_score() { return SCHAR_MAX - DELTA; } static constexpr int8_t zero_score() { return DELTA; } static void saturate(ScoreVector& v) {} }; #endif } #if defined(__SSE4_1__) | defined(__ARM_NEON) template static inline int8_t extract_channel(const DISPATCH_ARCH::ScoreVector& v, int i) { return v[i]; } template static inline void set_channel(DISPATCH_ARCH::ScoreVector& v, const int i, const int8_t x) { v.set(i, x); } #endifbbuchfink-diamond-08b3cbc/src/dp/swipe/000077500000000000000000000000001506104011400200555ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/dp/swipe/anchored.h000066400000000000000000000234371506104011400220220ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2019-2024 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "basic/sequence.h" #include "../score_vector.h" #include "util/simd/transpose.h" #include "banded_matrix.h" #include "config.h" #include "util/geo/geo.h" #include "util/util.h" #include "util/data_structures/array.h" #include "../score_vector_int8.h" #include "../score_vector_int16.h" using std::copy; using std::array; using std::numeric_limits; using std::vector; using std::pair; using std::tie; namespace DP { namespace AnchoredSwipe { #if ARCH_ID == 2 namespace DISPATCH_ARCH { static char blank[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static constexpr Loc L = 13; template struct TargetIterator { enum { CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS }; using Score = typename ::DISPATCH_ARCH::ScoreTraits::Score; TargetIterator(Target* targets, int64_t target_count, Loc target_len_max, DP::BandedSwipe::DISPATCH_ARCH::Matrix& matrix, const Options& options) : options(options), begin(targets), next(targets), end(targets + target_count), active(0), band(0) { while (active < CHANNELS && next < end) { int i = active; target_seqs[i] = Array(target_len_max + 32 + 1); init_target(i); matrix.init_channel_diag(i, -Geo::i(0, targets[i].d_begin)); } for (int i = active; i < CHANNELS; ++i) reset_channel(i); band = round_up(band, (Loc)CHANNELS); //matrix.init_channels_nw(-Geo::i(0, targets[0].d_begin), score_matrix.gap_open(), score_matrix.gap_extend()); } inline bool init_target(int channel) { while (next->band() <= 0 && next < end) ++next; if (next == end) return false; target_idx[channel] = int(next - begin); targets[channel] = *next++; loc[channel] = 0; target_seqs[channel].assign(MASK_LETTER); if (targets[channel].reverse) target_seqs[channel].push_back_reversed(targets[channel].seq.data(), targets[channel].seq.end()); else target_seqs[channel].push_back(targets[channel].seq.data(), targets[channel].seq.end()); target_seqs[channel].push_back(32, MASK_LETTER); if (options.profile == nullptr) { if (targets[channel].reverse) for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[channel][j] = targets[channel].profile_rev->get((int)j, targets[channel].query_start + Geo::i(0, targets[channel].d_begin) - 1); else for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[channel][j] = targets[channel].profile->get((int)j, targets[channel].query_start + Geo::i(0, targets[channel].d_begin) - 1); } else { for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[channel][j] = (const Score*)(targets[channel].reverse ? options.profile_rev[j] : options.profile[j]) + targets[channel].query_start + Geo::i(0, targets[channel].d_begin) - 1; } ++active; band = std::max(band, targets[channel].band()); return true; } inline void init_target_matrix(int channel, DP::BandedSwipe::DISPATCH_ARCH::Matrix& matrix, ScoreVector& max_score, ScoreVector& col_counter, ScoreVector& max_j) { matrix.init_channel_nw(channel, -Geo::i(0, targets[channel].d_begin), score_matrix.gap_open(), score_matrix.gap_extend()); set_channel(max_score, channel, -1); set_channel(col_counter, channel, 0); set_channel(max_j, channel, -1); } inline void reset_channel(int channel) { if (options.profile == nullptr) { for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[channel][j] = (const Score*)blank; } else for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[channel][j] = (const Score*)options.profile[0]; } inline void next_block(DP::BandedSwipe::DISPATCH_ARCH::Matrix& matrix, ScoreVector& max_score, ScoreVector& max_i, ScoreVector& max_j, ScoreVector& col_counter) { for (int i = 0; i < CHANNELS; ++i) { if (targets[i].blank()) { std::fill(letters[i].begin(), letters[i].end(), MASK_LETTER); continue; } if (loc[i] >= targets[i].seq.length() + 1) { const ::Score score = max_score[i]; if (score >= 0) { begin[target_idx[i]].score = score + 1; const Score j1 = max_j[i]; if (j1 < numeric_limits::max()) { begin[target_idx[i]].target_end = (Loc)j1 + 1 - 1; begin[target_idx[i]].query_end = Geo::i((Loc)j1, targets[i].d_begin) + (Loc)max_i[i] + 1 - 1; assert(begin[target_idx[i]].target_end > 0 && begin[target_idx[i]].query_end > 0); } else begin[target_idx[i]].score = numeric_limits::max(); } --active; targets[i].reset(); if (next < end) { if (!init_target(i)) { std::fill(letters[i].begin(), letters[i].end(), MASK_LETTER); reset_channel(i); continue; } init_target_matrix(i, matrix, max_score, col_counter, max_j); band = round_up(band, (Loc)CHANNELS); } else { std::fill(letters[i].begin(), letters[i].end(), MASK_LETTER); reset_channel(i); continue; } } copy(target_seqs[i].data() + loc[i], target_seqs[i].data() + loc[i] + L, letters[i].data()); loc[i] += L; if (profile_ptrs[i][0] != (const Score*)blank) for (int j = 0; j < AMINO_ACID_COUNT; ++j) profile_ptrs[i][j] += L; } } inline array column_ptrs(int k) { array prof_ptr; for (int i = 0; i < CHANNELS; ++i) { if(profile_ptrs[i][0] == (const Score*)blank) { prof_ptr[i] = (const Score*)blank; continue; } const Letter l = letter_mask(letters[i][k + L]); prof_ptr[i] = profile_ptrs[i][(int)l] + k; } return prof_ptr; } size_t net_cells(int k) const { size_t n = 0; for (int i = 0; i < CHANNELS; ++i) if (!targets[i].blank() && (loc[i] + k < targets[i].seq.length())) { int j = loc[i] + k, i0 = std::max(Geo::i(j, targets[i].d_begin), 0), i1 = std::min(Geo::i(j, targets[i].d_end), targets[i].query_length); //assert(i1 - i0 >= 0); n += std::max(i1 - i0, 0); } return n; } const Options& options; array, CHANNELS> targets; array, CHANNELS> target_seqs; Target* begin, * next, * end; int active; array, CHANNELS> profile_ptrs; array loc; array, CHANNELS> letters; array padding; array target_idx; Loc band; }; template Stats FLATTEN smith_waterman(DP::AnchoredSwipe::Target::Score>* targets, int64_t target_count, const Options& options) { using Score = typename ::DISPATCH_ARCH::ScoreTraits::Score; const Loc CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; constexpr Score SCORE_MIN = numeric_limits::min(); if (target_count == 0) return Stats(); alignas(32) Score scores[CHANNELS * CHANNELS]; Loc band_max, target_len_max; tie(band_max, target_len_max) = limits(targets, target_count); DP::BandedSwipe::DISPATCH_ARCH::Matrix matrix(round_up(band_max, CHANNELS), 0, ScoreVector(SCORE_MIN)); assert(round_up(band_max, CHANNELS) <= numeric_limits::max()); TargetIterator target_it(targets, target_count, target_len_max, matrix, options); const ScoreVector go = ScoreVector(score_matrix.gap_open() + score_matrix.gap_extend()), ge = ScoreVector(score_matrix.gap_extend()), one = ScoreVector(1); ScoreVector max_score(-1), col_counter(0), max_j(-1), max_i(0); Stats stats; while(target_it.next_block(matrix, max_score, max_i, max_j, col_counter), target_it.active > 0) { const int band = target_it.band; for (int k = -L; k < 0; ++k) { #ifdef DP_STAT stats.gross_cells += (size_t)band * CHANNELS; stats.net_cells += target_it.net_cells(k); #endif typename DP::BandedSwipe::DISPATCH_ARCH::Matrix::ColumnIterator it(matrix.begin(0, 0)); array prof_ptr = target_it.column_ptrs(k); ScoreVector vgap = ScoreVector(SCORE_MIN), hgap = ScoreVector(), col_best = ScoreVector(SCORE_MIN), row_counter(0), col_max_i(0); for (int i = 0; i < band;) { transpose_offset(prof_ptr.data(), CHANNELS, i / CHANNELS, scores, __m256i()); const Score* score_ptr = scores; do { hgap = it.hgap(); ScoreVector match_scores(score_ptr); ScoreVector score = it.diag() + match_scores; score = max(score, hgap); score = max(score, vgap); ScoreVector open = score - go; const ScoreVector gt_mask = score > col_best; col_max_i = blend(col_max_i, row_counter, gt_mask); row_counter += one; col_best = max(col_best, score); vgap -= ge; hgap -= ge; vgap = max(vgap, open); hgap = max(hgap, open); it.set_hgap(hgap); it.set_score(score); ++it; score_ptr += CHANNELS; ++i; } while ((i & (CHANNELS - 1)) != 0); } const ScoreVector gt_mask = col_best > max_score; max_j = blend(max_j, col_counter, gt_mask); max_i = blend(max_i, col_max_i, gt_mask); max_score = max(max_score, col_best); col_counter += one; } } return stats; } } #endif }}bbuchfink-diamond-08b3cbc/src/dp/swipe/anchored_wrapper.cpp000066400000000000000000000306021506104011400241050ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2019-2024 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "../dp.h" #include "config.h" #include "anchored.h" #include "../score_profile.h" #include "util/simd/dispatch.h" #include "stats/score_matrix.h" #include "align/def.h" using std::list; using std::vector; using std::unique_ptr; using std::pair; using std::sort; using std::runtime_error; using std::accumulate; using std::make_unique; namespace DP { namespace BandedSwipe { namespace DISPATCH_ARCH { struct TargetVector { //vector> int8; vector> int16; }; struct Profiles { struct Reverse {}; Profiles(Sequence seq, const int8_t* cbs, int64_t padding, const ScoreMatrix& matrix) { int16 = make_profile16(seq, cbs, padding, &matrix); } Profiles(const Profiles& p, Reverse): int16(p.int16.reverse()) {} //LongScoreProfile int8; LongScoreProfile int16; }; static Loc get_band(Loc qlen, Extension::Mode extension_mode) { //return (Extension::band(qlen, extension_mode) + 15) / 16 * 16; return config.sensitivity >= Sensitivity::ULTRA_SENSITIVE ? 160 : (config.sensitivity >= Sensitivity::MORE_SENSITIVE ? 96 : 32); } static void align_right(Sequence target_seq, bool reverse, Loc i, Loc j, Loc d_begin, Loc d_end, Score prefix_score, TargetVector& targets, int64_t target_idx, const LongScoreProfile* profile, const LongScoreProfile* profile_rev, const DP::AnchoredSwipe::Config& cfg) { Loc qlen = cfg.query.length() - i, tlen = target_seq.length(); //const int band_cap = std::max(std::min(qlen / 2, tlen / 2), 1); //const int band = std::min(std::max(get_band(cfg.query.length()), Loc((d_end - d_begin) * 0.15)), band_cap); //const int band = std::max(get_band(cfg.query.length()), Loc((d_end - d_begin) * 0.15)); const int band = get_band(cfg.query.length(), cfg.extension_mode); d_begin -= band; d_end += band - 1; const Loc d0 = Geo::clip_diag(Geo::diag_sub_matrix(d_begin, i, j), qlen, tlen), d1 = Geo::clip_diag(Geo::diag_sub_matrix(d_end, i, j), qlen, tlen); tlen = std::min(tlen, Geo::j(qlen - 1, d0) + 1); assert(tlen > 0); assert(d1 >= d0); const Sequence clipped_target = reverse ? target_seq.subseq(target_seq.length() - tlen, target_seq.length()) : target_seq.subseq(0, tlen); auto& t = targets.int16; t.emplace_back(clipped_target, d0, d1 + 1, i, qlen, target_idx, reverse); t.back().profile = profile; t.back().profile_rev = profile_rev; } static void align_left(Sequence target_seq, Loc i, Loc j, Loc d_begin, Loc d_end, Score suffix_score, TargetVector& targets, int64_t target_idx, const LongScoreProfile* profile, const LongScoreProfile* profile_rev, const DP::AnchoredSwipe::Config& cfg) { const Loc qlen = cfg.query.length(), tlen = target_seq.length(); const Loc ir = qlen - 1 - i, jr = tlen - 1 - j; align_right(target_seq.subseq(0, j + 1), true, ir, jr, Geo::rev_diag(d_end, qlen, tlen), Geo::rev_diag(d_begin, qlen, tlen), suffix_score, targets, target_idx, profile, profile_rev, cfg); } static void add_target(DpTarget& t, TargetVector& targets, int64_t& target_idx, const DP::AnchoredSwipe::Config& cfg) { //t.anchor = make_clipped_anchor(t.anchor, cfg.query, cfg.query_cbs, t.seq); //if (t.anchor.score == 0) //return; if (t.extend_right(cfg.query.length())) { const Loc i = t.anchor.query_end(), j = t.anchor.subject_end(); align_right(t.seq.subseq(j), false, i, j, t.anchor.d_min_right, t.anchor.d_max_right, t.anchor.prefix_score, targets, target_idx, t.prof, t.prof_reverse, cfg); ++target_idx; } if (t.extend_left()) { const Score suffix_score = cfg.score_hint - t.anchor.prefix_score + t.anchor.score; align_left(t.seq, t.anchor.query_begin() - 1, t.anchor.subject_begin() - 1, t.anchor.d_min_left, t.anchor.d_max_left, suffix_score, targets, target_idx, t.prof, t.prof_reverse, cfg); ++target_idx; } } static void swipe_threads(DP::AnchoredSwipe::Target* targets, int64_t count, const DP::AnchoredSwipe::Options& options, const DP::AnchoredSwipe::Config& cfg) { using Target = DP::AnchoredSwipe::Target; ThreadPool::TaskSet task_set(*cfg.thread_pool, 0); int64_t size = 0; Target* i0 = targets, *i1 = targets, *end = targets + count; while (i1 < end) { const auto n = std::min((ptrdiff_t)16, end - i1); size += accumulate(i1, i1 + n, (int64_t)0, [](int64_t n, const Target& t) {return n + t.gross_cells(); }); i1 += n; if (size >= config.swipe_task_size) { #if ARCH_ID == 2 task_set.enqueue(DP::AnchoredSwipe::DISPATCH_ARCH::smith_waterman<::DISPATCH_ARCH::ScoreVector>, i0, i1 - i0, options); #endif cfg.stats.inc(Statistics::SWIPE_TASKS_TOTAL); cfg.stats.inc(Statistics::SWIPE_TASKS_ASYNC); i0 = i1; size = 0; } } if (task_set.total() == 0) { cfg.stats.inc(Statistics::SWIPE_TASKS_TOTAL); #if ARCH_ID == 2 DP::AnchoredSwipe::DISPATCH_ARCH::smith_waterman<::DISPATCH_ARCH::ScoreVector>(i0, i1 - i0, options); #endif return; } if (i1 - i0 > 0) { cfg.stats.inc(Statistics::SWIPE_TASKS_TOTAL); cfg.stats.inc(Statistics::SWIPE_TASKS_ASYNC); #if ARCH_ID == 2 task_set.enqueue(DP::AnchoredSwipe::DISPATCH_ARCH::smith_waterman<::DISPATCH_ARCH::ScoreVector>, i0, i1 - i0, options); #endif } task_set.run(); } const ScoreMatrix& select_matrix(int qlen) { //if (qlen < 35) return pam30; //if (qlen <= 50)return pam70; //if (qlen <= 85)return blosum80; return score_matrix; } list anchored_swipe(Targets& targets, const DP::AnchoredSwipe::Config& cfg, std::pmr::monotonic_buffer_resource& pool) { #if ARCH_ID != 2 throw runtime_error("Anchored SWIPE requires at least AVX2 support"); #endif TaskTimer total; TargetVector target_vec; int64_t target_count = 0, target_len = 0; Loc max_target_len = 0; if(!cfg.target_profiles) for (int bin = 0; bin < DP::BINS; ++bin) for (const DpTarget& t : targets[bin]) { ++target_count; target_len += t.seq.length(); max_target_len = std::max(max_target_len, t.seq.length()); } else for (int bin = 0; bin < DP::BINS; ++bin) target_count += targets[bin].size(); TaskTimer timer; //target_vec.int8.reserve(target_count * 2); target_vec.int16.reserve(target_count * 2); // check for 16 bit overflow cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE_ALLOC, timer.microseconds()); timer.go(); unique_ptr profiles, profiles_rev; vector prof_pointers, prof_pointers_rev; const ScoreMatrix& matrix = score_matrix; // select_matrix(cfg.query.length()); if (!cfg.target_profiles) { profiles = make_unique(cfg.query, cfg.query_cbs, cfg.query.length() + max_target_len + 32, matrix); profiles_rev = make_unique(*profiles, Profiles::Reverse()); prof_pointers = profiles->int16.pointers(0); prof_pointers_rev = profiles_rev->int16.pointers(0); } cfg.stats.inc(Statistics::TIME_PROFILE, timer.microseconds()); timer.go(); int64_t target_idx = 0; for (int bin = 0; bin < DP::BINS; ++bin) for (DpTarget& t : targets[bin]) { add_target(t, target_vec, target_idx, cfg); } cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE_ADD, timer.microseconds()); auto& t = target_vec.int16; timer.go(); //sort(target_vec.int8.begin(), target_vec.int8.end()); sort(target_vec.int16.begin(), target_vec.int16.end()); cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE_SORT, timer.microseconds()); DP::AnchoredSwipe::Stats stats; DP::AnchoredSwipe::Options options{ prof_pointers.empty() ? nullptr : prof_pointers.data(), prof_pointers_rev.empty() ? nullptr : prof_pointers_rev.data() }; timer.go(); #ifdef __SSE4_1__ //DP::AnchoredSwipe::DISPATCH_ARCH::smith_waterman<::DISPATCH_ARCH::ScoreVector>(target_vec.int8.data(), target_vec.int8.size()); //stats = DP::AnchoredSwipe::DISPATCH_ARCH::smith_waterman<::DISPATCH_ARCH::ScoreVector>(target_vec.int16.data(), target_vec.int16.size(), options); swipe_threads(target_vec.int16.data(), target_vec.int16.size(), options, cfg); //cfg.stats.inc(Statistics::GROSS_DP_CELLS, stats.gross_cells); //cfg.stats.inc(Statistics::NET_DP_CELLS, stats.net_cells); #endif cfg.stats.inc(Statistics::TIME_SW, timer.microseconds()); timer.go(); //sort(target_vec.int8.begin(), target_vec.int8.end(), DP::AnchoredSwipe::Target::cmp_target_idx); sort(target_vec.int16.begin(), target_vec.int16.end(), DP::AnchoredSwipe::Target::cmp_target_idx); cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE_SORT, timer.microseconds()); timer.go(); auto target_it = target_vec.int16.cbegin(); list out; DP::Targets recompute; std::pmr::list matrices(&pool); Stats::Composition query_comp(Stats::composition(cfg.query)); for (int bin = 0; bin < DP::BINS; ++bin) for (const DpTarget& t : targets[bin]) { if (t.anchor.score == 0) continue; int score = t.anchor.score, i0 = t.anchor.query_begin(), i1 = t.anchor.query_end(), j0 = t.anchor.subject_begin(), j1 = t.anchor.subject_end(); #ifdef DP_STAT int64_t gross_cells = 0, net_cells = 0; #endif if (t.extend_right(cfg.query.length())) { score += target_it->score; i1 += target_it->query_end; j1 += target_it->target_end; #ifdef DP_STAT auto c = target_it->cells(); gross_cells += c.first; net_cells += c.second; #endif ++target_it; } if (t.extend_left()) { score += target_it->score; i0 -= target_it->query_end; j0 -= target_it->target_end; #ifdef DP_STAT auto c = target_it->cells(); gross_cells += c.first; net_cells += c.second; #endif ++target_it; } // filter for cover const double qcov = double(i1 - i0) / cfg.query.length() * 100.0, tcov = double(j1 - j0) / t.seq.length() * 100.0; if (config.query_or_target_cover > 0 || config.query_cover > 0 || config.subject_cover > 0) { if (!cfg.recompute_adjusted && (std::max(qcov, tcov) < config.query_or_target_cover || qcov < config.query_cover || tcov < config.subject_cover)) continue; } /*if (std::max(i0, cfg.query.length() - i1) > config.uncov_cap || std::max(j0, t.seq.length() - j1) > config.uncov_cap) continue;*/ const double evalue = matrix.evalue(score, cfg.query.length(), t.seq.length()); // consider adjusted matrix if(!cfg.recompute_adjusted && evalue > config.max_evalue) continue; if (cfg.recompute_adjusted) { matrices.emplace_back(query_comp, cfg.query.length(), Stats::CBS::MATRIX_ADJUST, t.seq, cfg.stats, pool, Stats::eUserSpecifiedRelEntropy); recompute[bin].push_back(DpTarget(t.seq, t.true_target_len, t.d_begin, t.d_end, t.target_idx, cfg.query.length(), &matrices.back(), DpTarget::CarryOver(), t.anchor)); } else { out.emplace_back(); out.back().score = score; out.back().evalue = evalue; out.back().bit_score = matrix.bitscore(score); out.back().swipe_target = t.target_idx; out.back().query_range = { i0, i1 }; out.back().query_source_range = out.back().query_range; out.back().subject_range = { j0, j1 }; out.back().subject_source_range = out.back().subject_range; #ifdef DP_STAT out.back().reserved1 = (int)gross_cells; // stats.gross_cells; out.back().reserved2 = (int)net_cells; // stats.net_cells; #endif out.back().approx_id = out.back().approx_id_percent(cfg.query, t.seq); } } cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE_OUTPUT, timer.microseconds()); cfg.stats.inc(Statistics::TIME_ANCHORED_SWIPE, total.microseconds()); if (cfg.recompute_adjusted) { DP::Params params{ cfg.query, nullptr, Frame(0), cfg.query.length(), nullptr, DP::Flags::NONE, false, 0, 0, HspValues::COORDS, cfg.stats, cfg.thread_pool }; return DP::BandedSwipe::swipe(recompute, params); } return out; } } DISPATCH_3(std::list, anchored_swipe, Targets&, targets, const DP::AnchoredSwipe::Config&, cfg, std::pmr::monotonic_buffer_resource&, pool) }}bbuchfink-diamond-08b3cbc/src/dp/swipe/banded_3frame_swipe.cpp000066400000000000000000000446301506104011400244510ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2019 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "util/simd/vector.h" #include "../dp.h" #include "swipe.h" #include "target_iterator.h" #include "util/data_structures/mem_buffer.h" #include "util/simd/dispatch.h" #include "../score_vector_int16.h" #include "../score_vector_int8.h" using std::list; using std::thread; using std::atomic; using std::pair; using std::vector; namespace DISPATCH_ARCH { template struct Banded3FrameSwipeMatrix { struct ColumnIterator { ColumnIterator(Sv* hgap_front, Sv* score_front) : hgap_ptr_(hgap_front), score_ptr_(score_front) { sm4 = ScoreTraits::zero(); sm3 = *score_ptr_; sm2 = *(score_ptr_ + 1); } inline void operator++() { ++hgap_ptr_; ++score_ptr_; sm4 = sm3; sm3 = sm2; sm2 = *(score_ptr_ + 1); } inline Sv hgap() const { return *(hgap_ptr_ + 3); } inline void set_hgap(const Sv& x) { *hgap_ptr_ = x; } inline void set_score(const Sv& x) { *score_ptr_ = x; } void set_zero() { *(score_ptr_ - 1) = ScoreTraits::zero(); *(score_ptr_ - 2) = ScoreTraits::zero(); *(score_ptr_ - 3) = ScoreTraits::zero(); } Sv *hgap_ptr_, *score_ptr_; Sv sm4, sm3, sm2; }; Banded3FrameSwipeMatrix(size_t band, size_t cols) : band_(band) { hgap_.resize(band + 3); score_.resize(band + 1); std::fill(hgap_.begin(), hgap_.end(), Sv()); std::fill(score_.begin(), score_.end(), Sv()); } inline ColumnIterator begin(size_t offset, size_t col) { return ColumnIterator(&hgap_[offset], &score_[offset]); } size_t band() const { return band_; } private: const size_t band_; #ifdef USE_TLS static thread_local MemBuffer hgap_, score_; #else MemBuffer hgap_, score_; #endif }; template struct Banded3FrameSwipeTracebackMatrix { typedef typename ScoreTraits::Score Score; struct ColumnIterator { ColumnIterator(Sv* hgap_front, Sv* score_front, Sv* score_front1) : hgap_ptr_(hgap_front), score_ptr_(score_front), score_ptr1_(score_front1) { sm4 = ScoreTraits::zero(); sm3 = *(score_ptr_++); sm2 = *(score_ptr_); } inline void operator++() { ++hgap_ptr_; ++score_ptr_; ++score_ptr1_; sm4 = sm3; sm3 = sm2; sm2 = *score_ptr_; } inline Sv hgap() const { return *(hgap_ptr_ + 3); } inline void set_hgap(const Sv& x) { *hgap_ptr_ = x; } inline void set_score(const Sv& x) { *score_ptr1_ = x; } void set_zero() { *(score_ptr1_ - 1) = ScoreTraits::zero(); *(score_ptr1_ - 2) = ScoreTraits::zero(); *(score_ptr1_ - 3) = ScoreTraits::zero(); } Sv* hgap_ptr_, *score_ptr_, *score_ptr1_; Sv sm4, sm3, sm2; }; struct TracebackIterator { TracebackIterator(const Score *score, size_t band, int frame, int i, int j) : band_(band), score_(score), frame(frame), i(i), j(j) { assert(i >= 0 && j >= 0); } Score score() const { return *score_; } Score sm3() const { return *(score_ - (band_ + 1) * ScoreTraits::CHANNELS); } Score sm4() const { return *(score_ - (band_ + 2) * ScoreTraits::CHANNELS); } Score sm2() const { return *(score_ - band_ * ScoreTraits::CHANNELS); } void walk_diagonal() { score_ -= (band_ + 1) * ScoreTraits::CHANNELS; --i; --j; assert(i >= -1 && j >= -1); } void walk_forward_shift() { score_ -= (band_ + 2) * ScoreTraits::CHANNELS; --i; --j; --frame; if (frame == -1) { frame = 2; --i; } assert(i >= -1 && j >= -1); } void walk_reverse_shift() { score_ -= band_ * ScoreTraits::CHANNELS; --i; --j; ++frame; if (frame == 3) { frame = 0; ++i; } assert(i >= -1 && j >= -1); } pair walk_gap(int d0, int d1) { const int i0 = std::max(d0 + j, 0), j0 = std::max(i - d1, -1); const Score *h = score_ - (band_ - 2) * ScoreTraits::CHANNELS, *h0 = score_ - (j - j0) * (band_ - 2) * ScoreTraits::CHANNELS; const Score *v = score_ - 3 * ScoreTraits::CHANNELS, *v0 = score_ - (i - i0 + 1) * 3 * ScoreTraits::CHANNELS; const Score score = this->score(); const Score e = score_matrix.gap_extend(); Score g = score_matrix.gap_open() + e; int l = 1; while (v > v0 && h > h0) { if (score + g == *h) { walk_hgap(h, l); return std::make_pair(op_deletion, l); } else if (score + g == *v) { walk_vgap(v, l); return std::make_pair(op_insertion, l); } h -= (band_ - 2) * ScoreTraits::CHANNELS; v -= 3 * ScoreTraits::CHANNELS; ++l; g += e; } while (v > v0) { if (score + g == *v) { walk_vgap(v, l); return std::make_pair(op_insertion, l); } v -= 3 * ScoreTraits::CHANNELS; ++l; g += e; } while (h > h0) { if (score + g == *h) { walk_hgap(h, l); return std::make_pair(op_deletion, l); } h -= (band_ - 2) * ScoreTraits::CHANNELS; ++l; g += e; } throw std::runtime_error("Traceback error."); } void walk_hgap(const Score *h, int l) { score_ = h; j -= l; assert(i >= -1 && j >= -1); } void walk_vgap(const Score *v, int l) { score_ = v; i -= l; assert(i >= -1 && j >= -1); } const size_t band_; const Score *score_; int frame, i, j; }; TracebackIterator traceback(size_t col, int i0, int j, int dna_len, size_t channel, Score score) const { const int i_ = std::max(-i0, 0) * 3, i1 = (int)std::min(band_, size_t(dna_len - 2 - i0 * 3)); const Score *s = (Score*)(&score_[col*(band_ + 1) + i_]) + channel; for (int i = i_; i < i1; ++i, s += ScoreTraits::CHANNELS) if (*s == score) return TracebackIterator(s, band_, i % 3, i0 + i / 3, j); throw std::runtime_error("Trackback error."); } Banded3FrameSwipeTracebackMatrix(size_t band, size_t cols) : band_(band) { hgap_.resize(band + 3); score_.resize((band + 1) * (cols + 1)); const Sv z = Sv(); std::fill(hgap_.begin(), hgap_.end(), z); std::fill(score_.begin(), score_.begin() + band + 1, z); for (size_t i = 0; i < cols; ++i) score_[i*(band + 1) + band] = z; } inline ColumnIterator begin(size_t offset, size_t col) { return ColumnIterator(&hgap_[offset], &score_[col*(band_ + 1) + offset], &score_[(col + 1)*(band_ + 1) + offset]); } size_t band() const { return band_; } private: const size_t band_; #ifdef USE_TLS static thread_local MemBuffer hgap_; #else MemBuffer hgap_; #endif MemBuffer score_; }; #ifdef USE_TLS template thread_local MemBuffer Banded3FrameSwipeMatrix::hgap_; template thread_local MemBuffer Banded3FrameSwipeMatrix::score_; template thread_local MemBuffer Banded3FrameSwipeTracebackMatrix::hgap_; #endif template struct Banded3FrameSwipeMatrixRef { }; template struct Banded3FrameSwipeMatrixRef<_sv, DP::Traceback> { typedef Banded3FrameSwipeTracebackMatrix<_sv> type; }; template struct Banded3FrameSwipeMatrixRef<_sv, DP::ScoreOnly> { typedef Banded3FrameSwipeMatrix<_sv> type; }; template Hsp traceback(Sequence *query, Strand strand, int dna_len, const Banded3FrameSwipeTracebackMatrix<_sv> &dp, const DpTarget &target, int d_begin, typename ScoreTraits<_sv>::Score max_score, double evalue, int max_col, int channel, int i0, int i1) { typedef typename ScoreTraits<_sv>::Score Score; const int j0 = i1 - (target.d_end - 1), d1 = target.d_end; typename Banded3FrameSwipeTracebackMatrix<_sv>::TracebackIterator it(dp.traceback(max_col + 1, i0 + max_col, j0 + max_col, dna_len, channel, max_score)); Hsp out(true); out.swipe_target = target.target_idx; out.score = ScoreTraits<_sv>::int_score(max_score) * config.cbs_matrix_scale; out.bit_score = score_matrix.bitscore(out.score); out.evalue = evalue; out.transcript.reserve(size_t(out.score * config.transcript_len_estimate)); out.set_end(it.i + 1, it.j + 1, Frame(strand, it.frame), dna_len); while (it.score() > ScoreTraits<_sv>::zero_score()) { const Letter q = query[it.frame][it.i], s = target.seq[it.j]; const Score m = score_matrix(q, s), score = it.score(); if (score == it.sm3() + m) { out.push_match(q, s, m > (Score)0); it.walk_diagonal(); } else if (score == it.sm4() + m - score_matrix.frame_shift()) { out.push_match(q, s, m > (Score)0); out.transcript.push_back(op_frameshift_forward); it.walk_forward_shift(); } else if (score == it.sm2() + m - score_matrix.frame_shift()) { out.push_match(q, s, m > (Score)0); out.transcript.push_back(op_frameshift_reverse); it.walk_reverse_shift(); } else { const pair g(it.walk_gap(d_begin, d1)); out.push_gap(g.first, g.second, target.seq.data() + it.j + g.second); } } out.set_begin(it.i + 1, it.j + 1, Frame(strand, it.frame), dna_len); out.transcript.reverse(); out.transcript.push_terminator(); out.subject_source_range = out.subject_range; return out; } template Hsp traceback(Sequence *query, Strand strand, int dna_len, const Banded3FrameSwipeMatrix<_sv> &dp, const DpTarget &target, int d_begin, typename ScoreTraits<_sv>::Score max_score, double evalue, int max_col, int channel, int i0, int i1) { Hsp out(false); const int j0 = i1 - (target.d_end - 1); out.swipe_target = target.target_idx; out.score = ScoreTraits<_sv>::int_score(max_score) * config.cbs_matrix_scale; out.bit_score = score_matrix.bitscore(out.score); out.evalue = evalue; out.query_range.end_ = std::min(i0 + max_col + (int)dp.band() / 3 / 2, (int)query[0].length()); out.query_range.begin_ = std::max(out.query_range.end_ - (j0 + max_col), 0); out.frame = strand == FORWARD ? 0 : 3; out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, Frame(out.frame)), TranslatedPosition(out.query_range.end_, Frame(out.frame)), dna_len); return out; } template list banded_3frame_swipe( const TranslatedSequence& query, Strand strand, std::vector::const_iterator subject_begin, std::vector::const_iterator subject_end, DpStat &stat, bool parallel, std::vector &overflow) { typedef typename Banded3FrameSwipeMatrixRef::type Matrix; typedef typename ScoreTraits::Score Score; assert(subject_end - subject_begin <= ScoreTraits::CHANNELS); Sequence q[3]; query.get_strand(strand, q); const int qlen = (int)q[0].length(), qlen2 = (int)q[1].length(), qlen3 = (int)q[2].length(); int band = 0; for (vector::const_iterator j = subject_begin; j < subject_end; ++j) band = std::max(band, j->d_end - j->d_begin); int i0 = INT_MAX, i1 = INT_MAX, d_begin[ScoreTraits::CHANNELS]; for (vector::const_iterator j = subject_begin; j < subject_end; ++j) { d_begin[j - subject_begin] = j->d_end - band; int i2 = std::max(j->d_end - 1, 0); i1 = std::min(i1, i2); i0 = std::min(i0, i2 + 1 - band); } TargetIterator targets(subject_begin, subject_end, false, i1, qlen, d_begin); Matrix dp(band * 3, targets.cols); const Sv open_penalty(score_matrix.gap_open() + score_matrix.gap_extend()), extend_penalty(score_matrix.gap_extend()), frameshift_penalty(score_matrix.frame_shift()); SwipeProfile profile; #ifndef __SSSE3__ std::array target_scores; #endif Score best[ScoreTraits::CHANNELS]; int max_col[ScoreTraits::CHANNELS]; for (int i = 0; i < ScoreTraits::CHANNELS; ++i) { best[i] = ScoreTraits::zero_score(); max_col[i] = 0; } int j = 0; while (targets.active.size() > 0) { const int i0_ = std::max(i0, 0), i1_ = std::min(i1, qlen - 1); if (i0_ > i1_) break; typename Matrix::ColumnIterator it(dp.begin((i0_ - i0) * 3, j)); if (i0_ - i0 > 0) it.set_zero(); Sv vgap0, vgap1, vgap2, hgap, col_best; vgap0 = vgap1 = vgap2 = col_best = ScoreTraits::zero(); #ifdef __SSSE3__ profile.set(targets.get()); #else profile.set(targets.get(target_scores.data())); #endif for (int i = i0_; i <= i1_; ++i) { hgap = it.hgap(); Sv next = cell_update(it.sm3, it.sm4, it.sm2, profile.get(q[0][i]), extend_penalty, open_penalty, frameshift_penalty, hgap, vgap0, col_best); it.set_hgap(hgap); it.set_score(next); ++it; if (i >= qlen2) break; hgap = it.hgap(); next = cell_update(it.sm3, it.sm4, it.sm2, profile.get(q[1][i]), extend_penalty, open_penalty, frameshift_penalty, hgap, vgap1, col_best); it.set_hgap(hgap); it.set_score(next); ++it; if (i >= qlen3) break; hgap = it.hgap(); next = cell_update(it.sm3, it.sm4, it.sm2, profile.get(q[2][i]), extend_penalty, open_penalty, frameshift_penalty, hgap, vgap2, col_best); it.set_hgap(hgap); it.set_score(next); ++it; } #ifdef DP_STAT //stat.net_cells += targets.live * (i1_ - i0_ + 1) * 3; //stat.gross_cells += ScoreTraits<_sv>::CHANNELS * (i1_ - i0_ + 1) * 3; #endif Score col_best_[ScoreTraits::CHANNELS]; store_sv(col_best, col_best_); for (int i = 0; i < targets.active.size();) { int channel = targets.active[i]; if (!targets.inc(channel)) targets.active.erase(i); else ++i; if (col_best_[channel] > best[channel]) { best[channel] = col_best_[channel]; max_col[channel] = j; } } ++i0; ++i1; ++j; } list out; for (int i = 0; i < targets.n_targets; ++i) { if (best[i] < ScoreTraits::max_score()) { const int score = ScoreTraits::int_score(best[i]) * config.cbs_matrix_scale; const double evalue = score_matrix.evalue(score, qlen, (unsigned)subject_begin[i].seq.length()); if (score_matrix.report_cutoff(score, evalue)) out.push_back(traceback(q, strand, (int)query.source().length(), dp, subject_begin[i], d_begin[i], best[i], evalue, max_col[i], i, i0 - j, i1 - j)); } else overflow.push_back(subject_begin[i]); } return out; } template list banded_3frame_swipe_targets(std::vector::const_iterator begin, vector::const_iterator end, bool score_only, const TranslatedSequence &query, Strand strand, DpStat &stat, bool parallel, std::vector &overflow) { list out; for (vector::const_iterator i = begin; i < end; i += std::min((ptrdiff_t)ScoreTraits::CHANNELS, end - i)) { if (score_only) out.splice(out.end(), banded_3frame_swipe(query, strand, i, i + std::min(ptrdiff_t(ScoreTraits::CHANNELS), end - i), stat, parallel, overflow)); else out.splice(out.end(), banded_3frame_swipe(query, strand, i, i + std::min(ptrdiff_t(ScoreTraits::CHANNELS), end - i), stat, parallel, overflow)); } return out; } void banded_3frame_swipe_worker(std::vector::const_iterator begin, std::vector::const_iterator end, atomic *next, bool score_only, const TranslatedSequence *query, Strand strand, list *out, vector *overflow) { DpStat stat; size_t pos; vector of; while (begin + (pos = next->fetch_add(config.swipe_chunk_size, std::memory_order_relaxed)) < end) #if defined(__SSE2__) | defined(__ARM_NEON) if(score_only) out->splice(out->end(), banded_3frame_swipe_targets>(begin + pos, min(begin + pos + config.swipe_chunk_size, end), score_only, *query, strand, stat, true, of)); else out->splice(out->end(), banded_3frame_swipe_targets(begin + pos, min(begin + pos + config.swipe_chunk_size, end), score_only, *query, strand, stat, true, of)); #else out->splice(out->end(), banded_3frame_swipe_targets(begin + pos, min(begin + pos + config.swipe_chunk_size, end), score_only, *query, strand, stat, true, of)); #endif *overflow = std::move(of); } list banded_3frame_swipe(const TranslatedSequence &query, Strand strand, vector::iterator target_begin, vector::iterator target_end, DpStat &stat, bool score_only, bool parallel) { vector overflow16, overflow32; #if defined (__SSE2__) | defined(__ARM_NEON) TaskTimer timer("Banded 3frame swipe (sort)", parallel ? 3 : UINT_MAX); std::stable_sort(target_begin, target_end); list out; if (parallel) { timer.go("Banded 3frame swipe (run)"); vector threads; vector*> thread_out; vector> thread_overflow(config.threads_); atomic next(0); for (int i = 0; i < config.threads_; ++i) { thread_out.push_back(new list); threads.emplace_back(banded_3frame_swipe_worker, target_begin, target_end, &next, score_only, &query, strand, thread_out.back(), &thread_overflow[i]); } for (auto &t : threads) t.join(); timer.go("Banded 3frame swipe (merge)"); for (list* l : thread_out) { out.splice(out.end(), *l); delete l; } overflow16.reserve(std::accumulate(thread_overflow.begin(), thread_overflow.end(), (size_t)0, [](size_t n, const vector &v) { return n + v.size(); })); for (const vector &v : thread_overflow) overflow16.insert(overflow16.end(), v.begin(), v.end()); } else { if(score_only) out = banded_3frame_swipe_targets>(target_begin, target_end, score_only, query, strand, stat, false, overflow16); else out = banded_3frame_swipe_targets(target_begin, target_end, score_only, query, strand, stat, false, overflow16); } out.splice(out.end(), banded_3frame_swipe_targets(overflow16.begin(), overflow16.end(), score_only, query, strand, stat, false, overflow32)); return out; #else return banded_3frame_swipe_targets(target_begin, target_end, score_only, query, strand, stat, false, overflow32); #endif } } DISPATCH_7(std::list, banded_3frame_swipe, const TranslatedSequence&, query, Strand, strand, std::vector::iterator, target_begin, std::vector::iterator, target_end, DpStat&, stat, bool, score_only, bool, parallel)bbuchfink-diamond-08b3cbc/src/dp/swipe/banded_matrix.h000066400000000000000000000263341506104011400230370ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "util/data_structures/mem_buffer.h" #include "stats/score_matrix.h" using std::pair; namespace DP { namespace BandedSwipe { namespace DISPATCH_ARCH { template struct Matrix { using Score = typename ::DISPATCH_ARCH::ScoreTraits::Score; static constexpr int CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; struct ColumnIterator { ColumnIterator(ScoreVector* hgap_front, ScoreVector* score_front) : hgap_ptr_(hgap_front), score_ptr_(score_front) { } inline void operator++() { ++hgap_ptr_; ++score_ptr_; } inline ScoreVector hgap() const { return *(hgap_ptr_ + 1); } inline ScoreVector diag() const { return *score_ptr_; } inline void set_hgap(const ScoreVector& x) { *hgap_ptr_ = x; } inline void set_score(const ScoreVector& x) { *score_ptr_ = x; } std::nullptr_t stat() { return nullptr; } std::nullptr_t hstat() { return nullptr; } std::nullptr_t trace_mask() { return nullptr; } void set_hstat(std::nullptr_t) {} inline void set_zero() {} ScoreVector*hgap_ptr_, *score_ptr_; }; Matrix(int band, size_t cols, ScoreVector init = ScoreVector()) : band_(band) { hgap_.resize(band + 1); score_.resize(band); std::fill(hgap_.begin(), hgap_.end(), init); std::fill(score_.begin(), score_.end(), init); } void init_channel_diag(int channel, int offset) { Score* ptr = (Score*)score_.begin(); ptr[offset * CHANNELS + channel] = 0; } void init_channel_nw(int channel, int offset, ::Score gap_open, ::Score gap_extend) { Score* ptr = (Score*)score_.begin(); ptr[offset * CHANNELS + channel] = 0; //Score s = -gap_open; for (int i = offset - 1; i >= 0; --i) { //s -= gap_extend; //ptr[i * CHANNELS + channel] = s; ptr[i * CHANNELS + channel] = std::numeric_limits::min(); } //s = -gap_open; for (int i = offset + 1; i < (int)score_.size(); ++i) { //s -= gap_extend; //ptr[i * CHANNELS + channel] = s; ptr[i * CHANNELS + channel] = std::numeric_limits::min(); } ptr = (Score*)hgap_.begin(); for (size_t i = 0; i < hgap_.size(); ++i) ptr[i * CHANNELS + channel] = std::numeric_limits::min(); } void init_channels_nw(int offset, ::Score gap_open, ::Score gap_extend) { Score* ptr = (Score*)score_.begin(); std::fill(&ptr[offset * CHANNELS], &ptr[(offset+1) * CHANNELS], 0); Score s = -gap_open; for (int i = offset - 1; i >= 0; --i) { s -= gap_extend; std::fill(&ptr[i * CHANNELS], &ptr[(i + 1) * CHANNELS], s); } s = -gap_open; for (int i = offset + 1; i < (int)score_.size(); ++i) { s -= gap_extend; std::fill(&ptr[i * CHANNELS], &ptr[(i + 1) * CHANNELS], s); } ptr = (Score*)hgap_.begin(); std::fill(ptr, ptr + hgap_.size() * CHANNELS, std::numeric_limits::min()); } inline ColumnIterator begin(int offset, int col) { return ColumnIterator(&hgap_[offset], &score_[offset]); } int band() const { return band_; } ScoreVector operator[](int i) const { return score_[i]; } #if defined(__APPLE__) || !defined(USE_TLS) MemBuffer hgap_, score_; #else static thread_local MemBuffer hgap_, score_; #endif private: int band_; }; template struct TracebackMatrix { typedef void* Stat; typedef typename ::DISPATCH_ARCH::ScoreTraits<_sv>::Score Score; static constexpr int CHANNELS = ::DISPATCH_ARCH::ScoreTraits<_sv>::CHANNELS; struct ColumnIterator { ColumnIterator(_sv* hgap_front, _sv* score_front, _sv* score_front1) : hgap_ptr_(hgap_front), score_ptr_(score_front), score_ptr1_(score_front1) { } inline void operator++() { ++hgap_ptr_; ++score_ptr_; ++score_ptr1_; } inline _sv hgap() const { return *(hgap_ptr_ + 1); } inline _sv diag() const { return *score_ptr_; } inline void set_hgap(const _sv& x) { *hgap_ptr_ = x; } inline void set_score(const _sv& x) { *score_ptr1_ = x; } void set_zero() { *(score_ptr1_ - 1) = _sv(); } std::nullptr_t stat() { return nullptr; } std::nullptr_t hstat() { return nullptr; } std::nullptr_t trace_mask() { return nullptr; } void set_hstat(std::nullptr_t) {} _sv *hgap_ptr_, *score_ptr_, *score_ptr1_; }; struct TracebackIterator { TracebackIterator(const Score *score, size_t band, int i, int j) : band_(band), score_(score), i(i), j(j) { assert(i >= 0 && j >= 0); } Score score() const { return *score_; } Score diag() const { return *(score_ - band_ * CHANNELS); } void walk_diagonal() { score_ -= band_ * ::DISPATCH_ARCH::ScoreTraits<_sv>::CHANNELS; --i; --j; assert(i >= -1 && j >= -1); } pair walk_gap(int d0, int d1) { const int i0 = std::max(d0 + j, 0), j0 = std::max(i - d1, -1); const Score *h = score_ - (band_ - 1) * CHANNELS, *h0 = score_ - (j - j0) * (band_ - 1) * CHANNELS; const Score *v = score_ - CHANNELS, *v0 = score_ - (i - i0 + 1) * CHANNELS; const Score e = score_matrix.gap_extend(); Score score = this->score() + (Score)score_matrix.gap_open() + e; int l = 1; while (v > v0 && h > h0) { if (score == *h) { walk_hgap(h, l); return std::make_pair(op_deletion, l); } else if (score == *v) { walk_vgap(v, l); return std::make_pair(op_insertion, l); } h -= (band_ - 1) * CHANNELS; v -= CHANNELS; ++l; score += e; } while (v > v0) { if (score == *v) { walk_vgap(v, l); return std::make_pair(op_insertion, l); } v -= CHANNELS; ++l; score += e; } while (h > h0) { if (score == *h) { walk_hgap(h, l); return std::make_pair(op_deletion, l); } h -= (band_ - 1) * CHANNELS; ++l; score += e; } throw std::runtime_error("Traceback error."); } void walk_hgap(const Score *h, int l) { score_ = h; j -= l; assert(i >= -1 && j >= -1); } void walk_vgap(const Score *v, int l) { score_ = v; i -= l; assert(i >= -1 && j >= -1); } const size_t band_; const Score *score_; int i, j; }; TracebackIterator traceback(size_t col, int i0, int j, int query_len, size_t channel, Score score) const { const int i_ = std::max(-i0, 0), i1 = (int)std::min(band_, size_t(query_len - i0)); const Score *s = (Score*)(&score_[col*band_ + i_]) + channel; for (int i = i_; i < i1; ++i, s += CHANNELS) if (*s == score) return TracebackIterator(s, band_, i0 + i, j); throw std::runtime_error("Trackback error."); } TracebackMatrix(size_t band, size_t cols) : band_(band) { hgap_.resize(band + 1); score_.resize(band * (cols + 1)); std::fill(hgap_.begin(), hgap_.end(), _sv()); std::fill(score_.begin(), score_.begin() + band, _sv()); } inline ColumnIterator begin(size_t offset, size_t col) { return ColumnIterator(&hgap_[offset], &score_[col*band_ + offset], &score_[(col + 1)*band_ + offset]); } _sv operator[](int i) const { return _sv(); } MemBuffer<_sv> hgap_, score_; private: const size_t band_; }; template struct TracebackVectorMatrix { typedef typename ::DISPATCH_ARCH::ScoreTraits::TraceMask TraceMask; typedef void* Stat; struct ColumnIterator { ColumnIterator(Sv* hgap_front, Sv* score_front, TraceMask* trace_mask_front) : hgap_ptr_(hgap_front), score_ptr_(score_front), trace_mask_ptr_(trace_mask_front) { } inline void operator++() { ++hgap_ptr_; ++score_ptr_; ++trace_mask_ptr_; } inline Sv hgap() const { return *(hgap_ptr_ + 1); } inline Sv diag() const { return *score_ptr_; } inline TraceMask* trace_mask() { return trace_mask_ptr_; } inline void set_hgap(const Sv& x) { *hgap_ptr_ = x; } inline void set_score(const Sv& x) { *score_ptr_ = x; } std::nullptr_t stat() { return nullptr; } std::nullptr_t hstat() { return nullptr; } void set_hstat(std::nullptr_t) {} inline void set_zero() {} Sv *hgap_ptr_, *score_ptr_; TraceMask* trace_mask_ptr_; }; struct TracebackIterator { TracebackIterator(const TraceMask *mask, size_t band, int i, int j, const int channel) : band_(band), mask_(mask), channel_mask_vgap(TraceMask::vmask(channel)), channel_mask_hgap(TraceMask::hmask(channel)), i(i), j(j) { assert(i >= 0 && j >= 0); } TraceMask mask() const { return *mask_; } void walk_diagonal() { mask_ -= band_; --i; --j; assert(i >= -1 && j >= -1); } pair walk_gap() { if (mask_->gap & channel_mask_vgap) { int l = 0; do { ++l; --i; --mask_; } while (((mask_->open & channel_mask_vgap) == 0) && (i > 0)); return std::make_pair(op_insertion, l); } else { int l = 0; do { ++l; --j; mask_ -= band_ - 1; } while (((mask_->open & channel_mask_hgap) == 0) && (j > 0)); return std::make_pair(op_deletion, l); } } const size_t band_; const TraceMask* mask_; const decltype(TraceMask::gap) channel_mask_vgap, channel_mask_hgap; int i, j; }; TracebackIterator traceback(size_t col, int i0, int band_i, int j, int query_len, const int channel) const { return TracebackIterator(&trace_mask_[col*band_ + band_i], band_, i0 + band_i, j, channel); } TracebackVectorMatrix(int band, size_t cols) : band_(band) { hgap_.resize(band + 1); score_.resize(band); trace_mask_.resize((cols + 1) * band); std::fill(hgap_.begin(), hgap_.end(), Sv()); std::fill(score_.begin(), score_.end(), Sv()); } inline ColumnIterator begin(int offset, int col) { return ColumnIterator(&hgap_[offset], &score_[offset], &trace_mask_[size_t(col + 1)*(size_t)band_ + (size_t)offset]); } int band() const { return band_; } Sv operator[](int i) const { return Sv(); } #if defined(__APPLE__) || !defined(USE_TLS) MemBuffer hgap_, score_; #else static thread_local MemBuffer<_sv> hgap_, score_; #endif MemBuffer trace_mask_; private: int band_; }; #if !defined(__APPLE__) && defined(USE_TLS) template thread_local MemBuffer Matrix::hgap_; template thread_local MemBuffer Matrix::score_; template thread_local MemBuffer TracebackVectorMatrix::hgap_; template thread_local MemBuffer TracebackVectorMatrix::score_; #endif template struct SelectMatrix { }; template struct SelectMatrix { using Type = TracebackVectorMatrix; }; template struct SelectMatrix { using Type = Matrix; }; }}}bbuchfink-diamond-08b3cbc/src/dp/swipe/banded_swipe.h000066400000000000000000000332621506104011400226600ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include "../dp.h" #include "swipe.h" #include "target_iterator.h" #include "basic/config.h" #include "util/data_structures/range_partition.h" #include "banded_matrix.h" using std::list; using std::pair; using std::vector; using std::array; using namespace DISPATCH_ARCH; namespace DP { namespace BandedSwipe { namespace DISPATCH_ARCH { template Hsp traceback(Cbs bias_correction, const TracebackMatrix &dp, const DpTarget &target, int d_begin, typename ScoreTraits::Score max_score, double evalue, int max_col, int channel, int i0, int i1, int max_band_i, Void, Params& p) { typedef typename ScoreTraits::Score Score; const int j0 = i1 - (target.d_end - 1), d1 = target.d_end; typename TracebackMatrix::TracebackIterator it(dp.traceback(max_col + 1, i0 + max_col, j0 + max_col, (int)p.query.length(), channel, max_score)); Hsp out(true); out.swipe_target = target.target_idx; out.swipe_bin = p.swipe_bin; out.score = ScoreTraits::int_score(max_score); out.evalue = evalue; out.bit_score = score_matrix.bitscore(out.score); out.corrected_bit_score = score_matrix.bitscore_corrected(out.score, p.query.length(), target.true_target_len); out.transcript.reserve(size_t(out.score * config.transcript_len_estimate)); out.matrix = target.matrix; out.frame = p.frame.index(); out.d_begin = target.d_begin; out.d_end = target.d_end; out.query_range.end_ = it.i + 1; out.subject_range.end_ = it.j + 1; while (it.score() > ScoreTraits::zero_score()) { const Letter q = p.query[it.i], s = target.seq[it.j]; const Score m = score_matrix(q, s), score = it.score(); const Score m2 = add_cbs_scalar(m, bias_correction[it.i]); if (score == saturated_add(it.diag(), m2)) { out.push_match(q, s, m > (Score)0); it.walk_diagonal(); } else { const pair g(it.walk_gap(d_begin, d1)); out.push_gap(g.first, g.second, target.seq.data() + it.j + g.second); } } out.query_range.begin_ = it.i + 1; out.subject_range.begin_ = it.j + 1; out.transcript.reverse(); out.transcript.push_terminator(); out.target_seq = target.seq; out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, p.frame), TranslatedPosition(out.query_range.end_, p.frame), p.query_source_len); out.subject_source_range = out.subject_range; out.approx_id = out.approx_id_percent(p.query, target.seq); return out; } template Hsp traceback(Cbs bias_correction, const Matrix &dp, const DpTarget &target, int d_begin, typename ScoreTraits::Score max_score, double evalue, int max_col, int channel, int i0, int i1, int max_band_i, const StatType& stats, Params& p) { Hsp out(false); out.swipe_target = target.target_idx; out.swipe_bin = p.swipe_bin; out.score = ScoreTraits::int_score(max_score); if (!target.adjusted_matrix()) out.score *= config.cbs_matrix_scale; out.evalue = evalue; out.bit_score = score_matrix.bitscore(out.score); out.corrected_bit_score = score_matrix.bitscore_corrected(out.score, p.query.length(), target.true_target_len); out.frame = p.frame.index(); out.matrix = target.matrix; const int j0 = i1 - (target.d_end - 1), i1_ = i0 + max_col + max_band_i + 1, j1_ = j0 + max_col + 1; if (target.carry_over.i1 == 0) { out.d_begin = target.d_begin; out.d_end = target.d_end; out.query_range.end_ = i1_; out.subject_range.end_ = j1_; out.target_seq = target.seq; } else { out.d_begin = -target.d_end + (int)p.query.length() - (int)target.seq.length() + 1; out.d_end = -target.d_begin + (int)p.query.length() - (int)target.seq.length() + 1; out.query_range.end_ = target.carry_over.i1; out.subject_range.end_ = target.carry_over.j1; out.identities = target.carry_over.ident; out.length = target.carry_over.len; out.query_range.begin_ = (int)p.query.length() - i1_; out.subject_range.begin_ = (int)target.seq.length() - j1_; out.approx_id = out.approx_id_percent(Sequence(p.query.reverse()), Sequence(target.seq.reverse())); } assign_stats(out, stats); out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, p.frame), TranslatedPosition(out.query_range.end_, p.frame), p.query_source_len); out.subject_source_range = out.subject_range; return out; } template Hsp traceback(Cbs bias_correction, const TracebackVectorMatrix &dp, const DpTarget &target, int d_begin, typename ScoreTraits::Score max_score, double evalue, int max_col, int channel, int i0, int i1, int max_band_i, Void, Params& p) { typedef typename ScoreTraits::Score Score; typedef typename ScoreTraits::TraceMask TraceMask; const auto channel_mask = TraceMask::vmask(channel) | TraceMask::hmask(channel); const int j0 = i1 - (target.d_end - 1), d1 = target.d_end; typename TracebackVectorMatrix::TracebackIterator it(dp.traceback(max_col + 1, i0 + max_col, max_band_i, j0 + max_col, (int)p.query.length(), channel)); Hsp out(true); out.swipe_target = target.target_idx; out.swipe_bin = p.swipe_bin; out.target_seq = target.seq; out.score = ScoreTraits::int_score(max_score); out.evalue = evalue; out.bit_score = score_matrix.bitscore(out.score); out.corrected_bit_score = score_matrix.bitscore_corrected(out.score, p.query.length(), target.true_target_len); out.transcript.reserve(size_t(out.score * config.transcript_len_estimate)); out.matrix = target.matrix; out.frame = p.frame.index(); out.d_begin = target.d_begin; out.d_end = target.d_end; out.query_range.end_ = it.i + 1; out.subject_range.end_ = it.j + 1; const int end_score = out.score; const bool adjusted_matrix = target.adjusted_matrix(); if (!adjusted_matrix) out.score *= config.cbs_matrix_scale; int score = 0; if(adjusted_matrix) throw std::runtime_error("Adjusted matrix not supported in TracebackVectorMatrix."); //const int* matrix = adjusted_matrix ? target.matrix->scores32.data() : score_matrix.matrix32(); const int* matrix = score_matrix.matrix32(); while (it.i >= 0 && it.j >= 0 && score < end_score) { if ((it.mask().gap & channel_mask) == 0) { const Letter q = p.query[it.i], s = target.seq[it.j]; const int m = matrix[int(s) * 32 + (int)q]; const int m2 = adjusted_matrix ? m : add_cbs_scalar(m, bias_correction[it.i]); score += m2; out.push_match(q, s, m > (Score)0); it.walk_diagonal(); } else { const pair g(it.walk_gap()); out.push_gap(g.first, g.second, target.seq.data() + it.j + g.second); score -= (score_matrix.gap_open() + g.second * score_matrix.gap_extend()) * target.matrix_scale(); } } if (score != end_score) throw std::runtime_error("Traceback error."); out.query_range.begin_ = it.i + 1; out.subject_range.begin_ = it.j + 1; out.transcript.reverse(); out.transcript.push_terminator(); out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, p.frame), TranslatedPosition(out.query_range.end_, p.frame), p.query_source_len); out.subject_source_range = out.subject_range; out.approx_id = out.approx_id_percent(p.query, target.seq); return out; } template list swipe(const TargetVec::const_iterator subject_begin, const TargetVec::const_iterator subject_end, Cbs composition_bias, TargetVec& overflow, Params& p) { typedef typename ScoreTraits::Score Score; using Cell = typename Cfg::Cell; using Matrix = typename SelectMatrix::Type; using RowCounter = typename Cfg::RowCounter; using IdMask = typename Cfg::IdMask; using StatType = decltype(extract_stats(Cell(), int())); constexpr int CHANNELS = ScoreTraits::CHANNELS; assert(subject_end - subject_begin <= CHANNELS); const int qlen = (int)p.query.length(); int band = 0; for (TargetVec::const_iterator j = subject_begin; j < subject_end; ++j) band = std::max(band, j->d_end - j->d_begin); if (band > RowCounter::MAX_LEN) throw std::runtime_error("Band size exceeds row counter maximum."); int i1 = INT_MAX, d_begin[CHANNELS]; const int target_count = int(subject_end - subject_begin); #ifdef STRICT_BAND int band_offset[CHANNELS]; #endif for (int i = 0; i < target_count; ++i) { d_begin[i] = subject_begin[i].d_end - band; #ifdef STRICT_BAND band_offset[i] = subject_begin[i].d_begin - d_begin[i]; #endif i1 = std::min(i1, std::max(subject_begin[i].d_end - 1, 0)); } int i0 = i1 + 1 - band; #ifdef STRICT_BAND RangePartition band_parts(band_offset, target_count, band); #endif ::DISPATCH_ARCH::TargetIterator targets(subject_begin, subject_end, p.reverse_targets, i1, qlen, d_begin); Matrix dp(band, targets.cols); const uint32_t cbs_mask = targets.cbs_mask(); const Score go = score_matrix.gap_open() + score_matrix.gap_extend(), go_s = go * (Score)config.cbs_matrix_scale, ge = score_matrix.gap_extend(), ge_s = ge * (Score)config.cbs_matrix_scale; const Sv open_penalty = blend_sv(go, go_s, cbs_mask), extend_penalty = blend_sv(ge, ge_s, cbs_mask); SwipeProfile profile; array target_scores; Score best[CHANNELS]; int max_col[CHANNELS], max_band_row[CHANNELS]; StatType stats[CHANNELS]; std::fill(best, best + CHANNELS, ScoreTraits::zero_score()); std::fill(max_col, max_col + CHANNELS, 0); std::fill(max_band_row, max_band_row + CHANNELS, 0); CBSBuffer cbs_buf(composition_bias, qlen, cbs_mask); int j = 0; while (targets.active.size() > 0) { const int i0_ = std::max(i0, 0), i1_ = std::min(i1, qlen - 1) + 1, band_offset = i0_ - i0; if (i0_ >= i1_) break; typename Matrix::ColumnIterator it(dp.begin(band_offset, j)); Cell vgap = Cell(), hgap = Cell(); Sv col_best = Sv(); RowCounter row_counter(band_offset); if (band_offset > 0) it.set_zero(); const auto target_seqv = targets.get(); const Sv target_seq = Sv(target_seqv); if (cbs_mask != 0) { if (targets.custom_matrix_16bit) profile.set(targets.get32().data()); else profile.set(targets.get(target_scores.data())); } else { #ifdef __SSSE3__ profile.set(target_seqv); #else profile.set(targets.get(target_scores.data())); #endif } #ifdef DP_STAT const uint64_t live = targets.live(); #endif #ifdef STRICT_BAND for (int part = 0; part < band_parts.count(); ++part) { const int i_begin = std::max(i0 + band_parts.begin(part), i0_); const int i_end = std::min(i0 + band_parts.end(part), i1_); const Sv target_mask = load_sv(band_parts.mask(part)); vgap += target_mask; #ifdef DP_STAT p.stat.inc(Statistics::GROSS_DP_CELLS, uint64_t(i_end - i_begin) * CHANNELS); p.stat.inc(Statistics::NET_DP_CELLS, uint64_t(i_end - i_begin) * popcount64(live & band_parts.bit_mask(part))); #endif for (int i = i_begin; i < i_end; ++i) { #else for (int i = i0_; i < i1_; ++i) { #endif hgap = it.hgap(); auto stat_h = it.hstat(); Sv match_scores = profile.get(p.query[i]); #ifdef STRICT_BAND hgap += target_mask; match_scores += target_mask; #endif const Cell next = swipe_cell_update(it.diag(), match_scores, cbs_buf(i), extend_penalty, open_penalty, hgap, vgap, col_best, it.trace_mask(), row_counter, IdMask(p.query[i], target_seq)); /*std::cout << "j=" << j << " i=" << i << " score=" << ScoreTraits<_sv>::int_score(extract_channel(next, 0)) << " q=" << value_traits.alphabet[query[i]] << " t=" << value_traits.alphabet[extract_channel(target_seq, 0)] << extract_stats(next, 0) << std::endl;*/ it.set_hgap(hgap); it.set_score(next); ++it; } #ifdef STRICT_BAND } #endif Score col_best_[CHANNELS], i_max[CHANNELS]; store_sv(col_best, col_best_); row_counter.store(i_max); for (int i = 0; i < targets.active.size();) { int channel = targets.active[i]; if (!targets.inc(channel)) targets.active.erase(i); else ++i; if (col_best_[channel] > best[channel]) { best[channel] = col_best_[channel]; max_col[channel] = j; max_band_row[channel] = ScoreTraits::int_score(i_max[channel]); stats[channel] = extract_stats(dp[max_band_row[channel]], channel); //std::cout << "stats[" << channel << "]=" << stats[channel] << std::endl; } } ++i0; ++i1; ++j; } list out; TaskTimer timer; for (int i = 0; i < targets.n_targets; ++i) { if (best[i] < ScoreTraits::max_score() && !overflow_stats(stats[i])) { int score = ScoreTraits::int_score(best[i]); if (!subject_begin[i].adjusted_matrix()) score *= config.cbs_matrix_scale; const double evalue = score_matrix.evalue(score, qlen, subject_begin[i].true_target_len); if (score > 0 && score_matrix.report_cutoff(score, evalue)) { out.push_back(traceback(composition_bias, dp, subject_begin[i], d_begin[i], best[i], evalue, max_col[i], i, i0 - j, i1 - j, max_band_row[i], stats[i], p)); } } else overflow.push_back(subject_begin[i]); } p.stat.inc(Statistics::TIME_TRACEBACK, timer.microseconds()); return out; } }}}bbuchfink-diamond-08b3cbc/src/dp/swipe/cell_update.h000066400000000000000000000104631506104011400225130ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "stat_cell.h" template struct DummyRowCounter { typedef typename ::DISPATCH_ARCH::ScoreTraits::Score Score; DummyRowCounter() {} DummyRowCounter(int) {} void store(Score* ptr) { std::fill(ptr, ptr + ::DISPATCH_ARCH::ScoreTraits::CHANNELS, ::DISPATCH_ARCH::ScoreTraits::zero_score()); } FORCE_INLINE void inc(const Sv&, const Sv&) {} enum { MAX_LEN = INT_MAX }; }; template struct VectorRowCounter { typedef typename ::DISPATCH_ARCH::ScoreTraits::Score Score; VectorRowCounter(int i) : i(::DISPATCH_ARCH::ScoreTraits::zero_score() + Score(i)), i_max() { } void inc(const Sv& best, const Sv& current_cell) { i_max = blend(i_max, i, best == current_cell); i += Sv(Score(1)); } void store(Score* ptr) { store_sv(i_max, ptr); } static constexpr int MAX_LEN = ::DISPATCH_ARCH::ScoreTraits::max_int_score(); Sv i; Sv i_max; }; template FORCE_INLINE Sv add_cbs(const Sv& v, void*) { return v; } template FORCE_INLINE Sv add_cbs(const Sv& v, const Sv& query_bias) { return v + query_bias; } template FORCE_INLINE Score add_cbs_scalar(Score x, int8_t b) { return x + Score(b); } template FORCE_INLINE Score add_cbs_scalar(Score x, void* b) { return x; } template FORCE_INLINE void make_gap_mask(typename ::DISPATCH_ARCH::ScoreTraits::TraceMask* trace_mask, const Sv& current_cell, const Sv& vertical_gap, const Sv& horizontal_gap) { trace_mask->gap = ::DISPATCH_ARCH::ScoreTraits::TraceMask::make(cmp_mask(current_cell, vertical_gap), cmp_mask(current_cell, horizontal_gap)); } template FORCE_INLINE void make_gap_mask(std::nullptr_t, const Sv&, const Sv&, const Sv&) { } template FORCE_INLINE void make_open_mask(typename ::DISPATCH_ARCH::ScoreTraits::TraceMask* trace_mask, const Sv& open, const Sv& vertical_gap, const Sv& horizontal_gap) { trace_mask->open = ::DISPATCH_ARCH::ScoreTraits::TraceMask::make(cmp_mask(vertical_gap, open), cmp_mask(horizontal_gap, open)); } template FORCE_INLINE void make_open_mask(std::nullptr_t, const Sv&, const Sv&, const Sv&) { } template FORCE_INLINE void set_max(Sv& v, const Sv& x) { v.max(x); } FORCE_INLINE void set_max(int32_t& v, const int32_t x) { v = std::max(v, x); } template FORCE_INLINE Cell swipe_cell_update(const Cell& diagonal_cell, const Sv& scores, Cbs query_bias, const Sv& gap_extension, const Sv& gap_open, Cell& horizontal_gap, Cell& vertical_gap, Sv& best, TraceMask trace_mask, RowCounter& row_counter, const IdMask& id_mask) { Cell current_cell = diagonal_cell; current_cell += add_cbs(scores, query_bias); //Sv open_v = current_cell; update_stats(current_cell, horizontal_gap, vertical_gap, id_mask); set_max(current_cell, horizontal_gap); set_max(current_cell, vertical_gap); saturate(current_cell); //open_v = blend(Sv(), current_cell, open_v == current_cell); make_gap_mask(trace_mask, current_cell, vertical_gap, horizontal_gap); set_max(best, static_cast(current_cell)); row_counter.inc(best, current_cell); vertical_gap -= gap_extension; horizontal_gap -= gap_extension; Cell open = current_cell; open -= gap_open; update_open(open, current_cell); set_max(horizontal_gap, open); set_max(vertical_gap, open); make_open_mask(trace_mask, open, vertical_gap, horizontal_gap); return current_cell; }bbuchfink-diamond-08b3cbc/src/dp/swipe/config.h000066400000000000000000000041171506104011400214760ustar00rootroot00000000000000#pragma once #include "basic/sequence.h" #include "util/geo/geo.h" #include "../score_profile.h" namespace DP { namespace AnchoredSwipe { struct Options { const int16_t* const* profile, * const* profile_rev; }; struct Stats { Stats(): gross_cells(0), net_cells(0) {} int64_t gross_cells, net_cells; }; template struct Target { Target() {} //Target(Sequence seq, Loc d_begin, Loc d_end, const Score* const* profile, Loc query_len, int64_t target_idx, bool reverse): Target(Sequence seq, Loc d_begin, Loc d_end, Loc query_start, Loc query_len, int64_t target_idx, bool reverse) : seq(seq), d_begin(d_begin), d_end(d_end), query_start(query_start), query_length(query_len), target_idx(target_idx), reverse(reverse), score(0), query_end(0), target_end(0) {} Sequence seq; Loc d_begin, d_end; //std::array profile; Loc query_start, query_length; int64_t target_idx; bool reverse; Score score; Loc query_end, target_end; const LongScoreProfile* profile, *profile_rev; bool blank() const { return seq.length() == 0; } void reset() { seq = Sequence(); } Loc band() const { return d_end - d_begin; } bool operator<(const Target& t) const { return band() < t.band(); } static bool cmp_target_idx(const Target& a, const Target& b) { return a.target_idx < b.target_idx; } std::pair cells() const { int64_t n = 0, g = 0; for (int j = 0; j < seq.length(); ++j) { int i0 = std::max(Geo::i(j, d_begin), 0), i1 = std::min(Geo::i(j, d_end), query_length); //assert(i1 - i0 >= 0); n += std::max(i1 - i0, 0); g += d_end - d_begin; } return { g,n }; } int64_t gross_cells() const { return int64_t(d_end - d_begin) * seq.length(); } }; template std::pair limits(const Target* targets, size_t count) { int band = 0, target_len = 0; for (const Target* i = targets; i < targets + count; ++i) { assert(i->band() > 0); band = std::max(band, i->band()); target_len = std::max(target_len, i->seq.length()); } return { band,target_len }; } }}bbuchfink-diamond-08b3cbc/src/dp/swipe/full_matrix.h000066400000000000000000000144431506104011400225620ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include "util/data_structures/mem_buffer.h" namespace DP { namespace Swipe { namespace DISPATCH_ARCH { template struct Matrix { struct ColumnIterator { ColumnIterator(Sv* hgap_front, Sv* score_front) : hgap_ptr_(hgap_front), score_ptr_(score_front) { } inline void operator++() { ++hgap_ptr_; ++score_ptr_; } inline Sv hgap() const { return *hgap_ptr_; } inline Sv diag() const { return *score_ptr_; } inline void set_hgap(const Sv& x) { *hgap_ptr_ = x; } inline void set_score(const Sv& x) { *score_ptr_ = x; } std::nullptr_t trace_mask() { return nullptr; } Sv *hgap_ptr_, *score_ptr_; }; Matrix(int rows, int) { hgap_.resize(rows); score_.resize(rows + 1); const auto z = Sv(); std::fill(hgap_.begin(), hgap_.end(), z); std::fill(score_.begin(), score_.end(), z); } inline ColumnIterator begin(int) { return ColumnIterator(hgap_.begin(), score_.begin()); } void set_zero(int c) { const int l = (int)hgap_.size(); const auto z = extract_channel(Sv(), 0); for (int i = 0; i < l; ++i) { set_channel(hgap_[i], c, z); set_channel(score_[i], c, z); } set_channel(score_[l], c, z); } constexpr int cols() const { return 1; } Sv operator[](int i) const { return score_[i + 1]; } private: #if defined(__APPLE__) || !defined(USE_TLS) MemBuffer hgap_, score_; #else static thread_local MemBuffer hgap_, score_; #endif }; #if !defined(__APPLE__) && defined(USE_TLS) template thread_local MemBuffer Matrix::hgap_; template thread_local MemBuffer Matrix::score_; #endif template struct TracebackVectorMatrix { typedef typename ::DISPATCH_ARCH::ScoreTraits::TraceMask TraceMask; typedef void* Stat; struct ColumnIterator { ColumnIterator(Sv* hgap_front, Sv* score_front, TraceMask* trace_mask_front) : hgap_ptr_(hgap_front), score_ptr_(score_front), trace_mask_ptr_(trace_mask_front) { } inline void operator++() { ++hgap_ptr_; ++score_ptr_; ++trace_mask_ptr_; } inline Sv hgap() const { return *hgap_ptr_; } inline Sv diag() const { return *score_ptr_; } inline TraceMask* trace_mask() { return trace_mask_ptr_; } inline void set_hgap(const Sv& x) { *hgap_ptr_ = x; } inline void set_score(const Sv& x) { *score_ptr_ = x; } std::nullptr_t stat() { return nullptr; } std::nullptr_t hstat() { return nullptr; } void set_hstat(std::nullptr_t) {} inline void set_zero() {} Sv* hgap_ptr_, *score_ptr_; TraceMask* trace_mask_ptr_; }; struct TracebackIterator { TracebackIterator(const TraceMask *mask, const TraceMask* mask_begin, const TraceMask* mask_end, int rows, int i, int j, int channel) : rows_(rows), mask_(mask), mask_begin_(mask_begin), mask_end_(mask_end), channel_mask_vgap(TraceMask::vmask(channel)), channel_mask_hgap(TraceMask::hmask(channel)), i(i), j(j) { assert(i >= 0 && j >= 0); } void wrap_mask() { if (mask_ < mask_begin_) mask_ = mask_end_ - (mask_begin_ - mask_); } TraceMask mask() const { return *mask_; } void walk_diagonal() { mask_ -= rows_ + 1; wrap_mask(); --i; --j; assert(i >= -1 && j >= -1); } std::pair walk_gap() { if (mask_->gap & channel_mask_vgap) { int l = 0; do { ++l; --i; --mask_; } while (((mask_->open & channel_mask_vgap) == 0) && (i > 0)); return std::make_pair(op_insertion, l); } else { int l = 0; do { ++l; --j; mask_ -= rows_; wrap_mask(); } while (((mask_->open & channel_mask_hgap) == 0) && (j > 0)); return std::make_pair(op_deletion, l); } } const int rows_; const TraceMask* mask_, *mask_begin_, *mask_end_; const decltype(TraceMask::gap) channel_mask_vgap, channel_mask_hgap; int i, j; }; TracebackIterator traceback(int col, int i, int j, int channel) const { return TracebackIterator(&trace_mask_[col*rows_ + i], trace_mask_.begin(), trace_mask_.end(), rows_, i, j, channel); } TracebackVectorMatrix(int rows, int cols) : rows_(rows), cols_(cols) { hgap_.resize(rows); score_.resize(rows + 1); trace_mask_.resize(cols * rows); std::fill(hgap_.begin(), hgap_.end(), Sv()); std::fill(score_.begin(), score_.end(), Sv()); } inline ColumnIterator begin(int col) { return ColumnIterator(hgap_.begin(), score_.begin(), &trace_mask_[col*rows_]); } void set_zero(int c) { const int l = (int)hgap_.size(); for (int i = 0; i < l; ++i) { set_channel(hgap_[i], c, ::DISPATCH_ARCH::ScoreTraits::zero_score()); set_channel(score_[i], c, ::DISPATCH_ARCH::ScoreTraits::zero_score()); } set_channel(score_[l], c, ::DISPATCH_ARCH::ScoreTraits::zero_score()); } int cols() const { return cols_; } Sv operator[](int i) const { return Sv(); } #if defined(__APPLE__) || !defined(USE_TLS) MemBuffer hgap_, score_; #else static thread_local MemBuffer hgap_, score_; #endif MemBuffer trace_mask_; private: int rows_, cols_; }; #if !defined(__APPLE__) && defined(USE_TLS) template thread_local MemBuffer TracebackVectorMatrix::hgap_; template thread_local MemBuffer TracebackVectorMatrix::score_; #endif template struct SelectMatrix { }; template struct SelectMatrix { using Type = TracebackVectorMatrix; }; template struct SelectMatrix { using Type = Matrix; }; }}}bbuchfink-diamond-08b3cbc/src/dp/swipe/full_swipe.h000066400000000000000000000236121506104011400224030ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include "swipe.h" #include "basic/sequence.h" #include "target_iterator.h" #include "full_matrix.h" #include "stat_cell.h" #include "../score_vector_int16.h" #include "../score_vector_int8.h" using std::vector; using std::list; using std::pair; using std::max; using namespace DISPATCH_ARCH; namespace DP { namespace Swipe { namespace DISPATCH_ARCH { template Hsp traceback(Cbs bias_correction, const Matrix& dp, const DpTarget& target, typename ScoreTraits::Score max_score, double evalue, int max_col, int max_i, int max_j, int channel, const StatType &stats, Params& p) { Hsp out(false); out.swipe_target = target.target_idx; out.swipe_bin = p.swipe_bin; out.score = ScoreTraits::int_score(max_score) * config.cbs_matrix_scale; out.evalue = evalue; out.bit_score = score_matrix.bitscore(out.score); out.corrected_bit_score = score_matrix.bitscore_corrected(out.score, p.query.length(), target.true_target_len); out.frame = p.frame.index(); if (target.carry_over.i1 == 0) { out.query_range.end_ = max_i + 1; out.subject_range.end_ = max_j + 1; } else { out.query_range.end_ = target.carry_over.i1; out.subject_range.end_ = target.carry_over.j1; out.identities = target.carry_over.ident; out.length = target.carry_over.len; out.query_range.begin_ = (int)p.query.length() - 1 - max_i; out.subject_range.begin_ = (int)target.seq.length() - 1 - max_j; try { out.approx_id = out.approx_id_percent(Sequence(p.query.reverse()), Sequence(target.seq.reverse())); } catch (std::out_of_range&) { throw std::runtime_error(std::string("Out_of_range query=") + std::string(p.query_id) + " target=" + target.seq.to_string()); } } out.target_seq = target.seq; out.matrix = target.matrix; assign_stats(out, stats); out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, p.frame), TranslatedPosition(out.query_range.end_, p.frame), p.query_source_len); out.subject_source_range = out.subject_range; return out; } template Hsp traceback(Cbs bias_correction, const TracebackVectorMatrix &dp, const DpTarget &target, typename ScoreTraits::Score max_score, double evalue, int max_col, int max_i, int max_j, int channel, Void, Params& p) { typedef typename ScoreTraits::Score Score; typedef typename ScoreTraits::TraceMask TraceMask; const auto channel_mask = TraceMask::vmask(channel) | TraceMask::hmask(channel); typename TracebackVectorMatrix::TracebackIterator it(dp.traceback(max_col, max_i, max_j, channel)); Hsp out(true); out.swipe_target = target.target_idx; out.swipe_bin = p.swipe_bin; out.score = ScoreTraits::int_score(max_score); out.evalue = evalue; out.bit_score = score_matrix.bitscore(out.score); out.corrected_bit_score = score_matrix.bitscore_corrected(out.score, p.query.length(), target.true_target_len); out.transcript.reserve(size_t(out.score * config.transcript_len_estimate)); out.frame = p.frame.index(); out.query_range.end_ = it.i + 1; out.subject_range.end_ = it.j + 1; const int end_score = out.score; int score = 0; const bool adjusted_matrix = target.adjusted_matrix(); if (!adjusted_matrix) out.score *= config.cbs_matrix_scale; //const int* matrix = adjusted_matrix ? target.matrix->scores32.data() : score_matrix.matrix32(); if (adjusted_matrix) throw std::runtime_error("Traceback with adjusted matrix not supported"); const int* matrix = score_matrix.matrix32(); while (it.i >= 0 && it.j >= 0 && score < end_score) { if ((it.mask().gap & channel_mask) == 0) { const Letter q = p.query[it.i], s = target.seq[it.j]; const int m = matrix[int(s) * 32 + (int)q]; const int m2 = adjusted_matrix ? m : add_cbs_scalar(m, bias_correction[it.i]); score += m2; out.push_match(q, s, m > (Score)0); it.walk_diagonal(); } else { const pair g(it.walk_gap()); out.push_gap(g.first, g.second, target.seq.data() + it.j + g.second); score -= score_matrix.gap_open() + g.second * score_matrix.gap_extend(); } } if (score != end_score) throw std::runtime_error("Traceback error. " + p.query.to_string()); out.query_range.begin_ = it.i + 1; out.subject_range.begin_ = it.j + 1; out.transcript.reverse(); out.transcript.push_terminator(); out.query_source_range = TranslatedPosition::absolute_interval(TranslatedPosition(out.query_range.begin_, p.frame), TranslatedPosition(out.query_range.end_, p.frame), p.query_source_len); out.subject_source_range = out.subject_range; out.approx_id = out.approx_id_percent(p.query, target.seq); return out; } template list swipe(const It target_begin, const It target_end, std::atomic* const next, Cbs composition_bias, TargetVec& overflow, Params& p) { using Score = typename ScoreTraits::Score; using Cell = typename Cfg::Cell; using Matrix = typename SelectMatrix::Type; using RowCounter = typename Cfg::RowCounter; using IdMask = typename Cfg::IdMask; using StatType = decltype(extract_stats(Cell(), int())); constexpr int CHANNELS = ScoreTraits::CHANNELS; int max_col[CHANNELS], max_i[CHANNELS], max_j[CHANNELS]; const int qlen = (int)p.query.length(); if (qlen > RowCounter::MAX_LEN) throw std::runtime_error("Query length exceeds row counter maximum."); if (config.cbs_matrix_scale != 1) throw std::runtime_error("Matrix scale != 1.0 not supported."); const Sv open_penalty(static_cast(score_matrix.gap_open() + score_matrix.gap_extend())), extend_penalty(static_cast(score_matrix.gap_extend())); //Sv best = Sv(); Score best[CHANNELS]; StatType hsp_stats[CHANNELS]; std::fill(best, best + CHANNELS, ScoreTraits::zero_score()); SwipeProfile profile; std::array target_scores; AsyncTargetBuffer targets(target_begin, target_end, p.target_max_len, p.reverse_targets, next); Matrix dp(qlen, targets.max_len()); CBSBuffer cbs_buf(composition_bias, qlen, 0); list out; int col = 0; while (targets.active.size() > 0) { typename Matrix::ColumnIterator it(dp.begin(col)); RowCounter row_counter(0); Cell vgap, hgap, last; Sv col_best; vgap = hgap = last = col_best = Sv(); const auto target_seq_vector = targets.seq_vector(); const Sv target_seq(target_seq_vector); if (targets.cbs_mask() != 0) { if (targets.custom_matrix_16bit) profile.set(targets.get32().data()); else profile.set(targets.get(target_scores.data())); } else { #ifdef __SSSE3__ profile.set(target_seq_vector); #else profile.set(targets.get(target_scores.data())); #endif } #ifdef DP_STAT p.stat.inc(Statistics::GROSS_DP_CELLS, uint64_t(qlen) * CHANNELS); #endif for (int i = 0; i < qlen; ++i) { hgap = it.hgap(); const Cell next = swipe_cell_update(it.diag(), profile.get(p.query[i]), cbs_buf(i), extend_penalty, open_penalty, hgap, vgap, col_best, it.trace_mask(), row_counter, IdMask(p.query[i], target_seq)); /*/std::cout << "j=" << targets.pos[0] << " i=" << i << " score=" << ScoreTraits<_sv>::int_score(extract_channel(next, 0)) << " q=" << value_traits.alphabet[p.query[i]] << " t=" << value_traits.alphabet[extract_channel(target_seq, 0)] << extract_stats(next, 0) << " j'=" << targets.dp_targets[0].seq.length() - targets.pos[0] << " i'=" << p.query.length() - i << std::endl;*/ it.set_hgap(hgap); it.set_score(last); last = next; ++it; } it.set_score(last); //best = max(best, col_best); Score col_best_[CHANNELS], i_max[CHANNELS]; store_sv(col_best, col_best_); row_counter.store(i_max); for (int i = 0; i < targets.active.size();) { int c = targets.active[i]; if (col_best_[c] > best[c]) { best[c] = col_best_[c]; max_col[c] = col; max_i[c] = ScoreTraits::int_score(i_max[c]); max_j[c] = targets.pos[c]; hsp_stats[c] = extract_stats(dp[max_i[c]], c); //std::cout << "stats[" << c << "]=" << hsp_stats[c] << " j=" << targets.pos[0] << " j'=" << targets.dp_targets[0].seq.length() - targets.pos[0] << " score=" << ScoreTraits<_sv>::int_score(best[c]) << std::endl; } bool reinit = false; if (col_best_[c] == ScoreTraits::max_score()) { overflow.push_back(targets.dp_targets[c]); reinit = true; } else if (!targets.inc(c)) { if (overflow_stats(hsp_stats[c])) overflow.push_back(targets.dp_targets[c]); else { const int s = ScoreTraits::int_score(best[c]) * config.cbs_matrix_scale; const double evalue = score_matrix.evalue(s, qlen, (unsigned)targets.dp_targets[c].true_target_len); if (s > 0 && score_matrix.report_cutoff(s, evalue)) out.push_back(traceback(composition_bias, dp, targets.dp_targets[c], best[c], evalue, max_col[c], max_i[c], max_j[c], c, hsp_stats[c], p)); } reinit = true; } if (reinit) { if (targets.init_target(i, c)) { dp.set_zero(c); //set_channel(best, c, ScoreTraits::zero_score()); best[c] = ScoreTraits::zero_score(); } else continue; } ++i; } col = (col + 1) % dp.cols(); } return out; } }}}bbuchfink-diamond-08b3cbc/src/dp/swipe/stat_cell.h000066400000000000000000000156111506104011400222040ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2021 Max Planck Society for the Advancement of Science e.V. Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "basic/match.h" FORCE_INLINE uint8_t cmp_mask(int x, int y) { return x == y; } FORCE_INLINE int blend(int v, int w, int mask) { return mask ? w : v; } template struct DummyIdMask { DummyIdMask(const Letter q, const Sv& t) {} }; template struct VectorIdMask { VectorIdMask(const Letter q, const Sv& t) : mask(blend(Sv(0), Sv(1), Sv(typename ::DISPATCH_ARCH::ScoreTraits::Score(q)) == t)) {} const Sv mask; }; template struct ForwardCell : public Sv { ForwardCell() : Sv(), ident(), len() {} ForwardCell(const Sv& v) : Sv(v), ident(), len() {} Sv ident, len; }; template<> struct ForwardCell { int32_t v, ident, len; operator int32_t() const { return v; } operator int32_t&() { return v; } ForwardCell(const int32_t v) : v(v), ident(0), len(0) {} ForwardCell() : v(0), ident(0), len(0) {} ForwardCell& operator-=(int32_t x) { v -= x; return *this; } ForwardCell& operator+=(int32_t x) { v += x; return *this; } void max(const ForwardCell& x) { v = std::max(v, x.v); } struct Stats { int ident, len; friend std::ostream& operator<<(std::ostream& s, const Stats& c) { s << " ident=" << c.ident << " len=" << c.len; return s; } }; }; template FORCE_INLINE void set_channel(ForwardCell& v, const int i, const typename ::DISPATCH_ARCH::ScoreTraits::Score x) { set_channel((Sv&)v, i, x); set_channel(v.ident, i, x); set_channel(v.len, i, x); } template struct BackwardCell : public Sv { BackwardCell() : Sv(), mismatch(), gapopen() {} BackwardCell(const Sv& v) : Sv(v), mismatch(), gapopen() {} Sv mismatch, gapopen; }; template<> struct BackwardCell { int32_t v, mismatch, gapopen; operator int32_t() const { return v; } operator int32_t& () { return v; } BackwardCell(const int32_t v) : v(v), mismatch(0), gapopen(0) {} BackwardCell() : v(0), mismatch(0), gapopen(0) {} BackwardCell& operator-=(int32_t x) { v -= x; return *this; } BackwardCell& operator+=(int32_t x) { v += x; return *this; } void max(const BackwardCell& x) { v = std::max(v, x.v); } struct Stats { int mismatch, gap_open; friend std::ostream& operator<<(std::ostream& s, const Stats& c) { s << " mismatch=" << c.mismatch << " gapopen=" << c.gap_open; return s; } }; }; template FORCE_INLINE void set_channel(BackwardCell& v, const int i, const typename ::DISPATCH_ARCH::ScoreTraits::Score x) { set_channel((Sv&)v, i, x); set_channel(v.mismatch, i, x); set_channel(v.gapopen, i, x); } struct Void { friend std::ostream& operator<<(std::ostream& s, const Void&) { return s; } }; template FORCE_INLINE Void extract_stats(const Sv&, int) { return Void(); } template FORCE_INLINE ForwardCell::Stats extract_stats(const ForwardCell& v, int channel) { const auto s = ::DISPATCH_ARCH::ScoreTraits::int_score; return { s(extract_channel(v.ident, channel)), s(extract_channel(v.len, channel)) }; } template FORCE_INLINE BackwardCell::Stats extract_stats(const BackwardCell& v, int channel) { const auto s = ::DISPATCH_ARCH::ScoreTraits::int_score; return { s(extract_channel(v.mismatch, channel)), s(extract_channel(v.gapopen, channel)) }; } template FORCE_INLINE bool overflow_stats(Void) { return false; } template FORCE_INLINE bool overflow_stats(const ForwardCell::Stats& stats) { constexpr auto m = DISPATCH_ARCH::ScoreTraits::max_int_score(); return stats.ident == m || stats.len == m; } template FORCE_INLINE bool overflow_stats(const BackwardCell::Stats& stats) { constexpr auto m = DISPATCH_ARCH::ScoreTraits::max_int_score(); return stats.gap_open == m || stats.mismatch == m; } FORCE_INLINE void assign_stats(Hsp& hsp, Void) {} FORCE_INLINE void assign_stats(Hsp& hsp, const ForwardCell::Stats& v) { hsp.identities = v.ident; hsp.length = v.len; } FORCE_INLINE void assign_stats(Hsp& hsp, const BackwardCell::Stats& v) { hsp.gap_openings = v.gap_open; hsp.mismatches = v.mismatch; hsp.gaps = hsp.length - hsp.identities - hsp.mismatches; } template FORCE_INLINE void update_stats(const Sv&, const Sv&, const Sv&, const DummyIdMask&) { } template FORCE_INLINE void update_stats(ForwardCell& current_cell, ForwardCell& horizontal_gap, ForwardCell& vertical_gap, const VectorIdMask& id_mask) { const Sv one = Sv(1); current_cell.ident += id_mask.mask; current_cell.len += one; horizontal_gap.len += one; vertical_gap.len += one; } template FORCE_INLINE void update_stats(BackwardCell& current_cell, BackwardCell& horizontal_gap, BackwardCell& vertical_gap, const VectorIdMask& id_mask) { current_cell.mismatch += Sv(1) - id_mask.mask; } template FORCE_INLINE void update_open(const Sv&, const Sv&) { } template FORCE_INLINE void update_open(ForwardCell& open, ForwardCell& current) { const Sv zero = Sv(), zero_mask = current == zero; current.ident = blend(current.ident, zero, zero_mask); current.len = blend(current.len, zero, zero_mask); } template FORCE_INLINE void update_open(BackwardCell& open, BackwardCell& current) { open.gapopen += Sv(1); const Sv zero = Sv(), zero_mask = current == zero; current.mismatch = blend(current.mismatch, zero, zero_mask); current.gapopen = blend(current.gapopen, zero, zero_mask); } template FORCE_INLINE void set_max(ForwardCell& v, const ForwardCell& x) { v.max(x); const Sv mask = v == x; v.ident = blend(v.ident, x.ident, mask); v.len = blend(v.len, x.len, mask); } template FORCE_INLINE void set_max(BackwardCell& v, const BackwardCell& x) { v.max(x); const Sv mask = v == x; v.mismatch = blend(v.mismatch, x.mismatch, mask); v.gapopen = blend(v.gapopen, x.gapopen, mask); } FORCE_INLINE void saturate(ForwardCell& c) { c.v = std::max(c.v, 0); } FORCE_INLINE void saturate(BackwardCell& c) { c.v = std::max(c.v, 0); }bbuchfink-diamond-08b3cbc/src/dp/swipe/swipe.h000066400000000000000000000120271506104011400213570ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "../score_vector.h" #include "basic/value.h" #include "util/system.h" #include "util/memory/alignment.h" #include "util/simd/transpose.h" #include "stats/score_matrix.h" namespace DP { struct NoCBS; } template struct CBSBuffer { CBSBuffer(const DP::NoCBS&, int, uint32_t) {} void* operator()(int i) const { return nullptr; } }; template struct CBSBuffer { CBSBuffer(const int8_t* v, int l, uint32_t channel_mask) { typedef typename ::DISPATCH_ARCH::ScoreTraits::Score Score; data.reserve(l); for (int i = 0; i < l; ++i) data.push_back(blend_sv(Score(v[i]), (Score)0, channel_mask)); } Sv operator()(int i) const { return data[i]; } std::vector> data; }; template FORCE_INLINE Sv cell_update(const Sv &diagonal_cell, const Sv &shift_cell0, const Sv &shift_cell1, const Sv &scores, const Sv &gap_extension, const Sv &gap_open, const Sv &frame_shift, Sv &horizontal_gap, Sv &vertical_gap, Sv &best) { using std::max; Sv current_cell = diagonal_cell + scores; const Sv f = scores - frame_shift; current_cell = max(current_cell, shift_cell0 + f); current_cell = max(current_cell, shift_cell1 + f); current_cell = max(max(current_cell, vertical_gap), horizontal_gap); saturate(current_cell); best = max(best, current_cell); vertical_gap -= gap_extension; horizontal_gap -= gap_extension; const Sv open = current_cell - gap_open; vertical_gap = max(vertical_gap, open); horizontal_gap = max(horizontal_gap, open); return current_cell; } namespace DISPATCH_ARCH { template struct SwipeProfile { #ifdef __SSSE3__ inline void set(typename ScoreTraits::Vector seq) { assert(sizeof(data_) / sizeof(Sv) >= value_traits.alphabet_size); for (unsigned j = 0; j < AMINO_ACID_COUNT; ++j) data_[j] = Sv(j, seq); } #endif inline const Sv& get(Letter i) const { return data_[(int)i]; } void set(const int8_t** target_scores) { #if ARCH_ID == 2 transpose(target_scores, 32, (int8_t*)data_, __m256i()); for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) data_[i].expand_from_8bit(); #elif defined(__ARM_NEON) transpose(target_scores, 16, (int8_t*)data_, int8x16_t()); for (int i = 0; i < 16; ++i) target_scores[i] += 16; transpose(target_scores, 16, (int8_t*)(&data_[16]), int8x16_t()); for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) data_[i].expand_from_8bit(); #elif defined(__SSE2__) transpose(target_scores, 16, (int8_t*)data_, __m128i()); for (int i = 0; i < 16; ++i) target_scores[i] += 16; transpose(target_scores, 16, (int8_t*)(&data_[16]), __m128i()); for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) data_[i].expand_from_8bit(); #else for (int i = 0; i < AMINO_ACID_COUNT; ++i) data_[i] = target_scores[0][i]; #endif } void set(const int32_t** target_scores) { typename ScoreTraits::Score s[ScoreTraits::CHANNELS]; for (size_t i = 0; i < AMINO_ACID_COUNT; ++i) { for (size_t j = 0; j < ScoreTraits::CHANNELS; ++j) s[j] = target_scores[j][i]; data_[i] = load_sv(s); } } //_sv data_[AMINO_ACID_COUNT]; Sv data_[32]; }; template<> struct SwipeProfile { #ifdef __AVX2__ void set(const __m256i& seq) { int16_t s[32]; _mm256_storeu_si256((__m256i*)s, seq); const int* row = score_matrix.row((char)s[0]); std::copy(row, row + 32, this->row); } #endif #ifdef __SSE2__ void set(const __m128i& seq) { int16_t s[8]; _mm_storeu_si128((__m128i*)s, seq); const int* row = score_matrix.row((char)s[0]); std::copy(row, row + 32, this->row); } #endif #ifdef __ARM_NEON void set(const int16x8_t& seq) { int16_t s[8]; vst1q_s16(s, seq); const int* row = score_matrix.row((char)s[0]); std::copy(row, row + 32, this->row); } #endif void set(uint64_t seq) { const int* row = score_matrix.row((char)seq); std::copy(row, row + 32, this->row); } void set(const int8_t** target_scores) { for (int i = 0; i < 32; ++i) row[i] = target_scores[0][i]; } void set(const int32_t** target_scores) { for (int i = 0; i < 32; ++i) row[i] = target_scores[0][i]; } int32_t get(char i) const { return row[(int)i]; } int32_t row[32]; }; }bbuchfink-diamond-08b3cbc/src/dp/swipe/swipe_wrapper.cpp000066400000000000000000000432361506104011400234600ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include #include #include #include #include "../score_vector_int16.h" #include "../score_vector_int8.h" #include "util/simd/vector.h" #include "../dp.h" #include "util/log_stream.h" #include "data/sequence_set.h" #include "../score_vector.h" #include "cell_update.h" #include "full_swipe.h" #include "util/geo/geo.h" #include "util/simd/dispatch.h" #include "banded_swipe.h" #include "stats/hauser_correction.h" #include "stats/stats.h" using std::unique_ptr; using std::list; using std::atomic; using std::thread; using std::array; using std::atomic_size_t; using std::mutex; using std::accumulate; using std::string; using std::pair; using std::runtime_error; template struct SwipeConfig { static constexpr bool traceback = tb; using RowCounter = RC; using Cell = C; using IdMask = IdM; }; namespace DP { namespace BandedSwipe { namespace DISPATCH_ARCH { static void sort(const TargetVec::iterator begin, const TargetVec::iterator end) { std::sort(begin, end); } static void sort(const SequenceSet::ConstIterator begin, const SequenceSet::ConstIterator end) { } static unsigned bin(int x) { return x < UCHAR_MAX ? 0 : (x < USHRT_MAX ? 1 : 2); } static const HspValues NO_TRACEBACK = HspValues::COORDS | HspValues::IDENT | HspValues::LENGTH | HspValues::MISMATCHES | HspValues::GAP_OPENINGS; int bin(HspValues v, int query_len, int score, int ungapped_score, const int64_t dp_size, unsigned score_width, const Loc mismatch_est) { unsigned b = 0; b = std::max(b, bin(score)); if (ungapped_score > config.cutoff_score_8bit) b = std::max(b, 1u); b = std::max(b, score_width); b = std::max(b, bin(mismatch_est)); #ifndef __ARM_NEON #ifndef __SSE4_1__ b = std::max(b, 1u); #endif #ifndef __SSE2__ b = 2; #endif #endif if (v != HspValues::NONE) { b = std::max(b, bin(query_len)); if (dp_size > config.max_swipe_dp) { if (flag_only(v, NO_TRACEBACK)) b += SCORE_BINS; else b = 2; } else if (flag_only(v, HspValues::COORDS) && !config.approx_backtrace) b += SCORE_BINS; } return b; } template static int64_t matrix_size(const int query_len, const TargetVec::const_iterator begin, const TargetVec::const_iterator end, const Flags flags) { int64_t s = 0; for (auto i = begin; i != end; ++i) { const int64_t cols = flag_any(flags, Flags::FULL_MATRIX) ? i->seq.length() : i->cols, size = int64_t(flag_any(flags, Flags::FULL_MATRIX) ? query_len : i->d_end - i->d_begin) * cols * ::DISPATCH_ARCH::ScoreTraits::CHANNELS / 2; s = std::max(size, s); } return s; } template static size_t matrix_size(const int query_len, const SequenceSet::ConstIterator begin, const SequenceSet::ConstIterator end, const Flags flags) { return 0; } static bool reversed(const HspValues v) { return flag_only(v, NO_TRACEBACK) && flag_any(v, HspValues::QUERY_START | HspValues::TARGET_START | HspValues::MISMATCHES | HspValues::GAP_OPENINGS); } template static list dispatch_swipe(const TargetVec::const_iterator subject_begin, const TargetVec::const_iterator subject_end, Cbs composition_bias, TargetVec& overflow, Params& p) { return ::DP::BandedSwipe::DISPATCH_ARCH::swipe(subject_begin, subject_end, composition_bias, overflow, p); } template static list dispatch_swipe(const SequenceSet::ConstIterator subject_begin, const SequenceSet::ConstIterator subject_end, Cbs composition_bias, TargetVec& overflow, Params& p) { return {}; } template static list dispatch_swipe(const It begin, const It end, atomic* const next, Cbs composition_bias, TargetVec& overflow, Params& p) { constexpr auto CHANNELS = TargetVec::const_iterator::difference_type(::DISPATCH_ARCH::ScoreTraits::CHANNELS); if (flag_any(p.flags, Flags::FULL_MATRIX)) return ::DP::Swipe::DISPATCH_ARCH::swipe(begin, end, next, composition_bias, overflow, p); else { list out; for (It i = begin; i < end; i += std::min(CHANNELS, end - i)) out.splice(out.end(), dispatch_swipe(i, i + std::min(CHANNELS, end - i), composition_bias, overflow, p)); return out; } } template static list dispatch_swipe(const It begin, const It end, atomic* const next, TargetVec &overflow, Params& p) { if (p.composition_bias == nullptr) return dispatch_swipe(begin, end, next, NoCBS(), overflow, p); else return dispatch_swipe(begin, end, next, p.composition_bias, overflow, p); } template static list dispatch_swipe(const It begin, const It end, atomic* const next, TargetVec &overflow, const int round, const int bin, Params& p) { if (p.v == HspValues::NONE) { using Cfg = SwipeConfig, Sv, DummyIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } if (bin < SCORE_BINS) { using Cfg = SwipeConfig, Sv, DummyIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } if (round == 0) { if (!flag_any(p.v, HspValues::IDENT | HspValues::LENGTH)) { using Cfg = SwipeConfig, Sv, DummyIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } else { using Cfg = SwipeConfig, ForwardCell, VectorIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } } else if (round == 1) { if (!flag_any(p.v, HspValues::MISMATCHES | HspValues::GAP_OPENINGS)) { using Cfg = SwipeConfig, Sv, DummyIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } else { using Cfg = SwipeConfig, BackwardCell, VectorIdMask>; return dispatch_swipe(begin, end, next, overflow, p); } } throw std::runtime_error("Unreachable"); } template static void swipe_worker(const It begin, const It end, atomic* const next, list *out, TargetVec *overflow, const int round, const int bin, Params* p) { const ptrdiff_t CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; Statistics stat2; size_t pos; TargetVec of; Params params{ p->query, p->query_id, p->frame, p->query_source_len, p->composition_bias, p->flags, p->reverse_targets, p->target_max_len, p->swipe_bin, p->v, stat2, nullptr }; if (flag_any(p->flags, Flags::FULL_MATRIX)) *out = dispatch_swipe(begin, end, next, of, round, bin, params); else while (begin + (pos = next->fetch_add(CHANNELS, std::memory_order_relaxed)) < end) { const auto start = begin + pos; out->splice(out->end(), dispatch_swipe(start, start + std::min(CHANNELS, end - start), next, of, round, bin, params)); } *overflow = std::move(of); p->stat += stat2; } template static void swipe_task(const It begin, const It end, list *out, TargetVec *overflow, mutex* mtx, const int round, const int bin, Params* p) { const ptrdiff_t CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; Statistics stat2; TargetVec of; atomic next(0); Params params{ p->query, p->query_id, p->frame, p->query_source_len, p->composition_bias, p->flags, p->reverse_targets, p->target_max_len, p->swipe_bin, p->v, stat2, nullptr }; list hsp = dispatch_swipe(begin, end, &next, of, round, bin, params); { std::lock_guard lock(*mtx); overflow->push_back(of); out->splice(out->end(), hsp); } p->stat += stat2; } template static list swipe_threads(const It begin, const It end, TargetVec &overflow, const int round, const int bin, Params& p) { const ptrdiff_t CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; if (begin == end) return {}; atomic next(0); if (flag_any(p.flags, Flags::PARALLEL)) { TaskTimer timer("Banded swipe (run)", config.target_parallel_verbosity); const size_t n = config.threads_align ? config.threads_align : config.threads_; vector threads; vector> thread_out(n); vector thread_overflow(n); for (size_t i = 0; i < n; ++i) threads.emplace_back(swipe_worker, begin, end, &next, &thread_out[i], &thread_overflow[i], round, bin, &p); for (auto &t : threads) t.join(); timer.go("Banded swipe (merge)"); list out; for (list &l : thread_out) out.splice(out.end(), l); overflow.reserve(std::accumulate(thread_overflow.begin(), thread_overflow.end(), (size_t)0, [](size_t n, const TargetVec &v) { return n + v.size(); })); for (const TargetVec& v : thread_overflow) overflow.push_back(v); return out; } if(!p.thread_pool) return dispatch_swipe(begin, end, &next, overflow, round, bin, p); list hsp; ThreadPool::TaskSet task_set(*p.thread_pool, 0); mutex mtx; int64_t size = 0; It i0 = begin, i1 = begin; while(i1 < end) { const auto n = std::min(CHANNELS, end - i1); size += accumulate(i1, i1 + n, (int64_t)0, [&p](int64_t n, const DpTarget& t) {return n + t.cells(p.flags, p.query.length()); }); i1 += n; if (size >= config.swipe_task_size) { task_set.enqueue(swipe_task, i0, i1, &hsp, &overflow, &mtx, round, bin, &p); p.stat.inc(Statistics::SWIPE_TASKS_TOTAL); p.stat.inc(Statistics::SWIPE_TASKS_ASYNC); i0 = i1; size = 0; } } if (task_set.total() == 0) { p.stat.inc(Statistics::SWIPE_TASKS_TOTAL); return dispatch_swipe(i0, i1, &next, overflow, round, bin, p); } if (i1 - i0 > 0) { p.stat.inc(Statistics::SWIPE_TASKS_TOTAL); p.stat.inc(Statistics::SWIPE_TASKS_ASYNC); task_set.enqueue(swipe_task, i0, i1, &hsp, &overflow, &mtx, round, bin, &p); } task_set.run(); return hsp; } template static pair, TargetVec> swipe_bin(const unsigned bin, const It begin, const It end, const int round, Params& p) { if (end - begin == 0) return { {},{} }; TargetVec overflow; list out; auto time_stat = flag_any(p.v, HspValues::TRANSCRIPT) ? Statistics::TIME_TRACEBACK_SW : Statistics::TIME_SW; if (!flag_any(p.flags, Flags::FULL_MATRIX)) sort(begin, end); p.stat.inc(Statistics::value(Statistics::EXT8 + bin % SCORE_BINS), end - begin); TaskTimer timer; switch (bin) { #if defined(__SSE4_1__) | defined(__ARM_NEON) case 0: case 3: if (flag_any(p.flags, Flags::SEMI_GLOBAL)) out = swipe_threads<::DISPATCH_ARCH::ScoreVector, It>(begin, end, overflow, round, bin, p); else out = swipe_threads<::DISPATCH_ARCH::ScoreVector, It>(begin, end, overflow, round, bin, p); break; #endif #if defined(__SSE2__) | defined(__ARM_NEON) case 1: case 4: if (flag_any(p.flags, Flags::SEMI_GLOBAL)) out = swipe_threads<::DISPATCH_ARCH::ScoreVector, It>(begin, end, overflow, round, bin, p); else out = swipe_threads<::DISPATCH_ARCH::ScoreVector, It>(begin, end, overflow, round, bin, p); break; #endif case 2: case 5: out = swipe_threads(begin, end, overflow, round, bin, p); break; default: throw std::runtime_error("Invalid SWIPE bin."); } if (!flag_any(p.flags, Flags::PARALLEL)) p.stat.inc(time_stat, timer.microseconds()); return { out, overflow }; } static Loc mismatch_est(const Loc query_len, const Loc target_len, const int32_t aln_len, const HspValues v) { if (!flag_any(v, HspValues::MISMATCHES)) return 0; const Loc m = std::min(query_len, target_len); return aln_len > 0 ? std::min(aln_len, m) : m; } static list recompute_reversed(list &hsps, Params& p) { Targets dp_targets; const Loc qlen = p.query.length(); for (auto i = hsps.begin(); i != hsps.end(); ++i) { const double qcov = i->query_cover_percent(p.query_source_len), tcov = i->subject_cover_percent(i->target_seq.length()); const pair min_range_len = i->min_range_len(config.query_or_target_cover > 0 ? config.query_or_target_cover : config.query_cover, config.query_or_target_cover > 0 ? config.query_or_target_cover : config.subject_cover, qlen, i->target_seq.length()); const double qa = Stats::approx_id(i->score, min_range_len.first, 0), ta = Stats::approx_id(i->score, min_range_len.second, 0); if (qcov < config.query_cover || tcov < config.subject_cover || std::max(qcov, tcov) < config.query_or_target_cover || (config.query_or_target_cover == 0 && std::min(qa, ta) < config.approx_min_id.get(0.0)) || (config.query_or_target_cover > 0 && std::max(qa, ta) < config.approx_min_id.get(0.0))) continue; Sequence reversed_seq(i->target_seq.data(), i->target_seq.data() + i->subject_range.end_); assert(i->swipe_bin >= 0); const Loc band = flag_any(p.flags, Flags::FULL_MATRIX) ? qlen : i->d_end - i->d_begin, tlen = i->subject_range.end_, b = std::max(bin(p.v, band, i->score, 0, INT64_MAX, 0, mismatch_est(i->query_range.end_, tlen, i->length, p.v)), i->swipe_bin); assert(b >= SCORE_BINS); const DpTarget::CarryOver carry_over{ i->query_range.end_, i->subject_range.end_, i->identities, i->length }; //dp_targets[b].emplace_back(reversed_seq, i->target_seq.length(), Geo::rev_diag(i->d_end-1, qlen, tlen), Geo::rev_diag(i->d_begin, qlen, tlen) + 1, //Interval(), 0, i->swipe_target, qlen, i->matrix, carry_over); dp_targets[b].emplace_back(reversed_seq, i->target_seq.length(), Geo::rev_diag(i->d_end - 1, qlen, tlen), Geo::rev_diag(i->d_begin, qlen, tlen) + 1, i->swipe_target, qlen, i->matrix, carry_over); } vector reversed = p.query.reverse(); vector rev_cbs = HauserCorrection::reverse(p.composition_bias, p.query.length()); const int8_t* cbs = p.composition_bias ? rev_cbs.data() : nullptr; Params params{ Sequence(reversed), p.query_id, p.frame, p.query_source_len, cbs, p.flags, true, 0, p.swipe_bin, p.v, p.stat, p.thread_pool }; list out; #ifndef STRICT_BAND unique_ptr overflow_targets; #endif for (unsigned bin = SCORE_BINS; bin < BINS; ++bin) { params.target_max_len = dp_targets[bin].max_len(); params.swipe_bin = bin; auto r = swipe_bin(bin, dp_targets[bin].begin(), dp_targets[bin].end(), 1, params); if (!r.second.empty()) { assert(bin != BINS - 1); #ifdef STRICT_BAND throw runtime_error("Non-empty overflow list in reversed DP. Query = " + string(p.query_id) + " bin=" + std::to_string(bin) + " target=" + r.second.front().seq.to_string() + " d_begin=" + std::to_string(r.second.front().d_begin) + " d_end=" + std::to_string(r.second.front().d_end)); #else if (!overflow_targets) overflow_targets = std::make_unique(); for (auto it = r.second.begin(); it != r.second.end(); ++it) { for(const Hsp& hsp: hsps) { if(hsp.swipe_target == it->target_idx) { (*overflow_targets)[bin + 1].emplace_back(hsp.target_seq, hsp.target_seq.length(), hsp.d_begin, hsp.d_end, hsp.swipe_target, p.query.length(), hsp.matrix, DpTarget::CarryOver()); } } } #endif } out.splice(out.end(), r.first); } #ifndef STRICT_BAND if(overflow_targets) { list recompute = ::DP::BandedSwipe::swipe(*overflow_targets, p); out.splice(out.end(), recompute); } #endif return out; } list swipe(const Targets &targets, Params& p) { pair, TargetVec> result; list out, out_tmp; for (int algo_bin = 0; algo_bin < ALGO_BINS; ++algo_bin) { for (int score_bin = 0; score_bin < SCORE_BINS; ++score_bin) { const int bin = algo_bin * SCORE_BINS + score_bin; TargetVec round_targets; round_targets.reserve(targets[bin].size() + result.second.size()); round_targets.push_back(targets[bin]); round_targets.push_back(result.second); p.target_max_len = round_targets.max_len(); p.swipe_bin = bin; result = swipe_bin(bin, round_targets.begin(), round_targets.end(), 0, p); if(algo_bin == 0) out.splice(out.end(), result.first); else out_tmp.splice(out_tmp.end(), result.first);; } assert(result.second.empty()); } if (!out_tmp.empty()) out.splice(out.end(), recompute_reversed(out_tmp, p)); return out; } list swipe_set(const SequenceSet::ConstIterator begin, const SequenceSet::ConstIterator end, Params& p) { const unsigned b = bin(p.v, 0, 0, 0, 0, 0, 0); pair, TargetVec> result = swipe_bin(b, begin, end, 0, p); if (reversed(p.v)) result.first = recompute_reversed(result.first, p); if (b < BINS - 1 && !result.second.empty()) { Targets targets; targets[b + 1] = std::move(result.second); result.first.splice(result.first.end(), swipe(targets, p)); } return result.first; } } DISPATCH_2(std::list, swipe, const Targets&, targets, Params&, params) DISPATCH_3(std::list, swipe_set, const SequenceSet::ConstIterator, begin, const SequenceSet::ConstIterator, end, Params&, params) DISPATCH_7(int, bin, HspValues, v, int, query_len, int, score, int, ungapped_score, const int64_t, dp_size, unsigned, score_width, const Loc, mismatch_est) }}bbuchfink-diamond-08b3cbc/src/dp/swipe/target_iterator.h000066400000000000000000000220551506104011400234310ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2016-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include "../dp.h" #include "basic/value.h" #include "util/data_structures/array.h" template struct SmallVector { SmallVector() : n(0) {} T& operator[](int i) { return data[i]; } const T& operator[](int i) const { return data[i]; } int size() const { return n; } void push_back(const T& x) { data[n++] = x; } void erase(int i) { memmove(&data[i], &data[i + 1], (--n - i) * sizeof(T)); } private: T data[N]; int n; }; namespace DISPATCH_ARCH { template struct TargetIterator { typedef ::DISPATCH_ARCH::SIMD::Vector SeqVector; enum { CHANNELS = SeqVector::CHANNELS }; TargetIterator(DP::TargetVec::const_iterator subject_begin, DP::TargetVec::const_iterator subject_end, bool reverse_targets, int i1, int qlen, int *d_begin) : n_targets(int(subject_end - subject_begin)), cols(0), custom_matrix_16bit(false), subject_begin(subject_begin) { for (int next = 0; next < std::min((int)CHANNELS, n_targets); ++next) { const DpTarget &t = subject_begin[next]; pos[next] = i1 - (t.d_end - 1); const int d0 = d_begin[next]; //const int d0 = t.d_begin; const int j1 = std::min(qlen - 1 - d0, (int)(t.seq.length() - 1)) + 1; cols = std::max(cols, j1 - pos[next]); active.push_back(next); if (config.comp_based_stats == ::Stats::CBS::MATRIX_ADJUST && !t.matrix) throw std::runtime_error("TargetIterator: No matrix provided for adjusted matrix."); if (t.adjusted_matrix() && (t.matrix->score_max > SCHAR_MAX || t.matrix->score_min < SCHAR_MIN)) custom_matrix_16bit = true; target_seqs[next] = Array(t.seq.length()); if(reverse_targets) target_seqs[next].assign_reversed(t.seq.data(), t.seq.end()); else target_seqs[next].assign(t.seq.data(), t.seq.end()); } } uint64_t live() const { uint64_t n = 0; for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; if (pos[channel] >= 0) n |= 1llu << channel; } return n; } char operator[](int channel) const { if (pos[channel] >= 0) { return target_seqs[channel][pos[channel]]; } else return SUPER_HARD_MASK; } SeqVector get() const { alignas(32) T s[CHANNELS]; std::fill(s, s + CHANNELS, SUPER_HARD_MASK); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; s[channel] = (*this)[channel]; } return SeqVector(s); } const int8_t** get(const int8_t** target_scores) const { static const int8_t blank[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::fill(target_scores, target_scores + 32, blank); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; const int l = (int)(*this)[channel]; const DpTarget& dp_target = subject_begin[channel]; target_scores[channel] = dp_target.adjusted_matrix() ? &dp_target.matrix->scores[32 * l] : &score_matrix.matrix8()[32 * l]; } return target_scores; } std::vector get32() const { static const int32_t blank[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::vector target_scores(CHANNELS); std::fill(target_scores.begin(), target_scores.end(), blank); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; const int l = (int)(*this)[channel]; const DpTarget& dp_target = subject_begin[channel]; if(dp_target.adjusted_matrix()) throw std::runtime_error("TargetIterator does not support adjusted matrices."); //target_scores[channel] = dp_target.adjusted_matrix() ? &dp_target.matrix->scores32[32 * l] : &score_matrix.matrix32()[32 * l]; target_scores[channel] = &score_matrix.matrix32()[32 * l]; } return target_scores; } bool inc(int channel) { ++pos[channel]; if (pos[channel] >= subject_begin[channel].seq.length()) return false; return true; } uint32_t cbs_mask() const { uint32_t r = 0; for (uint32_t i = 0; i < (uint32_t)n_targets; ++i) if (subject_begin[i].adjusted_matrix()) r |= 1 << i; return r; } int pos[CHANNELS], n_targets, cols; bool custom_matrix_16bit; SmallVector active; const DP::TargetVec::const_iterator subject_begin; std::array, CHANNELS> target_seqs; }; template struct AsyncTargetBuffer { typedef ::DISPATCH_ARCH::SIMD::Vector SeqVector; enum { CHANNELS = SeqVector::CHANNELS }; AsyncTargetBuffer(const It begin, const It end, Loc max_target_len, bool reverse_targets, std::atomic* const next): reverse_targets(reverse_targets), begin(begin), target_count(BlockId(end - begin)), next(next), custom_matrix_16bit(false) { BlockId n; int i = 0; while (i < CHANNELS && (n = next->fetch_add(1, std::memory_order_relaxed)) < target_count) { DpTarget t = begin[n]; if (t.blank()) t.target_idx = n; pos[i] = 0; dp_targets[i] = t; active.push_back(i); target_seqs[i] = Array(max_target_len); if (reverse_targets) target_seqs[i].assign_reversed(t.seq.data(), t.seq.end()); else target_seqs[i].assign(t.seq.data(), t.seq.end()); ++i; } } int max_len() const { int l = 0; for (BlockId i = 0; i < target_count; ++i) l = std::max(l, (int)DpTarget(begin[i]).seq.length()); return l; } char operator[](int channel) const { if (pos[channel] >= 0) { return target_seqs[channel][pos[channel]]; } else return SUPER_HARD_MASK; } SeqVector seq_vector() const { alignas(32) T s[CHANNELS]; std::fill(s, s + CHANNELS, SUPER_HARD_MASK); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; s[channel] = (*this)[channel]; } return SeqVector(s); } const int8_t** get(const int8_t** target_scores) const { static const int8_t blank[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::fill(target_scores, target_scores + 32, blank); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; const int l = (int)(*this)[channel]; const DpTarget& dp_target = dp_targets[channel]; target_scores[channel] = dp_target.adjusted_matrix() ? &dp_target.matrix->scores[32 * l] : &score_matrix.matrix8()[32 * l]; } return target_scores; } std::vector get32() const { static const int32_t blank[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; std::vector target_scores(CHANNELS); std::fill(target_scores.begin(), target_scores.end(), blank); for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; const int l = (int)(*this)[channel]; const DpTarget& dp_target = dp_targets[channel]; //target_scores[channel] = dp_target.adjusted_matrix() ? &dp_target.matrix->scores32[32 * l] : &score_matrix.matrix32()[32 * l]; if( dp_target.adjusted_matrix() ) throw std::runtime_error("AsyncTargetBuffer does not support adjusted matrices."); target_scores[channel] = &score_matrix.matrix32()[32 * l]; } return target_scores; } bool init_target(int i, int channel) { const BlockId n = (*next)++; if (n >= target_count) { active.erase(i); return false; } DpTarget t = begin[n]; if (t.blank()) t.target_idx = n; pos[channel] = 0; dp_targets[channel] = t; if (reverse_targets) target_seqs[channel].assign_reversed(t.seq.data(), t.seq.end()); else target_seqs[channel].assign(t.seq.data(), t.seq.end()); return true; } bool inc(int channel) { ++pos[channel]; if (pos[channel] >= (int)dp_targets[channel].seq.length()) return false; return true; } uint32_t cbs_mask() { uint32_t r = 0; custom_matrix_16bit = false; for (int i = 0; i < active.size(); ++i) { const int channel = active[i]; if (dp_targets[channel].adjusted_matrix()) { r |= 1 << channel; if (dp_targets[channel].matrix->score_max > SCHAR_MAX || dp_targets[channel].matrix->score_min < SCHAR_MIN) custom_matrix_16bit = true; } } return r; } const bool reverse_targets; int pos[CHANNELS]; SmallVector active; const It begin; const BlockId target_count; std::atomic* const next; DpTarget dp_targets[CHANNELS]; bool custom_matrix_16bit; std::array, CHANNELS> target_seqs; }; }bbuchfink-diamond-08b3cbc/src/dp/ungapped.h000066400000000000000000000041311506104011400207010ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2022 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "basic/value.h" #include "util/geo/diagonal_segment.h" #include "stats/hauser_correction.h" //int xdrop_ungapped(const Letter *query, const Letter *subject, unsigned seed_len, unsigned &delta, unsigned &len); //int xdrop_ungapped(const Letter *query, const Letter *subject, unsigned &delta, unsigned &len); int xdrop_ungapped_right(const Letter *query, const Letter *subject, int &len); int ungapped_window(const Letter* query, const Letter* subject, int window); DiagonalSegment xdrop_ungapped(const Sequence &query, const HauserCorrection& query_bc, const Sequence &subject, int qa, int sa); DiagonalSegment xdrop_ungapped(const Sequence& query, const int8_t* query_cbs, const Sequence& subject, int qa, int sa, bool count_identities); DiagonalSegment xdrop_ungapped(const Sequence& query, const Sequence& subject, const DiagonalSegment& anchor); int score_range(Sequence query, Sequence subject, int i, int j, int j_end); template DiagonalSegment score_range_s(Sequence query, Cbs query_cbs, Sequence subject, int i, int j, int j_end); Score self_score(const Sequence& seq); Hsp trivial(Sequence query, Sequence target, const int8_t* query_cbs); Anchor make_clipped_anchor(const Anchor& anchor, Sequence query, const int8_t* query_cbs, Sequence target); Anchor make_null_anchor(const Anchor& anchor);bbuchfink-diamond-08b3cbc/src/dp/ungapped_align.cpp000066400000000000000000000264131506104011400224150ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2017 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "dp.h" #include "../stats/score_matrix.h" #include "../stats/hauser_correction.h" #include "../util/sequence/sequence.h" using std::max; using std::pair; using std::min; using std::nullptr_t; using std::vector; int xdrop_ungapped(const Letter *query, const Letter *subject, unsigned &delta, unsigned &len) { int score(0), st(0), n=1; delta = 0; const Letter *q(query - 1), *s(subject - 1); while (score - st < config.raw_ungapped_xdrop && *q != Sequence::DELIMITER && *s != Sequence::DELIMITER) { #ifdef SEQ_MASK st += score_matrix(letter_mask(*q), letter_mask(*s)); #else st += score_matrix(*q, *s); #endif if (st > score) { score = st; delta = n; } --q; --s; ++n; } q = query; s = subject; st = score; n = 1; len = 0; while (score - st < config.raw_ungapped_xdrop && *q != Sequence::DELIMITER && *s != Sequence::DELIMITER) { #ifdef SEQ_MASK st += score_matrix(letter_mask(*q), letter_mask(*s)); #else st += score_matrix(*q, *s); #endif if (st > score) { score = st; len = n; } ++q; ++s; ++n; } len += delta; return score; } DiagonalSegment xdrop_ungapped(const Sequence &query, const HauserCorrection& query_bc, const Sequence &subject, int qa, int sa) { const float xdrop = (float)config.raw_ungapped_xdrop; float score = 0, st = 0; int n = 1, delta = 0, len = 0; int q = qa - 1, s = sa - 1; Letter ql, sl; while (score - st < xdrop && (ql = query[q]) != Sequence::DELIMITER && (sl = subject[s]) != Sequence::DELIMITER) { st += score_matrix(ql, sl) + query_bc[q]; if (st > score) { score = st; delta = n; } --q; --s; ++n; } q = qa; s = sa; st = score; n = 1; while (score - st < xdrop && (ql = query[q]) != Sequence::DELIMITER && (sl = subject[s]) != Sequence::DELIMITER) { st += score_matrix(ql, sl) + query_bc[q]; if (st > score) { score = st; len = n; } ++q; ++s; ++n; } return DiagonalSegment(qa - delta, sa - delta, len + delta, (int)score); } static void add_cbs(Score&, Loc, nullptr_t) {} static void add_cbs(Score& score, Loc loc, const int8_t* cbs) { score += (Score)cbs[loc]; } struct CountIdentities { CountIdentities() : n(0) {} void operator()(Letter a, Letter b) { const bool eq = a == b; n += (Loc)eq; } void update(Loc& ident) { ident += n; n = 0; } Loc n; }; struct ScoreOnly { void operator()(Letter a, Letter b) const {} void update(Loc) const {} }; template DiagonalSegment xdrop_ungapped(const Sequence& query, Cbs query_cbs, const Sequence& subject, int qa, int sa, const Id&) { Id id; const int xdrop = config.raw_ungapped_xdrop; int score = 0, st = 0; int n = 1, delta = 0, len = 0, ident = 0; int q = qa - 1, s = sa - 1; Letter ql, sl; while (score - st < xdrop && (ql = query[q]) != Sequence::DELIMITER && (sl = subject[s]) != Sequence::DELIMITER) { st += score_matrix(ql, sl); add_cbs(st, q, query_cbs); id(ql, sl); if (st > score) { score = st; delta = n; id.update(ident); } --q; --s; ++n; } q = qa; s = sa; st = score; n = 1; id = Id(); while (score - st < xdrop && (ql = query[q]) != Sequence::DELIMITER && (sl = subject[s]) != Sequence::DELIMITER) { st += score_matrix(ql, sl); add_cbs(st, q, query_cbs); id(ql, sl); if (st > score) { score = st; len = n; id.update(ident); } ++q; ++s; ++n; } return DiagonalSegment(qa - delta, sa - delta, len + delta, score, ident); } DiagonalSegment xdrop_ungapped(const Sequence& query, const int8_t* query_cbs, const Sequence& subject, int qa, int sa, bool count_identities) { if (count_identities) { if (query_cbs == nullptr) return xdrop_ungapped(query, nullptr, subject, qa, sa, CountIdentities()); else return xdrop_ungapped(query, query_cbs, subject, qa, sa, CountIdentities()); } else { if (query_cbs == nullptr) return xdrop_ungapped(query, nullptr, subject, qa, sa, ScoreOnly()); else return xdrop_ungapped(query, query_cbs, subject, qa, sa, ScoreOnly()); } } int xdrop_ungapped_right(const Letter *query, const Letter *subject, int &len) { int score(0), st(0), n = 1; len = 0; const Letter *q = query; const Letter *s = subject; while (score - st < config.raw_ungapped_xdrop && *q != Sequence::DELIMITER && *s != Sequence::DELIMITER) { #ifdef SEQ_MASK st += score_matrix(letter_mask(*q), letter_mask(*s)); #else st += score_matrix(*q, *s); #endif if (st > score) { score = st; len = n; } ++q; ++s; ++n; } return score; } int ungapped_window(const Letter* query, const Letter* subject, int window) { int score = 0, st = 0, n = 0; const Letter* q = query, * s = subject; while (n < window) { st += score_matrix(letter_mask(*q), letter_mask(*s)); st = std::max(st, 0); score = std::max(score, st); ++q; ++s; ++n; } return score; } Score self_score(const Sequence& seq) { Score s = 0, sl = 0; if (Stats::CBS::hauser(config.comp_based_stats)) { HauserCorrection cbs(seq); for (Loc i = 0; i < seq.length(); ++i) { const Letter l = seq[i]; sl += score_matrix(l, l) + cbs.int8[i]; sl = max(sl, 0); s = max(s, sl); } } else { for (Loc i = 0; i < seq.length(); ++i) { const Letter l = seq[i]; sl += score_matrix(l, l); sl = max(sl, 0); s = max(s, sl); } } return s; } int score_range(Sequence query, Sequence subject, int i, int j, int j_end) { int score = 0; while (j < j_end) { score += score_matrix(query[i], subject[j]); ++i; ++j; } return score; } template DiagonalSegment score_range_s(Sequence query, Cbs query_cbs, Sequence subject, int i_begin, int j_begin, int j_end) { int score = 0, i = i_begin; for (Loc j = j_begin; j < j_end; ++j, ++i) { score += score_matrix(query[i], subject[j]); add_cbs(score, i, query_cbs); } return DiagonalSegment(i_begin, j_begin, j_end - j_begin, score); } template DiagonalSegment score_range_s(Sequence, const int8_t*, Sequence, int, int, int); template DiagonalSegment score_range_s(Sequence, nullptr_t, Sequence, int, int, int); template struct Increment { T operator()(T x) const { return ++x; } }; template struct Decrement { T operator()(T x) const { return --x; } }; template pair xdrop_anchored(const Letter* p1, const Letter* p2, Loc len, Inc inc) { if (len == 0) return { 0,0 }; Score max_score = 0, score = 0; Loc max_n = 0, n = 0; do { score += score_matrix(letter_mask(*p1), letter_mask(*p2)); ++n; p1 = inc(p1); p2 = inc(p2); if (score > max_score) { max_score = score; max_n = n; } } while (n < len && max_score - score < config.raw_ungapped_xdrop); return { max_score, max_n }; } DiagonalSegment xdrop_ungapped(const Sequence& query, const Sequence& subject, const DiagonalSegment& anchor) { auto left = xdrop_anchored(query.data() + anchor.i - 1, subject.data() + anchor.j - 1, std::min(anchor.i, anchor.j), Decrement()); auto right = xdrop_anchored(query.data() + anchor.query_end(), subject.data() + anchor.subject_end(), std::min(query.length() - anchor.query_end(), subject.length() - anchor.subject_end()), Increment()); return { anchor.i - left.second, anchor.j - left.second, anchor.len + left.second + right.second, left.first + right.first + score_range(query, subject, anchor.i, anchor.j, anchor.subject_end()) }; } static Hsp trivial(Sequence query, Sequence target, Loc dq, Loc dt, const int8_t* query_cbs) { static const Loc WINDOW = 40, ID = 30; const Loc l = min(query.length() - dq, target.length() - dt); const uint64_t bits = ((uint64_t)1 << WINDOW) - 1; Loc n = 0; Score score = 0; uint64_t mask = 0; for (Loc i = 0; i < l; ++i) { uint64_t eq = query[i + dq] == target[i + dt]; mask = ((mask << 1) | eq) & bits; ++n; if (n >= WINDOW && popcount64(mask) < ID) return Hsp(); score += score_matrix(query[i + dq], target[i + dt]); if (query_cbs) score += query_cbs[i + dq]; } const double evalue = score_matrix.evalue(score, query.length(), target.length()); if (evalue > config.max_evalue) return Hsp(); if (l < WINDOW && (double)popcount64(mask) / l < ID / WINDOW) return Hsp(); Hsp hsp; hsp.score = score; hsp.query_range = hsp.query_source_range = { dq, dq + l }; hsp.subject_range = { dt, dt + l }; hsp.evalue = evalue; hsp.bit_score = score_matrix.bitscore(score); return hsp; } Hsp trivial(Sequence query, Sequence target, const int8_t* query_cbs) { if (query.length() <= target.length()) { for (Loc i = 0; i <= target.length() - query.length(); ++i) { Hsp hsp = trivial(query, target, 0, i, query_cbs); if (hsp.score) return hsp; } } else { for (Loc i = 0; i <= query.length() - target.length(); ++i) { Hsp hsp = trivial(query, target, i, 0, query_cbs); if (hsp.score) return hsp; } } return Hsp(); } Anchor make_clipped_anchor(const Anchor& anchor, Sequence query, const int8_t* query_cbs, Sequence target) { const Sequence q = query.subseq(anchor.query_begin(), anchor.query_end()), t = target.subseq(anchor.subject_begin(), anchor.subject_end()); const vector s = Util::Seq::window_scores(q, t, config.anchor_window); const Score cutoff = (Score)round(config.anchor_score * config.anchor_window); const auto pred = [cutoff](Score s) { return s >= cutoff; }; const auto max_window = max_element(s.begin(), s.end()); const auto right = find_if_not(max_window + 1, s.cend(), pred); const auto max_window_r = s.crbegin() + (s.cend() - max_window - 1); const auto left_r = find_if_not(max_window_r + 1, s.crend(), pred); Loc d1 = Loc(right - s.cbegin()), d0 = std::max(Loc(s.crend() - left_r - config.anchor_window + 1), 0); while (d0 < q.length() && q[d0] != t[d0]) ++d0; while (d1 > 0 && q[d1 - 1] != t[d1 - 1]) --d1; if (d1 <= d0) return DiagonalSegment(); const DiagonalSegment clipped_anchor = query_cbs == nullptr ? score_range_s(query, nullptr, target, anchor.query_begin() + d0, anchor.subject_begin() + d0, anchor.subject_begin() + d1) : score_range_s(query, query_cbs, target, anchor.query_begin() + d0, anchor.subject_begin() + d0, anchor.subject_begin() + d1); const Score clipped_score = query_cbs == nullptr ? score_range_s(query, nullptr, target, anchor.query_begin() + d1, anchor.subject_begin() + d1, anchor.subject_end()).score : score_range_s(query, query_cbs, target, anchor.query_begin() + d1, anchor.subject_begin() + d1, anchor.subject_end()).score; return Anchor(clipped_anchor, anchor.d_min_left, anchor.d_max_left, anchor.d_min_right, anchor.d_max_right, anchor.prefix_score - clipped_score); } Anchor make_null_anchor(const Anchor& anchor) { return Anchor(anchor.i + anchor.len / 2, anchor.j + anchor.len / 2, 0, 0); }bbuchfink-diamond-08b3cbc/src/dp/ungapped_simd.cpp000066400000000000000000000061751506104011400222620ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #include #include "score_vector_int8.h" #include "ungapped_simd.h" #include "util/simd/transpose.h" #include "ungapped.h" #include "util/simd/dispatch.h" #include "util/simd/vector.h" using namespace DISPATCH_ARCH; namespace DP { namespace DISPATCH_ARCH { void window_ungapped(const Letter *query, const Letter **subjects, int subject_count, int window, int *out) { #if defined(__SSE4_1__) | defined(__aarch64__) using Sv = ScoreVector; typedef ::DISPATCH_ARCH::SIMD::Vector SeqV; constexpr int CHANNELS = ::DISPATCH_ARCH::ScoreTraits::CHANNELS; assert(subject_count <= CHANNELS); alignas(CHANNELS) Letter subject_vector[CHANNELS * CHANNELS]; Sv score, best; const Letter* subject_ptr[CHANNELS], * query_end = query + window; std::copy(subjects, subjects + subject_count, subject_ptr); for (int i = 0; i < window; i += CHANNELS) { transpose(subject_ptr, subject_count, subject_vector, SeqV()); for (size_t j = 0; j < CHANNELS && query < query_end;) { SeqV subject_letters(&subject_vector[j * CHANNELS]); unsigned query_letter = unsigned(*query); #ifdef SEQ_MASK query_letter &= (unsigned)LETTER_MASK; #endif const Sv match(query_letter, subject_letters); score = score + match; best = max(best, score); ++query; subject_ptr[j] += CHANNELS; ++j; } } int8_t best2[CHANNELS]; best.store(best2); const int d = CHANNELS - subject_count; for (int i = 0; i < subject_count; ++i) out[i] = ScoreTraits::int_score(best2[d + i]); #endif } void window_ungapped_best(const Letter* query, const Letter** subjects, int subject_count, int window, int* out) { #if defined(__SSE4_1__) | defined(__aarch64__) if (subject_count < 4) { #endif for (int i = 0; i < subject_count; ++i) out[i] = ungapped_window(query, subjects[i], window); #if defined(__SSE4_1__) | defined(__aarch64__) } #endif #if ARCH_ID == 2 //else if (subject_count <= 16) //::DP::ARCH_SSE4_1::window_ungapped(query, subjects, subject_count, window, out); else window_ungapped(query, subjects, subject_count, window, out); #elif defined(__SSE4_1__) | defined(__aarch64__) window_ungapped(query, subjects, subject_count, window, out); #endif } } DISPATCH_5(void, window_ungapped, const Letter*, query, const Letter**, subjects, int, subject_count, int, window, int*, out); DISPATCH_5(void, window_ungapped_best, const Letter*, query, const Letter**, subjects, int, subject_count, int, window, int*, out); }bbuchfink-diamond-08b3cbc/src/dp/ungapped_simd.h000066400000000000000000000017541506104011400217250ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2020 Max Planck Society for the Advancement of Science e.V. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "basic/value.h" namespace DP { void window_ungapped(const Letter* query, const Letter** subjects, int subject_count, int window, int* out); void window_ungapped_best(const Letter* query, const Letter** subjects, int subject_count, int window, int* out); }bbuchfink-diamond-08b3cbc/src/legacy/000077500000000000000000000000001506104011400175675ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/legacy/dmnd/000077500000000000000000000000001506104011400205115ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/legacy/dmnd/compact_array.h000066400000000000000000000051361506104011400235130ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2018 Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include "util/io/deserializer.h" #include "util/algo/varint.h" struct CompactArray { CompactArray(Deserializer &in, size_t size, size_t data_size) : data_(data_size) { in.read(data_.data(), data_size); if(data_size > (size_t)UINT_MAX) init(size, data_size, limits64_); else init(size, data_size, limits_); } std::vector operator[](size_t i) const { return data_.size() > (size_t)UINT_MAX ? get(i, limits64_) : get(i, limits_); } size_t size() const { return (data_.size() > (size_t)UINT_MAX ? limits64_.size() : limits_.size()) - 1; } private: template void init(int64_t size, int64_t data_size, std::vector& limits) { limits.reserve(size + 1); limits.push_back(0); const char* ptr = data_.data(); for (int64_t i = 0; i < size; ++i) { ptr = skip_vec(ptr); const int64_t offset = ptr - data_.data(); if (offset > (int64_t)std::numeric_limits::max()) throw std::runtime_error("Array size overflow."); limits.push_back((Int)offset); } if ((int64_t)limits.back() != data_size) throw std::runtime_error("Error loading CompactArray."); } template std::vector get(size_t i, const std::vector& limits) const { return read_vec(&data_[limits[i]]); } static std::vector read_vec(const char* ptr) { uint32_t n; std::tie(n, ptr) = read_varuint32(ptr); std::vector out; out.reserve(n); for (uint32_t i = 0; i < n; ++i) { uint32_t v; std::tie(v, ptr) = read_varuint32(ptr); out.push_back(v); } return out; } static const char* skip_vec(const char* ptr) { uint32_t n; std::tie(n, ptr) = read_varuint32(ptr); for (uint32_t i = 0; i < n; ++i) { uint32_t v; std::tie(v, ptr) = read_varuint32(ptr); } return ptr; } std::vector data_; std::vector limits_; std::vector limits64_; }; bbuchfink-diamond-08b3cbc/src/legacy/dmnd/io.h000066400000000000000000000045601506104011400212760ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2024 Benjamin Buchfink Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include "util/algo/varint.h" #include "util/io/serializer.h" static inline void write_varint(Serializer& s, int32_t x) { char buf[5]; char* end = write_varuint32(x, buf); s.write_raw(buf, end - buf); } template static inline void serialize_varint(Serializer& s, It begin, It end) { for (It i = begin; i != end; ++i) write_varint(s, *i); } template static inline void serialize(Serializer& s, It begin, It end) { for (It i = begin; i != end; ++i) s << *i; } static inline void serialize(Serializer& s, const std::set& v) { write_varint(s, (int32_t)v.size()); serialize_varint(s, v.cbegin(), v.cend()); } static inline void serialize(Serializer& s, const std::vector& v) { s.write((uint32_t)v.size()); serialize(s, v.cbegin(), v.cend()); } static inline void serialize(Serializer& s, const std::vector& v) { s.write((uint32_t)v.size()); serialize(s, v.cbegin(), v.cend()); } template void serialize(Serializer& s, const std::pair& p) { s << p.first << p.second; } static inline void deserialize(Deserializer& d, std::vector& out) { uint32_t n; d >> n; out.clear(); out.reserve(n); std::string s; for (uint32_t i = 0; i < n; ++i) { d >> s; out.push_back(std::move(s)); } } static inline void deserialize(Deserializer& d, std::vector& out) { uint32_t n; d >> n; out.clear(); out.reserve(n); int32_t x; for (uint32_t i = 0; i < n; ++i) { d >> x; out.push_back(x); } } template void deserialize(Deserializer& s, std::pair& out) { s >> out.first >> out.second; }bbuchfink-diamond-08b3cbc/src/legacy/dmnd/record_reader.h000066400000000000000000000022561506104011400234670ustar00rootroot00000000000000#pragma once #include #include #include #include "util/io/deserializer.h" struct Finish {}; struct DynamicRecordReader { DynamicRecordReader(Deserializer& d) : d_(d) { d >> size_; } DynamicRecordReader& operator>>(unsigned long long& x) { if (size_ >= sizeof(unsigned long long)) { d_ >> x; size_ -= sizeof(unsigned long long); } else x = 0; return *this; } DynamicRecordReader& operator>>(unsigned long& x) { if (size_ >= sizeof(unsigned long)) { d_ >> x; size_ -= sizeof(unsigned long); } else x = 0; return *this; } template DynamicRecordReader& read(const T* ptr, size_t count) { const size_t s = count * sizeof(T); if (size_ >= s) { d_.read(ptr, count); size_ -= s; } else memset((void*)ptr, 0, s); return *this; } DynamicRecordReader& operator>>(int& x) { if (size_ >= sizeof(int)) { d_ >> x; size_ -= sizeof(int); } else x = 0; return *this; } void operator>>(const Finish&) { if (size_ == 0) return; char* buf = new char[size_]; d_.read(buf, size_); delete[] buf; size_ = 0; } private: Deserializer& d_; uint64_t size_; };bbuchfink-diamond-08b3cbc/src/legacy/util/000077500000000000000000000000001506104011400205445ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/legacy/util/task_queue.h000066400000000000000000000073721506104011400230740ustar00rootroot00000000000000/**** DIAMOND protein aligner Copyright (C) 2013-2021 Max Planck Society for the Advancement of Science e.V. Benjamin Buchfink Eberhard Karls Universitaet Tuebingen Code developed by Benjamin Buchfink This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ****/ #pragma once #include #include #include // #define ENABLE_LOGGING template struct TaskQueue { TaskQueue(size_t limit, Callback& callback): queue_ (limit), state_ (limit), head_ (0), tail_ (0), limit_ (limit), head_idx_ (0), queued_ (0), queued_size_ (0), at_end_ (false), callback_ (callback) { } bool waiting() const { return tail_ - head_ >= limit_; } template bool get(size_t &n, T*& res, _init &init) { { std::unique_lock lock(mtx_); #ifdef ENABLE_LOGGING log_stream << "Task_queue get() thread=" << tthread::thread::get_current_thread_id() << " waiting=" << waiting() << " head=" << head_ << " tail=" << tail_ << endl; #endif while(waiting() && !at_end_) cond_.wait(lock); if(at_end_) { #ifdef ENABLE_LOGGING log_stream << "Task_queue get() thread=" << tthread::thread::get_current_thread_id() << " quit" << endl; #endif return false; } n = tail_++; res = &slot(n); if (!init()) at_end_ = true; #ifdef ENABLE_LOGGING log_stream << "Task_queue get() thread=" << tthread::thread::get_current_thread_id() << " n=" << n << endl; #endif } if(at_end_) cond_.notify_all(); return true; } void wake_all() { cond_.notify_all(); } void push(size_t n) { mtx_.lock(); if(n == head_) { #ifdef ENABLE_LOGGING log_stream << "Task_queue flush() thread=" << tthread::thread::get_current_thread_id() << " n=" << n << endl; #endif mtx_.unlock(); flush(); } else { #ifdef ENABLE_LOGGING message_stream << "Task_queue push() thread=" << tthread::thread::get_current_thread_id() << " n=" << n << " head=" << head_ << " size=" << queued_size_ << endl; #endif state_[idx(n)] = true; ++queued_; queued_size_ += slot(n).size(); mtx_.unlock(); } } unsigned flush() { bool next = false; unsigned n = 0; do { callback_(slot(head_)); { mtx_.lock(); #ifdef ENABLE_LOGGING log_stream << "Task_queue flush() thread=" << tthread::thread::get_current_thread_id() << " head=" << head_ << " waiting=" << tail_-head_ << "/" << limit_ << " size=" << queued_size_ << endl; #endif state_[idx(head_)] = false; ++head_; head_idx_ = (head_idx_ + 1) % limit_; if (state_[idx(head_)]) { next = true; #ifdef ENABLE_LOGGING log_stream << "Task_queue n=" << queued_ << endl; #endif --queued_; queued_size_ -= slot(head_).size(); } else next = false; mtx_.unlock(); } cond_.notify_one(); ++n; } while (next); return n; } private: size_t idx(size_t n) const { return (head_idx_ + n - head_)%limit_; } T& slot(size_t n) { return queue_[idx(n)]; } std::vector queue_; std::vector state_; std::mutex mtx_; std::condition_variable cond_; size_t head_, tail_, limit_, head_idx_, queued_, queued_size_; bool at_end_; Callback &callback_; }; bbuchfink-diamond-08b3cbc/src/lib/000077500000000000000000000000001506104011400170715ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/000077500000000000000000000000001506104011400201205ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/CMakeLists.txt000066400000000000000000000012661506104011400226650ustar00rootroot00000000000000include(RegexUtils) test_escape_string_as_regex() file(GLOB Eigen_directory_files "*") escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") foreach(f ${Eigen_directory_files}) if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/src") list(APPEND Eigen_directory_files_to_install ${f}) endif() endforeach(f ${Eigen_directory_files}) install(FILES ${Eigen_directory_files_to_install} DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel ) install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel FILES_MATCHING PATTERN "*.h") bbuchfink-diamond-08b3cbc/src/lib/Eigen/Cholesky000066400000000000000000000022661506104011400216320ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CHOLESKY_MODULE_H #define EIGEN_CHOLESKY_MODULE_H #include "Core" #include "Jacobi" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup Cholesky_Module Cholesky module * * * * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. * Those decompositions are also accessible via the following methods: * - MatrixBase::llt() * - MatrixBase::ldlt() * - SelfAdjointView::llt() * - SelfAdjointView::ldlt() * * \code * #include * \endcode */ #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" #ifdef EIGEN_USE_LAPACKE #ifdef EIGEN_USE_MKL #include "mkl_lapacke.h" #else #include "src/misc/lapacke.h" #endif #include "src/Cholesky/LLT_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLESKY_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/CholmodSupport000066400000000000000000000035541506104011400230340ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CHOLMODSUPPORT_MODULE_H #define EIGEN_CHOLMODSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" extern "C" { #include } /** \ingroup Support_modules * \defgroup CholmodSupport_Module CholmodSupport module * * This module provides an interface to the Cholmod library which is part of the suitesparse package. * It provides the two following main factorization classes: * - class CholmodSupernodalLLT: a supernodal LLT Cholesky factorization. * - class CholmodDecomposiiton: a general L(D)LT Cholesky factorization with automatic or explicit runtime selection of the underlying factorization method (supernodal or simplicial). * * For the sake of completeness, this module also propose the two following classes: * - class CholmodSimplicialLLT * - class CholmodSimplicialLDLT * Note that these classes does not bring any particular advantage compared to the built-in * SimplicialLLT and SimplicialLDLT factorization classes. * * \code * #include * \endcode * * In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be linked to the cholmod library and its dependencies. * The dependencies depend on how cholmod has been compiled. * For a cmake based project, you can use our FindCholmod.cmake module to help you in this task. * */ #include "src/CholmodSupport/CholmodSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLMODSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/Core000066400000000000000000000432671506104011400207470ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2011 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CORE_H #define EIGEN_CORE_H // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" #if defined(__CUDACC__) && !defined(EIGEN_NO_CUDA) #define EIGEN_CUDACC __CUDACC__ #endif #if defined(__CUDA_ARCH__) && !defined(EIGEN_NO_CUDA) #define EIGEN_CUDA_ARCH __CUDA_ARCH__ #endif #if defined(__CUDACC_VER_MAJOR__) && (__CUDACC_VER_MAJOR__ >= 9) #define EIGEN_CUDACC_VER ((__CUDACC_VER_MAJOR__ * 10000) + (__CUDACC_VER_MINOR__ * 100)) #elif defined(__CUDACC_VER__) #define EIGEN_CUDACC_VER __CUDACC_VER__ #else #define EIGEN_CUDACC_VER 0 #endif // Handle NVCC/CUDA/SYCL #if defined(__CUDACC__) || defined(__SYCL_DEVICE_ONLY__) // Do not try asserts on CUDA and SYCL! #ifndef EIGEN_NO_DEBUG #define EIGEN_NO_DEBUG #endif #ifdef EIGEN_INTERNAL_DEBUGGING #undef EIGEN_INTERNAL_DEBUGGING #endif #ifdef EIGEN_EXCEPTIONS #undef EIGEN_EXCEPTIONS #endif // All functions callable from CUDA code must be qualified with __device__ #ifdef __CUDACC__ // Do not try to vectorize on CUDA and SYCL! #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #define EIGEN_DEVICE_FUNC __host__ __device__ // We need cuda_runtime.h to ensure that that EIGEN_USING_STD_MATH macro // works properly on the device side #include #else #define EIGEN_DEVICE_FUNC #endif #else #define EIGEN_DEVICE_FUNC #endif // When compiling CUDA device code with NVCC, pull in math functions from the // global namespace. In host mode, and when device doee with clang, use the // std versions. #if defined(__CUDA_ARCH__) && defined(__NVCC__) #define EIGEN_USING_STD_MATH(FUNC) using ::FUNC; #else #define EIGEN_USING_STD_MATH(FUNC) using std::FUNC; #endif #if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_USE_SYCL) #define EIGEN_EXCEPTIONS #endif #ifdef EIGEN_EXCEPTIONS #include #endif // then include this file where all our macros are defined. It's really important to do it first because // it's where we do all the alignment settings (platform detection and honoring the user's will if he // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. #include "src/Core/util/Macros.h" // Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. #if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6) #pragma GCC optimize ("-fno-ipa-cp-clone") #endif #include // this include file manages BLAS and MKL related macros // and inclusion of their respective header files #include "src/Core/util/MKL_support.h" // if alignment is disabled, then disable vectorization. Note: EIGEN_MAX_ALIGN_BYTES is the proper check, it takes into // account both the user's will (EIGEN_MAX_ALIGN_BYTES,EIGEN_DONT_ALIGN) and our own platform checks #if EIGEN_MAX_ALIGN_BYTES==0 #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #endif #if EIGEN_COMP_MSVC #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled #if (EIGEN_COMP_MSVC >= 1500) // 2008 or later // Remember that usage of defined() in a #define is undefined by the standard. // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || EIGEN_ARCH_x86_64 #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER #endif #endif #else // Remember that usage of defined() in a #define is undefined by the standard #if (defined __SSE2__) && ( (!EIGEN_COMP_GNUC) || EIGEN_COMP_ICC || EIGEN_GNUC_AT_LEAST(4,2) ) #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC #endif #endif #ifndef EIGEN_DONT_VECTORIZE #if defined (EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER) // Defines symbols for compile-time detection of which instructions are // used. // EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_SSE #define EIGEN_VECTORIZE_SSE2 // Detect sse3/ssse3/sse4: // gcc and icc defines __SSE3__, ... // there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you // want to force the use of those instructions with msvc. #ifdef __SSE3__ #define EIGEN_VECTORIZE_SSE3 #endif #ifdef __SSSE3__ #define EIGEN_VECTORIZE_SSSE3 #endif #ifdef __SSE4_1__ #define EIGEN_VECTORIZE_SSE4_1 #endif #ifdef __SSE4_2__ #define EIGEN_VECTORIZE_SSE4_2 #endif #ifdef __AVX__ #define EIGEN_VECTORIZE_AVX #define EIGEN_VECTORIZE_SSE3 #define EIGEN_VECTORIZE_SSSE3 #define EIGEN_VECTORIZE_SSE4_1 #define EIGEN_VECTORIZE_SSE4_2 #endif #ifdef __AVX2__ #define EIGEN_VECTORIZE_AVX2 #endif #ifdef __FMA__ #define EIGEN_VECTORIZE_FMA #endif #if defined(__AVX512F__) && defined(EIGEN_ENABLE_AVX512) #define EIGEN_VECTORIZE_AVX512 #define EIGEN_VECTORIZE_AVX2 #define EIGEN_VECTORIZE_AVX #define EIGEN_VECTORIZE_FMA #ifdef __AVX512DQ__ #define EIGEN_VECTORIZE_AVX512DQ #endif #ifdef __AVX512ER__ #define EIGEN_VECTORIZE_AVX512ER #endif #endif // include files // This extern "C" works around a MINGW-w64 compilation issue // https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354 // In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do). // However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations // with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know; // so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too. // notice that since these are C headers, the extern "C" is theoretically needed anyways. extern "C" { // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: #if EIGEN_COMP_ICC >= 1110 #include #else #include #include #include #ifdef EIGEN_VECTORIZE_SSE3 #include #endif #ifdef EIGEN_VECTORIZE_SSSE3 #include #endif #ifdef EIGEN_VECTORIZE_SSE4_1 #include #endif #ifdef EIGEN_VECTORIZE_SSE4_2 #include #endif #if defined(EIGEN_VECTORIZE_AVX) || defined(EIGEN_VECTORIZE_AVX512) #include #endif #endif } // end extern "C" #elif defined __VSX__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_VSX #include // We need to #undef all these ugly tokens defined in // => use __vector instead of vector #undef bool #undef vector #undef pixel #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ALTIVEC #include // We need to #undef all these ugly tokens defined in // => use __vector instead of vector #undef bool #undef vector #undef pixel #elif (defined __ARM_NEON) || (defined __ARM_NEON__) #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include #elif (defined __s390x__ && defined __VEC__) #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ZVECTOR #include #endif #endif #if defined(__F16C__) && !defined(EIGEN_COMP_CLANG) // We can use the optimized fp16 to float and float to fp16 conversion routines #define EIGEN_HAS_FP16_C #endif #if defined __CUDACC__ #define EIGEN_VECTORIZE_CUDA #include #if EIGEN_CUDACC_VER >= 70500 #define EIGEN_HAS_CUDA_FP16 #endif #endif #if defined EIGEN_HAS_CUDA_FP16 #include #include #endif #if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) #define EIGEN_HAS_OPENMP #endif #ifdef EIGEN_HAS_OPENMP #include #endif // MSVC for windows mobile does not have the errno.h file #if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM #define EIGEN_HAS_ERRNO #endif #ifdef EIGEN_HAS_ERRNO #include #endif #include #include #include #include #include #include #ifndef EIGEN_NO_IO #include #endif #include #include #include #include // for CHAR_BIT // for min/max: #include // for std::is_nothrow_move_assignable #ifdef EIGEN_INCLUDE_TYPE_TRAITS #include #endif // for outputting debug info #ifdef EIGEN_DEBUG_ASSIGN #include #endif // required for __cpuid, needs to be included after cmath #if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE #include #endif /** \brief Namespace containing all symbols from the %Eigen library. */ namespace Eigen { inline static const char *SimdInstructionSetsInUse(void) { #if defined(EIGEN_VECTORIZE_AVX512) return "AVX512, FMA, AVX2, AVX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_AVX) return "AVX SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_2) return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_1) return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; #elif defined(EIGEN_VECTORIZE_SSSE3) return "SSE, SSE2, SSE3, SSSE3"; #elif defined(EIGEN_VECTORIZE_SSE3) return "SSE, SSE2, SSE3"; #elif defined(EIGEN_VECTORIZE_SSE2) return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; #elif defined(EIGEN_VECTORIZE_VSX) return "VSX"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; #elif defined(EIGEN_VECTORIZE_ZVECTOR) return "S390X ZVECTOR"; #else return "None"; #endif } } // end namespace Eigen #if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT // This will generate an error message: #error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information #endif namespace Eigen { // we use size_t frequently and we'll never remember to prepend it with std:: everytime just to // ensure QNX/QCC support using std::size_t; // gcc 4.6.0 wants std:: for ptrdiff_t using std::ptrdiff_t; } /** \defgroup Core_Module Core module * This is the main module of Eigen providing dense matrix and vector support * (both fixed and dynamic size) with all the features corresponding to a BLAS library * and much more... * * \code * #include * \endcode */ #include "src/Core/util/Constants.h" #include "src/Core/util/Meta.h" #include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" #include "src/Core/GenericPacketMath.h" #include "src/Core/MathFunctionsImpl.h" #include "src/Core/arch/Default/ConjHelper.h" #if defined EIGEN_VECTORIZE_AVX512 #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/AVX/PacketMath.h" #include "src/Core/arch/AVX/MathFunctions.h" #include "src/Core/arch/AVX512/PacketMath.h" #include "src/Core/arch/AVX512/MathFunctions.h" #elif defined EIGEN_VECTORIZE_AVX // Use AVX for floats and doubles, SSE for integers #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/Complex.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/AVX/PacketMath.h" #include "src/Core/arch/AVX/MathFunctions.h" #include "src/Core/arch/AVX/Complex.h" #include "src/Core/arch/AVX/TypeCasting.h" #include "src/Core/arch/SSE/TypeCasting.h" #elif defined EIGEN_VECTORIZE_SSE #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" #include "src/Core/arch/SSE/TypeCasting.h" #elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) #include "src/Core/arch/AltiVec/PacketMath.h" #include "src/Core/arch/AltiVec/MathFunctions.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" #include "src/Core/arch/NEON/MathFunctions.h" #include "src/Core/arch/NEON/Complex.h" #elif defined EIGEN_VECTORIZE_ZVECTOR #include "src/Core/arch/ZVector/PacketMath.h" #include "src/Core/arch/ZVector/MathFunctions.h" #include "src/Core/arch/ZVector/Complex.h" #endif // Half float support #include "src/Core/arch/CUDA/Half.h" #include "src/Core/arch/CUDA/PacketMathHalf.h" #include "src/Core/arch/CUDA/TypeCasting.h" #if defined EIGEN_VECTORIZE_CUDA #include "src/Core/arch/CUDA/PacketMath.h" #include "src/Core/arch/CUDA/MathFunctions.h" #endif #include "src/Core/arch/Default/Settings.h" #include "src/Core/functors/TernaryFunctors.h" #include "src/Core/functors/BinaryFunctors.h" #include "src/Core/functors/UnaryFunctors.h" #include "src/Core/functors/NullaryFunctors.h" #include "src/Core/functors/StlFunctors.h" #include "src/Core/functors/AssignmentFunctors.h" // Specialized functors to enable the processing of complex numbers // on CUDA devices #include "src/Core/arch/CUDA/Complex.h" #include "src/Core/IO.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" #include "src/Core/Product.h" #include "src/Core/CoreEvaluators.h" #include "src/Core/AssignEvaluator.h" #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 #include "src/Core/Assign.h" #endif #include "src/Core/ArrayBase.h" #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" // #include "src/Core/ForceAlignedAccess.h" #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" #include "src/Core/Matrix.h" #include "src/Core/Array.h" #include "src/Core/CwiseTernaryOp.h" #include "src/Core/CwiseBinaryOp.h" #include "src/Core/CwiseUnaryOp.h" #include "src/Core/CwiseNullaryOp.h" #include "src/Core/CwiseUnaryView.h" #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" #include "src/Core/Stride.h" #include "src/Core/MapBase.h" #include "src/Core/Map.h" #include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" #include "src/Core/GeneralProduct.h" #include "src/Core/Solve.h" #include "src/Core/Inverse.h" #include "src/Core/SolverBase.h" #include "src/Core/PermutationMatrix.h" #include "src/Core/Transpositions.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" #include "src/Core/ProductEvaluators.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" #include "src/Core/products/GeneralMatrixMatrixTriangular.h" #include "src/Core/products/SelfadjointMatrixVector.h" #include "src/Core/products/SelfadjointMatrixMatrix.h" #include "src/Core/products/SelfadjointProduct.h" #include "src/Core/products/SelfadjointRank2Update.h" #include "src/Core/products/TriangularMatrixVector.h" #include "src/Core/products/TriangularMatrixMatrix.h" #include "src/Core/products/TriangularSolverMatrix.h" #include "src/Core/products/TriangularSolverVector.h" #include "src/Core/BandMatrix.h" #include "src/Core/CoreIterators.h" #include "src/Core/ConditionEstimator.h" #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" #include "src/Core/VectorwiseOp.h" #include "src/Core/Random.h" #include "src/Core/Replicate.h" #include "src/Core/Reverse.h" #include "src/Core/ArrayWrapper.h" #ifdef EIGEN_USE_BLAS #include "src/Core/products/GeneralMatrixMatrix_BLAS.h" #include "src/Core/products/GeneralMatrixVector_BLAS.h" #include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h" #include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h" #include "src/Core/products/SelfadjointMatrixVector_BLAS.h" #include "src/Core/products/TriangularMatrixMatrix_BLAS.h" #include "src/Core/products/TriangularMatrixVector_BLAS.h" #include "src/Core/products/TriangularSolverMatrix_BLAS.h" #endif // EIGEN_USE_BLAS #ifdef EIGEN_USE_MKL_VML #include "src/Core/Assign_MKL.h" #endif #include "src/Core/GlobalFunctions.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CORE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/Dense000066400000000000000000000001721506104011400211010ustar00rootroot00000000000000#include "Core" #include "LU" #include "Cholesky" #include "QR" #include "SVD" #include "Geometry" #include "Eigenvalues" bbuchfink-diamond-08b3cbc/src/lib/Eigen/Eigen000066400000000000000000000000431506104011400210670ustar00rootroot00000000000000#include "Dense" #include "Sparse" bbuchfink-diamond-08b3cbc/src/lib/Eigen/Eigenvalues000066400000000000000000000034361506104011400223200ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_EIGENVALUES_MODULE_H #define EIGEN_EIGENVALUES_MODULE_H #include "Core" #include "Cholesky" #include "Jacobi" #include "Householder" #include "LU" #include "Geometry" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup Eigenvalues_Module Eigenvalues module * * * * This module mainly provides various eigenvalue solvers. * This module also provides some MatrixBase methods, including: * - MatrixBase::eigenvalues(), * - MatrixBase::operatorNorm() * * \code * #include * \endcode */ #include "src/misc/RealSvd2x2.h" #include "src/Eigenvalues/Tridiagonalization.h" #include "src/Eigenvalues/RealSchur.h" #include "src/Eigenvalues/EigenSolver.h" #include "src/Eigenvalues/SelfAdjointEigenSolver.h" #include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h" #include "src/Eigenvalues/HessenbergDecomposition.h" #include "src/Eigenvalues/ComplexSchur.h" #include "src/Eigenvalues/ComplexEigenSolver.h" #include "src/Eigenvalues/RealQZ.h" #include "src/Eigenvalues/GeneralizedEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" #ifdef EIGEN_USE_LAPACKE #ifdef EIGEN_USE_MKL #include "mkl_lapacke.h" #else #include "src/misc/lapacke.h" #endif #include "src/Eigenvalues/RealSchur_LAPACKE.h" #include "src/Eigenvalues/ComplexSchur_LAPACKE.h" #include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_EIGENVALUES_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/Geometry000066400000000000000000000040021506104011400216320ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GEOMETRY_MODULE_H #define EIGEN_GEOMETRY_MODULE_H #include "Core" #include "SVD" #include "LU" #include #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup Geometry_Module Geometry module * * This module provides support for: * - fixed-size homogeneous transformations * - translation, scaling, 2D and 3D rotations * - \link Quaternion quaternions \endlink * - cross products (\ref MatrixBase::cross, \ref MatrixBase::cross3) * - orthognal vector generation (\ref MatrixBase::unitOrthogonal) * - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink * - \link AlignedBox axis aligned bounding boxes \endlink * - \link umeyama least-square transformation fitting \endlink * * \code * #include * \endcode */ #include "src/Geometry/OrthoMethods.h" #include "src/Geometry/EulerAngles.h" #include "src/Geometry/Homogeneous.h" #include "src/Geometry/RotationBase.h" #include "src/Geometry/Rotation2D.h" #include "src/Geometry/Quaternion.h" #include "src/Geometry/AngleAxis.h" #include "src/Geometry/Transform.h" #include "src/Geometry/Translation.h" #include "src/Geometry/Scaling.h" #include "src/Geometry/Hyperplane.h" #include "src/Geometry/ParametrizedLine.h" #include "src/Geometry/AlignedBox.h" #include "src/Geometry/Umeyama.h" // Use the SSE optimized version whenever possible. At the moment the // SSE version doesn't compile when AVX is enabled #if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX #include "src/Geometry/arch/Geometry_SSE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_GEOMETRY_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/Householder000066400000000000000000000015521506104011400223270ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_HOUSEHOLDER_MODULE_H #define EIGEN_HOUSEHOLDER_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup Householder_Module Householder module * This module provides Householder transformations. * * \code * #include * \endcode */ #include "src/Householder/Householder.h" #include "src/Householder/HouseholderSequence.h" #include "src/Householder/BlockHouseholder.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_HOUSEHOLDER_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/IterativeLinearSolvers000066400000000000000000000040431506104011400245110ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H #define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H #include "SparseCore" #include "OrderingMethods" #include "src/Core/util/DisableStupidWarnings.h" /** * \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module * * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. * Those solvers are accessible via the following classes: * - ConjugateGradient for selfadjoint (hermitian) matrices, * - LeastSquaresConjugateGradient for rectangular least-square problems, * - BiCGSTAB for general square matrices. * * These iterative solvers are associated with some preconditioners: * - IdentityPreconditioner - not really useful * - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices. * - IncompleteLUT - incomplete LU factorization with dual thresholding * * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. * \code #include \endcode */ #include "src/IterativeLinearSolvers/SolveWithGuess.h" #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" #include "src/IterativeLinearSolvers/ConjugateGradient.h" #include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h" #include "src/IterativeLinearSolvers/BiCGSTAB.h" #include "src/IterativeLinearSolvers/IncompleteLUT.h" #include "src/IterativeLinearSolvers/IncompleteCholesky.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/Jacobi000066400000000000000000000016531506104011400212370ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_JACOBI_MODULE_H #define EIGEN_JACOBI_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup Jacobi_Module Jacobi module * This module provides Jacobi and Givens rotations. * * \code * #include * \endcode * * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation: * - MatrixBase::applyOnTheLeft() * - MatrixBase::applyOnTheRight(). */ #include "src/Jacobi/Jacobi.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_JACOBI_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/LU000066400000000000000000000026311506104011400203650ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LU_MODULE_H #define EIGEN_LU_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup LU_Module LU module * This module includes %LU decomposition and related notions such as matrix inversion and determinant. * This module defines the following MatrixBase methods: * - MatrixBase::inverse() * - MatrixBase::determinant() * * \code * #include * \endcode */ #include "src/misc/Kernel.h" #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" #include "src/LU/PartialPivLU.h" #ifdef EIGEN_USE_LAPACKE #ifdef EIGEN_USE_MKL #include "mkl_lapacke.h" #else #include "src/misc/lapacke.h" #endif #include "src/LU/PartialPivLU_LAPACKE.h" #endif #include "src/LU/Determinant.h" #include "src/LU/InverseImpl.h" // Use the SSE optimized version whenever possible. At the moment the // SSE version doesn't compile when AVX is enabled #if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX #include "src/LU/arch/Inverse_SSE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/MetisSupport000066400000000000000000000017371506104011400225310ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_METISSUPPORT_MODULE_H #define EIGEN_METISSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" extern "C" { #include } /** \ingroup Support_modules * \defgroup MetisSupport_Module MetisSupport module * * \code * #include * \endcode * This module defines an interface to the METIS reordering package (http://glaros.dtc.umn.edu/gkhome/views/metis). * It can be used just as any other built-in method as explained in \link OrderingMethods_Module here. \endlink */ #include "src/MetisSupport/MetisSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_METISSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/OrderingMethods000066400000000000000000000046631506104011400231510ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ORDERINGMETHODS_MODULE_H #define EIGEN_ORDERINGMETHODS_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" /** * \defgroup OrderingMethods_Module OrderingMethods module * * This module is currently for internal use only * * It defines various built-in and external ordering methods for sparse matrices. * They are typically used to reduce the number of elements during * the sparse matrix decomposition (LLT, LU, QR). * Precisely, in a preprocessing step, a permutation matrix P is computed using * those ordering methods and applied to the columns of the matrix. * Using for instance the sparse Cholesky decomposition, it is expected that * the nonzeros elements in LLT(A*P) will be much smaller than that in LLT(A). * * * Usage : * \code * #include * \endcode * * A simple usage is as a template parameter in the sparse decomposition classes : * * \code * SparseLU > solver; * \endcode * * \code * SparseQR > solver; * \endcode * * It is possible as well to call directly a particular ordering method for your own purpose, * \code * AMDOrdering ordering; * PermutationMatrix perm; * SparseMatrix A; * //Fill the matrix ... * * ordering(A, perm); // Call AMD * \endcode * * \note Some of these methods (like AMD or METIS), need the sparsity pattern * of the input matrix to be symmetric. When the matrix is structurally unsymmetric, * Eigen computes internally the pattern of \f$A^T*A\f$ before calling the method. * If your matrix is already symmetric (at leat in structure), you can avoid that * by calling the method with a SelfAdjointView type. * * \code * // Call the ordering on the pattern of the lower triangular matrix A * ordering(A.selfadjointView(), perm); * \endcode */ #ifndef EIGEN_MPL2_ONLY #include "src/OrderingMethods/Amd.h" #endif #include "src/OrderingMethods/Ordering.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_ORDERINGMETHODS_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/PaStiXSupport000066400000000000000000000032141506104011400226100ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PASTIXSUPPORT_MODULE_H #define EIGEN_PASTIXSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" extern "C" { #include #include } #ifdef complex #undef complex #endif /** \ingroup Support_modules * \defgroup PaStiXSupport_Module PaStiXSupport module * * This module provides an interface to the PaSTiX library. * PaSTiX is a general \b supernodal, \b parallel and \b opensource sparse solver. * It provides the two following main factorization classes: * - class PastixLLT : a supernodal, parallel LLt Cholesky factorization. * - class PastixLDLT: a supernodal, parallel LDLt Cholesky factorization. * - class PastixLU : a supernodal, parallel LU factorization (optimized for a symmetric pattern). * * \code * #include * \endcode * * In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be linked to the PaSTiX library and its dependencies. * The dependencies depend on how PaSTiX has been compiled. * For a cmake based project, you can use our FindPaSTiX.cmake module to help you in this task. * */ #include "src/PaStiXSupport/PaStiXSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_PASTIXSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/PardisoSupport000066400000000000000000000021341506104011400230410ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PARDISOSUPPORT_MODULE_H #define EIGEN_PARDISOSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" #include /** \ingroup Support_modules * \defgroup PardisoSupport_Module PardisoSupport module * * This module brings support for the Intel(R) MKL PARDISO direct sparse solvers. * * \code * #include * \endcode * * In order to use this module, the MKL headers must be accessible from the include paths, and your binary must be linked to the MKL library and its dependencies. * See this \ref TopicUsingIntelMKL "page" for more information on MKL-Eigen integration. * */ #include "src/PardisoSupport/PardisoSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_PARDISOSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/QR000066400000000000000000000024451506104011400203720ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QR_MODULE_H #define EIGEN_QR_MODULE_H #include "Core" #include "Cholesky" #include "Jacobi" #include "Householder" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup QR_Module QR module * * * * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: * - MatrixBase::householderQr() * - MatrixBase::colPivHouseholderQr() * - MatrixBase::fullPivHouseholderQr() * * \code * #include * \endcode */ #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" #include "src/QR/CompleteOrthogonalDecomposition.h" #ifdef EIGEN_USE_LAPACKE #ifdef EIGEN_USE_MKL #include "mkl_lapacke.h" #else #include "src/misc/lapacke.h" #endif #include "src/QR/HouseholderQR_LAPACKE.h" #include "src/QR/ColPivHouseholderQR_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_QR_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/QtAlignedMalloc000066400000000000000000000016611506104011400230470ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QTMALLOC_MODULE_H #define EIGEN_QTMALLOC_MODULE_H #include "Core" #if (!EIGEN_MALLOC_ALREADY_ALIGNED) #include "src/Core/util/DisableStupidWarnings.h" void *qMalloc(std::size_t size) { return Eigen::internal::aligned_malloc(size); } void qFree(void *ptr) { Eigen::internal::aligned_free(ptr); } void *qRealloc(void *ptr, std::size_t size) { void* newPtr = Eigen::internal::aligned_malloc(size); std::memcpy(newPtr, ptr, size); Eigen::internal::aligned_free(ptr); return newPtr; } #include "src/Core/util/ReenableStupidWarnings.h" #endif #endif // EIGEN_QTMALLOC_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/SPQRSupport000066400000000000000000000022121506104011400222220ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPQRSUPPORT_MODULE_H #define EIGEN_SPQRSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" #include "SuiteSparseQR.hpp" /** \ingroup Support_modules * \defgroup SPQRSupport_Module SuiteSparseQR module * * This module provides an interface to the SPQR library, which is part of the suitesparse package. * * \code * #include * \endcode * * In order to use this module, the SPQR headers must be accessible from the include paths, and your binary must be linked to the SPQR library and its dependencies (Cholmod, AMD, COLAMD,...). * For a cmake based project, you can use our FindSPQR.cmake and FindCholmod.Cmake modules * */ #include "src/CholmodSupport/CholmodSupport.h" #include "src/SPQRSupport/SuiteSparseQRSupport.h" #endif bbuchfink-diamond-08b3cbc/src/lib/Eigen/SVD000066400000000000000000000031351506104011400205010ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H #include "QR" #include "Householder" #include "Jacobi" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup SVD_Module SVD module * * * * This module provides SVD decomposition for matrices (both real and complex). * Two decomposition algorithms are provided: * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. * These decompositions are accessible via the respective classes and following MatrixBase methods: * - MatrixBase::jacobiSvd() * - MatrixBase::bdcSvd() * * \code * #include * \endcode */ #include "src/misc/RealSvd2x2.h" #include "src/SVD/UpperBidiagonalization.h" #include "src/SVD/SVDBase.h" #include "src/SVD/JacobiSVD.h" #include "src/SVD/BDCSVD.h" #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) #ifdef EIGEN_USE_MKL #include "mkl_lapacke.h" #else #include "src/misc/lapacke.h" #endif #include "src/SVD/JacobiSVD_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SVD_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ bbuchfink-diamond-08b3cbc/src/lib/Eigen/Sparse000066400000000000000000000016271506104011400213060ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPARSE_MODULE_H #define EIGEN_SPARSE_MODULE_H /** \defgroup Sparse_Module Sparse meta-module * * Meta-module including all related modules: * - \ref SparseCore_Module * - \ref OrderingMethods_Module * - \ref SparseCholesky_Module * - \ref SparseLU_Module * - \ref SparseQR_Module * - \ref IterativeLinearSolvers_Module * \code #include \endcode */ #include "SparseCore" #include "OrderingMethods" #ifndef EIGEN_MPL2_ONLY #include "SparseCholesky" #endif #include "SparseLU" #include "SparseQR" #include "IterativeLinearSolvers" #endif // EIGEN_SPARSE_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/SparseCholesky000066400000000000000000000025331506104011400230050ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2013 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPARSECHOLESKY_MODULE_H #define EIGEN_SPARSECHOLESKY_MODULE_H #include "SparseCore" #include "OrderingMethods" #include "src/Core/util/DisableStupidWarnings.h" /** * \defgroup SparseCholesky_Module SparseCholesky module * * This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices. * Those decompositions are accessible via the following classes: * - SimplicialLLt, * - SimplicialLDLt * * Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module. * * \code * #include * \endcode */ #ifdef EIGEN_MPL2_ONLY #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY #include "src/SparseCholesky/SimplicialCholesky_impl.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SPARSECHOLESKY_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/SparseCore000066400000000000000000000043001506104011400221060ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPARSECORE_MODULE_H #define EIGEN_SPARSECORE_MODULE_H #include "Core" #include "src/Core/util/DisableStupidWarnings.h" #include #include #include #include #include /** * \defgroup SparseCore_Module SparseCore module * * This module provides a sparse matrix representation, and basic associated matrix manipulations * and operations. * * See the \ref TutorialSparse "Sparse tutorial" * * \code * #include * \endcode * * This module depends on: Core. */ #include "src/SparseCore/SparseUtil.h" #include "src/SparseCore/SparseMatrixBase.h" #include "src/SparseCore/SparseAssign.h" #include "src/SparseCore/CompressedStorage.h" #include "src/SparseCore/AmbiVector.h" #include "src/SparseCore/SparseCompressedBase.h" #include "src/SparseCore/SparseMatrix.h" #include "src/SparseCore/SparseMap.h" #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" #include "src/SparseCore/SparseRef.h" #include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" #include "src/SparseCore/SparseTranspose.h" #include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseDot.h" #include "src/SparseCore/SparseRedux.h" #include "src/SparseCore/SparseView.h" #include "src/SparseCore/SparseDiagonalProduct.h" #include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" #include "src/SparseCore/SparseSelfAdjointView.h" #include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/TriangularSolver.h" #include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseFuzzy.h" #include "src/SparseCore/SparseSolverBase.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SPARSECORE_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/SparseLU000066400000000000000000000032611506104011400215430ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2012 DÊsirÊ Nuentsa-Wakam // Copyright (C) 2012 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPARSELU_MODULE_H #define EIGEN_SPARSELU_MODULE_H #include "SparseCore" /** * \defgroup SparseLU_Module SparseLU module * This module defines a supernodal factorization of general sparse matrices. * The code is fully optimized for supernode-panel updates with specialized kernels. * Please, see the documentation of the SparseLU class for more details. */ // Ordering interface #include "OrderingMethods" #include "src/SparseLU/SparseLU_gemm_kernel.h" #include "src/SparseLU/SparseLU_Structs.h" #include "src/SparseLU/SparseLU_SupernodalMatrix.h" #include "src/SparseLU/SparseLUImpl.h" #include "src/SparseCore/SparseColEtree.h" #include "src/SparseLU/SparseLU_Memory.h" #include "src/SparseLU/SparseLU_heap_relax_snode.h" #include "src/SparseLU/SparseLU_relax_snode.h" #include "src/SparseLU/SparseLU_pivotL.h" #include "src/SparseLU/SparseLU_panel_dfs.h" #include "src/SparseLU/SparseLU_kernel_bmod.h" #include "src/SparseLU/SparseLU_panel_bmod.h" #include "src/SparseLU/SparseLU_column_dfs.h" #include "src/SparseLU/SparseLU_column_bmod.h" #include "src/SparseLU/SparseLU_copy_to_ucol.h" #include "src/SparseLU/SparseLU_pruneL.h" #include "src/SparseLU/SparseLU_Utils.h" #include "src/SparseLU/SparseLU.h" #endif // EIGEN_SPARSELU_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/SparseQR000066400000000000000000000022531506104011400215450ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SPARSEQR_MODULE_H #define EIGEN_SPARSEQR_MODULE_H #include "SparseCore" #include "OrderingMethods" #include "src/Core/util/DisableStupidWarnings.h" /** \defgroup SparseQR_Module SparseQR module * \brief Provides QR decomposition for sparse matrices * * This module provides a simplicial version of the left-looking Sparse QR decomposition. * The columns of the input matrix should be reordered to limit the fill-in during the * decomposition. Built-in methods (COLAMD, AMD) or external methods (METIS) can be used to this end. * See the \link OrderingMethods_Module OrderingMethods\endlink module for the list * of built-in and external ordering methods. * * \code * #include * \endcode * * */ #include "src/SparseCore/SparseColEtree.h" #include "src/SparseQR/SparseQR.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif bbuchfink-diamond-08b3cbc/src/lib/Eigen/StdDeque000066400000000000000000000014351506104011400215640ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDDEQUE_MODULE_H #define EIGEN_STDDEQUE_MODULE_H #include "Core" #include #if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) #else #include "src/StlSupport/StdDeque.h" #endif #endif // EIGEN_STDDEQUE_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/StdList000066400000000000000000000013261506104011400214330ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDLIST_MODULE_H #define EIGEN_STDLIST_MODULE_H #include "Core" #include #if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) #else #include "src/StlSupport/StdList.h" #endif #endif // EIGEN_STDLIST_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/StdVector000066400000000000000000000014431506104011400217620ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2009 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_STDVECTOR_MODULE_H #define EIGEN_STDVECTOR_MODULE_H #include "Core" #include #if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) #else #include "src/StlSupport/StdVector.h" #endif #endif // EIGEN_STDVECTOR_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/SuperLUSupport000066400000000000000000000043031506104011400227770ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SUPERLUSUPPORT_MODULE_H #define EIGEN_SUPERLUSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" #ifdef EMPTY #define EIGEN_EMPTY_WAS_ALREADY_DEFINED #endif typedef int int_t; #include #include #include // slu_util.h defines a preprocessor token named EMPTY which is really polluting, // so we remove it in favor of a SUPERLU_EMPTY token. // If EMPTY was already defined then we don't undef it. #if defined(EIGEN_EMPTY_WAS_ALREADY_DEFINED) # undef EIGEN_EMPTY_WAS_ALREADY_DEFINED #elif defined(EMPTY) # undef EMPTY #endif #define SUPERLU_EMPTY (-1) namespace Eigen { struct SluMatrix; } /** \ingroup Support_modules * \defgroup SuperLUSupport_Module SuperLUSupport module * * This module provides an interface to the SuperLU library. * It provides the following factorization class: * - class SuperLU: a supernodal sequential LU factorization. * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods). * * \warning This wrapper requires at least versions 4.0 of SuperLU. The 3.x versions are not supported. * * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting. * * \code * #include * \endcode * * In order to use this module, the superlu headers must be accessible from the include paths, and your binary must be linked to the superlu library and its dependencies. * The dependencies depend on how superlu has been compiled. * For a cmake based project, you can use our FindSuperLU.cmake module to help you in this task. * */ #include "src/SuperLUSupport/SuperLUSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SUPERLUSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/UmfPackSupport000066400000000000000000000025461506104011400227750ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_UMFPACKSUPPORT_MODULE_H #define EIGEN_UMFPACKSUPPORT_MODULE_H #include "SparseCore" #include "src/Core/util/DisableStupidWarnings.h" extern "C" { #include } /** \ingroup Support_modules * \defgroup UmfPackSupport_Module UmfPackSupport module * * This module provides an interface to the UmfPack library which is part of the suitesparse package. * It provides the following factorization class: * - class UmfPackLU: a multifrontal sequential LU factorization. * * \code * #include * \endcode * * In order to use this module, the umfpack headers must be accessible from the include paths, and your binary must be linked to the umfpack library and its dependencies. * The dependencies depend on how umfpack has been compiled. * For a cmake based project, you can use our FindUmfPack.cmake module to help you in this task. * */ #include "src/UmfPackSupport/UmfPackSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_UMFPACKSUPPORT_MODULE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/000077500000000000000000000000001506104011400207075ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Cholesky/000077500000000000000000000000001506104011400224705ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Cholesky/LDLT.h000066400000000000000000000576401506104011400234140ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2011 Gael Guennebaud // Copyright (C) 2009 Keir Mierle // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2011 Timothy E. Holy // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H namespace Eigen { namespace internal { template struct LDLT_Traits; // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; } /** \ingroup Cholesky_Module * * \class LDLT * * \brief Robust Cholesky decomposition of a matrix with pivoting * * \tparam _MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. * The other triangular part won't be read. * * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L * is lower triangular with a unit diagonal and D is a diagonal matrix. * * The decomposition uses pivoting to ensure stability, so that L will have * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root * on D also stabilizes the computation. * * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. * * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT */ template class LDLT { public: typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 typedef typename MatrixType::StorageIndex StorageIndex; typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; typedef PermutationMatrix PermutationType; typedef internal::LDLT_Traits Traits; /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ LDLT() : m_matrix(), m_transpositions(), m_sign(internal::ZeroSign), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. * \sa LDLT() */ explicit LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), m_sign(internal::ZeroSign), m_isInitialized(false) {} /** \brief Constructor with decomposition * * This calculates the decomposition for the input \a matrix. * * \sa LDLT(Index size) */ template explicit LDLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_sign(internal::ZeroSign), m_isInitialized(false) { compute(matrix.derived()); } /** \brief Constructs a LDLT factorization from a given matrix * * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref. * * \sa LDLT(const EigenBase&) */ template explicit LDLT(EigenBase& matrix) : m_matrix(matrix.derived()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_sign(internal::ZeroSign), m_isInitialized(false) { compute(matrix.derived()); } /** Clear any existing decomposition * \sa rankUpdate(w,sigma) */ void setZero() { m_isInitialized = false; } /** \returns a view of the upper triangular matrix U */ inline typename Traits::MatrixU matrixU() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return Traits::getU(m_matrix); } /** \returns a view of the lower triangular matrix L */ inline typename Traits::MatrixL matrixL() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return Traits::getL(m_matrix); } /** \returns the permutation matrix P as a transposition sequence. */ inline const TranspositionType& transpositionsP() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_transpositions; } /** \returns the coefficients of the diagonal matrix D */ inline Diagonal vectorD() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_matrix.diagonal(); } /** \returns true if the matrix is positive (semidefinite) */ inline bool isPositive() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; } /** \returns true if the matrix is negative (semidefinite) */ inline bool isNegative(void) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; } /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. * * This function also supports in-place solves using the syntax x = decompositionObject.solve(x) . * * \note_about_checking_solutions * * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function * computes the least-square solution of \f$ A x = b \f$ is \f$ A \f$ is singular. * * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() */ template inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); return Solve(*this, b.derived()); } template bool solveInPlace(MatrixBase &bAndX) const; template LDLT& compute(const EigenBase& matrix); /** \returns an estimate of the reciprocal condition number of the matrix of * which \c *this is the LDLT decomposition. */ RealScalar rcond() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return internal::rcond_estimate_helper(m_l1_norm, *this); } template LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); /** \returns the internal LDLT decomposition matrix * * TODO: document the storage layout */ inline const MatrixType& matrixLDLT() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_matrix; } MatrixType reconstructedMatrix() const; /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. * * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: * \code x = decomposition.adjoint().solve(b) \endcode */ const LDLT& adjoint() const { return *this; }; inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, * \c NumericalIssue if the factorization failed because of a zero pivot. */ ComputationInfo info() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_info; } #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC void _solve_impl(const RhsType &rhs, DstType &dst) const; #endif protected: static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); } /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. * The strict upper part is used during the decomposition, the strict lower * part correspond to the coefficients of L (its diagonal is equal to 1 and * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; RealScalar m_l1_norm; TranspositionType m_transpositions; TmpMatrixType m_temporary; internal::SignMatrix m_sign; bool m_isInitialized; ComputationInfo m_info; }; namespace internal { template struct ldlt_inplace; template<> struct ldlt_inplace { template static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { using std::abs; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef typename TranspositionType::StorageIndex IndexType; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); bool found_zero_pivot = false; bool ret = true; if (size <= 1) { transpositions.setIdentity(); if(size==0) sign = ZeroSign; else if (numext::real(mat.coeff(0,0)) > static_cast(0) ) sign = PositiveSemiDef; else if (numext::real(mat.coeff(0,0)) < static_cast(0)) sign = NegativeSemiDef; else sign = ZeroSign; return true; } for (Index k = 0; k < size; ++k) { // Find largest diagonal element Index index_of_biggest_in_corner; mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); if(k != index_of_biggest_in_corner) { // apply the transposition while taking care to consider only // the lower triangular part Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); for(Index i=k+1;i::IsComplex) mat.coeffRef(index_of_biggest_in_corner,k) = numext::conj(mat.coeff(index_of_biggest_in_corner,k)); } // partition the matrix: // A00 | - | - // lu = A10 | A11 | - // A20 | A21 | A22 Index rs = size - k - 1; Block A21(mat,k+1,k,rs,1); Block A10(mat,k,0,1,k); Block A20(mat,k+1,0,rs,k); if(k>0) { temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); if(rs>0) A21.noalias() -= A20 * temp.head(k); } // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot // was smaller than the cutoff value. However, since LDLT is not rank-revealing // we should only make sure that we do not introduce INF or NaN values. // Remark that LAPACK also uses 0 as the cutoff value. RealScalar realAkk = numext::real(mat.coeffRef(k,k)); bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); if(k==0 && !pivot_is_valid) { // The entire diagonal is zero, there is nothing more to do // except filling the transpositions, and checking whether the matrix is zero. sign = ZeroSign; for(Index j = 0; j0) && pivot_is_valid) A21 /= realAkk; else if(rs>0) ret = ret && (A21.array()==Scalar(0)).all(); if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed else if(!pivot_is_valid) found_zero_pivot = true; if (sign == PositiveSemiDef) { if (realAkk < static_cast(0)) sign = Indefinite; } else if (sign == NegativeSemiDef) { if (realAkk > static_cast(0)) sign = Indefinite; } else if (sign == ZeroSign) { if (realAkk > static_cast(0)) sign = PositiveSemiDef; else if (realAkk < static_cast(0)) sign = NegativeSemiDef; } } return ret; } // Reference for the algorithm: Davis and Hager, "Multiple Rank // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) // Trivial rearrangements of their computations (Timothy E. Holy) // allow their algorithm to work for rank-1 updates even if the // original matrix is not of full rank. // Here only rank-1 updates are implemented, to reduce the // requirement for intermediate storage and improve accuracy template static bool updateInPlace(MatrixType& mat, MatrixBase& w, const typename MatrixType::RealScalar& sigma=1) { using numext::isfinite; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; const Index size = mat.rows(); eigen_assert(mat.cols() == size && w.size()==size); RealScalar alpha = 1; // Apply the update for (Index j = 0; j < size; j++) { // Check for termination due to an original decomposition of low-rank if (!(isfinite)(alpha)) break; // Update the diagonal terms RealScalar dj = numext::real(mat.coeff(j,j)); Scalar wj = w.coeff(j); RealScalar swj2 = sigma*numext::abs2(wj); RealScalar gamma = dj*alpha + swj2; mat.coeffRef(j,j) += swj2/alpha; alpha += swj2/dj; // Update the terms of L Index rs = size-j-1; w.tail(rs) -= wj * mat.col(j).tail(rs); if(gamma != 0) mat.col(j).tail(rs) += (sigma*numext::conj(wj)/gamma)*w.tail(rs); } return true; } template static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, const typename MatrixType::RealScalar& sigma=1) { // Apply the permutation to the input w tmp = transpositions * w; return ldlt_inplace::updateInPlace(mat,tmp,sigma); } }; template<> struct ldlt_inplace { template static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) { Transpose matt(mat); return ldlt_inplace::unblocked(matt, transpositions, temp, sign); } template static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, const typename MatrixType::RealScalar& sigma=1) { Transpose matt(mat); return ldlt_inplace::update(matt, transpositions, tmp, w.conjugate(), sigma); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } }; } // end namespace internal /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ template template LDLT& LDLT::compute(const EigenBase& a) { check_template_parameters(); eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix = a.derived(); // Compute matrix L1 norm = max abs column sum. m_l1_norm = RealScalar(0); // TODO move this code to SelfAdjointView for (Index col = 0; col < size; ++col) { RealScalar abs_col_sum; if (_UpLo == Lower) abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); else abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); if (abs_col_sum > m_l1_norm) m_l1_norm = abs_col_sum; } m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); m_sign = internal::ZeroSign; m_info = internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success : NumericalIssue; m_isInitialized = true; return *this; } /** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T. * \param w a vector to be incorporated into the decomposition. * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column vectors. Optional; default value is +1. * \sa setZero() */ template template LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) { typedef typename TranspositionType::StorageIndex IndexType; const Index size = w.rows(); if (m_isInitialized) { eigen_assert(m_matrix.rows()==size); } else { m_matrix.resize(size,size); m_matrix.setZero(); m_transpositions.resize(size); for (Index i = 0; i < size; i++) m_transpositions.coeffRef(i) = IndexType(i); m_temporary.resize(size); m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; m_isInitialized = true; } internal::ldlt_inplace::update(m_matrix, m_transpositions, m_temporary, w, sigma); return *this; } #ifndef EIGEN_PARSED_BY_DOXYGEN template template void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { eigen_assert(rhs.rows() == rows()); // dst = P b dst = m_transpositions * rhs; // dst = L^-1 (P b) matrixL().solveInPlace(dst); // dst = D^-1 (L^-1 P b) // more precisely, use pseudo-inverse of D (see bug 241) using std::abs; const typename Diagonal::RealReturnType vecD(vectorD()); // In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min()) // and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS: // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest // diagonal element is not well justified and leads to numerical issues in some cases. // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. // Using numeric_limits::min() gives us more robustness to denormals. RealScalar tolerance = (std::numeric_limits::min)(); for (Index i = 0; i < vecD.size(); ++i) { if(abs(vecD(i)) > tolerance) dst.row(i) /= vecD(i); else dst.row(i).setZero(); } // dst = L^-T (D^-1 L^-1 P b) matrixU().solveInPlace(dst); // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b dst = m_transpositions.transpose() * dst; } #endif /** \internal use x = ldlt_object.solve(x); * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. * * This version avoids a copy when the right hand side matrix b is not * needed anymore. * * \sa LDLT::solve(), MatrixBase::ldlt() */ template template bool LDLT::solveInPlace(MatrixBase &bAndX) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows() == bAndX.rows()); bAndX = this->solve(bAndX); return true; } /** \returns the matrix represented by the decomposition, * i.e., it returns the product: P^T L D L^* P. * This function is provided for debug purpose. */ template MatrixType LDLT::reconstructedMatrix() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); MatrixType res(size,size); // P res.setIdentity(); res = transpositionsP() * res; // L^* P res = matrixU() * res; // D(L^*P) res = vectorD().real().asDiagonal() * res; // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) res = transpositionsP().transpose() * res; return res; } /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this * \sa MatrixBase::ldlt() */ template inline const LDLT::PlainObject, UpLo> SelfAdjointView::ldlt() const { return LDLT(m_matrix); } /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this * \sa SelfAdjointView::ldlt() */ template inline const LDLT::PlainObject> MatrixBase::ldlt() const { return LDLT(derived()); } } // end namespace Eigen #endif // EIGEN_LDLT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Cholesky/LLT.h000066400000000000000000000437331506104011400233060ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_LLT_H #define EIGEN_LLT_H namespace Eigen { namespace internal{ template struct LLT_Traits; } /** \ingroup Cholesky_Module * * \class LLT * * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features * * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. * The other triangular part won't be read. * * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite * matrix A such that A = LL^* = U^*U, where L is lower triangular. * * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b, * for that purpose, we recommend the Cholesky decomposition without square root which is more stable * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other * situations like generalised eigen problems with hermitian matrices. * * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices, * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations * has a solution. * * Example: \include LLT_example.cpp * Output: \verbinclude LLT_example.out * * \b Performance: for best performance, it is recommended to use a column-major storage format * with the Lower triangular part (the default), or, equivalently, a row-major storage format * with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization * step, and rank-updates can be up to 3 times slower. * * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. * * Note that during the decomposition, only the lower (or upper, as defined by _UpLo) triangular part of A is considered. * Therefore, the strict lower part does not have to store correct values. * * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT */ template class LLT { public: typedef _MatrixType MatrixType; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 typedef typename MatrixType::StorageIndex StorageIndex; enum { PacketSize = internal::packet_traits::size, AlignmentMask = int(PacketSize)-1, UpLo = _UpLo }; typedef internal::LLT_Traits Traits; /** * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via LLT::compute(const MatrixType&). */ LLT() : m_matrix(), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. * \sa LLT() */ explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} template explicit LLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { compute(matrix.derived()); } /** \brief Constructs a LDLT factorization from a given matrix * * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when * \c MatrixType is a Eigen::Ref. * * \sa LLT(const EigenBase&) */ template explicit LLT(EigenBase& matrix) : m_matrix(matrix.derived()), m_isInitialized(false) { compute(matrix.derived()); } /** \returns a view of the upper triangular matrix U */ inline typename Traits::MatrixU matrixU() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return Traits::getU(m_matrix); } /** \returns a view of the lower triangular matrix L */ inline typename Traits::MatrixL matrixL() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return Traits::getL(m_matrix); } /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. * * Since this LLT class assumes anyway that the matrix A is invertible, the solution * theoretically exists and is unique regardless of b. * * Example: \include LLT_solve.cpp * Output: \verbinclude LLT_solve.out * * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() */ template inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); return Solve(*this, b.derived()); } template void solveInPlace(const MatrixBase &bAndX) const; template LLT& compute(const EigenBase& matrix); /** \returns an estimate of the reciprocal condition number of the matrix of * which \c *this is the Cholesky decomposition. */ RealScalar rcond() const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative"); return internal::rcond_estimate_helper(m_l1_norm, *this); } /** \returns the LLT decomposition matrix * * TODO: document the storage layout */ inline const MatrixType& matrixLLT() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return m_matrix; } MatrixType reconstructedMatrix() const; /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, * \c NumericalIssue if the matrix.appears not to be positive definite. */ ComputationInfo info() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return m_info; } /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. * * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: * \code x = decomposition.adjoint().solve(b) \endcode */ const LLT& adjoint() const { return *this; }; inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } template LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC void _solve_impl(const RhsType &rhs, DstType &dst) const; #endif protected: static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); } /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. */ MatrixType m_matrix; RealScalar m_l1_norm; bool m_isInitialized; ComputationInfo m_info; }; namespace internal { template struct llt_inplace; template static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) { using std::sqrt; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef typename MatrixType::ColXpr ColXpr; typedef typename internal::remove_all::type ColXprCleaned; typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; typedef Matrix TempVectorType; typedef typename TempVectorType::SegmentReturnType TempVecSegment; Index n = mat.cols(); eigen_assert(mat.rows()==n && vec.size()==n); TempVectorType temp; if(sigma>0) { // This version is based on Givens rotations. // It is faster than the other one below, but only works for updates, // i.e., for sigma > 0 temp = sqrt(sigma) * vec; for(Index i=0; i g; g.makeGivens(mat(i,i), -temp(i), &mat(i,i)); Index rs = n-i-1; if(rs>0) { ColXprSegment x(mat.col(i).tail(rs)); TempVecSegment y(temp.tail(rs)); apply_rotation_in_the_plane(x, y, g); } } } else { temp = vec; RealScalar beta = 1; for(Index j=0; j struct llt_inplace { typedef typename NumTraits::Real RealScalar; template static Index unblocked(MatrixType& mat) { using std::sqrt; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); for(Index k = 0; k < size; ++k) { Index rs = size-k-1; // remaining size Block A21(mat,k+1,k,rs,1); Block A10(mat,k,0,1,k); Block A20(mat,k+1,0,rs,k); RealScalar x = numext::real(mat.coeff(k,k)); if (k>0) x -= A10.squaredNorm(); if (x<=RealScalar(0)) return k; mat.coeffRef(k,k) = x = sqrt(x); if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); if (rs>0) A21 /= x; } return -1; } template static Index blocked(MatrixType& m) { eigen_assert(m.rows()==m.cols()); Index size = m.rows(); if(size<32) return unblocked(m); Index blockSize = size/8; blockSize = (blockSize/16)*16; blockSize = (std::min)((std::max)(blockSize,Index(8)), Index(128)); for (Index k=0; k A11(m,k, k, bs,bs); Block A21(m,k+bs,k, rs,bs); Block A22(m,k+bs,k+bs,rs,rs); Index ret; if((ret=unblocked(A11))>=0) return k+ret; if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); if(rs>0) A22.template selfadjointView().rankUpdate(A21,typename NumTraits::Literal(-1)); // bottleneck } return -1; } template static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } }; template struct llt_inplace { typedef typename NumTraits::Real RealScalar; template static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::unblocked(matt); } template static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::blocked(matt); } template static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { Transpose matt(mat); return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); } }; template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; } // end namespace internal /** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix * * \returns a reference to *this * * Example: \include TutorialLinAlgComputeTwice.cpp * Output: \verbinclude TutorialLinAlgComputeTwice.out */ template template LLT& LLT::compute(const EigenBase& a) { check_template_parameters(); eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); if (!internal::is_same_dense(m_matrix, a.derived())) m_matrix = a.derived(); // Compute matrix L1 norm = max abs column sum. m_l1_norm = RealScalar(0); // TODO move this code to SelfAdjointView for (Index col = 0; col < size; ++col) { RealScalar abs_col_sum; if (_UpLo == Lower) abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); else abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); if (abs_col_sum > m_l1_norm) m_l1_norm = abs_col_sum; } m_isInitialized = true; bool ok = Traits::inplace_decomposition(m_matrix); m_info = ok ? Success : NumericalIssue; return *this; } /** Performs a rank one update (or dowdate) of the current decomposition. * If A = LL^* before the rank one update, * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector * of same dimension. */ template template LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType); eigen_assert(v.size()==m_matrix.cols()); eigen_assert(m_isInitialized); if(internal::llt_inplace::rankUpdate(m_matrix,v,sigma)>=0) m_info = NumericalIssue; else m_info = Success; return *this; } #ifndef EIGEN_PARSED_BY_DOXYGEN template template void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { dst = rhs; solveInPlace(dst); } #endif /** \internal use x = llt_object.solve(x); * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * * This version avoids a copy when the right hand side matrix b is not needed anymore. * * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. * This function will const_cast it, so constness isn't honored here. * * \sa LLT::solve(), MatrixBase::llt() */ template template void LLT::solveInPlace(const MatrixBase &bAndX) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==bAndX.rows()); matrixL().solveInPlace(bAndX); matrixU().solveInPlace(bAndX); } /** \returns the matrix represented by the decomposition, * i.e., it returns the product: L L^*. * This function is provided for debug purpose. */ template MatrixType LLT::reconstructedMatrix() const { eigen_assert(m_isInitialized && "LLT is not initialized."); return matrixL() * matrixL().adjoint().toDenseMatrix(); } /** \cholesky_module * \returns the LLT decomposition of \c *this * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject> MatrixBase::llt() const { return LLT(derived()); } /** \cholesky_module * \returns the LLT decomposition of \c *this * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject, UpLo> SelfAdjointView::llt() const { return LLT(m_matrix); } } // end namespace Eigen #endif // EIGEN_LLT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Cholesky/LLT_LAPACKE.h000066400000000000000000000076061506104011400244250ustar00rootroot00000000000000/* Copyright (c) 2011, Intel Corporation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** * Content : Eigen bindings to LAPACKe * LLt decomposition based on LAPACKE_?potrf function. ******************************************************************************** */ #ifndef EIGEN_LLT_LAPACKE_H #define EIGEN_LLT_LAPACKE_H namespace Eigen { namespace internal { template struct lapacke_llt; #define EIGEN_LAPACKE_LLT(EIGTYPE, BLASTYPE, LAPACKE_PREFIX) \ template<> struct lapacke_llt \ { \ template \ static inline Index potrf(MatrixType& m, char uplo) \ { \ lapack_int matrix_order; \ lapack_int size, lda, info, StorageOrder; \ EIGTYPE* a; \ eigen_assert(m.rows()==m.cols()); \ /* Set up parameters for ?potrf */ \ size = convert_index(m.rows()); \ StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \ matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ a = &(m.coeffRef(0,0)); \ lda = convert_index(m.outerStride()); \ \ info = LAPACKE_##LAPACKE_PREFIX##potrf( matrix_order, uplo, size, (BLASTYPE*)a, lda ); \ info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ }; \ template<> struct llt_inplace \ { \ template \ static Index blocked(MatrixType& m) \ { \ return lapacke_llt::potrf(m, 'L'); \ } \ template \ static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ }; \ template<> struct llt_inplace \ { \ template \ static Index blocked(MatrixType& m) \ { \ return lapacke_llt::potrf(m, 'U'); \ } \ template \ static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { \ Transpose matt(mat); \ return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ } \ }; EIGEN_LAPACKE_LLT(double, double, d) EIGEN_LAPACKE_LLT(float, float, s) EIGEN_LAPACKE_LLT(dcomplex, lapack_complex_double, z) EIGEN_LAPACKE_LLT(scomplex, lapack_complex_float, c) } // end namespace internal } // end namespace Eigen #endif // EIGEN_LLT_LAPACKE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/CholmodSupport/000077500000000000000000000000001506104011400236715ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/CholmodSupport/CholmodSupport.h000066400000000000000000000534431506104011400270350ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CHOLMODSUPPORT_H #define EIGEN_CHOLMODSUPPORT_H namespace Eigen { namespace internal { template struct cholmod_configure_matrix; template<> struct cholmod_configure_matrix { template static void run(CholmodType& mat) { mat.xtype = CHOLMOD_REAL; mat.dtype = CHOLMOD_DOUBLE; } }; template<> struct cholmod_configure_matrix > { template static void run(CholmodType& mat) { mat.xtype = CHOLMOD_COMPLEX; mat.dtype = CHOLMOD_DOUBLE; } }; // Other scalar types are not yet suppotred by Cholmod // template<> struct cholmod_configure_matrix { // template // static void run(CholmodType& mat) { // mat.xtype = CHOLMOD_REAL; // mat.dtype = CHOLMOD_SINGLE; // } // }; // // template<> struct cholmod_configure_matrix > { // template // static void run(CholmodType& mat) { // mat.xtype = CHOLMOD_COMPLEX; // mat.dtype = CHOLMOD_SINGLE; // } // }; } // namespace internal /** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. * Note that the data are shared. */ template cholmod_sparse viewAsCholmod(Ref > mat) { cholmod_sparse res; res.nzmax = mat.nonZeros(); res.nrow = mat.rows(); res.ncol = mat.cols(); res.p = mat.outerIndexPtr(); res.i = mat.innerIndexPtr(); res.x = mat.valuePtr(); res.z = 0; res.sorted = 1; if(mat.isCompressed()) { res.packed = 1; res.nz = 0; } else { res.packed = 0; res.nz = mat.innerNonZeroPtr(); } res.dtype = 0; res.stype = -1; if (internal::is_same<_StorageIndex,int>::value) { res.itype = CHOLMOD_INT; } else if (internal::is_same<_StorageIndex,long>::value) { res.itype = CHOLMOD_LONG; } else { eigen_assert(false && "Index type not supported yet"); } // setup res.xtype internal::cholmod_configure_matrix<_Scalar>::run(res); res.stype = 0; return res; } template const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) { cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); return res; } template const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat) { cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); return res; } /** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. * The data are not copied but shared. */ template cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) { cholmod_sparse res = viewAsCholmod(Ref >(mat.matrix().const_cast_derived())); if(UpLo==Upper) res.stype = 1; if(UpLo==Lower) res.stype = -1; return res; } /** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix. * The data are not copied but shared. */ template cholmod_dense viewAsCholmod(MatrixBase& mat) { EIGEN_STATIC_ASSERT((internal::traits::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); typedef typename Derived::Scalar Scalar; cholmod_dense res; res.nrow = mat.rows(); res.ncol = mat.cols(); res.nzmax = res.nrow * res.ncol; res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride(); res.x = (void*)(mat.derived().data()); res.z = 0; internal::cholmod_configure_matrix::run(res); return res; } /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. * The data are not copied but shared. */ template MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) { return MappedSparseMatrix (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); } enum CholmodMode { CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt }; /** \ingroup CholmodSupport_Module * \class CholmodBase * \brief The base class for the direct Cholesky factorization of Cholmod * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT */ template class CholmodBase : public SparseSolverBase { protected: typedef SparseSolverBase Base; using Base::derived; using Base::m_isInitialized; public: typedef _MatrixType MatrixType; enum { UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef MatrixType CholMatrixType; typedef typename MatrixType::StorageIndex StorageIndex; enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; public: CholmodBase() : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); } explicit CholmodBase(const MatrixType& matrix) : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); compute(matrix); } ~CholmodBase() { if(m_cholmodFactor) cholmod_free_factor(&m_cholmodFactor, &m_cholmod); cholmod_finish(&m_cholmod); } inline StorageIndex cols() const { return internal::convert_index(m_cholmodFactor->n); } inline StorageIndex rows() const { return internal::convert_index(m_cholmodFactor->n); } /** \brief Reports whether previous computation was successful. * * \returns \c Success if computation was succesful, * \c NumericalIssue if the matrix.appears to be negative. */ ComputationInfo info() const { eigen_assert(m_isInitialized && "Decomposition is not initialized."); return m_info; } /** Computes the sparse Cholesky decomposition of \a matrix */ Derived& compute(const MatrixType& matrix) { analyzePattern(matrix); factorize(matrix); return derived(); } /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. * * \sa factorize() */ void analyzePattern(const MatrixType& matrix) { if(m_cholmodFactor) { cholmod_free_factor(&m_cholmodFactor, &m_cholmod); m_cholmodFactor = 0; } cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); m_cholmodFactor = cholmod_analyze(&A, &m_cholmod); this->m_isInitialized = true; this->m_info = Success; m_analysisIsOk = true; m_factorizationIsOk = false; } /** Performs a numeric decomposition of \a matrix * * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed. * * \sa analyzePattern() */ void factorize(const MatrixType& matrix) { eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod); // If the factorization failed, minor is the column at which it did. On success minor == n. this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue); m_factorizationIsOk = true; } /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations. * See the Cholmod user guide for details. */ cholmod_common& cholmod() { return m_cholmod; } #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template void _solve_impl(const MatrixBase &b, MatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; EIGEN_UNUSED_VARIABLE(size); eigen_assert(size==b.rows()); // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref. Ref > b_ref(b.derived()); cholmod_dense b_cd = viewAsCholmod(b_ref); cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod); if(!x_cd) { this->m_info = NumericalIssue; return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); cholmod_free_dense(&x_cd, &m_cholmod); } /** \internal */ template void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; EIGEN_UNUSED_VARIABLE(size); eigen_assert(size==b.rows()); // note: cs stands for Cholmod Sparse Ref > b_ref(b.const_cast_derived()); cholmod_sparse b_cs = viewAsCholmod(b_ref); cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod); if(!x_cs) { this->m_info = NumericalIssue; return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest.derived() = viewAsEigen(*x_cs); cholmod_free_sparse(&x_cs, &m_cholmod); } #endif // EIGEN_PARSED_BY_DOXYGEN /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization. * * During the numerical factorization, an offset term is added to the diagonal coefficients:\n * \c d_ii = \a offset + \c d_ii * * The default is \a offset=0. * * \returns a reference to \c *this. */ Derived& setShift(const RealScalar& offset) { m_shiftOffset[0] = double(offset); return derived(); } /** \returns the determinant of the underlying matrix from the current factorization */ Scalar determinant() const { using std::exp; return exp(logDeterminant()); } /** \returns the log determinant of the underlying matrix from the current factorization */ Scalar logDeterminant() const { using std::log; using numext::real; eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); RealScalar logDet = 0; Scalar *x = static_cast(m_cholmodFactor->x); if (m_cholmodFactor->is_super) { // Supernodal factorization stored as a packed list of dense column-major blocs, // as described by the following structure: // super[k] == index of the first column of the j-th super node StorageIndex *super = static_cast(m_cholmodFactor->super); // pi[k] == offset to the description of row indices StorageIndex *pi = static_cast(m_cholmodFactor->pi); // px[k] == offset to the respective dense block StorageIndex *px = static_cast(m_cholmodFactor->px); Index nb_super_nodes = m_cholmodFactor->nsuper; for (Index k=0; k < nb_super_nodes; ++k) { StorageIndex ncols = super[k + 1] - super[k]; StorageIndex nrows = pi[k + 1] - pi[k]; Map, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1)); logDet += sk.real().log().sum(); } } else { // Simplicial factorization stored as standard CSC matrix. StorageIndex *p = static_cast(m_cholmodFactor->p); Index size = m_cholmodFactor->n; for (Index k=0; kis_ll) logDet *= 2.0; return logDet; }; template void dumpMemory(Stream& /*s*/) {} protected: mutable cholmod_common m_cholmod; cholmod_factor* m_cholmodFactor; double m_shiftOffset[2]; mutable ComputationInfo m_info; int m_factorizationIsOk; int m_analysisIsOk; }; /** \ingroup CholmodSupport_Module * \class CholmodSimplicialLLT * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod * * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization * using the Cholmod library. * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest. * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * * \implsparsesolverconcept * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \warning Only double precision real and complex scalar types are supported by Cholmod. * * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT */ template class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > { typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base; using Base::m_cholmod; public: typedef _MatrixType MatrixType; CholmodSimplicialLLT() : Base() { init(); } CholmodSimplicialLLT(const MatrixType& matrix) : Base() { init(); this->compute(matrix); } ~CholmodSimplicialLLT() {} protected: void init() { m_cholmod.final_asis = 0; m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; m_cholmod.final_ll = 1; } }; /** \ingroup CholmodSupport_Module * \class CholmodSimplicialLDLT * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod * * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization * using the Cholmod library. * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest. * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * * \implsparsesolverconcept * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \warning Only double precision real and complex scalar types are supported by Cholmod. * * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT */ template class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > { typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base; using Base::m_cholmod; public: typedef _MatrixType MatrixType; CholmodSimplicialLDLT() : Base() { init(); } CholmodSimplicialLDLT(const MatrixType& matrix) : Base() { init(); this->compute(matrix); } ~CholmodSimplicialLDLT() {} protected: void init() { m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; } }; /** \ingroup CholmodSupport_Module * \class CholmodSupernodalLLT * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod * * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization * using the Cholmod library. * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * * \implsparsesolverconcept * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \warning Only double precision real and complex scalar types are supported by Cholmod. * * \sa \ref TutorialSparseSolverConcept */ template class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > { typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base; using Base::m_cholmod; public: typedef _MatrixType MatrixType; CholmodSupernodalLLT() : Base() { init(); } CholmodSupernodalLLT(const MatrixType& matrix) : Base() { init(); this->compute(matrix); } ~CholmodSupernodalLLT() {} protected: void init() { m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_SUPERNODAL; } }; /** \ingroup CholmodSupport_Module * \class CholmodDecomposition * \brief A general Cholesky factorization and solver based on Cholmod * * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices * X and B can be either dense or sparse. * * This variant permits to change the underlying Cholesky method at runtime. * On the other hand, it does not provide access to the result of the factorization. * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization. * * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * * \implsparsesolverconcept * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * * \warning Only double precision real and complex scalar types are supported by Cholmod. * * \sa \ref TutorialSparseSolverConcept */ template class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > { typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base; using Base::m_cholmod; public: typedef _MatrixType MatrixType; CholmodDecomposition() : Base() { init(); } CholmodDecomposition(const MatrixType& matrix) : Base() { init(); this->compute(matrix); } ~CholmodDecomposition() {} void setMode(CholmodMode mode) { switch(mode) { case CholmodAuto: m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_AUTO; break; case CholmodSimplicialLLt: m_cholmod.final_asis = 0; m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; m_cholmod.final_ll = 1; break; case CholmodSupernodalLLt: m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_SUPERNODAL; break; case CholmodLDLt: m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; break; default: break; } } protected: void init() { m_cholmod.final_asis = 1; m_cholmod.supernodal = CHOLMOD_AUTO; } }; } // end namespace Eigen #endif // EIGEN_CHOLMODSUPPORT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/000077500000000000000000000000001506104011400215775ustar00rootroot00000000000000bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Array.h000066400000000000000000000275231506104011400230370ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAY_H #define EIGEN_ARRAY_H namespace Eigen { namespace internal { template struct traits > : traits > { typedef ArrayXpr XprKind; typedef ArrayBase > XprBase; }; } /** \class Array * \ingroup Core_Module * * \brief General-purpose arrays with easy API for coefficient-wise operations * * The %Array class is very similar to the Matrix class. It provides * general-purpose one- and two-dimensional arrays. The difference between the * %Array and the %Matrix class is primarily in the API: the API for the * %Array class provides easy access to coefficient-wise operations, while the * API for the %Matrix class provides easy access to linear-algebra * operations. * * See documentation of class Matrix for detailed information on the template parameters * storage layout. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. * * \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy */ template class Array : public PlainObjectBase > { public: typedef PlainObjectBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Array) enum { Options = _Options }; typedef typename Base::PlainObject PlainObject; protected: template friend struct internal::conservative_resize_like_impl; using Base::m_storage; public: using Base::base; using Base::coeff; using Base::coeffRef; /** * The usage of * using Base::operator=; * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped * the usage of 'using'. This should be done only for operator=. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) { return Base::operator=(other); } /** Set all the entries to \a value. * \sa DenseBase::setConstant(), DenseBase::fill() */ /* This overload is needed because the usage of * using Base::operator=; * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped * the usage of 'using'. This should be done only for operator=. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) { Base::setConstant(value); return *this; } /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const DenseBase& other) { return Base::_set(other); } /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); } /** Default constructor. * * For fixed-size matrices, does nothing. * * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix * is called a null matrix. This constructor is the unique way to create null matrices: resizing * a matrix to 0 is not supported. * * \sa resize(Index,Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array() : Base() { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ?? /** \internal */ EIGEN_DEVICE_FUNC Array(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #endif #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC Array(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); } EIGEN_DEVICE_FUNC Array& operator=(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Array(const T& x) { Base::_check_template_params(); Base::template _init1(x); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) { Base::_check_template_params(); this->template _init2(val0, val1); } #else /** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */ EIGEN_DEVICE_FUNC explicit Array(const Scalar *data); /** Constructs a vector or row-vector with given dimension. \only_for_vectors * * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, * it is redundant to pass the dimension here, so it makes more sense to use the default * constructor Array() instead. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Array(Index dim); /** constructs an initialized 1x1 Array with the given coefficient */ Array(const Scalar& value); /** constructs an uninitialized array with \a rows rows and \a cols columns. * * This is useful for dynamic-size arrays. For fixed-size arrays, * it is redundant to pass these parameters, so one should use the default constructor * Array() instead. */ Array(Index rows, Index cols); /** constructs an initialized 2D vector with given coefficients */ Array(const Scalar& val0, const Scalar& val1); #endif /** constructs an initialized 3D vector with given coefficients */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) m_storage.data()[0] = val0; m_storage.data()[1] = val1; m_storage.data()[2] = val2; } /** constructs an initialized 4D vector with given coefficients */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) m_storage.data()[0] = val0; m_storage.data()[1] = val1; m_storage.data()[2] = val2; m_storage.data()[3] = val3; } /** Copy constructor */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Array& other) : Base(other) { } private: struct PrivateType {}; public: /** \sa MatrixBase::operator=(const EigenBase&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const EigenBase &other, typename internal::enable_if::value, PrivateType>::type = PrivateType()) : Base(other.derived()) { } EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } #ifdef EIGEN_ARRAY_PLUGIN #include EIGEN_ARRAY_PLUGIN #endif private: template friend struct internal::matrix_swap_impl; }; /** \defgroup arraytypedefs Global array typedefs * \ingroup Core_Module * * Eigen defines several typedef shortcuts for most common 1D and 2D array types. * * The general patterns are the following: * * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd * for complex double. * * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats. * * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is * a fixed-size 1D array of 4 complex floats. * * \sa class Array */ #define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ /** \ingroup arraytypedefs */ \ typedef Array Array##SizeSuffix##SizeSuffix##TypeSuffix; \ /** \ingroup arraytypedefs */ \ typedef Array Array##SizeSuffix##TypeSuffix; #define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ /** \ingroup arraytypedefs */ \ typedef Array Array##Size##X##TypeSuffix; \ /** \ingroup arraytypedefs */ \ typedef Array Array##X##Size##TypeSuffix; #define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \ EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cf) EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cd) #undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES #undef EIGEN_MAKE_ARRAY_TYPEDEFS #undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE #define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ using Eigen::Matrix##SizeSuffix##TypeSuffix; \ using Eigen::Vector##SizeSuffix##TypeSuffix; \ using Eigen::RowVector##SizeSuffix##TypeSuffix; #define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ #define EIGEN_USING_ARRAY_TYPEDEFS \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) } // end namespace Eigen #endif // EIGEN_ARRAY_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ArrayBase.h000066400000000000000000000200551506104011400236230ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAYBASE_H #define EIGEN_ARRAYBASE_H namespace Eigen { template class MatrixWrapper; /** \class ArrayBase * \ingroup Core_Module * * \brief Base class for all 1D and 2D array, and related expressions * * An array is similar to a dense vector or matrix. While matrices are mathematical * objects with well defined linear algebra operators, an array is just a collection * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence, * all operations applied to an array are performed coefficient wise. Furthermore, * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient * constructors allowing to easily write generic code working for both scalar values * and arrays. * * This class is the base that is inherited by all array expression types. * * \tparam Derived is the derived type, e.g., an array or an expression type. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. * * \sa class MatrixBase, \ref TopicClassHierarchy */ template class ArrayBase : public DenseBase { public: #ifndef EIGEN_PARSED_BY_DOXYGEN /** The base class for a given storage type. */ typedef ArrayBase StorageBaseType; typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::operator=; using Base::operator+=; using Base::operator-=; using Base::operator*=; using Base::operator/=; typedef typename Base::CoeffReturnType CoeffReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Base::PlainObject PlainObject; /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,PlainObject> ConstantReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase #define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/ArrayCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseBinaryOps.h" # include "../plugins/ArrayCwiseBinaryOps.h" # ifdef EIGEN_ARRAYBASE_PLUGIN # include EIGEN_ARRAYBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS #undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ArrayBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } /** Set all the entries to \a value. * \sa DenseBase::setConstant(), DenseBase::fill() */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const Scalar &value) { Base::setConstant(value); return derived(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const Scalar& scalar); EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const Scalar& scalar); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const ArrayBase& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const ArrayBase& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const ArrayBase& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const ArrayBase& other); public: EIGEN_DEVICE_FUNC ArrayBase& array() { return *this; } EIGEN_DEVICE_FUNC const ArrayBase& array() const { return *this; } /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ EIGEN_DEVICE_FUNC MatrixWrapper matrix() { return MatrixWrapper(derived()); } EIGEN_DEVICE_FUNC const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } protected: EIGEN_DEFAULT_COPY_CONSTRUCTOR(ArrayBase) EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(ArrayBase) private: explicit ArrayBase(Index); ArrayBase(Index,Index); template explicit ArrayBase(const ArrayBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const MatrixBase& ) {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} // mixing arrays and matrices is not legal template Derived& operator-=(const MatrixBase& ) {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator-=(const ArrayBase &other) { call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } /** replaces \c *this by \c *this + \a other. * * \returns a reference to \c *this */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator+=(const ArrayBase& other) { call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } /** replaces \c *this by \c *this * \a other coefficient wise. * * \returns a reference to \c *this */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { call_assignment(derived(), other.derived(), internal::mul_assign_op()); return derived(); } /** replaces \c *this by \c *this / \a other coefficient wise. * * \returns a reference to \c *this */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & ArrayBase::operator/=(const ArrayBase& other) { call_assignment(derived(), other.derived(), internal::div_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_ARRAYBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ArrayWrapper.h000066400000000000000000000151671506104011400244010ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ARRAYWRAPPER_H #define EIGEN_ARRAYWRAPPER_H namespace Eigen { /** \class ArrayWrapper * \ingroup Core_Module * * \brief Expression of a mathematical vector or matrix as an array object * * This class is the return type of MatrixBase::array(), and most of the time * this is the only way it is use. * * \sa MatrixBase::array(), class MatrixWrapper */ namespace internal { template struct traits > : public traits::type > { typedef ArrayXpr XprKind; // Let's remove NestByRefBit enum { Flags0 = traits::type >::Flags, LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag }; }; } template class ArrayWrapper : public ArrayBase > { public: typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, Scalar, const Scalar >::type ScalarWithConstIfNotLvalue; typedef typename internal::ref_selector::non_const_type NestedExpressionType; using Base::coeffRef; EIGEN_DEVICE_FUNC explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.coeffRef(rowId, colId); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.coeffRef(index); } template EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { dst = m_expression; } const typename internal::remove_all::type& EIGEN_DEVICE_FUNC nestedExpression() const { return m_expression; } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; }; /** \class MatrixWrapper * \ingroup Core_Module * * \brief Expression of an array as a mathematical vector or matrix * * This class is the return type of ArrayBase::matrix(), and most of the time * this is the only way it is use. * * \sa MatrixBase::matrix(), class ArrayWrapper */ namespace internal { template struct traits > : public traits::type > { typedef MatrixXpr XprKind; // Let's remove NestByRefBit enum { Flags0 = traits::type >::Flags, LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag }; }; } template class MatrixWrapper : public MatrixBase > { public: typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, Scalar, const Scalar >::type ScalarWithConstIfNotLvalue; typedef typename internal::ref_selector::non_const_type NestedExpressionType; using Base::coeffRef; EIGEN_DEVICE_FUNC explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.derived().coeffRef(rowId, colId); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.coeffRef(index); } EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_expression; } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; }; } // end namespace Eigen #endif // EIGEN_ARRAYWRAPPER_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Assign.h000066400000000000000000000052401506104011400231750ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007 Michael Olbrich // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ASSIGN_H #define EIGEN_ASSIGN_H namespace Eigen { template template EIGEN_STRONG_INLINE Derived& DenseBase ::lazyAssign(const DenseBase& other) { enum{ SameType = internal::is_same::value }; EIGEN_STATIC_ASSERT_LVALUE(Derived) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) eigen_assert(rows() == other.rows() && cols() == other.cols()); internal::call_assignment_no_alias(derived(),other.derived()); return derived(); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { internal::call_assignment(derived(), other.derived()); return derived(); } template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { other.derived().evalTo(derived()); return derived(); } } // end namespace Eigen #endif // EIGEN_ASSIGN_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/AssignEvaluator.h000066400000000000000000001124111506104011400250570ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2011 Benoit Jacob // Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2011-2012 Jitse Niesen // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ASSIGN_EVALUATOR_H #define EIGEN_ASSIGN_EVALUATOR_H namespace Eigen { // This implementation is based on Assign.h namespace internal { /*************************************************************************** * Part 1 : the logic deciding a strategy for traversal and unrolling * ***************************************************************************/ // copy_using_evaluator_traits is based on assign_traits template struct copy_using_evaluator_traits { typedef typename DstEvaluator::XprType Dst; typedef typename Dst::Scalar DstScalar; enum { DstFlags = DstEvaluator::Flags, SrcFlags = SrcEvaluator::Flags }; public: enum { DstAlignment = DstEvaluator::Alignment, SrcAlignment = SrcEvaluator::Alignment, DstHasDirectAccess = (DstFlags & DirectAccessBit) == DirectAccessBit, JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment) }; private: enum { InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) : int(Dst::RowsAtCompileTime), InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) : int(Dst::MaxRowsAtCompileTime), OuterStride = int(outer_stride_at_compile_time::ret), MaxSizeAtCompileTime = Dst::SizeAtCompileTime }; // TODO distinguish between linear traversal and inner-traversals typedef typename find_best_packet::type LinearPacketType; typedef typename find_best_packet::type InnerPacketType; enum { LinearPacketSize = unpacket_traits::size, InnerPacketSize = unpacket_traits::size }; public: enum { LinearRequiredAlignment = unpacket_traits::alignment, InnerRequiredAlignment = unpacket_traits::alignment }; private: enum { DstIsRowMajor = DstFlags&RowMajorBit, SrcIsRowMajor = SrcFlags&RowMajorBit, StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), MightVectorize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) && bool(functor_traits::PacketAccess), MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(InnerPacketSize)==0 && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0 && (EIGEN_UNALIGNED_VECTORIZE || int(JointAlignment)>=int(InnerRequiredAlignment)), MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), MayLinearVectorize = bool(MightVectorize) && bool(MayLinearize) && bool(DstHasDirectAccess) && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic), /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, so it's only good for large enough sizes. */ MaySliceVectorize = bool(MightVectorize) && bool(DstHasDirectAccess) && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=(EIGEN_UNALIGNED_VECTORIZE?InnerPacketSize:(3*InnerPacketSize))) /* slice vectorization can be slow, so we only want it if the slices are big, which is indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block in a fixed-size matrix However, with EIGEN_UNALIGNED_VECTORIZE and unrolling, slice vectorization is still worth it */ }; public: enum { Traversal = int(MayLinearVectorize) && (LinearPacketSize>InnerPacketSize) ? int(LinearVectorizedTraversal) : int(MayInnerVectorize) ? int(InnerVectorizedTraversal) : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(MayLinearize) ? int(LinearTraversal) : int(DefaultTraversal), Vectorized = int(Traversal) == InnerVectorizedTraversal || int(Traversal) == LinearVectorizedTraversal || int(Traversal) == SliceVectorizedTraversal }; typedef typename conditional::type PacketType; private: enum { ActualPacketSize = int(Traversal)==LinearVectorizedTraversal ? LinearPacketSize : Vectorized ? InnerPacketSize : 1, UnrollingLimit = EIGEN_UNROLLING_LIMIT * ActualPacketSize, MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic && int(Dst::SizeAtCompileTime) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit), MayUnrollInner = int(InnerSize) != Dynamic && int(InnerSize) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit) }; public: enum { Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) ? ( int(MayUnrollCompletely) ? int(CompleteUnrolling) : int(MayUnrollInner) ? int(InnerUnrolling) : int(NoUnrolling) ) : int(Traversal) == int(LinearVectorizedTraversal) ? ( bool(MayUnrollCompletely) && ( EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment))) ? int(CompleteUnrolling) : int(NoUnrolling) ) : int(Traversal) == int(LinearTraversal) ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) #if EIGEN_UNALIGNED_VECTORIZE : int(Traversal) == int(SliceVectorizedTraversal) ? ( bool(MayUnrollInner) ? int(InnerUnrolling) : int(NoUnrolling) ) #endif : int(NoUnrolling) }; #ifdef EIGEN_DEBUG_ASSIGN static void debug() { std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; std::cerr.setf(std::ios::hex, std::ios::basefield); std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl; std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl; std::cerr.unsetf(std::ios::hex); EIGEN_DEBUG_VAR(DstAlignment) EIGEN_DEBUG_VAR(SrcAlignment) EIGEN_DEBUG_VAR(LinearRequiredAlignment) EIGEN_DEBUG_VAR(InnerRequiredAlignment) EIGEN_DEBUG_VAR(JointAlignment) EIGEN_DEBUG_VAR(InnerSize) EIGEN_DEBUG_VAR(InnerMaxSize) EIGEN_DEBUG_VAR(LinearPacketSize) EIGEN_DEBUG_VAR(InnerPacketSize) EIGEN_DEBUG_VAR(ActualPacketSize) EIGEN_DEBUG_VAR(StorageOrdersAgree) EIGEN_DEBUG_VAR(MightVectorize) EIGEN_DEBUG_VAR(MayLinearize) EIGEN_DEBUG_VAR(MayInnerVectorize) EIGEN_DEBUG_VAR(MayLinearVectorize) EIGEN_DEBUG_VAR(MaySliceVectorize) std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; EIGEN_DEBUG_VAR(SrcEvaluator::CoeffReadCost) EIGEN_DEBUG_VAR(UnrollingLimit) EIGEN_DEBUG_VAR(MayUnrollCompletely) EIGEN_DEBUG_VAR(MayUnrollInner) std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; std::cerr << std::endl; } #endif }; /*************************************************************************** * Part 2 : meta-unrollers ***************************************************************************/ /************************ *** Default traversal *** ************************/ template struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling { // FIXME: this is not very clean, perhaps this information should be provided by the kernel? typedef typename Kernel::DstEvaluatorType DstEvaluatorType; typedef typename DstEvaluatorType::XprType DstXprType; enum { outer = Index / DstXprType::InnerSizeAtCompileTime, inner = Index % DstXprType::InnerSizeAtCompileTime }; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { kernel.assignCoeffByOuterInner(outer, inner); copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); } }; template struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; template struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) { kernel.assignCoeffByOuterInner(outer, Index_); copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); } }; template struct copy_using_evaluator_DefaultTraversal_InnerUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { } }; /*********************** *** Linear traversal *** ***********************/ template struct copy_using_evaluator_LinearTraversal_CompleteUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) { kernel.assignCoeff(Index); copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); } }; template struct copy_using_evaluator_LinearTraversal_CompleteUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; /************************** *** Inner vectorization *** **************************/ template struct copy_using_evaluator_innervec_CompleteUnrolling { // FIXME: this is not very clean, perhaps this information should be provided by the kernel? typedef typename Kernel::DstEvaluatorType DstEvaluatorType; typedef typename DstEvaluatorType::XprType DstXprType; typedef typename Kernel::PacketType PacketType; enum { outer = Index / DstXprType::InnerSizeAtCompileTime, inner = Index % DstXprType::InnerSizeAtCompileTime, SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, DstAlignment = Kernel::AssignmentTraits::DstAlignment }; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { kernel.template assignPacketByOuterInner(outer, inner); enum { NextIndex = Index + unpacket_traits::size }; copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); } }; template struct copy_using_evaluator_innervec_CompleteUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } }; template struct copy_using_evaluator_innervec_InnerUnrolling { typedef typename Kernel::PacketType PacketType; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) { kernel.template assignPacketByOuterInner(outer, Index_); enum { NextIndex = Index_ + unpacket_traits::size }; copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); } }; template struct copy_using_evaluator_innervec_InnerUnrolling { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { } }; /*************************************************************************** * Part 3 : implementation of all cases ***************************************************************************/ // dense_assignment_loop is based on assign_impl template struct dense_assignment_loop; /************************ *** Default traversal *** ************************/ template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel) { for(Index outer = 0; outer < kernel.outerSize(); ++outer) { for(Index inner = 0; inner < kernel.innerSize(); ++inner) { kernel.assignCoeffByOuterInner(outer, inner); } } } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; const Index outerSize = kernel.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); } }; /*************************** *** Linear vectorization *** ***************************/ // The goal of unaligned_dense_assignment_loop is simply to factorize the handling // of the non vectorizable beginning and ending parts template struct unaligned_dense_assignment_loop { // if IsAligned = true, then do nothing template EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {} }; template <> struct unaligned_dense_assignment_loop { // MSVC must not inline this functions. If it does, it fails to optimize the // packet access path. // FIXME check which version exhibits this issue #if EIGEN_COMP_MSVC template static EIGEN_DONT_INLINE void run(Kernel &kernel, Index start, Index end) #else template EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index start, Index end) #endif { for (Index index = start; index < end; ++index) kernel.assignCoeff(index); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { const Index size = kernel.size(); typedef typename Kernel::Scalar Scalar; typedef typename Kernel::PacketType PacketType; enum { requestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment, packetSize = unpacket_traits::size, dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), dstAlignment = packet_traits::AlignedOnScalar ? int(requestedAlignment) : int(Kernel::AssignmentTraits::DstAlignment), srcAlignment = Kernel::AssignmentTraits::JointAlignment }; const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned(kernel.dstDataPtr(), size); const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; unaligned_dense_assignment_loop::run(kernel, 0, alignedStart); for(Index index = alignedStart; index < alignedEnd; index += packetSize) kernel.template assignPacket(index); unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; typedef typename Kernel::PacketType PacketType; enum { size = DstXprType::SizeAtCompileTime, packetSize =unpacket_traits::size, alignedSize = (size/packetSize)*packetSize }; copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); } }; /************************** *** Inner vectorization *** **************************/ template struct dense_assignment_loop { typedef typename Kernel::PacketType PacketType; enum { SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, DstAlignment = Kernel::AssignmentTraits::DstAlignment }; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { const Index innerSize = kernel.innerSize(); const Index outerSize = kernel.outerSize(); const Index packetSize = unpacket_traits::size; for(Index outer = 0; outer < outerSize; ++outer) for(Index inner = 0; inner < innerSize; inner+=packetSize) kernel.template assignPacketByOuterInner(outer, inner); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; typedef typename Kernel::AssignmentTraits Traits; const Index outerSize = kernel.outerSize(); for(Index outer = 0; outer < outerSize; ++outer) copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); } }; /*********************** *** Linear traversal *** ***********************/ template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { const Index size = kernel.size(); for(Index i = 0; i < size; ++i) kernel.assignCoeff(i); } }; template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); } }; /************************** *** Slice vectorization *** ***************************/ template struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::Scalar Scalar; typedef typename Kernel::PacketType PacketType; enum { packetSize = unpacket_traits::size, requestedAlignment = int(Kernel::AssignmentTraits::InnerRequiredAlignment), alignable = packet_traits::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar), dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), dstAlignment = alignable ? int(requestedAlignment) : int(Kernel::AssignmentTraits::DstAlignment) }; const Scalar *dst_ptr = kernel.dstDataPtr(); if((!bool(dstIsAligned)) && (UIntPtr(dst_ptr) % sizeof(Scalar))>0) { // the pointer is not aligend-on scalar, so alignment is not possible return dense_assignment_loop::run(kernel); } const Index packetAlignedMask = packetSize - 1; const Index innerSize = kernel.innerSize(); const Index outerSize = kernel.outerSize(); const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0; Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); for(Index outer = 0; outer < outerSize; ++outer) { const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); // do the non-vectorizable part of the assignment for(Index inner = 0; inner(outer, inner); // do the non-vectorizable part of the assignment for(Index inner = alignedEnd; inner struct dense_assignment_loop { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) { typedef typename Kernel::DstEvaluatorType::XprType DstXprType; typedef typename Kernel::PacketType PacketType; enum { size = DstXprType::InnerSizeAtCompileTime, packetSize =unpacket_traits::size, vectorizableSize = (size/packetSize)*packetSize }; for(Index outer = 0; outer < kernel.outerSize(); ++outer) { copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); } } }; #endif /*************************************************************************** * Part 4 : Generic dense assignment kernel ***************************************************************************/ // This class generalize the assignment of a coefficient (or packet) from one dense evaluator // to another dense writable evaluator. // It is parametrized by the two evaluators, and the actual assignment functor. // This abstraction level permits to keep the evaluation loops as simple and as generic as possible. // One can customize the assignment using this generic dense_assignment_kernel with different // functors, or by completely overloading it, by-passing a functor. template class generic_dense_assignment_kernel { protected: typedef typename DstEvaluatorTypeT::XprType DstXprType; typedef typename SrcEvaluatorTypeT::XprType SrcXprType; public: typedef DstEvaluatorTypeT DstEvaluatorType; typedef SrcEvaluatorTypeT SrcEvaluatorType; typedef typename DstEvaluatorType::Scalar Scalar; typedef copy_using_evaluator_traits AssignmentTraits; typedef typename AssignmentTraits::PacketType PacketType; EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) { #ifdef EIGEN_DEBUG_ASSIGN AssignmentTraits::debug(); #endif } EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); } EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); } EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); } EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); } EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); } EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); } EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; } EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; } /// Assign src(row,col) to dst(row,col) through the assignment functor. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col) { m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); } /// \sa assignCoeff(Index,Index) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index) { m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); } /// \sa assignCoeff(Index,Index) EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner) { Index row = rowIndexByOuterInner(outer, inner); Index col = colIndexByOuterInner(outer, inner); assignCoeff(row, col); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col) { m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index) { m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner) { Index row = rowIndexByOuterInner(outer, inner); Index col = colIndexByOuterInner(outer, inner); assignPacket(row, col); } EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) { typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::RowsAtCompileTime) == 1 ? 0 : int(Traits::ColsAtCompileTime) == 1 ? inner : int(DstEvaluatorType::Flags)&RowMajorBit ? outer : inner; } EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) { typedef typename DstEvaluatorType::ExpressionTraits Traits; return int(Traits::ColsAtCompileTime) == 1 ? 0 : int(Traits::RowsAtCompileTime) == 1 ? inner : int(DstEvaluatorType::Flags)&RowMajorBit ? inner : outer; } EIGEN_DEVICE_FUNC const Scalar* dstDataPtr() const { return m_dstExpr.data(); } protected: DstEvaluatorType& m_dst; const SrcEvaluatorType& m_src; const Functor &m_functor; // TODO find a way to avoid the needs of the original expression DstXprType& m_dstExpr; }; /*************************************************************************** * Part 5 : Entry point for dense rectangular assignment ***************************************************************************/ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/) { EIGEN_ONLY_USED_FOR_DEBUG(dst); EIGEN_ONLY_USED_FOR_DEBUG(src); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op &/*func*/) { Index dstRows = src.rows(); Index dstCols = src.cols(); if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) { typedef evaluator DstEvaluatorType; typedef evaluator SrcEvaluatorType; SrcEvaluatorType srcEvaluator(src); // NOTE To properly handle A = (A*A.transpose())/s with A rectangular, // we need to resize the destination after the source evaluator has been created. resize_if_allowed(dst, src, func); DstEvaluatorType dstEvaluator(dst); typedef generic_dense_assignment_kernel Kernel; Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); dense_assignment_loop::run(kernel); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src) { call_dense_assignment_loop(dst, src, internal::assign_op()); } /*************************************************************************** * Part 6 : Generic assignment ***************************************************************************/ // Based on the respective shapes of the destination and source, // the class AssignmentKind determine the kind of assignment mechanism. // AssignmentKind must define a Kind typedef. template struct AssignmentKind; // Assignement kind defined in this file: struct Dense2Dense {}; struct EigenBase2EigenBase {}; template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; template<> struct AssignmentKind { typedef Dense2Dense Kind; }; // This is the main assignment class template< typename DstXprType, typename SrcXprType, typename Functor, typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, typename EnableIf = void> struct Assignment; // The only purpose of this call_assignment() function is to deal with noalias() / "assume-aliasing" and automatic transposition. // Indeed, I (Gael) think that this concept of "assume-aliasing" was a mistake, and it makes thing quite complicated. // So this intermediate function removes everything related to "assume-aliasing" such that Assignment // does not has to bother about these annoying details. template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment(Dst& dst, const Src& src) { call_assignment(dst, src, internal::assign_op()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment(const Dst& dst, const Src& src) { call_assignment(dst, src, internal::assign_op()); } // Deal with "assume-aliasing" template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if< evaluator_assume_aliasing::value, void*>::type = 0) { typename plain_matrix_type::type tmp(src); call_assignment_no_alias(dst, tmp, func); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::value, void*>::type = 0) { call_assignment_no_alias(dst, src, func); } // by-pass "assume-aliasing" // When there is no aliasing, we require that 'dst' has been properly resized template class StorageBase, typename Src, typename Func> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment(NoAlias& dst, const Src& src, const Func& func) { call_assignment_no_alias(dst.expression(), src, func); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) { enum { NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1) ) && int(Dst::SizeAtCompileTime) != 1 }; typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; typedef typename internal::conditional, Dst&>::type ActualDstType; ActualDstType actualDst(dst); // TODO check whether this is the right place to perform these checks: EIGEN_STATIC_ASSERT_LVALUE(Dst) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); Assignment::run(actualDst, src, func); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment_no_alias(Dst& dst, const Src& src) { call_assignment_no_alias(dst, src, internal::assign_op()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func) { // TODO check whether this is the right place to perform these checks: EIGEN_STATIC_ASSERT_LVALUE(Dst) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src) EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar); Assignment::run(dst, src, func); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src) { call_assignment_no_alias_no_transpose(dst, src, internal::assign_op()); } // forward declaration template void check_for_aliasing(const Dst &dst, const Src &src); // Generic Dense to Dense assignment // Note that the last template argument "Weak" is needed to make it possible to perform // both partial specialization+SFINAE without ambiguous specialization template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> struct Assignment { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const Functor &func) { #ifndef EIGEN_NO_DEBUG internal::check_for_aliasing(dst, src); #endif call_dense_assignment_loop(dst, src, func); } }; // Generic assignment through evalTo. // TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. // Note that the last template argument "Weak" is needed to make it possible to perform // both partial specialization+SFINAE without ambiguous specialization template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> struct Assignment { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) { Index dstRows = src.rows(); Index dstCols = src.cols(); if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); src.evalTo(dst); } // NOTE The following two functions are templated to avoid their instanciation if not needed // This is needed because some expressions supports evalTo only and/or have 'void' as scalar type. template EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) { Index dstRows = src.rows(); Index dstCols = src.cols(); if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); src.addTo(dst); } template EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) { Index dstRows = src.rows(); Index dstCols = src.cols(); if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); src.subTo(dst); } }; } // namespace internal } // end namespace Eigen #endif // EIGEN_ASSIGN_EVALUATOR_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Assign_MKL.h000066400000000000000000000302771506104011400237100ustar00rootroot00000000000000/* Copyright (c) 2011, Intel Corporation. All rights reserved. Copyright (C) 2015 Gael Guennebaud Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** * Content : Eigen bindings to Intel(R) MKL * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin() ******************************************************************************** */ #ifndef EIGEN_ASSIGN_VML_H #define EIGEN_ASSIGN_VML_H namespace Eigen { namespace internal { template class vml_assign_traits { private: enum { DstHasDirectAccess = Dst::Flags & DirectAccessBit, SrcHasDirectAccess = Src::Flags & DirectAccessBit, StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) : int(Dst::RowsAtCompileTime), InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) : int(Dst::Flags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) : int(Dst::MaxRowsAtCompileTime), MaxSizeAtCompileTime = Dst::SizeAtCompileTime, MightEnableVml = StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD }; public: enum { EnableVml = MightEnableVml && LargeEnough, Traversal = MightLinearize ? LinearTraversal : DefaultTraversal }; }; #define EIGEN_PP_EXPAND(ARG) ARG #if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) #define EIGEN_VMLMODE_EXPAND_LA , VML_HA #else #define EIGEN_VMLMODE_EXPAND_LA , VML_LA #endif #define EIGEN_VMLMODE_EXPAND__ #define EIGEN_VMLMODE_PREFIX_LA vm #define EIGEN_VMLMODE_PREFIX__ v #define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_,VMLMODE) #define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ template< typename DstXprType, typename SrcXprNested> \ struct Assignment, SrcXprNested>, assign_op, \ Dense2Dense, typename enable_if::EnableVml>::type> { \ typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ resize_if_allowed(dst, src, func); \ eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ if(vml_assign_traits::Traversal==LinearTraversal) { \ VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(), \ (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ } else { \ const Index outerSize = dst.outerSize(); \ for(Index outer = 0; outer < outerSize; ++outer) { \ const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ &(src.nestedExpression().coeffRef(0, outer)); \ EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, \ (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ } \ } \ } \ }; \ #define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),s##VMLOP), float, float, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),d##VMLOP), double, double, VMLMODE) #define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),c##VMLOP), scomplex, MKL_Complex8, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),z##VMLOP), dcomplex, MKL_Complex16, VMLMODE) #define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA) // EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA) EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _) EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _) #define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ template< typename DstXprType, typename SrcXprNested, typename Plain> \ struct Assignment, SrcXprNested, \ const CwiseNullaryOp,Plain> >, assign_op, \ Dense2Dense, typename enable_if::EnableVml>::type> { \ typedef CwiseBinaryOp, SrcXprNested, \ const CwiseNullaryOp,Plain> > SrcXprType; \ static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ resize_if_allowed(dst, src, func); \ eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ VMLTYPE exponent = reinterpret_cast(src.rhs().functor().m_other); \ if(vml_assign_traits::Traversal==LinearTraversal) \ { \ VMLOP( dst.size(), (const VMLTYPE*)src.lhs().data(), exponent, \ (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ } else { \ const Index outerSize = dst.outerSize(); \ for(Index outer = 0; outer < outerSize; ++outer) { \ const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.lhs().coeffRef(outer,0)) : \ &(src.lhs().coeffRef(0, outer)); \ EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, exponent, \ (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ } \ } \ } \ }; EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA) EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA) EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA) EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA) } // end namespace internal } // end namespace Eigen #endif // EIGEN_ASSIGN_VML_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/BandMatrix.h000066400000000000000000000331261506104011400240060ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BANDMATRIX_H #define EIGEN_BANDMATRIX_H namespace Eigen { namespace internal { template class BandMatrixBase : public EigenBase { public: enum { Flags = internal::traits::Flags, CoeffReadCost = internal::traits::CoeffReadCost, RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, Supers = internal::traits::Supers, Subs = internal::traits::Subs, Options = internal::traits::Options }; typedef typename internal::traits::Scalar Scalar; typedef Matrix DenseMatrixType; typedef typename DenseMatrixType::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef EigenBase Base; protected: enum { DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic, SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime) }; public: using Base::derived; using Base::rows; using Base::cols; /** \returns the number of super diagonals */ inline Index supers() const { return derived().supers(); } /** \returns the number of sub diagonals */ inline Index subs() const { return derived().subs(); } /** \returns an expression of the underlying coefficient matrix */ inline const CoefficientsType& coeffs() const { return derived().coeffs(); } /** \returns an expression of the underlying coefficient matrix */ inline CoefficientsType& coeffs() { return derived().coeffs(); } /** \returns a vector expression of the \a i -th column, * only the meaningful part is returned. * \warning the internal storage must be column major. */ inline Block col(Index i) { EIGEN_STATIC_ASSERT((Options&RowMajor)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); Index start = 0; Index len = coeffs().rows(); if (i<=supers()) { start = supers()-i; len = (std::min)(rows(),std::max(0,coeffs().rows() - (supers()-i))); } else if (i>=rows()-subs()) len = std::max(0,coeffs().rows() - (i + 1 - rows() + subs())); return Block(coeffs(), start, i, len, 1); } /** \returns a vector expression of the main diagonal */ inline Block diagonal() { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } /** \returns a vector expression of the main diagonal (const version) */ inline const Block diagonal() const { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } template struct DiagonalIntReturnType { enum { ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)), Conjugate = ReturnOpposite && NumTraits::IsComplex, ActualIndex = ReturnOpposite ? -Index : Index, DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic) ? Dynamic : (ActualIndex<0 ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex)) }; typedef Block BuildType; typedef typename internal::conditional,BuildType >, BuildType>::type Type; }; /** \returns a vector expression of the \a N -th sub or super diagonal */ template inline typename DiagonalIntReturnType::Type diagonal() { return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); } /** \returns a vector expression of the \a N -th sub or super diagonal */ template inline const typename DiagonalIntReturnType::Type diagonal() const { return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); } /** \returns a vector expression of the \a i -th sub or super diagonal */ inline Block diagonal(Index i) { eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); } /** \returns a vector expression of the \a i -th sub or super diagonal */ inline const Block diagonal(Index i) const { eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); } template inline void evalTo(Dest& dst) const { dst.resize(rows(),cols()); dst.setZero(); dst.diagonal() = diagonal(); for (Index i=1; i<=supers();++i) dst.diagonal(i) = diagonal(i); for (Index i=1; i<=subs();++i) dst.diagonal(-i) = diagonal(-i); } DenseMatrixType toDenseMatrix() const { DenseMatrixType res(rows(),cols()); evalTo(res); return res; } protected: inline Index diagonalLength(Index i) const { return i<0 ? (std::min)(cols(),rows()+i) : (std::min)(rows(),cols()-i); } }; /** * \class BandMatrix * \ingroup Core_Module * * \brief Represents a rectangular matrix with a banded storage * * \tparam _Scalar Numeric type, i.e. float, double, int * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * \tparam _Supers Number of super diagonal * \tparam _Subs Number of sub diagonal * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint * The former controls \ref TopicStorageOrders "storage order", and defaults to * column-major. The latter controls whether the matrix represents a selfadjoint * matrix in which case either Supers of Subs have to be null. * * \sa class TridiagonalMatrix */ template struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; typedef Eigen::Index StorageIndex; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _Rows, MaxColsAtCompileTime = _Cols, Flags = LvalueBit, Supers = _Supers, Subs = _Subs, Options = _Options, DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic }; typedef Matrix CoefficientsType; }; template class BandMatrix : public BandMatrixBase > { public: typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { } /** \returns the number of columns */ inline Index rows() const { return m_rows.value(); } /** \returns the number of rows */ inline Index cols() const { return m_coeffs.cols(); } /** \returns the number of super diagonals */ inline Index supers() const { return m_supers.value(); } /** \returns the number of sub diagonals */ inline Index subs() const { return m_subs.value(); } inline const CoefficientsType& coeffs() const { return m_coeffs; } inline CoefficientsType& coeffs() { return m_coeffs; } protected: CoefficientsType m_coeffs; internal::variable_if_dynamic m_rows; internal::variable_if_dynamic m_supers; internal::variable_if_dynamic m_subs; }; template class BandMatrixWrapper; template struct traits > { typedef typename _CoefficientsType::Scalar Scalar; typedef typename _CoefficientsType::StorageKind StorageKind; typedef typename _CoefficientsType::StorageIndex StorageIndex; enum { CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost, RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _Rows, MaxColsAtCompileTime = _Cols, Flags = LvalueBit, Supers = _Supers, Subs = _Subs, Options = _Options, DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic }; typedef _CoefficientsType CoefficientsType; }; template class BandMatrixWrapper : public BandMatrixBase > { public: typedef typename internal::traits::Scalar Scalar; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef typename internal::traits::StorageIndex StorageIndex; explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { EIGEN_UNUSED_VARIABLE(cols); //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows()); } /** \returns the number of columns */ inline Index rows() const { return m_rows.value(); } /** \returns the number of rows */ inline Index cols() const { return m_coeffs.cols(); } /** \returns the number of super diagonals */ inline Index supers() const { return m_supers.value(); } /** \returns the number of sub diagonals */ inline Index subs() const { return m_subs.value(); } inline const CoefficientsType& coeffs() const { return m_coeffs; } protected: const CoefficientsType& m_coeffs; internal::variable_if_dynamic m_rows; internal::variable_if_dynamic m_supers; internal::variable_if_dynamic m_subs; }; /** * \class TridiagonalMatrix * \ingroup Core_Module * * \brief Represents a tridiagonal matrix with a compact banded storage * * \tparam Scalar Numeric type, i.e. float, double, int * \tparam Size Number of rows and cols, or \b Dynamic * \tparam Options Can be 0 or \b SelfAdjoint * * \sa class BandMatrix */ template class TridiagonalMatrix : public BandMatrix { typedef BandMatrix Base; typedef typename Base::StorageIndex StorageIndex; public: explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } inline const typename Base::template DiagonalIntReturnType<1>::Type super() const { return Base::template diagonal<1>(); } inline typename Base::template DiagonalIntReturnType<-1>::Type sub() { return Base::template diagonal<-1>(); } inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const { return Base::template diagonal<-1>(); } protected: }; struct BandShape {}; template struct evaluator_traits > : public evaluator_traits_base > { typedef BandShape Shape; }; template struct evaluator_traits > : public evaluator_traits_base > { typedef BandShape Shape; }; template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_BANDMATRIX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Block.h000066400000000000000000000432201506104011400230030ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_BLOCK_H #define EIGEN_BLOCK_H namespace Eigen { namespace internal { template struct traits > : traits { typedef typename traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename ref_selector::type XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum{ MatrixRows = traits::RowsAtCompileTime, MatrixCols = traits::ColsAtCompileTime, RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows, ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols, MaxRowsAtCompileTime = BlockRows==0 ? 0 : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : int(traits::MaxRowsAtCompileTime), MaxColsAtCompileTime = BlockCols==0 ? 0 : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits::MaxColsAtCompileTime), XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), InnerStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), OuterStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, // FIXME DirectAccessBit should not be handled by expressions // // Alignment is needed by MapBase's assertions // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator Alignment = 0 }; }; template::ret> class BlockImpl_dense; } // end namespace internal template class BlockImpl; /** \class Block * \ingroup Core_Module * * \brief Expression of a fixed-size or dynamic-size block * * \tparam XprType the type of the expression in which we are taking a block * \tparam BlockRows the number of rows of the block we are taking at compile time (optional) * \tparam BlockCols the number of columns of the block we are taking at compile time (optional) * \tparam InnerPanel is true, if the block maps to a set of rows of a row major matrix or * to set of columns of a column major matrix (optional). The parameter allows to determine * at compile time whether aligned access is possible on the block expression. * * This class represents an expression of either a fixed-size or dynamic-size block. It is the return * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and * most of the time this is the only way it is used. * * However, if you want to directly maniputate block expressions, * for instance if you want to write a function returning such an expression, you * will need to use this class. * * Here is an example illustrating the dynamic case: * \include class_Block.cpp * Output: \verbinclude class_Block.out * * \note Even though this expression has dynamic size, in the case where \a XprType * has fixed size, this expression inherits a fixed maximal size which means that evaluating * it does not cause a dynamic memory allocation. * * Here is an example illustrating the fixed-size case: * \include class_FixedBlock.cpp * Output: \verbinclude class_FixedBlock.out * * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock */ template class Block : public BlockImpl::StorageKind> { typedef BlockImpl::StorageKind> Impl; public: //typedef typename Impl::Base Base; typedef Impl Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) typedef typename internal::remove_all::type NestedExpression; /** Column or Row constructor */ EIGEN_DEVICE_FUNC inline Block(XprType& xpr, Index i) : Impl(xpr,i) { eigen_assert( (i>=0) && ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 0 && startRow + BlockRows <= xpr.rows() && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= xpr.cols()); } /** Dynamic-size constructor */ EIGEN_DEVICE_FUNC inline Block(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : Impl(xpr, startRow, startCol, blockRows, blockCols) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } }; // The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense // that must be specialized for direct and non-direct access... template class BlockImpl : public internal::BlockImpl_dense { typedef internal::BlockImpl_dense Impl; typedef typename XprType::StorageIndex StorageIndex; public: typedef Impl Base; EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index startRow, Index startCol) : Impl(xpr, startRow, startCol) {} EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : Impl(xpr, startRow, startCol, blockRows, blockCols) {} }; namespace internal { /** \internal Internal implementation of dense Blocks in the general case. */ template class BlockImpl_dense : public internal::dense_xpr_base >::type { typedef Block BlockType; typedef typename internal::ref_selector::non_const_type XprTypeNested; public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) // class InnerIterator; // FIXME apparently never used /** Column or Row constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) : m_xpr(xpr), // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1, // all other cases are invalid. // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), m_blockRows(BlockRows==1 ? 1 : xpr.rows()), m_blockCols(BlockCols==1 ? 1 : xpr.cols()) {} /** Fixed-size constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(BlockRows), m_blockCols(BlockCols) {} /** Dynamic-size constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_blockRows.value(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_blockCols.value(); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index rowId, Index colId) { EIGEN_STATIC_ASSERT_LVALUE(XprType) return m_xpr.coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_xpr.derived().coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const { return m_xpr.coeff(rowId + m_startRow.value(), colId + m_startCol.value()); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { EIGEN_STATIC_ASSERT_LVALUE(XprType) return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_xpr.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } template inline PacketScalar packet(Index rowId, Index colId) const { return m_xpr.template packet(rowId + m_startRow.value(), colId + m_startCol.value()); } template inline void writePacket(Index rowId, Index colId, const PacketScalar& val) { m_xpr.template writePacket(rowId + m_startRow.value(), colId + m_startCol.value(), val); } template inline PacketScalar packet(Index index) const { return m_xpr.template packet (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); } template inline void writePacket(Index index, const PacketScalar& val) { m_xpr.template writePacket (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); } #ifdef EIGEN_PARSED_BY_DOXYGEN /** \sa MapBase::data() */ EIGEN_DEVICE_FUNC inline const Scalar* data() const; EIGEN_DEVICE_FUNC inline Index innerStride() const; EIGEN_DEVICE_FUNC inline Index outerStride() const; #endif EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } EIGEN_DEVICE_FUNC XprType& nestedExpression() { return m_xpr; } EIGEN_DEVICE_FUNC StorageIndex startRow() const { return m_startRow.value(); } EIGEN_DEVICE_FUNC StorageIndex startCol() const { return m_startCol.value(); } protected: XprTypeNested m_xpr; const internal::variable_if_dynamic m_startRow; const internal::variable_if_dynamic m_startCol; const internal::variable_if_dynamic m_blockRows; const internal::variable_if_dynamic m_blockCols; }; /** \internal Internal implementation of dense Blocks in the direct access case.*/ template class BlockImpl_dense : public MapBase > { typedef Block BlockType; typedef typename internal::ref_selector::non_const_type XprTypeNested; enum { XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 }; public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) /** Column or Row constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), m_xpr(xpr), m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0) { init(); } /** Fixed-size constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } /** Dynamic-size constructor */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } EIGEN_DEVICE_FUNC XprType& nestedExpression() { return m_xpr; } /** \sa MapBase::innerStride() */ EIGEN_DEVICE_FUNC inline Index innerStride() const { return internal::traits::HasSameStorageOrderAsXprType ? m_xpr.innerStride() : m_xpr.outerStride(); } /** \sa MapBase::outerStride() */ EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_outerStride; } EIGEN_DEVICE_FUNC StorageIndex startRow() const { return m_startRow.value(); } EIGEN_DEVICE_FUNC StorageIndex startCol() const { return m_startCol.value(); } #ifndef __SUNPRO_CC // FIXME sunstudio is not friendly with the above friend... // META-FIXME there is no 'friend' keyword around here. Is this obsolete? protected: #endif #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal used by allowAligned() */ EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) : Base(data, blockRows, blockCols), m_xpr(xpr) { init(); } #endif protected: EIGEN_DEVICE_FUNC void init() { m_outerStride = internal::traits::HasSameStorageOrderAsXprType ? m_xpr.outerStride() : m_xpr.innerStride(); } XprTypeNested m_xpr; const internal::variable_if_dynamic m_startRow; const internal::variable_if_dynamic m_startCol; Index m_outerStride; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_BLOCK_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/BooleanRedux.h000066400000000000000000000102311506104011400243340ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_ALLANDANY_H #define EIGEN_ALLANDANY_H namespace Eigen { namespace internal { template struct all_unroller { typedef typename Derived::ExpressionTraits Traits; enum { col = (UnrollCount-1) / Traits::RowsAtCompileTime, row = (UnrollCount-1) % Traits::RowsAtCompileTime }; static inline bool run(const Derived &mat) { return all_unroller::run(mat) && mat.coeff(row, col); } }; template struct all_unroller { static inline bool run(const Derived &/*mat*/) { return true; } }; template struct all_unroller { static inline bool run(const Derived &) { return false; } }; template struct any_unroller { typedef typename Derived::ExpressionTraits Traits; enum { col = (UnrollCount-1) / Traits::RowsAtCompileTime, row = (UnrollCount-1) % Traits::RowsAtCompileTime }; static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); } }; template struct any_unroller { static inline bool run(const Derived & /*mat*/) { return false; } }; template struct any_unroller { static inline bool run(const Derived &) { return false; } }; } // end namespace internal /** \returns true if all coefficients are true * * Example: \include MatrixBase_all.cpp * Output: \verbinclude MatrixBase_all.out * * \sa any(), Cwise::operator<() */ template inline bool DenseBase::all() const { typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; Evaluator evaluator(derived()); if(unroll) return internal::all_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if (!evaluator.coeff(i, j)) return false; return true; } } /** \returns true if at least one coefficient is true * * \sa all() */ template inline bool DenseBase::any() const { typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; Evaluator evaluator(derived()); if(unroll) return internal::any_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if (evaluator.coeff(i, j)) return true; return false; } } /** \returns the number of coefficients which evaluate to true * * \sa all(), any() */ template inline Eigen::Index DenseBase::count() const { return derived().template cast().template cast().sum(); } /** \returns true is \c *this contains at least one Not A Number (NaN). * * \sa allFinite() */ template inline bool DenseBase::hasNaN() const { #if EIGEN_COMP_MSVC || (defined __FAST_MATH__) return derived().array().isNaN().any(); #else return !((derived().array()==derived().array()).all()); #endif } /** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. * * \sa hasNaN() */ template inline bool DenseBase::allFinite() const { #if EIGEN_COMP_MSVC || (defined __FAST_MATH__) return derived().array().isFinite().all(); #else return !((derived()-derived()).hasNaN()); #endif } } // end namespace Eigen #endif // EIGEN_ALLANDANY_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CommaInitializer.h000066400000000000000000000130711506104011400252120ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COMMAINITIALIZER_H #define EIGEN_COMMAINITIALIZER_H namespace Eigen { /** \class CommaInitializer * \ingroup Core_Module * * \brief Helper class used by the comma initializer operator * * This class is internally used to implement the comma initializer feature. It is * the return type of MatrixBase::operator<<, and most of the time this is the only * way it is used. * * \sa \blank \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() */ template struct CommaInitializer { typedef typename XprType::Scalar Scalar; EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { m_xpr.coeffRef(0,0) = s; } template EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const DenseBase& other) : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) { m_xpr.block(0, 0, other.rows(), other.cols()) = other; } /* Copy/Move constructor which transfers ownership. This is crucial in * absence of return value optimization to avoid assertions during destruction. */ // FIXME in C++11 mode this could be replaced by a proper RValue constructor EIGEN_DEVICE_FUNC inline CommaInitializer(const CommaInitializer& o) : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { // Mark original object as finished. In absence of R-value references we need to const_cast: const_cast(o).m_row = m_xpr.rows(); const_cast(o).m_col = m_xpr.cols(); const_cast(o).m_currentBlockRows = 0; } /* inserts a scalar value in the target matrix */ EIGEN_DEVICE_FUNC CommaInitializer& operator,(const Scalar& s) { if (m_col==m_xpr.cols()) { m_row+=m_currentBlockRows; m_col = 0; m_currentBlockRows = 1; eigen_assert(m_row EIGEN_DEVICE_FUNC CommaInitializer& operator,(const DenseBase& other) { if (m_col==m_xpr.cols() && (other.cols()!=0 || other.rows()!=m_currentBlockRows)) { m_row+=m_currentBlockRows; m_col = 0; m_currentBlockRows = other.rows(); eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() && "Too many rows passed to comma initializer (operator<<)"); } eigen_assert((m_col + other.cols() <= m_xpr.cols()) && "Too many coefficients passed to comma initializer (operator<<)"); eigen_assert(m_currentBlockRows==other.rows()); m_xpr.template block (m_row, m_col, other.rows(), other.cols()) = other; m_col += other.cols(); return *this; } EIGEN_DEVICE_FUNC inline ~CommaInitializer() #if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS EIGEN_EXCEPTION_SPEC(Eigen::eigen_assert_exception) #endif { finished(); } /** \returns the built matrix once all its coefficients have been set. * Calling finished is 100% optional. Its purpose is to write expressions * like this: * \code * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); * \endcode */ EIGEN_DEVICE_FUNC inline XprType& finished() { eigen_assert(((m_row+m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) && m_col == m_xpr.cols() && "Too few coefficients passed to comma initializer (operator<<)"); return m_xpr; } XprType& m_xpr; // target expression Index m_row; // current row id Index m_col; // current col id Index m_currentBlockRows; // current block height }; /** \anchor MatrixBaseCommaInitRef * Convenient operator to set the coefficients of a matrix. * * The coefficients must be provided in a row major order and exactly match * the size of the matrix. Otherwise an assertion is raised. * * Example: \include MatrixBase_set.cpp * Output: \verbinclude MatrixBase_set.out * * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order. * * \sa CommaInitializer::finished(), class CommaInitializer */ template inline CommaInitializer DenseBase::operator<< (const Scalar& s) { return CommaInitializer(*static_cast(this), s); } /** \sa operator<<(const Scalar&) */ template template inline CommaInitializer DenseBase::operator<<(const DenseBase& other) { return CommaInitializer(*static_cast(this), other); } } // end namespace Eigen #endif // EIGEN_COMMAINITIALIZER_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ConditionEstimator.h000066400000000000000000000155161506104011400255760ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CONDITIONESTIMATOR_H #define EIGEN_CONDITIONESTIMATOR_H namespace Eigen { namespace internal { template struct rcond_compute_sign { static inline Vector run(const Vector& v) { const RealVector v_abs = v.cwiseAbs(); return (v_abs.array() == static_cast(0)) .select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs)); } }; // Partial specialization to avoid elementwise division for real vectors. template struct rcond_compute_sign { static inline Vector run(const Vector& v) { return (v.array() < static_cast(0)) .select(-Vector::Ones(v.size()), Vector::Ones(v.size())); } }; /** * \returns an estimate of ||inv(matrix)||_1 given a decomposition of * \a matrix that implements .solve() and .adjoint().solve() methods. * * This function implements Algorithms 4.1 and 5.1 from * http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf * which also forms the basis for the condition number estimators in * LAPACK. Since at most 10 calls to the solve method of dec are * performed, the total cost is O(dims^2), as opposed to O(dims^3) * needed to compute the inverse matrix explicitly. * * The most common usage is in estimating the condition number * ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be * computed directly in O(n^2) operations. * * Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and * LLT. * * \sa FullPivLU, PartialPivLU, LDLT, LLT. */ template typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec) { typedef typename Decomposition::MatrixType MatrixType; typedef typename Decomposition::Scalar Scalar; typedef typename Decomposition::RealScalar RealScalar; typedef typename internal::plain_col_type::type Vector; typedef typename internal::plain_col_type::type RealVector; const bool is_complex = (NumTraits::IsComplex != 0); eigen_assert(dec.rows() == dec.cols()); const Index n = dec.rows(); if (n == 0) return 0; // Disable Index to float conversion warning #ifdef __INTEL_COMPILER #pragma warning push #pragma warning ( disable : 2259 ) #endif Vector v = dec.solve(Vector::Ones(n) / Scalar(n)); #ifdef __INTEL_COMPILER #pragma warning pop #endif // lower_bound is a lower bound on // ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1 // and is the objective maximized by the ("super-") gradient ascent // algorithm below. RealScalar lower_bound = v.template lpNorm<1>(); if (n == 1) return lower_bound; // Gradient ascent algorithm follows: We know that the optimum is achieved at // one of the simplices v = e_i, so in each iteration we follow a // super-gradient to move towards the optimal one. RealScalar old_lower_bound = lower_bound; Vector sign_vector(n); Vector old_sign_vector; Index v_max_abs_index = -1; Index old_v_max_abs_index = v_max_abs_index; for (int k = 0; k < 4; ++k) { sign_vector = internal::rcond_compute_sign::run(v); if (k > 0 && !is_complex && sign_vector == old_sign_vector) { // Break if the solution stagnated. break; } // v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )| v = dec.adjoint().solve(sign_vector); v.real().cwiseAbs().maxCoeff(&v_max_abs_index); if (v_max_abs_index == old_v_max_abs_index) { // Break if the solution stagnated. break; } // Move to the new simplex e_j, where j = v_max_abs_index. v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j. lower_bound = v.template lpNorm<1>(); if (lower_bound <= old_lower_bound) { // Break if the gradient step did not increase the lower_bound. break; } if (!is_complex) { old_sign_vector = sign_vector; } old_v_max_abs_index = v_max_abs_index; old_lower_bound = lower_bound; } // The following calculates an independent estimate of ||matrix||_1 by // multiplying matrix by a vector with entries of slowly increasing // magnitude and alternating sign: // v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1. // This improvement to Hager's algorithm above is due to Higham. It was // added to make the algorithm more robust in certain corner cases where // large elements in the matrix might otherwise escape detection due to // exact cancellation (especially when op and op_adjoint correspond to a // sequence of backsubstitutions and permutations), which could cause // Hager's algorithm to vastly underestimate ||matrix||_1. Scalar alternating_sign(RealScalar(1)); for (Index i = 0; i < n; ++i) { // The static_cast is needed when Scalar is a complex and RealScalar implements expression templates v[i] = alternating_sign * static_cast(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1)))); alternating_sign = -alternating_sign; } v = dec.solve(v); const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n)); return numext::maxi(lower_bound, alternate_lower_bound); } /** \brief Reciprocal condition number estimator. * * Computing a decomposition of a dense matrix takes O(n^3) operations, while * this method estimates the condition number quickly and reliably in O(n^2) * operations. * * \returns an estimate of the reciprocal condition number * (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and * its decomposition. Supports the following decompositions: FullPivLU, * PartialPivLU, LDLT, and LLT. * * \sa FullPivLU, PartialPivLU, LDLT, LLT. */ template typename Decomposition::RealScalar rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec) { typedef typename Decomposition::RealScalar RealScalar; eigen_assert(dec.rows() == dec.cols()); if (dec.rows() == 0) return NumTraits::infinity(); if (matrix_norm == RealScalar(0)) return RealScalar(0); if (dec.rows() == 1) return RealScalar(1); const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec); return (inverse_matrix_norm == RealScalar(0) ? RealScalar(0) : (RealScalar(1) / inverse_matrix_norm) / matrix_norm); } } // namespace internal } // namespace Eigen #endif bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CoreEvaluators.h000066400000000000000000001713651506104011400247230ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2011 Benoit Jacob // Copyright (C) 2011-2014 Gael Guennebaud // Copyright (C) 2011-2012 Jitse Niesen // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COREEVALUATORS_H #define EIGEN_COREEVALUATORS_H namespace Eigen { namespace internal { // This class returns the evaluator kind from the expression storage kind. // Default assumes index based accessors template struct storage_kind_to_evaluator_kind { typedef IndexBased Kind; }; // This class returns the evaluator shape from the expression storage kind. // It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. template struct storage_kind_to_shape; template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; template<> struct storage_kind_to_shape { typedef SolverShape Shape; }; template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; template<> struct storage_kind_to_shape { typedef TranspositionsShape Shape; }; // Evaluators have to be specialized with respect to various criteria such as: // - storage/structure/shape // - scalar type // - etc. // Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. // We currently distinguish the following kind of evaluators: // - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) // - binary_evaluator for expression taking two arguments (CwiseBinaryOp) // - ternary_evaluator for expression taking three arguments (CwiseTernaryOp) // - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. // - mapbase_evaluator for Map, Block, Ref // - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) template< typename T, typename Arg1Kind = typename evaluator_traits::Kind, typename Arg2Kind = typename evaluator_traits::Kind, typename Arg3Kind = typename evaluator_traits::Kind, typename Arg1Scalar = typename traits::Scalar, typename Arg2Scalar = typename traits::Scalar, typename Arg3Scalar = typename traits::Scalar> struct ternary_evaluator; template< typename T, typename LhsKind = typename evaluator_traits::Kind, typename RhsKind = typename evaluator_traits::Kind, typename LhsScalar = typename traits::Scalar, typename RhsScalar = typename traits::Scalar> struct binary_evaluator; template< typename T, typename Kind = typename evaluator_traits::Kind, typename Scalar = typename T::Scalar> struct unary_evaluator; // evaluator_traits contains traits for evaluator template struct evaluator_traits_base { // by default, get evaluator kind and shape from storage typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; }; // Default evaluator traits template struct evaluator_traits : public evaluator_traits_base { }; template::Shape > struct evaluator_assume_aliasing { static const bool value = false; }; // By default, we assume a unary expression: template struct evaluator : public unary_evaluator { typedef unary_evaluator Base; EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : Base(xpr) {} }; // TODO: Think about const-correctness template struct evaluator : evaluator { EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : evaluator(xpr) {} }; // ---------- base class for all evaluators ---------- template struct evaluator_base : public noncopyable { // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. typedef traits ExpressionTraits; enum { Alignment = 0 }; }; // -------------------- Matrix and Array -------------------- // // evaluator is a common base class for the // Matrix and Array evaluators. // Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, // so no need for more sophisticated dispatching. template struct evaluator > : evaluator_base { typedef PlainObjectBase PlainObjectType; typedef typename PlainObjectType::Scalar Scalar; typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; enum { IsRowMajor = PlainObjectType::IsRowMajor, IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, CoeffReadCost = NumTraits::ReadCost, Flags = traits::EvaluatorFlags, Alignment = traits::Alignment }; EIGEN_DEVICE_FUNC evaluator() : m_data(0), m_outerStride(IsVectorAtCompileTime ? 0 : int(IsRowMajor) ? ColsAtCompileTime : RowsAtCompileTime) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { if (IsRowMajor) return m_data[row * m_outerStride.value() + col]; else return m_data[row + col * m_outerStride.value()]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_data[index]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { if (IsRowMajor) return const_cast(m_data)[row * m_outerStride.value() + col]; else return const_cast(m_data)[row + col * m_outerStride.value()]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return const_cast(m_data)[index]; } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { if (IsRowMajor) return ploadt(m_data + row * m_outerStride.value() + col); else return ploadt(m_data + row + col * m_outerStride.value()); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return ploadt(m_data + index); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { if (IsRowMajor) return pstoret (const_cast(m_data) + row * m_outerStride.value() + col, x); else return pstoret (const_cast(m_data) + row + col * m_outerStride.value(), x); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { return pstoret(const_cast(m_data) + index, x); } protected: const Scalar *m_data; // We do not need to know the outer stride for vectors variable_if_dynamic m_outerStride; }; template struct evaluator > : evaluator > > { typedef Matrix XprType; EIGEN_DEVICE_FUNC evaluator() {} EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) : evaluator >(m) { } }; template struct evaluator > : evaluator > > { typedef Array XprType; EIGEN_DEVICE_FUNC evaluator() {} EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) : evaluator >(m) { } }; // -------------------- Transpose -------------------- template struct unary_evaluator, IndexBased> : evaluator_base > { typedef Transpose XprType; enum { CoeffReadCost = evaluator::CoeffReadCost, Flags = evaluator::Flags ^ RowMajorBit, Alignment = evaluator::Alignment }; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(col, row); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(col, row); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename XprType::Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_argImpl.template packet(col, row); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return m_argImpl.template packet(index); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { m_argImpl.template writePacket(col, row, x); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { m_argImpl.template writePacket(index, x); } protected: evaluator m_argImpl; }; // -------------------- CwiseNullaryOp -------------------- // Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. // Likewise, there is not need to more sophisticated dispatching here. template::value, bool has_unary = has_unary_operator::value, bool has_binary = has_binary_operator::value> struct nullary_wrapper { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return op(i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return op.template packetOp(i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } }; template struct nullary_wrapper { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType=0, IndexType=0) const { return op(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType=0, IndexType=0) const { return op.template packetOp(); } }; template struct nullary_wrapper { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j=0) const { return op(i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j=0) const { return op.template packetOp(i,j); } }; // We need the following specialization for vector-only functors assigned to a runtime vector, // for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd. // In this case, i==0 and j is used for the actual iteration. template struct nullary_wrapper { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { eigen_assert(i==0 || j==0); return op(i+j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { eigen_assert(i==0 || j==0); return op.template packetOp(i+j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } }; template struct nullary_wrapper {}; #if 0 && EIGEN_COMP_MSVC>0 // Disable this ugly workaround. This is now handled in traits::match, // but this piece of code might still become handly if some other weird compilation // erros pop up again. // MSVC exhibits a weird compilation error when // compiling: // Eigen::MatrixXf A = MatrixXf::Random(3,3); // Ref R = 2.f*A; // and that has_*ary_operator> have not been instantiated yet. // The "problem" is that evaluator<2.f*A> is instantiated by traits::match<2.f*A> // and at that time has_*ary_operator returns true regardless of T. // Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>. // The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(), // and packet() are really instantiated as implemented below: // This is a simple wrapper around Index to enforce the re-instantiation of // has_*ary_operator when needed. template struct nullary_wrapper_workaround_msvc { nullary_wrapper_workaround_msvc(const T&); operator T()const; }; template struct nullary_wrapper { template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return nullary_wrapper >::value, has_unary_operator >::value, has_binary_operator >::value>().operator()(op,i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return nullary_wrapper >::value, has_unary_operator >::value, has_binary_operator >::value>().operator()(op,i); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return nullary_wrapper >::value, has_unary_operator >::value, has_binary_operator >::value>().template packetOp(op,i,j); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return nullary_wrapper >::value, has_unary_operator >::value, has_binary_operator >::value>().template packetOp(op,i); } }; #endif // MSVC workaround template struct evaluator > : evaluator_base > { typedef CwiseNullaryOp XprType; typedef typename internal::remove_all::type PlainObjectTypeCleaned; enum { CoeffReadCost = internal::functor_traits::Cost, Flags = (evaluator::Flags & ( HereditaryBits | (functor_has_linear_access::ret ? LinearAccessBit : 0) | (functor_traits::PacketAccess ? PacketAccessBit : 0))) | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), Alignment = AlignedMax }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) : m_functor(n.functor()), m_wrapper() { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(IndexType row, IndexType col) const { return m_wrapper(m_functor, row, col); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(IndexType index) const { return m_wrapper(m_functor,index); } template EIGEN_STRONG_INLINE PacketType packet(IndexType row, IndexType col) const { return m_wrapper.template packetOp(m_functor, row, col); } template EIGEN_STRONG_INLINE PacketType packet(IndexType index) const { return m_wrapper.template packetOp(m_functor, index); } protected: const NullaryOp m_functor; const internal::nullary_wrapper m_wrapper; }; // -------------------- CwiseUnaryOp -------------------- template struct unary_evaluator, IndexBased > : evaluator_base > { typedef CwiseUnaryOp XprType; enum { CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, Flags = evaluator::Flags & (HereditaryBits | LinearAccessBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), Alignment = evaluator::Alignment }; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& op) : m_functor(op.functor()), m_argImpl(op.nestedExpression()) { EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_functor(m_argImpl.coeff(row, col)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_functor(m_argImpl.coeff(index)); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_functor.packetOp(m_argImpl.template packet(row, col)); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return m_functor.packetOp(m_argImpl.template packet(index)); } protected: const UnaryOp m_functor; evaluator m_argImpl; }; // -------------------- CwiseTernaryOp -------------------- // this is a ternary expression template struct evaluator > : public ternary_evaluator > { typedef CwiseTernaryOp XprType; typedef ternary_evaluator > Base; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} }; template struct ternary_evaluator, IndexBased, IndexBased> : evaluator_base > { typedef CwiseTernaryOp XprType; enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, Arg1Flags = evaluator::Flags, Arg2Flags = evaluator::Flags, Arg3Flags = evaluator::Flags, SameType = is_same::value && is_same::value, StorageOrdersAgree = (int(Arg1Flags)&RowMajorBit)==(int(Arg2Flags)&RowMajorBit) && (int(Arg1Flags)&RowMajorBit)==(int(Arg3Flags)&RowMajorBit), Flags0 = (int(Arg1Flags) | int(Arg2Flags) | int(Arg3Flags)) & ( HereditaryBits | (int(Arg1Flags) & int(Arg2Flags) & int(Arg3Flags) & ( (StorageOrdersAgree ? LinearAccessBit : 0) | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) ) ) ), Flags = (Flags0 & ~RowMajorBit) | (Arg1Flags & RowMajorBit), Alignment = EIGEN_PLAIN_ENUM_MIN( EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment), evaluator::Alignment) }; EIGEN_DEVICE_FUNC explicit ternary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_arg1Impl(xpr.arg1()), m_arg2Impl(xpr.arg2()), m_arg3Impl(xpr.arg3()) { EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_functor(m_arg1Impl.coeff(row, col), m_arg2Impl.coeff(row, col), m_arg3Impl.coeff(row, col)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_functor(m_arg1Impl.coeff(index), m_arg2Impl.coeff(index), m_arg3Impl.coeff(index)); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_functor.packetOp(m_arg1Impl.template packet(row, col), m_arg2Impl.template packet(row, col), m_arg3Impl.template packet(row, col)); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return m_functor.packetOp(m_arg1Impl.template packet(index), m_arg2Impl.template packet(index), m_arg3Impl.template packet(index)); } protected: const TernaryOp m_functor; evaluator m_arg1Impl; evaluator m_arg2Impl; evaluator m_arg3Impl; }; // -------------------- CwiseBinaryOp -------------------- // this is a binary expression template struct evaluator > : public binary_evaluator > { typedef CwiseBinaryOp XprType; typedef binary_evaluator > Base; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} }; template struct binary_evaluator, IndexBased, IndexBased> : evaluator_base > { typedef CwiseBinaryOp XprType; enum { CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, LhsFlags = evaluator::Flags, RhsFlags = evaluator::Flags, SameType = is_same::value, StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( HereditaryBits | (int(LhsFlags) & int(RhsFlags) & ( (StorageOrdersAgree ? LinearAccessBit : 0) | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) ) ) ), Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment,evaluator::Alignment) }; EIGEN_DEVICE_FUNC explicit binary_evaluator(const XprType& xpr) : m_functor(xpr.functor()), m_lhsImpl(xpr.lhs()), m_rhsImpl(xpr.rhs()) { EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_functor(m_lhsImpl.coeff(row, col), m_rhsImpl.coeff(row, col)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index)); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_functor.packetOp(m_lhsImpl.template packet(row, col), m_rhsImpl.template packet(row, col)); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return m_functor.packetOp(m_lhsImpl.template packet(index), m_rhsImpl.template packet(index)); } protected: const BinaryOp m_functor; evaluator m_lhsImpl; evaluator m_rhsImpl; }; // -------------------- CwiseUnaryView -------------------- template struct unary_evaluator, IndexBased> : evaluator_base > { typedef CwiseUnaryView XprType; enum { CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)), Alignment = 0 // FIXME it is not very clear why alignment is necessarily lost... }; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) : m_unaryOp(op.functor()), m_argImpl(op.nestedExpression()) { EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_unaryOp(m_argImpl.coeff(row, col)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_unaryOp(m_argImpl.coeff(index)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_unaryOp(m_argImpl.coeffRef(row, col)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_unaryOp(m_argImpl.coeffRef(index)); } protected: const UnaryOp m_unaryOp; evaluator m_argImpl; }; // -------------------- Map -------------------- // FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? // but that might complicate template specialization template struct mapbase_evaluator; template struct mapbase_evaluator : evaluator_base { typedef Derived XprType; typedef typename XprType::PointerType PointerType; typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; enum { IsRowMajor = XprType::RowsAtCompileTime, ColsAtCompileTime = XprType::ColsAtCompileTime, CoeffReadCost = NumTraits::ReadCost }; EIGEN_DEVICE_FUNC explicit mapbase_evaluator(const XprType& map) : m_data(const_cast(map.data())), m_innerStride(map.innerStride()), m_outerStride(map.outerStride()) { EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_data[col * colStride() + row * rowStride()]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_data[index * m_innerStride.value()]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_data[col * colStride() + row * rowStride()]; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_data[index * m_innerStride.value()]; } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { PointerType ptr = m_data + row * rowStride() + col * colStride(); return internal::ploadt(ptr); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return internal::ploadt(m_data + index * m_innerStride.value()); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { PointerType ptr = m_data + row * rowStride() + col * colStride(); return internal::pstoret(ptr, x); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { internal::pstoret(m_data + index * m_innerStride.value(), x); } protected: EIGEN_DEVICE_FUNC inline Index rowStride() const { return XprType::IsRowMajor ? m_outerStride.value() : m_innerStride.value(); } EIGEN_DEVICE_FUNC inline Index colStride() const { return XprType::IsRowMajor ? m_innerStride.value() : m_outerStride.value(); } PointerType m_data; const internal::variable_if_dynamic m_innerStride; const internal::variable_if_dynamic m_outerStride; }; template struct evaluator > : public mapbase_evaluator, PlainObjectType> { typedef Map XprType; typedef typename XprType::Scalar Scalar; // TODO: should check for smaller packet types once we can handle multi-sized packet types typedef typename packet_traits::type PacketScalar; enum { InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 ? int(PlainObjectType::InnerStrideAtCompileTime) : int(StrideType::InnerStrideAtCompileTime), OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 ? int(PlainObjectType::OuterStrideAtCompileTime) : int(StrideType::OuterStrideAtCompileTime), HasNoInnerStride = InnerStrideAtCompileTime == 1, HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, HasNoStride = HasNoInnerStride && HasNoOuterStride, IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit), LinearAccessMask = bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit), Flags = int( evaluator::Flags) & (LinearAccessMask&PacketAccessMask), Alignment = int(MapOptions)&int(AlignedMask) }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) : mapbase_evaluator(map) { } }; // -------------------- Ref -------------------- template struct evaluator > : public mapbase_evaluator, PlainObjectType> { typedef Ref XprType; enum { Flags = evaluator >::Flags, Alignment = evaluator >::Alignment }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& ref) : mapbase_evaluator(ref) { } }; // -------------------- Block -------------------- template::ret> struct block_evaluator; template struct evaluator > : block_evaluator { typedef Block XprType; typedef typename XprType::Scalar Scalar; // TODO: should check for smaller packet types once we can handle multi-sized packet types typedef typename packet_traits::type PacketScalar; enum { CoeffReadCost = evaluator::CoeffReadCost, RowsAtCompileTime = traits::RowsAtCompileTime, ColsAtCompileTime = traits::ColsAtCompileTime, MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = traits::MaxColsAtCompileTime, ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 : ArgTypeIsRowMajor, HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), InnerStrideAtCompileTime = HasSameStorageOrderAsArgType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), OuterStrideAtCompileTime = HasSameStorageOrderAsArgType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), MaskPacketAccessBit = (InnerStrideAtCompileTime == 1 || HasSameStorageOrderAsArgType) ? PacketAccessBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, FlagsRowMajorBit = XprType::Flags&RowMajorBit, Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | DirectAccessBit | MaskPacketAccessBit), Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit, PacketAlignment = unpacket_traits::alignment, Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (OuterStrideAtCompileTime!=0) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0, Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, Alignment0) }; typedef block_evaluator block_evaluator_type; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } }; // no direct-access => dispatch to a unary evaluator template struct block_evaluator : unary_evaluator > { typedef Block XprType; EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) : unary_evaluator(block) {} }; template struct unary_evaluator, IndexBased> : evaluator_base > { typedef Block XprType; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block) : m_argImpl(block.nestedExpression()), m_startRow(block.startRow()), m_startCol(block.startCol()), m_linear_offset(InnerPanel?(XprType::IsRowMajor ? block.startRow()*block.cols() : block.startCol()*block.rows()):0) { } typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; enum { RowsAtCompileTime = XprType::RowsAtCompileTime, ForwardLinearAccess = InnerPanel && bool(evaluator::Flags&LinearAccessBit) }; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { if (ForwardLinearAccess) return m_argImpl.coeff(m_linear_offset.value() + index); else return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { if (ForwardLinearAccess) return m_argImpl.coeffRef(m_linear_offset.value() + index); else return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_argImpl.template packet(m_startRow.value() + row, m_startCol.value() + col); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { if (ForwardLinearAccess) return m_argImpl.template packet(m_linear_offset.value() + index); else return packet(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { return m_argImpl.template writePacket(m_startRow.value() + row, m_startCol.value() + col, x); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { if (ForwardLinearAccess) return m_argImpl.template writePacket(m_linear_offset.value() + index, x); else return writePacket(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0, x); } protected: evaluator m_argImpl; const variable_if_dynamic m_startRow; const variable_if_dynamic m_startCol; const variable_if_dynamic m_linear_offset; }; // TODO: This evaluator does not actually use the child evaluator; // all action is via the data() as returned by the Block expression. template struct block_evaluator : mapbase_evaluator, typename Block::PlainObject> { typedef Block XprType; typedef typename XprType::Scalar Scalar; EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) : mapbase_evaluator(block) { // TODO: for the 3.3 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime eigen_assert(((internal::UIntPtr(block.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); } }; // -------------------- Select -------------------- // NOTE shall we introduce a ternary_evaluator? // TODO enable vectorization for Select template struct evaluator > : evaluator_base > { typedef Select XprType; enum { CoeffReadCost = evaluator::CoeffReadCost + EIGEN_PLAIN_ENUM_MAX(evaluator::CoeffReadCost, evaluator::CoeffReadCost), Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits, Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment) }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) : m_conditionImpl(select.conditionMatrix()), m_thenImpl(select.thenMatrix()), m_elseImpl(select.elseMatrix()) { EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { if (m_conditionImpl.coeff(row, col)) return m_thenImpl.coeff(row, col); else return m_elseImpl.coeff(row, col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { if (m_conditionImpl.coeff(index)) return m_thenImpl.coeff(index); else return m_elseImpl.coeff(index); } protected: evaluator m_conditionImpl; evaluator m_thenImpl; evaluator m_elseImpl; }; // -------------------- Replicate -------------------- template struct unary_evaluator > : evaluator_base > { typedef Replicate XprType; typedef typename XprType::CoeffReturnType CoeffReturnType; enum { Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor }; typedef typename internal::nested_eval::type ArgTypeNested; typedef typename internal::remove_all::type ArgTypeNestedCleaned; enum { CoeffReadCost = evaluator::CoeffReadCost, LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0, Flags = (evaluator::Flags & (HereditaryBits|LinearAccessMask) & ~RowMajorBit) | (traits::Flags & RowMajorBit), Alignment = evaluator::Alignment }; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& replicate) : m_arg(replicate.nestedExpression()), m_argImpl(m_arg), m_rows(replicate.nestedExpression().rows()), m_cols(replicate.nestedExpression().cols()) {} EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { // try to avoid using modulo; this is a pure optimization strategy const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 : RowFactor==1 ? row : row % m_rows.value(); const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 : ColFactor==1 ? col : col % m_cols.value(); return m_argImpl.coeff(actual_row, actual_col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { // try to avoid using modulo; this is a pure optimization strategy const Index actual_index = internal::traits::RowsAtCompileTime==1 ? (ColFactor==1 ? index : index%m_cols.value()) : (RowFactor==1 ? index : index%m_rows.value()); return m_argImpl.coeff(actual_index); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 : RowFactor==1 ? row : row % m_rows.value(); const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 : ColFactor==1 ? col : col % m_cols.value(); return m_argImpl.template packet(actual_row, actual_col); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { const Index actual_index = internal::traits::RowsAtCompileTime==1 ? (ColFactor==1 ? index : index%m_cols.value()) : (RowFactor==1 ? index : index%m_rows.value()); return m_argImpl.template packet(actual_index); } protected: const ArgTypeNested m_arg; evaluator m_argImpl; const variable_if_dynamic m_rows; const variable_if_dynamic m_cols; }; // -------------------- PartialReduxExpr -------------------- template< typename ArgType, typename MemberOp, int Direction> struct evaluator > : evaluator_base > { typedef PartialReduxExpr XprType; typedef typename internal::nested_eval::type ArgTypeNested; typedef typename internal::remove_all::type ArgTypeNestedCleaned; typedef typename ArgType::Scalar InputScalar; typedef typename XprType::Scalar Scalar; enum { TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime) }; typedef typename MemberOp::template Cost CostOpType; enum { CoeffReadCost = TraversalSize==Dynamic ? HugeCost : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value), Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&(HereditaryBits&(~RowMajorBit))) | LinearAccessBit, Alignment = 0 // FIXME this will need to be improved once PartialReduxExpr is vectorized }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) : m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) { EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : int(CostOpType::value)); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const { if (Direction==Vertical) return m_functor(m_arg.col(j)); else return m_functor(m_arg.row(i)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index index) const { if (Direction==Vertical) return m_functor(m_arg.col(index)); else return m_functor(m_arg.row(index)); } protected: typename internal::add_const_on_value_type::type m_arg; const MemberOp m_functor; }; // -------------------- MatrixWrapper and ArrayWrapper -------------------- // // evaluator_wrapper_base is a common base class for the // MatrixWrapper and ArrayWrapper evaluators. template struct evaluator_wrapper_base : evaluator_base { typedef typename remove_all::type ArgType; enum { CoeffReadCost = evaluator::CoeffReadCost, Flags = evaluator::Flags, Alignment = evaluator::Alignment }; EIGEN_DEVICE_FUNC explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} typedef typename ArgType::Scalar Scalar; typedef typename ArgType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(row, col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(row, col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return m_argImpl.template packet(row, col); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { return m_argImpl.template packet(index); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { m_argImpl.template writePacket(row, col, x); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { m_argImpl.template writePacket(index, x); } protected: evaluator m_argImpl; }; template struct unary_evaluator > : evaluator_wrapper_base > { typedef MatrixWrapper XprType; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; template struct unary_evaluator > : evaluator_wrapper_base > { typedef ArrayWrapper XprType; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) : evaluator_wrapper_base >(wrapper.nestedExpression()) { } }; // -------------------- Reverse -------------------- // defined in Reverse.h: template struct reverse_packet_cond; template struct unary_evaluator > : evaluator_base > { typedef Reverse XprType; typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; enum { IsRowMajor = XprType::IsRowMajor, IsColMajor = !IsRowMajor, ReverseRow = (Direction == Vertical) || (Direction == BothDirections), ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), ReversePacket = (Direction == BothDirections) || ((Direction == Vertical) && IsColMajor) || ((Direction == Horizontal) && IsRowMajor), CoeffReadCost = evaluator::CoeffReadCost, // let's enable LinearAccess only with vectorization because of the product overhead // FIXME enable DirectAccess with negative strides? Flags0 = evaluator::Flags, LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) || ((ReverseRow && XprType::ColsAtCompileTime==1) || (ReverseCol && XprType::RowsAtCompileTime==1)) ? LinearAccessBit : 0, Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess), Alignment = 0 // FIXME in some rare cases, Alignment could be preserved, like a Vector4f. }; EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& reverse) : m_argImpl(reverse.nestedExpression()), m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1), m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) { } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); } template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { enum { PacketSize = unpacket_traits::size, OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 }; typedef internal::reverse_packet_cond reverse_packet; return reverse_packet::run(m_argImpl.template packet( ReverseRow ? m_rows.value() - row - OffsetRow : row, ReverseCol ? m_cols.value() - col - OffsetCol : col)); } template EIGEN_STRONG_INLINE PacketType packet(Index index) const { enum { PacketSize = unpacket_traits::size }; return preverse(m_argImpl.template packet(m_rows.value() * m_cols.value() - index - PacketSize)); } template EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) { // FIXME we could factorize some code with packet(i,j) enum { PacketSize = unpacket_traits::size, OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 }; typedef internal::reverse_packet_cond reverse_packet; m_argImpl.template writePacket( ReverseRow ? m_rows.value() - row - OffsetRow : row, ReverseCol ? m_cols.value() - col - OffsetCol : col, reverse_packet::run(x)); } template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) { enum { PacketSize = unpacket_traits::size }; m_argImpl.template writePacket (m_rows.value() * m_cols.value() - index - PacketSize, preverse(x)); } protected: evaluator m_argImpl; // If we do not reverse rows, then we do not need to know the number of rows; same for columns // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors. const variable_if_dynamic m_rows; const variable_if_dynamic m_cols; }; // -------------------- Diagonal -------------------- template struct evaluator > : evaluator_base > { typedef Diagonal XprType; enum { CoeffReadCost = evaluator::CoeffReadCost, Flags = (unsigned int)(evaluator::Flags & (HereditaryBits | DirectAccessBit) & ~RowMajorBit) | LinearAccessBit, Alignment = 0 }; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& diagonal) : m_argImpl(diagonal.nestedExpression()), m_index(diagonal.index()) { } typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index) const { return m_argImpl.coeff(row + rowOffset(), row + colOffset()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { return m_argImpl.coeff(index + rowOffset(), index + colOffset()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index) { return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); } protected: evaluator m_argImpl; const internal::variable_if_dynamicindex m_index; private: EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } }; //---------------------------------------------------------------------- // deprecated code //---------------------------------------------------------------------- // -------------------- EvalToTemp -------------------- // expression class for evaluating nested expression to a temporary template class EvalToTemp; template struct traits > : public traits { }; template class EvalToTemp : public dense_xpr_base >::type { public: typedef typename dense_xpr_base::type Base; EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) explicit EvalToTemp(const ArgType& arg) : m_arg(arg) { } const ArgType& arg() const { return m_arg; } Index rows() const { return m_arg.rows(); } Index cols() const { return m_arg.cols(); } private: const ArgType& m_arg; }; template struct evaluator > : public evaluator { typedef EvalToTemp XprType; typedef typename ArgType::PlainObject PlainObject; typedef evaluator Base; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : m_result(xpr.arg()) { ::new (static_cast(this)) Base(m_result); } // This constructor is used when nesting an EvalTo evaluator in another evaluator EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) : m_result(arg) { ::new (static_cast(this)) Base(m_result); } protected: PlainObject m_result; }; } // namespace internal } // end namespace Eigen #endif // EIGEN_COREEVALUATORS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CoreIterators.h000066400000000000000000000106551506104011400245440ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_COREITERATORS_H #define EIGEN_COREITERATORS_H namespace Eigen { /* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core */ namespace internal { template class inner_iterator_selector; } /** \class InnerIterator * \brief An InnerIterator allows to loop over the element of any matrix expression. * * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. * * TODO: add a usage example */ template class InnerIterator { protected: typedef internal::inner_iterator_selector::Kind> IteratorType; typedef internal::evaluator EvaluatorType; typedef typename internal::traits::Scalar Scalar; public: /** Construct an iterator over the \a outerId -th row or column of \a xpr */ InnerIterator(const XprType &xpr, const Index &outerId) : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) {} /// \returns the value of the current coefficient. EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } /** Increment the iterator \c *this to the next non-zero coefficient. * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView */ EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } /// \returns the column or row index of the current coefficient. EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } /// \returns the row index of the current coefficient. EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } /// \returns the column index of the current coefficient. EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } /// \returns \c true if the iterator \c *this still references a valid coefficient. EIGEN_STRONG_INLINE operator bool() const { return m_iter; } protected: EvaluatorType m_eval; IteratorType m_iter; private: // If you get here, then you're not using the right InnerIterator type, e.g.: // SparseMatrix A; // SparseMatrix::InnerIterator it(A,0); template InnerIterator(const EigenBase&,Index outer); }; namespace internal { // Generic inner iterator implementation for dense objects template class inner_iterator_selector { protected: typedef evaluator EvaluatorType; typedef typename traits::Scalar Scalar; enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; public: EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) {} EIGEN_STRONG_INLINE Scalar value() const { return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) : m_eval.coeff(m_inner, m_outer); } EIGEN_STRONG_INLINE inner_iterator_selector& operator++() { m_inner++; return *this; } EIGEN_STRONG_INLINE Index index() const { return m_inner; } inline Index row() const { return IsRowMajor ? m_outer : index(); } inline Index col() const { return IsRowMajor ? index() : m_outer; } EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } protected: const EvaluatorType& m_eval; Index m_inner; const Index m_outer; const Index m_end; }; // For iterator-based evaluator, inner-iterator is already implemented as // evaluator<>::InnerIterator template class inner_iterator_selector : public evaluator::InnerIterator { protected: typedef typename evaluator::InnerIterator Base; typedef evaluator EvaluatorType; public: EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) : Base(eval, outerId) {} }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_COREITERATORS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CwiseBinaryOp.h000066400000000000000000000166511506104011400244770ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_BINARY_OP_H #define EIGEN_CWISE_BINARY_OP_H namespace Eigen { namespace internal { template struct traits > { // we must not inherit from traits since it has // the potential to cause problems with MSVC typedef typename remove_all::type Ancestor; typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = traits::RowsAtCompileTime, ColsAtCompileTime = traits::ColsAtCompileTime, MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = traits::MaxColsAtCompileTime }; // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), // we still want to handle the case when the result type is different. typedef typename result_of< BinaryOp( const typename Lhs::Scalar&, const typename Rhs::Scalar& ) >::type Scalar; typedef typename cwise_promote_storage_type::StorageKind, typename traits::StorageKind, BinaryOp>::ret StorageKind; typedef typename promote_index_type::StorageIndex, typename traits::StorageIndex>::type StorageIndex; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { Flags = cwise_promote_storage_order::StorageKind,typename traits::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value }; }; } // end namespace internal template class CwiseBinaryOpImpl; /** \class CwiseBinaryOp * \ingroup Core_Module * * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions * * \tparam BinaryOp template functor implementing the operator * \tparam LhsType the type of the left-hand side * \tparam RhsType the type of the right-hand side * * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. * It is the return type of binary operators, by which we mean only those binary operators where * both the left-hand side and the right-hand side are Eigen expressions. * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. * * Most of the time, this is the only way that it is used, so you typically don't have to name * CwiseBinaryOp types explicitly. * * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp */ template class CwiseBinaryOp : public CwiseBinaryOpImpl< BinaryOp, LhsType, RhsType, typename internal::cwise_promote_storage_type::StorageKind, typename internal::traits::StorageKind, BinaryOp>::ret>, internal::no_assignment_operator { public: typedef typename internal::remove_all::type Functor; typedef typename internal::remove_all::type Lhs; typedef typename internal::remove_all::type Rhs; typedef typename CwiseBinaryOpImpl< BinaryOp, LhsType, RhsType, typename internal::cwise_promote_storage_type::StorageKind, typename internal::traits::StorageKind, BinaryOp>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) typedef typename internal::ref_selector::type LhsNested; typedef typename internal::ref_selector::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) { EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); // require the sizes to match EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::RowsAtCompileTime==Dynamic) return m_rhs.rows(); else return m_lhs.rows(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::ColsAtCompileTime==Dynamic) return m_rhs.cols(); else return m_lhs.cols(); } /** \returns the left hand side nested expression */ EIGEN_DEVICE_FUNC const _LhsNested& lhs() const { return m_lhs; } /** \returns the right hand side nested expression */ EIGEN_DEVICE_FUNC const _RhsNested& rhs() const { return m_rhs; } /** \returns the functor representing the binary operation */ EIGEN_DEVICE_FUNC const BinaryOp& functor() const { return m_functor; } protected: LhsNested m_lhs; RhsNested m_rhs; const BinaryOp m_functor; }; // Generic API dispatcher template class CwiseBinaryOpImpl : public internal::generic_xpr_base >::type { public: typedef typename internal::generic_xpr_base >::type Base; }; /** replaces \c *this by \c *this - \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } /** replaces \c *this by \c *this + \a other. * * \returns a reference to \c *this */ template template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_CWISE_BINARY_OP_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CwiseNullaryOp.h000066400000000000000000000753001506104011400246750ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_NULLARY_OP_H #define EIGEN_CWISE_NULLARY_OP_H namespace Eigen { namespace internal { template struct traits > : traits { enum { Flags = traits::Flags & RowMajorBit }; }; } // namespace internal /** \class CwiseNullaryOp * \ingroup Core_Module * * \brief Generic expression of a matrix where all coefficients are defined by a functor * * \tparam NullaryOp template functor implementing the operator * \tparam PlainObjectType the underlying plain matrix/array type * * This class represents an expression of a generic nullary operator. * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, * and most of the time this is the only way it is used. * * However, if you want to write a function returning such an expression, you * will need to use this class. * * The functor NullaryOp must expose one of the following method:
\c operator()() if the procedural generation does not depend on the coefficient entries (e.g., random numbers)
\c operator()(Index i)if the procedural generation makes sense for vectors only and that it depends on the coefficient index \c i (e.g., linspace)
\c operator()(Index i,Index j)if the procedural generation depends on the matrix coordinates \c i, \c j (e.g., to generate a checkerboard with 0 and 1)
* It is also possible to expose the last two operators if the generation makes sense for matrices but can be optimized for vectors. * * See DenseBase::NullaryExpr(Index,const CustomNullaryOp&) for an example binding * C++11 random number generators. * * A nullary expression can also be used to implement custom sophisticated matrix manipulations * that cannot be covered by the existing set of natively supported matrix manipulations. * See this \ref TopicCustomizing_NullaryExpr "page" for some examples and additional explanations * on the behavior of CwiseNullaryOp. * * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr */ template class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp >::type, internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) EIGEN_DEVICE_FUNC CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) : m_rows(rows), m_cols(cols), m_functor(func) { eigen_assert(rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } /** \returns the functor representing the nullary operation */ EIGEN_DEVICE_FUNC const NullaryOp& functor() const { return m_functor; } protected: const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; const NullaryOp m_functor; }; /** \returns an expression of a matrix defined by a custom functor \a func * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) { return CwiseNullaryOp(rows, cols, func); } /** \returns an expression of a matrix defined by a custom functor \a func * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * Here is an example with C++11 random generators: \include random_cpp11.cpp * Output: \verbinclude random_cpp11.out * * \sa class CwiseNullaryOp */ template template EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); else return CwiseNullaryOp(size, 1, func); } /** \returns an expression of a matrix defined by a custom functor \a func * * This variant is only for fixed-size DenseBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(const CustomNullaryOp& func) { return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); } /** \returns an expression of a constant matrix of value \a value * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this DenseBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(Index rows, Index cols, const Scalar& value) { return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value * * The parameter \a size is the size of the returned vector. * Must be compatible with this DenseBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(Index size, const Scalar& value) { return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value * * This variant is only for fixed-size DenseBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * The template parameter \a CustomNullaryOp is the type of the functor. * * \sa class CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Constant(const Scalar& value) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); } /** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(Index,const Scalar&,const Scalar&) * * \sa LinSpaced(Index,Scalar,Scalar), setLinSpaced(Index,const Scalar&,const Scalar&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(const Scalar&,const Scalar&) * * \sa LinSpaced(Scalar,Scalar) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** * \brief Sets a linearly spaced vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * * Example: \include DenseBase_LinSpaced.cpp * Output: \verbinclude DenseBase_LinSpaced.out * * For integer scalar types, an even spacing is possible if and only if the length of the range, * i.e., \c high-low is a scalar multiple of \c size-1, or if \c size is a scalar multiple of the * number of values \c high-low+1 (meaning each value can be repeated the same number of time). * If one of these two considions is not satisfied, then \c high is lowered to the largest value * satisfying one of this constraint. * Here are some examples: * * Example: \include DenseBase_LinSpacedInt.cpp * Output: \verbinclude DenseBase_LinSpacedInt.out * * \sa setLinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&) * Special version for fixed size types which does not require the size parameter. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ template EIGEN_DEVICE_FUNC bool DenseBase::isApproxToConstant (const Scalar& val, const RealScalar& prec) const { typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if(!internal::isApprox(self.coeff(i, j), val, prec)) return false; return true; } /** This is just an alias for isApproxToConstant(). * * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ template EIGEN_DEVICE_FUNC bool DenseBase::isConstant (const Scalar& val, const RealScalar& prec) const { return isApproxToConstant(val, prec); } /** Alias for setConstant(): sets all coefficients in this expression to \a val. * * \sa setConstant(), Constant(), class CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) { setConstant(val); } /** Sets all coefficients in this expression to value \a val. * * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) { return derived() = Constant(rows(), cols(), val); } /** Resizes to the given \a size, and sets all coefficients in this expression to the given value \a val. * * \only_for_vectors * * Example: \include Matrix_setConstant_int.cpp * Output: \verbinclude Matrix_setConstant_int.out * * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setConstant(Index size, const Scalar& val) { resize(size); return setConstant(val); } /** Resizes to the given size, and sets all coefficients in this expression to the given value \a val. * * \param rows the new number of rows * \param cols the new number of columns * \param val the value to which all coefficients are set * * Example: \include Matrix_setConstant_int_int.cpp * Output: \verbinclude Matrix_setConstant_int_int.out * * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& val) { resize(rows, cols); return setConstant(val); } /** * \brief Sets a linearly spaced vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * * Example: \include DenseBase_setLinSpaced.cpp * Output: \verbinclude DenseBase_setLinSpaced.out * * For integer scalar types, do not miss the explanations on the definition * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. * * \sa LinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); } /** * \brief Sets a linearly spaced vector. * * The function fills \c *this with equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * * For integer scalar types, do not miss the explanations on the definition * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. * * \sa LinSpaced(Index,const Scalar&,const Scalar&), setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return setLinSpaced(size(), low, high); } // zero: /** \returns an expression of a zero matrix. * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * Example: \include MatrixBase_zero_int_int.cpp * Output: \verbinclude MatrixBase_zero_int_int.out * * \sa Zero(), Zero(Index) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero(Index rows, Index cols) { return Constant(rows, cols, Scalar(0)); } /** \returns an expression of a zero vector. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Zero() should be used * instead. * * Example: \include MatrixBase_zero_int.cpp * Output: \verbinclude MatrixBase_zero_int.out * * \sa Zero(), Zero(Index,Index) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero(Index size) { return Constant(size, Scalar(0)); } /** \returns an expression of a fixed-size zero matrix or vector. * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_zero.cpp * Output: \verbinclude MatrixBase_zero.out * * \sa Zero(Index), Zero(Index,Index) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Zero() { return Constant(Scalar(0)); } /** \returns true if *this is approximately equal to the zero matrix, * within the precision given by \a prec. * * Example: \include MatrixBase_isZero.cpp * Output: \verbinclude MatrixBase_isZero.out * * \sa class CwiseNullaryOp, Zero() */ template EIGEN_DEVICE_FUNC bool DenseBase::isZero(const RealScalar& prec) const { typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; return true; } /** Sets all coefficients in this expression to zero. * * Example: \include MatrixBase_setZero.cpp * Output: \verbinclude MatrixBase_setZero.out * * \sa class CwiseNullaryOp, Zero() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setZero() { return setConstant(Scalar(0)); } /** Resizes to the given \a size, and sets all coefficients in this expression to zero. * * \only_for_vectors * * Example: \include Matrix_setZero_int.cpp * Output: \verbinclude Matrix_setZero_int.out * * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setZero(Index newSize) { resize(newSize); return setConstant(Scalar(0)); } /** Resizes to the given size, and sets all coefficients in this expression to zero. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setZero_int_int.cpp * Output: \verbinclude Matrix_setZero_int_int.out * * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setZero(Index rows, Index cols) { resize(rows, cols); return setConstant(Scalar(0)); } // ones: /** \returns an expression of a matrix where all coefficients equal one. * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used * instead. * * Example: \include MatrixBase_ones_int_int.cpp * Output: \verbinclude MatrixBase_ones_int_int.out * * \sa Ones(), Ones(Index), isOnes(), class Ones */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones(Index rows, Index cols) { return Constant(rows, cols, Scalar(1)); } /** \returns an expression of a vector where all coefficients equal one. * * The parameter \a newSize is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Ones() should be used * instead. * * Example: \include MatrixBase_ones_int.cpp * Output: \verbinclude MatrixBase_ones_int.out * * \sa Ones(), Ones(Index,Index), isOnes(), class Ones */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones(Index newSize) { return Constant(newSize, Scalar(1)); } /** \returns an expression of a fixed-size matrix or vector where all coefficients equal one. * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_ones.cpp * Output: \verbinclude MatrixBase_ones.out * * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType DenseBase::Ones() { return Constant(Scalar(1)); } /** \returns true if *this is approximately equal to the matrix where all coefficients * are equal to 1, within the precision given by \a prec. * * Example: \include MatrixBase_isOnes.cpp * Output: \verbinclude MatrixBase_isOnes.out * * \sa class CwiseNullaryOp, Ones() */ template EIGEN_DEVICE_FUNC bool DenseBase::isOnes (const RealScalar& prec) const { return isApproxToConstant(Scalar(1), prec); } /** Sets all coefficients in this expression to one. * * Example: \include MatrixBase_setOnes.cpp * Output: \verbinclude MatrixBase_setOnes.out * * \sa class CwiseNullaryOp, Ones() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() { return setConstant(Scalar(1)); } /** Resizes to the given \a newSize, and sets all coefficients in this expression to one. * * \only_for_vectors * * Example: \include Matrix_setOnes_int.cpp * Output: \verbinclude Matrix_setOnes_int.out * * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setOnes(Index newSize) { resize(newSize); return setConstant(Scalar(1)); } /** Resizes to the given size, and sets all coefficients in this expression to one. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setOnes_int_int.cpp * Output: \verbinclude Matrix_setOnes_int_int.out * * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& PlainObjectBase::setOnes(Index rows, Index cols) { resize(rows, cols); return setConstant(Scalar(1)); } // Identity: /** \returns an expression of the identity matrix (not necessarily square). * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used * instead. * * Example: \include MatrixBase_identity_int_int.cpp * Output: \verbinclude MatrixBase_identity_int_int.out * * \sa Identity(), setIdentity(), isIdentity() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType MatrixBase::Identity(Index rows, Index cols) { return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); } /** \returns an expression of the identity matrix (not necessarily square). * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variant taking size arguments. * * Example: \include MatrixBase_identity.cpp * Output: \verbinclude MatrixBase_identity.out * * \sa Identity(Index,Index), setIdentity(), isIdentity() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType MatrixBase::Identity() { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) return MatrixBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op()); } /** \returns true if *this is approximately equal to the identity matrix * (not necessarily square), * within the precision given by \a prec. * * Example: \include MatrixBase_isIdentity.cpp * Output: \verbinclude MatrixBase_isIdentity.out * * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity() */ template bool MatrixBase::isIdentity (const RealScalar& prec) const { typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) { for(Index i = 0; i < rows(); ++i) { if(i == j) { if(!internal::isApprox(self.coeff(i, j), static_cast(1), prec)) return false; } else { if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; } } } return true; } namespace internal { template=16)> struct setIdentity_impl { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { return m = Derived::Identity(m.rows(), m.cols()); } }; template struct setIdentity_impl { EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { m.setZero(); const Index size = numext::mini(m.rows(), m.cols()); for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); return m; } }; } // end namespace internal /** Writes the identity expression (not necessarily square) into *this. * * Example: \include MatrixBase_setIdentity.cpp * Output: \verbinclude MatrixBase_setIdentity.out * * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() { return internal::setIdentity_impl::run(derived()); } /** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setIdentity_int_int.cpp * Output: \verbinclude Matrix_setIdentity_int_int.out * * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) { derived().resize(rows, cols); return setIdentity(); } /** \returns an expression of the i-th unit (basis) vector. * * \only_for_vectors * * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i); } /** \returns an expression of the i-th unit (basis) vector. * * \only_for_vectors * * This variant is for fixed-size vector only. * * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) return BasisReturnType(SquareMatrixType::Identity(),i); } /** \returns an expression of the X axis unit vector (1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() { return Derived::Unit(0); } /** \returns an expression of the Y axis unit vector (0,1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() { return Derived::Unit(1); } /** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() { return Derived::Unit(2); } /** \returns an expression of the W axis unit vector (0,0,0,1) * * \only_for_vectors * * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() { return Derived::Unit(3); } } // end namespace Eigen #endif // EIGEN_CWISE_NULLARY_OP_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CwiseTernaryOp.h000066400000000000000000000201001506104011400246570ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2016 Eugene Brevdo // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_TERNARY_OP_H #define EIGEN_CWISE_TERNARY_OP_H namespace Eigen { namespace internal { template struct traits > { // we must not inherit from traits since it has // the potential to cause problems with MSVC typedef typename remove_all::type Ancestor; typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = traits::RowsAtCompileTime, ColsAtCompileTime = traits::ColsAtCompileTime, MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = traits::MaxColsAtCompileTime }; // even though we require Arg1, Arg2, and Arg3 to have the same scalar type // (see CwiseTernaryOp constructor), // we still want to handle the case when the result type is different. typedef typename result_of::type Scalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::StorageIndex StorageIndex; typedef typename Arg1::Nested Arg1Nested; typedef typename Arg2::Nested Arg2Nested; typedef typename Arg3::Nested Arg3Nested; typedef typename remove_reference::type _Arg1Nested; typedef typename remove_reference::type _Arg2Nested; typedef typename remove_reference::type _Arg3Nested; enum { Flags = _Arg1Nested::Flags & RowMajorBit }; }; } // end namespace internal template class CwiseTernaryOpImpl; /** \class CwiseTernaryOp * \ingroup Core_Module * * \brief Generic expression where a coefficient-wise ternary operator is * applied to two expressions * * \tparam TernaryOp template functor implementing the operator * \tparam Arg1Type the type of the first argument * \tparam Arg2Type the type of the second argument * \tparam Arg3Type the type of the third argument * * This class represents an expression where a coefficient-wise ternary * operator is applied to three expressions. * It is the return type of ternary operators, by which we mean only those * ternary operators where * all three arguments are Eigen expressions. * For example, the return type of betainc(matrix1, matrix2, matrix3) is a * CwiseTernaryOp. * * Most of the time, this is the only way that it is used, so you typically * don't have to name * CwiseTernaryOp types explicitly. * * \sa MatrixBase::ternaryExpr(const MatrixBase &, const * MatrixBase &, const CustomTernaryOp &) const, class CwiseBinaryOp, * class CwiseUnaryOp, class CwiseNullaryOp */ template class CwiseTernaryOp : public CwiseTernaryOpImpl< TernaryOp, Arg1Type, Arg2Type, Arg3Type, typename internal::traits::StorageKind>, internal::no_assignment_operator { public: typedef typename internal::remove_all::type Arg1; typedef typename internal::remove_all::type Arg2; typedef typename internal::remove_all::type Arg3; typedef typename CwiseTernaryOpImpl< TernaryOp, Arg1Type, Arg2Type, Arg3Type, typename internal::traits::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseTernaryOp) typedef typename internal::ref_selector::type Arg1Nested; typedef typename internal::ref_selector::type Arg2Nested; typedef typename internal::ref_selector::type Arg3Nested; typedef typename internal::remove_reference::type _Arg1Nested; typedef typename internal::remove_reference::type _Arg2Nested; typedef typename internal::remove_reference::type _Arg3Nested; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseTernaryOp(const Arg1& a1, const Arg2& a2, const Arg3& a3, const TernaryOp& func = TernaryOp()) : m_arg1(a1), m_arg2(a2), m_arg3(a3), m_functor(func) { // require the sizes to match EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg2) EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg3) // The index types should match EIGEN_STATIC_ASSERT((internal::is_same< typename internal::traits::StorageKind, typename internal::traits::StorageKind>::value), STORAGE_KIND_MUST_MATCH) EIGEN_STATIC_ASSERT((internal::is_same< typename internal::traits::StorageKind, typename internal::traits::StorageKind>::value), STORAGE_KIND_MUST_MATCH) eigen_assert(a1.rows() == a2.rows() && a1.cols() == a2.cols() && a1.rows() == a3.rows() && a1.cols() == a3.cols()); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time // optimizations if (internal::traits::type>:: RowsAtCompileTime == Dynamic && internal::traits::type>:: RowsAtCompileTime == Dynamic) return m_arg3.rows(); else if (internal::traits::type>:: RowsAtCompileTime == Dynamic && internal::traits::type>:: RowsAtCompileTime == Dynamic) return m_arg2.rows(); else return m_arg1.rows(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time // optimizations if (internal::traits::type>:: ColsAtCompileTime == Dynamic && internal::traits::type>:: ColsAtCompileTime == Dynamic) return m_arg3.cols(); else if (internal::traits::type>:: ColsAtCompileTime == Dynamic && internal::traits::type>:: ColsAtCompileTime == Dynamic) return m_arg2.cols(); else return m_arg1.cols(); } /** \returns the first argument nested expression */ EIGEN_DEVICE_FUNC const _Arg1Nested& arg1() const { return m_arg1; } /** \returns the first argument nested expression */ EIGEN_DEVICE_FUNC const _Arg2Nested& arg2() const { return m_arg2; } /** \returns the third argument nested expression */ EIGEN_DEVICE_FUNC const _Arg3Nested& arg3() const { return m_arg3; } /** \returns the functor representing the ternary operation */ EIGEN_DEVICE_FUNC const TernaryOp& functor() const { return m_functor; } protected: Arg1Nested m_arg1; Arg2Nested m_arg2; Arg3Nested m_arg3; const TernaryOp m_functor; }; // Generic API dispatcher template class CwiseTernaryOpImpl : public internal::generic_xpr_base< CwiseTernaryOp >::type { public: typedef typename internal::generic_xpr_base< CwiseTernaryOp >::type Base; }; } // end namespace Eigen #endif // EIGEN_CWISE_TERNARY_OP_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CwiseUnaryOp.h000066400000000000000000000074451506104011400243520ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_UNARY_OP_H #define EIGEN_CWISE_UNARY_OP_H namespace Eigen { namespace internal { template struct traits > : traits { typedef typename result_of< UnaryOp(const typename XprType::Scalar&) >::type Scalar; typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { Flags = _XprTypeNested::Flags & RowMajorBit }; }; } template class CwiseUnaryOpImpl; /** \class CwiseUnaryOp * \ingroup Core_Module * * \brief Generic expression where a coefficient-wise unary operator is applied to an expression * * \tparam UnaryOp template functor implementing the operator * \tparam XprType the type of the expression to which we are applying the unary operator * * This class represents an expression where a unary operator is applied to an expression. * It is the return type of all operations taking exactly 1 input expression, regardless of the * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix * is considered unary, because only the right-hand side is an expression, and its * return type is a specialization of CwiseUnaryOp. * * Most of the time, this is the only way that it is used, so you typically don't have to name * CwiseUnaryOp types explicitly. * * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp */ template class CwiseUnaryOp : public CwiseUnaryOpImpl::StorageKind>, internal::no_assignment_operator { public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) typedef typename internal::ref_selector::type XprTypeNested; typedef typename internal::remove_all::type NestedExpression; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } /** \returns the functor representing the unary operation */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const UnaryOp& functor() const { return m_functor; } /** \returns the nested expression */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \returns the nested expression */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::remove_all::type& nestedExpression() { return m_xpr; } protected: XprTypeNested m_xpr; const UnaryOp m_functor; }; // Generic API dispatcher template class CwiseUnaryOpImpl : public internal::generic_xpr_base >::type { public: typedef typename internal::generic_xpr_base >::type Base; }; } // end namespace Eigen #endif // EIGEN_CWISE_UNARY_OP_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/CwiseUnaryView.h000066400000000000000000000123661506104011400247040ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_CWISE_UNARY_VIEW_H #define EIGEN_CWISE_UNARY_VIEW_H namespace Eigen { namespace internal { template struct traits > : traits { typedef typename result_of< ViewOp(const typename traits::Scalar&) >::type Scalar; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic ? int(Dynamic) : int(MatrixTypeInnerStride) * int(sizeof(typename traits::Scalar) / sizeof(Scalar)), OuterStrideAtCompileTime = outer_stride_at_compile_time::ret == Dynamic ? int(Dynamic) : outer_stride_at_compile_time::ret * int(sizeof(typename traits::Scalar) / sizeof(Scalar)) }; }; } template class CwiseUnaryViewImpl; /** \class CwiseUnaryView * \ingroup Core_Module * * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector * * \tparam ViewOp template functor implementing the view * \tparam MatrixType the type of the matrix we are applying the unary operator * * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. * It is the return type of real() and imag(), and most of the time this is the only way it is used. * * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp */ template class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> { public: typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) typedef typename internal::ref_selector::non_const_type MatrixTypeNested; typedef typename internal::remove_all::type NestedExpression; explicit inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } /** \returns the functor representing unary operation */ const ViewOp& functor() const { return m_functor; } /** \returns the nested expression */ const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } /** \returns the nested expression */ typename internal::remove_reference::type& nestedExpression() { return m_matrix.const_cast_derived(); } protected: MatrixTypeNested m_matrix; ViewOp m_functor; }; // Generic API dispatcher template class CwiseUnaryViewImpl : public internal::generic_xpr_base >::type { public: typedef typename internal::generic_xpr_base >::type Base; }; template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type { public: typedef CwiseUnaryView Derived; typedef typename internal::dense_xpr_base< CwiseUnaryView >::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } protected: EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(CwiseUnaryViewImpl) }; } // end namespace Eigen #endif // EIGEN_CWISE_UNARY_VIEW_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/DenseBase.h000066400000000000000000000656371506104011400236220ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSEBASE_H #define EIGEN_DENSEBASE_H namespace Eigen { namespace internal { // The index type defined by EIGEN_DEFAULT_DENSE_INDEX_TYPE must be a signed type. // This dummy function simply aims at checking that at compile time. static inline void check_DenseIndex_is_signed() { EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); } } // end namespace internal /** \class DenseBase * \ingroup Core_Module * * \brief Base class for all dense matrices, vectors, and arrays * * This class is the base that is inherited by all dense objects (matrix, vector, arrays, * and related expression types). The common Eigen API for dense objects is contained in this class. * * \tparam Derived is the derived type, e.g., a matrix type or an expression. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. * * \sa \blank \ref TopicClassHierarchy */ template class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN : public DenseCoeffsBase::value> #else : public DenseCoeffsBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: /** Inner iterator type to iterate over the coefficients of a row or column. * \sa class InnerIterator */ typedef Eigen::InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; /** * \brief The type used to store indices * \details This typedef is relevant for types that store multiple indices such as * PermutationMatrix or Transpositions, otherwise it defaults to Eigen::Index * \sa \blank \ref TopicPreprocessorDirectives, Eigen::Index, SparseMatrixBase. */ typedef typename internal::traits::StorageIndex StorageIndex; /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. */ typedef typename internal::traits::Scalar Scalar; /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. * * It is an alias for the Scalar type */ typedef Scalar value_type; typedef typename NumTraits::Real RealScalar; typedef DenseCoeffsBase::value> Base; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::rowIndexByOuterInner; using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; using Base::operator(); using Base::operator[]; using Base::x; using Base::y; using Base::z; using Base::w; using Base::stride; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; typedef typename Base::CoeffReturnType CoeffReturnType; enum { RowsAtCompileTime = internal::traits::RowsAtCompileTime, /**< The number of rows at compile-time. This is just a copy of the value provided * by the \a Derived type. If a value is not known at compile-time, * it is set to the \a Dynamic constant. * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ ColsAtCompileTime = internal::traits::ColsAtCompileTime, /**< The number of columns at compile-time. This is just a copy of the value provided * by the \a Derived type. If a value is not known at compile-time, * it is set to the \a Dynamic constant. * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, internal::traits::ColsAtCompileTime>::ret), /**< This is equal to the number of coefficients, i.e. the number of * rows times the number of columns, or to \a Dynamic if this is not * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, /**< This value is equal to the maximum possible number of rows that this expression * might have. If this expression might have an arbitrarily high number of rows, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime */ MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, /**< This value is equal to the maximum possible number of columns that this expression * might have. If this expression might have an arbitrarily high number of columns, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime */ MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime>::ret), /**< This value is equal to the maximum possible number of coefficients that this expression * might have. If this expression might have an arbitrarily high number of coefficients, * this value is set to \a Dynamic. * * This value is useful to know when evaluating an expression, in order to determine * whether it is possible to avoid doing a dynamic memory allocation. * * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime */ IsVectorAtCompileTime = internal::traits::MaxRowsAtCompileTime == 1 || internal::traits::MaxColsAtCompileTime == 1, /**< This is set to true if either the number of rows or the number of * columns is known at compile-time to be equal to 1. Indeed, in that case, * we are dealing with a column-vector (if there is only one column) or with * a row-vector (if there is only one row). */ Flags = internal::traits::Flags, /**< This stores expression \ref flags flags which may or may not be inherited by new expressions * constructed from this one. See the \ref flags "list of flags". */ IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */ InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; typedef typename internal::find_best_packet::type PacketScalar; enum { IsPlainObjectBase = 0 }; /** The plain matrix type corresponding to this expression. * \sa PlainObject */ typedef Matrix::Scalar, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime, AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), internal::traits::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime > PlainMatrix; /** The plain array type corresponding to this expression. * \sa PlainObject */ typedef Array::Scalar, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime, AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), internal::traits::MaxRowsAtCompileTime, internal::traits::MaxColsAtCompileTime > PlainArray; /** \brief The plain matrix or array type corresponding to this expression. * * This is not necessarily exactly the return type of eval(). In the case of plain matrices, * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed * that the return type of eval() is either PlainObject or const PlainObject&. */ typedef typename internal::conditional::XprKind,MatrixXpr >::value, PlainMatrix, PlainArray>::type PlainObject; /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ EIGEN_DEVICE_FUNC inline Index nonZeros() const { return size(); } /** \returns the outer size. * * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a * column-major matrix, and the number of rows for a row-major matrix. */ EIGEN_DEVICE_FUNC Index outerSize() const { return IsVectorAtCompileTime ? 1 : int(IsRowMajor) ? this->rows() : this->cols(); } /** \returns the inner size. * * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a * column-major matrix, and the number of columns for a row-major matrix. */ EIGEN_DEVICE_FUNC Index innerSize() const { return IsVectorAtCompileTime ? this->size() : int(IsRowMajor) ? this->cols() : this->rows(); } /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ EIGEN_DEVICE_FUNC void resize(Index newSize) { EIGEN_ONLY_USED_FOR_DEBUG(newSize); eigen_assert(newSize == this->size() && "DenseBase::resize() does not actually allow to resize."); } /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { EIGEN_ONLY_USED_FOR_DEBUG(rows); EIGEN_ONLY_USED_FOR_DEBUG(cols); eigen_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal \deprecated Represents a vector with linearly spaced coefficients that allows sequential access only. */ typedef CwiseNullaryOp,PlainObject> SequentialLinSpacedReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ typedef CwiseNullaryOp,PlainObject> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this. \returns a reference to *this. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase &other); template EIGEN_DEVICE_FUNC Derived& operator+=(const EigenBase &other); template EIGEN_DEVICE_FUNC Derived& operator-=(const EigenBase &other); template EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& func); /** \internal * Copies \a other into *this without evaluating other. \returns a reference to *this. * \deprecated */ template EIGEN_DEVICE_FUNC Derived& lazyAssign(const DenseBase& other); EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); /** \deprecated it now returns \c *this */ template EIGEN_DEPRECATED const Derived& flagged() const { return derived(); } template EIGEN_DEVICE_FUNC CommaInitializer operator<< (const DenseBase& other); typedef Transpose TransposeReturnType; EIGEN_DEVICE_FUNC TransposeReturnType transpose(); typedef typename internal::add_const >::type ConstTransposeReturnType; EIGEN_DEVICE_FUNC ConstTransposeReturnType transpose() const; EIGEN_DEVICE_FUNC void transposeInPlace(); EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index size, const Scalar& value); EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(const Scalar& value); EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(Index size, const Scalar& low, const Scalar& high); EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(const Scalar& low, const Scalar& high); template EIGEN_DEVICE_FUNC static const CwiseNullaryOp NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); template EIGEN_DEVICE_FUNC static const CwiseNullaryOp NullaryExpr(Index size, const CustomNullaryOp& func); template EIGEN_DEVICE_FUNC static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index rows, Index cols); EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index size); EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(); EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index rows, Index cols); EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index size); EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(); EIGEN_DEVICE_FUNC void fill(const Scalar& value); EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value); EIGEN_DEVICE_FUNC Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); EIGEN_DEVICE_FUNC Derived& setLinSpaced(const Scalar& low, const Scalar& high); EIGEN_DEVICE_FUNC Derived& setZero(); EIGEN_DEVICE_FUNC Derived& setOnes(); EIGEN_DEVICE_FUNC Derived& setRandom(); template EIGEN_DEVICE_FUNC bool isApprox(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const RealScalar& other, const RealScalar& prec = NumTraits::dummy_precision()) const; template EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; inline bool hasNaN() const; inline bool allFinite() const; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const Scalar& other); EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const Scalar& other); typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; /** \returns the matrix or vector obtained by evaluating this expression. * * Notice that in the case of a plain matrix or vector (not an expression) this function just returns * a const reference, in order to avoid a useless copy. * * \warning Be carefull with eval() and the auto C++ keyword, as detailed in this \link TopicPitfalls_auto_keyword page \endlink. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EvalReturnType eval() const { // Even though MSVC does not honor strong inlining when the return type // is a dynamic matrix, we desperately need strong inlining for fixed // size types on MSVC. return typename internal::eval::type(derived()); } /** swaps *this with the expression \a other. * */ template EIGEN_DEVICE_FUNC void swap(const DenseBase& other) { EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); eigen_assert(rows()==other.rows() && cols()==other.cols()); call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } /** swaps *this with the matrix or array \a other. * */ template EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { eigen_assert(rows()==other.rows() && cols()==other.cols()); call_assignment(derived(), other.derived(), internal::swap_assign_op()); } EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; EIGEN_DEVICE_FUNC inline ForceAlignedAccess forceAlignedAccess(); template EIGEN_DEVICE_FUNC inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; template EIGEN_DEVICE_FUNC inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); EIGEN_DEVICE_FUNC Scalar sum() const; EIGEN_DEVICE_FUNC Scalar mean() const; EIGEN_DEVICE_FUNC Scalar trace() const; EIGEN_DEVICE_FUNC Scalar prod() const; EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff() const; EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff() const; template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* index) const; template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* index) const; template EIGEN_DEVICE_FUNC Scalar redux(const BinaryOp& func) const; template EIGEN_DEVICE_FUNC void visit(Visitor& func) const; /** \returns a WithFormat proxy object allowing to print a matrix the with given * format \a fmt. * * See class IOFormat for some examples. * * \sa class IOFormat, class WithFormat */ inline const WithFormat format(const IOFormat& fmt) const { return WithFormat(derived(), fmt); } /** \returns the unique coefficient of a 1x1 expression */ EIGEN_DEVICE_FUNC CoeffReturnType value() const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); return derived().coeff(0,0); } EIGEN_DEVICE_FUNC bool all() const; EIGEN_DEVICE_FUNC bool any() const; EIGEN_DEVICE_FUNC Index count() const; typedef VectorwiseOp RowwiseReturnType; typedef const VectorwiseOp ConstRowwiseReturnType; typedef VectorwiseOp ColwiseReturnType; typedef const VectorwiseOp ConstColwiseReturnType; /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations * * Example: \include MatrixBase_rowwise.cpp * Output: \verbinclude MatrixBase_rowwise.out * * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ //Code moved here due to a CUDA compiler bug EIGEN_DEVICE_FUNC inline ConstRowwiseReturnType rowwise() const { return ConstRowwiseReturnType(derived()); } EIGEN_DEVICE_FUNC RowwiseReturnType rowwise(); /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations * * Example: \include MatrixBase_colwise.cpp * Output: \verbinclude MatrixBase_colwise.out * * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting */ EIGEN_DEVICE_FUNC inline ConstColwiseReturnType colwise() const { return ConstColwiseReturnType(derived()); } EIGEN_DEVICE_FUNC ColwiseReturnType colwise(); typedef CwiseNullaryOp,PlainObject> RandomReturnType; static const RandomReturnType Random(Index rows, Index cols); static const RandomReturnType Random(Index size); static const RandomReturnType Random(); template const Select select(const DenseBase& thenMatrix, const DenseBase& elseMatrix) const; template inline const Select select(const DenseBase& thenMatrix, const typename ThenDerived::Scalar& elseScalar) const; template inline const Select select(const typename ElseDerived::Scalar& thenScalar, const DenseBase& elseMatrix) const; template RealScalar lpNorm() const; template EIGEN_DEVICE_FUNC const Replicate replicate() const; /** * \return an expression of the replication of \c *this * * Example: \include MatrixBase_replicate_int_int.cpp * Output: \verbinclude MatrixBase_replicate_int_int.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate */ //Code moved here due to a CUDA compiler bug EIGEN_DEVICE_FUNC const Replicate replicate(Index rowFactor, Index colFactor) const { return Replicate(derived(), rowFactor, colFactor); } typedef Reverse ReverseReturnType; typedef const Reverse ConstReverseReturnType; EIGEN_DEVICE_FUNC ReverseReturnType reverse(); /** This is the const version of reverse(). */ //Code moved here due to a CUDA compiler bug EIGEN_DEVICE_FUNC ConstReverseReturnType reverse() const { return ConstReverseReturnType(derived()); } EIGEN_DEVICE_FUNC void reverseInPlace(); #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) # include "../plugins/BlockMethods.h" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS #undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF // disable the use of evalTo for dense objects with a nice compilation error template EIGEN_DEVICE_FUNC inline void evalTo(Dest& ) const { EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); } protected: EIGEN_DEFAULT_COPY_CONSTRUCTOR(DenseBase) /** Default constructor. Do nothing. */ EIGEN_DEVICE_FUNC DenseBase() { /* Just checks for self-consistency of the flags. * Only do it when debugging Eigen, as this borders on paranoia and could slow compilation down */ #ifdef EIGEN_INTERNAL_DEBUGGING EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor)) && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))), INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION) #endif } private: EIGEN_DEVICE_FUNC explicit DenseBase(int); EIGEN_DEVICE_FUNC DenseBase(int,int); template EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase&); }; } // end namespace Eigen #endif // EIGEN_DENSEBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/DenseCoeffsBase.h000066400000000000000000000572241506104011400247410ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSECOEFFSBASE_H #define EIGEN_DENSECOEFFSBASE_H namespace Eigen { namespace internal { template struct add_const_on_value_type_if_arithmetic { typedef typename conditional::value, T, typename add_const_on_value_type::type>::type type; }; } /** \brief Base class providing read-only coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam #ReadOnlyAccessors Constant indicating read-only access * * This class defines the \c operator() \c const function and friends, which can be used to read specific * entries of a matrix or array. * * \sa DenseCoeffsBase, DenseCoeffsBase, * \ref TopicClassHierarchy */ template class DenseCoeffsBase : public EigenBase { public: typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; // Explanation for this CoeffReturnType typedef. // - This is the return type of the coeff() method. // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value). // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is // not possible, since the underlying expressions might not offer a valid address the reference could be referring to. typedef typename internal::conditional::Flags&LvalueBit), const Scalar&, typename internal::conditional::value, Scalar, const Scalar>::type >::type CoeffReturnType; typedef typename internal::add_const_on_value_type_if_arithmetic< typename internal::packet_traits::type >::type PacketReturnType; typedef EigenBase Base; using Base::rows; using Base::cols; using Base::size; using Base::derived; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 : int(Derived::ColsAtCompileTime) == 1 ? inner : int(Derived::Flags)&RowMajorBit ? outer : inner; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const { return int(Derived::ColsAtCompileTime) == 1 ? 0 : int(Derived::RowsAtCompileTime) == 1 ? inner : int(Derived::Flags)&RowMajorBit ? inner : outer; } /** Short version: don't use this function, use * \link operator()(Index,Index) const \endlink instead. * * Long version: this function is similar to * \link operator()(Index,Index) const \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator()(Index,Index) const \endlink. * * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return internal::evaluator(derived()).coeff(row,col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return coeff(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \returns the coefficient at given the given row and column. * * \sa operator()(Index,Index), operator[](Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return coeff(row, col); } /** Short version: don't use this function, use * \link operator[](Index) const \endlink instead. * * Long version: this function is similar to * \link operator[](Index) const \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameter \a index is in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator[](Index) const \endlink. * * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); return internal::evaluator(derived()).coeff(index); } /** \returns the coefficient at given index. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, * z() const, w() const */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator[](Index index) const { EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) eigen_assert(index >= 0 && index < size()); return coeff(index); } /** \returns the coefficient at given index. * * This is synonymous to operator[](Index) const. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, * z() const, w() const */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index index) const { eigen_assert(index >= 0 && index < size()); return coeff(index); } /** equivalent to operator[](0). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType x() const { return (*this)[0]; } /** equivalent to operator[](1). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType y() const { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); return (*this)[1]; } /** equivalent to operator[](2). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType z() const { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); return (*this)[2]; } /** equivalent to operator[](3). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType w() const { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); return (*this)[3]; } /** \internal * \returns the packet of coefficients starting at the given row and column. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit. * * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { typedef typename internal::packet_traits::type DefaultPacketType; eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return internal::evaluator(derived()).template packet(row,col); } /** \internal */ template EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const { return packet(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \internal * \returns the packet of coefficients starting at the given index. It is your responsibility * to ensure that a packet really starts there. This method is only available on expressions having the * PacketAccessBit and the LinearAccessBit. * * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets * starting at an address which is a multiple of the packet size. */ template EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) typedef typename internal::packet_traits::type DefaultPacketType; eigen_internal_assert(index >= 0 && index < size()); return internal::evaluator(derived()).template packet(index); } protected: // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase. // But some methods are only available in the DirectAccess case. // So we add dummy methods here with these names, so that "using... " doesn't fail. // It's not private so that the child class DenseBase can access them, and it's not public // either since it's an implementation detail, so has to be protected. void coeffRef(); void coeffRefByOuterInner(); void writePacket(); void writePacketByOuterInner(); void copyCoeff(); void copyCoeffByOuterInner(); void copyPacket(); void copyPacketByOuterInner(); void stride(); void innerStride(); void outerStride(); void rowStride(); void colStride(); }; /** \brief Base class providing read/write coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam #WriteAccessors Constant indicating read/write access * * This class defines the non-const \c operator() function and friends, which can be used to write specific * entries of a matrix or array. This class inherits DenseCoeffsBase which * defines the const variant for reading specific entries. * * \sa DenseCoeffsBase, \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; using Base::coeff; using Base::rows; using Base::cols; using Base::size; using Base::derived; using Base::rowIndexByOuterInner; using Base::colIndexByOuterInner; using Base::operator[]; using Base::operator(); using Base::x; using Base::y; using Base::z; using Base::w; /** Short version: don't use this function, use * \link operator()(Index,Index) \endlink instead. * * Long version: this function is similar to * \link operator()(Index,Index) \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator()(Index,Index) \endlink. * * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return internal::evaluator(derived()).coeffRef(row,col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRefByOuterInner(Index outer, Index inner) { return coeffRef(rowIndexByOuterInner(outer, inner), colIndexByOuterInner(outer, inner)); } /** \returns a reference to the coefficient at given the given row and column. * * \sa operator[](Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index row, Index col) { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); return coeffRef(row, col); } /** Short version: don't use this function, use * \link operator[](Index) \endlink instead. * * Long version: this function is similar to * \link operator[](Index) \endlink, but without the assertion. * Use this for limiting the performance cost of debugging code when doing * repeated coefficient access. Only use this when it is guaranteed that the * parameters \a row and \a col are in range. * * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this * function equivalent to \link operator[](Index) \endlink. * * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); return internal::evaluator(derived()).coeffRef(index); } /** \returns a reference to the coefficient at given index. * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator[](Index index) { EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) eigen_assert(index >= 0 && index < size()); return coeffRef(index); } /** \returns a reference to the coefficient at given index. * * This is synonymous to operator[](Index). * * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. * * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index index) { eigen_assert(index >= 0 && index < size()); return coeffRef(index); } /** equivalent to operator[](0). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& x() { return (*this)[0]; } /** equivalent to operator[](1). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& y() { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); return (*this)[1]; } /** equivalent to operator[](2). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& z() { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); return (*this)[2]; } /** equivalent to operator[](3). */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& w() { EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); return (*this)[3]; } }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam #DirectAccessors Constant indicating direct access * * This class defines functions to work with strides which can be used to access entries directly. This class * inherits DenseCoeffsBase which defines functions to access entries read-only using * \c operator() . * * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; using Base::rows; using Base::cols; using Base::size; using Base::derived; /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. * * \sa outerStride(), rowStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); } /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns * in a column-major matrix). * * \sa innerStride(), rowStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); } // FIXME shall we remove it ? inline Index stride() const { return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); } /** \returns the pointer increment between two consecutive rows. * * \sa innerStride(), outerStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); } /** \returns the pointer increment between two consecutive columns. * * \sa innerStride(), outerStride(), rowStride() */ EIGEN_DEVICE_FUNC inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); } }; /** \brief Base class providing direct read/write coefficient access to matrices and arrays. * \ingroup Core_Module * \tparam Derived Type of the derived class * \tparam #DirectWriteAccessors Constant indicating direct access * * This class defines functions to work with strides which can be used to access entries directly. This class * inherits DenseCoeffsBase which defines functions to access entries read/write using * \c operator(). * * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase { public: typedef DenseCoeffsBase Base; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; using Base::rows; using Base::cols; using Base::size; using Base::derived; /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. * * \sa outerStride(), rowStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); } /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns * in a column-major matrix). * * \sa innerStride(), rowStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); } // FIXME shall we remove it ? inline Index stride() const { return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); } /** \returns the pointer increment between two consecutive rows. * * \sa innerStride(), outerStride(), colStride() */ EIGEN_DEVICE_FUNC inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); } /** \returns the pointer increment between two consecutive columns. * * \sa innerStride(), outerStride(), rowStride() */ EIGEN_DEVICE_FUNC inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); } }; namespace internal { template struct first_aligned_impl { static inline Index run(const Derived&) { return 0; } }; template struct first_aligned_impl { static inline Index run(const Derived& m) { return internal::first_aligned(m.data(), m.size()); } }; /** \internal \returns the index of the first element of the array stored by \a m that is properly aligned with respect to \a Alignment for vectorization. * * \tparam Alignment requested alignment in Bytes. * * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more * documentation. */ template static inline Index first_aligned(const DenseBase& m) { enum { ReturnZero = (int(evaluator::Alignment) >= Alignment) || !(Derived::Flags & DirectAccessBit) }; return first_aligned_impl::run(m.derived()); } template static inline Index first_default_aligned(const DenseBase& m) { typedef typename Derived::Scalar Scalar; typedef typename packet_traits::type DefaultPacketType; return internal::first_aligned::alignment),Derived>(m); } template::ret> struct inner_stride_at_compile_time { enum { ret = traits::InnerStrideAtCompileTime }; }; template struct inner_stride_at_compile_time { enum { ret = 0 }; }; template::ret> struct outer_stride_at_compile_time { enum { ret = traits::OuterStrideAtCompileTime }; }; template struct outer_stride_at_compile_time { enum { ret = 0 }; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_DENSECOEFFSBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/DenseStorage.h000066400000000000000000000532751506104011400243470ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2010-2013 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIXSTORAGE_H #define EIGEN_MATRIXSTORAGE_H #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) X; EIGEN_DENSE_STORAGE_CTOR_PLUGIN; #else #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) #endif namespace Eigen { namespace internal { struct constructor_without_unaligned_array_assert {}; template EIGEN_DEVICE_FUNC void check_static_allocation_size() { // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit #if EIGEN_STACK_ALLOCATION_LIMIT EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); #endif } /** \internal * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: * to 16 bytes boundary if the total size is a multiple of 16 bytes. */ template ::value > struct plain_array { T array[Size]; EIGEN_DEVICE_FUNC plain_array() { check_static_allocation_size(); } EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } }; #if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) #elif EIGEN_GNUC_AT_LEAST(4,7) // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: template EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ eigen_assert((internal::UIntPtr(eigen_unaligned_array_assert_workaround_gcc47(array)) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ eigen_assert((internal::UIntPtr(array) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #endif template struct plain_array { EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size]; EIGEN_DEVICE_FUNC plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7); check_static_allocation_size(); } EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } }; template struct plain_array { EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size]; EIGEN_DEVICE_FUNC plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15); check_static_allocation_size(); } EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } }; template struct plain_array { EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size]; EIGEN_DEVICE_FUNC plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31); check_static_allocation_size(); } EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } }; template struct plain_array { EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size]; EIGEN_DEVICE_FUNC plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63); check_static_allocation_size(); } EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } }; template struct plain_array { T array[1]; EIGEN_DEVICE_FUNC plain_array() {} EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) {} }; } // end namespace internal /** \internal * * \class DenseStorage * \ingroup Core_Module * * \brief Stores the data of a matrix * * This class stores the data of fixed-size, dynamic-size or mixed matrices * in a way as compact as possible. * * \sa Matrix */ template class DenseStorage; // purely fixed-size matrix template class DenseStorage { internal::plain_array m_data; public: EIGEN_DEVICE_FUNC DenseStorage() { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) } EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) } EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) m_data = other.m_data; return *this; } EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); EIGEN_UNUSED_VARIABLE(size); EIGEN_UNUSED_VARIABLE(rows); EIGEN_UNUSED_VARIABLE(cols); } EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // null matrix template class DenseStorage { public: EIGEN_DEVICE_FUNC DenseStorage() {} EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) {} EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) { return *this; } EIGEN_DEVICE_FUNC DenseStorage(Index,Index,Index) {} EIGEN_DEVICE_FUNC void swap(DenseStorage& ) {} EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} EIGEN_DEVICE_FUNC const T *data() const { return 0; } EIGEN_DEVICE_FUNC T *data() { return 0; } }; // more specializations for null matrices; these are necessary to resolve ambiguities template class DenseStorage : public DenseStorage { }; template class DenseStorage : public DenseStorage { }; template class DenseStorage : public DenseStorage { }; // dynamic-size matrix with fixed-size storage template class DenseStorage { internal::plain_array m_data; Index m_rows; Index m_cols; public: EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0), m_cols(0) {} EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { m_data = other.m_data; m_rows = other.m_rows; m_cols = other.m_cols; } return *this; } EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index cols) : m_rows(rows), m_cols(cols) {} EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } EIGEN_DEVICE_FUNC Index rows() const {return m_rows;} EIGEN_DEVICE_FUNC Index cols() const {return m_cols;} EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed width template class DenseStorage { internal::plain_array m_data; Index m_rows; public: EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0) {} EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { m_data = other.m_data; m_rows = other.m_rows; } return *this; } EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index) : m_rows(rows) {} EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} EIGEN_DEVICE_FUNC Index cols(void) const {return _Cols;} EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index) { m_rows = rows; } EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index) { m_rows = rows; } EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed height template class DenseStorage { internal::plain_array m_data; Index m_cols; public: EIGEN_DEVICE_FUNC DenseStorage() : m_cols(0) {} EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { m_data = other.m_data; m_cols = other.m_cols; } return *this; } EIGEN_DEVICE_FUNC DenseStorage(Index, Index, Index cols) : m_cols(cols) {} EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } EIGEN_DEVICE_FUNC Index rows(void) const {return _Rows;} EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} void conservativeResize(Index, Index, Index cols) { m_cols = cols; } void resize(Index, Index, Index cols) { m_cols = cols; } EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // purely dynamic matrix. template class DenseStorage { T *m_data; Index m_rows; Index m_cols; public: EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0), m_cols(0) {} EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) eigen_internal_assert(size==rows*cols && rows>=0 && cols >=0); } EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(internal::conditional_aligned_new_auto(other.m_rows*other.m_cols)) , m_rows(other.m_rows) , m_cols(other.m_cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*m_cols) internal::smart_copy(other.m_data, other.m_data+other.m_rows*other.m_cols, m_data); } EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { DenseStorage tmp(other); this->swap(tmp); } return *this; } #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_rows(std::move(other.m_rows)) , m_cols(std::move(other.m_cols)) { other.m_data = nullptr; other.m_rows = 0; other.m_cols = 0; } EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); swap(m_rows, other.m_rows); swap(m_cols, other.m_cols); return *this; } #endif EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} void conservativeResize(Index size, Index rows, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); m_rows = rows; m_cols = cols; } EIGEN_DEVICE_FUNC void resize(Index size, Index rows, Index cols) { if(size != m_rows*m_cols) { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } m_rows = rows; m_cols = cols; } EIGEN_DEVICE_FUNC const T *data() const { return m_data; } EIGEN_DEVICE_FUNC T *data() { return m_data; } }; // matrix with dynamic width and fixed height (so that matrix has dynamic size). template class DenseStorage { T *m_data; Index m_cols; public: EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_cols(0) {} explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) eigen_internal_assert(size==rows*cols && rows==_Rows && cols >=0); EIGEN_UNUSED_VARIABLE(rows); } EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(internal::conditional_aligned_new_auto(_Rows*other.m_cols)) , m_cols(other.m_cols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_cols*_Rows) internal::smart_copy(other.m_data, other.m_data+_Rows*m_cols, m_data); } EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { DenseStorage tmp(other); this->swap(tmp); } return *this; } #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_cols(std::move(other.m_cols)) { other.m_data = nullptr; other.m_cols = 0; } EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); swap(m_cols, other.m_cols); return *this; } #endif EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} EIGEN_DEVICE_FUNC void conservativeResize(Index size, Index, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); m_cols = cols; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index, Index cols) { if(size != _Rows*m_cols) { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } m_cols = cols; } EIGEN_DEVICE_FUNC const T *data() const { return m_data; } EIGEN_DEVICE_FUNC T *data() { return m_data; } }; // matrix with dynamic height and fixed width (so that matrix has dynamic size). template class DenseStorage { T *m_data; Index m_rows; public: EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0) {} explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) eigen_internal_assert(size==rows*cols && rows>=0 && cols == _Cols); EIGEN_UNUSED_VARIABLE(cols); } EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(internal::conditional_aligned_new_auto(other.m_rows*_Cols)) , m_rows(other.m_rows) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*_Cols) internal::smart_copy(other.m_data, other.m_data+other.m_rows*_Cols, m_data); } EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { DenseStorage tmp(other); this->swap(tmp); } return *this; } #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_rows(std::move(other.m_rows)) { other.m_data = nullptr; other.m_rows = 0; } EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); swap(m_rows, other.m_rows); return *this; } #endif EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} void conservativeResize(Index size, Index rows, Index) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); m_rows = rows; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index rows, Index) { if(size != m_rows*_Cols) { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative m_data = internal::conditional_aligned_new_auto(size); else m_data = 0; EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } m_rows = rows; } EIGEN_DEVICE_FUNC const T *data() const { return m_data; } EIGEN_DEVICE_FUNC T *data() { return m_data; } }; } // end namespace Eigen #endif // EIGEN_MATRIX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Diagonal.h000066400000000000000000000225751506104011400235010ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2009 Benoit Jacob // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONAL_H #define EIGEN_DIAGONAL_H namespace Eigen { /** \class Diagonal * \ingroup Core_Module * * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix * * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. * A positive value means a superdiagonal, a negative value means a subdiagonal. * You can also use DynamicIndex so the index can be set at runtime. * * The matrix is not required to be square. * * This class represents an expression of the main diagonal, or any sub/super diagonal * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the * time this is the only way it is used. * * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index) */ namespace internal { template struct traits > : traits { typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { RowsAtCompileTime = (int(DiagIndex) == DynamicIndex || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), ColsAtCompileTime = 1, MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic : DiagIndex == DynamicIndex ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, MatrixType::MaxColsAtCompileTime) : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 }; }; } template class Diagonal : public internal::dense_xpr_base< Diagonal >::type { public: enum { DiagIndex = _DiagIndex }; typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) EIGEN_DEVICE_FUNC explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) { eigen_assert( a_index <= m_matrix.cols() && -a_index <= m_matrix.rows() ); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) EIGEN_DEVICE_FUNC inline Index rows() const { return m_index.value()<0 ? numext::mini(m_matrix.cols(),m_matrix.rows()+m_index.value()) : numext::mini(m_matrix.rows(),m_matrix.cols()-m_index.value()); } EIGEN_DEVICE_FUNC inline Index cols() const { return 1; } EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.outerStride() + 1; } EIGEN_DEVICE_FUNC inline Index outerStride() const { return 0; } typedef typename internal::conditional< internal::is_lvalue::value, Scalar, const Scalar >::type ScalarWithConstIfNotLvalue; EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index row, Index) const { return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index) const { return m_matrix.coeff(row+rowOffset(), row+colOffset()); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index idx) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index idx) const { return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index idx) const { return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); } EIGEN_DEVICE_FUNC inline const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } EIGEN_DEVICE_FUNC inline Index index() const { return m_index.value(); } protected: typename internal::ref_selector::non_const_type m_matrix; const internal::variable_if_dynamicindex m_index; private: // some compilers may fail to optimize std::max etc in case of compile-time constants... EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } // trigger a compile-time error if someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; /** \returns an expression of the main diagonal of the matrix \c *this * * \c *this is not required to be square. * * Example: \include MatrixBase_diagonal.cpp * Output: \verbinclude MatrixBase_diagonal.out * * \sa class Diagonal */ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { return DiagonalReturnType(derived()); } /** This is the const version of diagonal(). */ template inline typename MatrixBase::ConstDiagonalReturnType MatrixBase::diagonal() const { return ConstDiagonalReturnType(derived()); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this * * \c *this is not required to be square. * * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. * * Example: \include MatrixBase_diagonal_int.cpp * Output: \verbinclude MatrixBase_diagonal_int.out * * \sa MatrixBase::diagonal(), class Diagonal */ template inline typename MatrixBase::DiagonalDynamicIndexReturnType MatrixBase::diagonal(Index index) { return DiagonalDynamicIndexReturnType(derived(), index); } /** This is the const version of diagonal(Index). */ template inline typename MatrixBase::ConstDiagonalDynamicIndexReturnType MatrixBase::diagonal(Index index) const { return ConstDiagonalDynamicIndexReturnType(derived(), index); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this * * \c *this is not required to be square. * * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. * * Example: \include MatrixBase_diagonal_template_int.cpp * Output: \verbinclude MatrixBase_diagonal_template_int.out * * \sa MatrixBase::diagonal(), class Diagonal */ template template inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { return typename DiagonalIndexReturnType::Type(derived()); } /** This is the const version of diagonal(). */ template template inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { return typename ConstDiagonalIndexReturnType::Type(derived()); } } // end namespace Eigen #endif // EIGEN_DIAGONAL_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/DiagonalMatrix.h000066400000000000000000000305721506104011400246620ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONALMATRIX_H #define EIGEN_DIAGONALMATRIX_H namespace Eigen { #ifndef EIGEN_PARSED_BY_DOXYGEN template class DiagonalBase : public EigenBase { public: typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::RealScalar RealScalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::StorageIndex StorageIndex; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, Flags = NoPreferredStorageOrderBit }; typedef Matrix DenseMatrixType; typedef DenseMatrixType DenseType; typedef DiagonalMatrix PlainObject; EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast(this); } EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast(this); } EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return derived().diagonal(); } EIGEN_DEVICE_FUNC inline Index rows() const { return diagonal().size(); } EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } template EIGEN_DEVICE_FUNC const Product operator*(const MatrixBase &matrix) const { return Product(derived(),matrix.derived()); } typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; EIGEN_DEVICE_FUNC inline const InverseReturnType inverse() const { return InverseReturnType(diagonal().cwiseInverse()); } EIGEN_DEVICE_FUNC inline const DiagonalWrapper operator*(const Scalar& scalar) const { return DiagonalWrapper(diagonal() * scalar); } EIGEN_DEVICE_FUNC friend inline const DiagonalWrapper operator*(const Scalar& scalar, const DiagonalBase& other) { return DiagonalWrapper(scalar * other.diagonal()); } }; #endif /** \class DiagonalMatrix * \ingroup Core_Module * * \brief Represents a diagonal matrix with its storage * * \param _Scalar the type of coefficients * \param SizeAtCompileTime the dimension of the matrix, or Dynamic * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults * to SizeAtCompileTime. Most of the time, you do not need to specify it. * * \sa class DiagonalWrapper */ namespace internal { template struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; typedef DiagonalShape StorageKind; enum { Flags = LvalueBit | NoPreferredStorageOrderBit }; }; } template class DiagonalMatrix : public DiagonalBase > { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::StorageIndex StorageIndex; #endif protected: DiagonalVectorType m_diagonal; public: /** const version of diagonal(). */ EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return m_diagonal; } /** \returns a reference to the stored vector of diagonal coefficients. */ EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return m_diagonal; } /** Default constructor without initialization */ EIGEN_DEVICE_FUNC inline DiagonalMatrix() {} /** Constructs a diagonal matrix with given dimension */ EIGEN_DEVICE_FUNC explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} /** 3D constructor. */ EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} /** Copy constructor. */ template EIGEN_DEVICE_FUNC inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */ inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {} #endif /** generic constructor from expression of the diagonal coefficients */ template EIGEN_DEVICE_FUNC explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) {} /** Copy operator. */ template EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalBase& other) { m_diagonal = other.diagonal(); return *this; } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalMatrix& other) { m_diagonal = other.diagonal(); return *this; } #endif /** Resizes to given size. */ EIGEN_DEVICE_FUNC inline void resize(Index size) { m_diagonal.resize(size); } /** Sets all coefficients to zero. */ EIGEN_DEVICE_FUNC inline void setZero() { m_diagonal.setZero(); } /** Resizes and sets all coefficients to zero. */ EIGEN_DEVICE_FUNC inline void setZero(Index size) { m_diagonal.setZero(size); } /** Sets this matrix to be the identity matrix of the current size. */ EIGEN_DEVICE_FUNC inline void setIdentity() { m_diagonal.setOnes(); } /** Sets this matrix to be the identity matrix of the given size. */ EIGEN_DEVICE_FUNC inline void setIdentity(Index size) { m_diagonal.setOnes(size); } }; /** \class DiagonalWrapper * \ingroup Core_Module * * \brief Expression of a diagonal matrix * * \param _DiagonalVectorType the type of the vector of diagonal coefficients * * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients, * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal() * and most of the time this is the only way that it is used. * * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal() */ namespace internal { template struct traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::StorageIndex StorageIndex; typedef DiagonalShape StorageKind; typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit }; }; } template class DiagonalWrapper : public DiagonalBase >, internal::no_assignment_operator { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef _DiagonalVectorType DiagonalVectorType; typedef DiagonalWrapper Nested; #endif /** Constructor from expression of diagonal coefficients to wrap. */ EIGEN_DEVICE_FUNC explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ EIGEN_DEVICE_FUNC const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: typename DiagonalVectorType::Nested m_diagonal; }; /** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients * * \only_for_vectors * * Example: \include MatrixBase_asDiagonal.cpp * Output: \verbinclude MatrixBase_asDiagonal.out * * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal() **/ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { return DiagonalWrapper(derived()); } /** \returns true if *this is approximately equal to a diagonal matrix, * within the precision given by \a prec. * * Example: \include MatrixBase_isDiagonal.cpp * Output: \verbinclude MatrixBase_isDiagonal.out * * \sa asDiagonal() */ template bool MatrixBase::isDiagonal(const RealScalar& prec) const { if(cols() != rows()) return false; RealScalar maxAbsOnDiagonal = static_cast(-1); for(Index j = 0; j < cols(); ++j) { RealScalar absOnDiagonal = numext::abs(coeff(j,j)); if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; } for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < j; ++i) { if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false; if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false; } return true; } namespace internal { template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; struct Diagonal2Dense {}; template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; // Diagonal matrix to Dense assignment template< typename DstXprType, typename SrcXprType, typename Functor> struct Assignment { static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) { Index dstRows = src.rows(); Index dstCols = src.cols(); if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); dst.setZero(); dst.diagonal() = src.diagonal(); } static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) { dst.diagonal() += src.diagonal(); } static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) { dst.diagonal() -= src.diagonal(); } }; } // namespace internal } // end namespace Eigen #endif // EIGEN_DIAGONALMATRIX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/DiagonalProduct.h000066400000000000000000000017121506104011400250300ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2007-2009 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DIAGONALPRODUCT_H #define EIGEN_DIAGONALPRODUCT_H namespace Eigen { /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. */ template template inline const Product MatrixBase::operator*(const DiagonalBase &a_diagonal) const { return Product(derived(),a_diagonal.derived()); } } // end namespace Eigen #endif // EIGEN_DIAGONALPRODUCT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Dot.h000066400000000000000000000263631506104011400225100ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008, 2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DOT_H #define EIGEN_DOT_H namespace Eigen { namespace internal { // helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot // with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE // looking at the static assertions. Thus this is a trick to get better compile errors. template struct dot_nocheck { typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; typedef typename conj_prod::result_type ResScalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.template binaryExpr(b).sum(); } }; template struct dot_nocheck { typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; typedef typename conj_prod::result_type ResScalar; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static ResScalar run(const MatrixBase& a, const MatrixBase& b) { return a.transpose().template binaryExpr(b).sum(); } }; } // end namespace internal /** \fn MatrixBase::dot * \returns the dot product of *this with other. * * \only_for_vectors * * \note If the scalar type is complex numbers, then this function returns the hermitian * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the * second variable. * * \sa squaredNorm(), norm() */ template template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType MatrixBase::dot(const MatrixBase& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) #if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) typedef internal::scalar_conj_product_op func; EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); #endif eigen_assert(size() == other.size()); return internal::dot_nocheck::run(*this, other); } //---------- implementation of L2 norm and related functions ---------- /** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. * In both cases, it consists in the sum of the square of all the matrix entries. * For vectors, this is also equals to the dot product of \c *this with itself. * * \sa dot(), norm(), lpNorm() */ template EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const { return numext::real((*this).cwiseAbs2().sum()); } /** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm. * In both cases, it consists in the square root of the sum of the square of all the matrix entries. * For vectors, this is also equals to the square root of the dot product of \c *this with itself. * * \sa lpNorm(), dot(), squaredNorm() */ template EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::norm() const { return numext::sqrt(squaredNorm()); } /** \returns an expression of the quotient of \c *this by its own norm. * * \warning If the input vector is too small (i.e., this->norm()==0), * then this function returns a copy of the input. * * \only_for_vectors * * \sa norm(), normalize() */ template EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject MatrixBase::normalized() const { typedef typename internal::nested_eval::type _Nested; _Nested n(derived()); RealScalar z = n.squaredNorm(); // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU if(z>RealScalar(0)) return n / numext::sqrt(z); else return n; } /** Normalizes the vector, i.e. divides it by its own norm. * * \only_for_vectors * * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. * * \sa norm(), normalized() */ template EIGEN_STRONG_INLINE void MatrixBase::normalize() { RealScalar z = squaredNorm(); // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU if(z>RealScalar(0)) derived() /= numext::sqrt(z); } /** \returns an expression of the quotient of \c *this by its own norm while avoiding underflow and overflow. * * \only_for_vectors * * This method is analogue to the normalized() method, but it reduces the risk of * underflow and overflow when computing the norm. * * \warning If the input vector is too small (i.e., this->norm()==0), * then this function returns a copy of the input. * * \sa stableNorm(), stableNormalize(), normalized() */ template EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject MatrixBase::stableNormalized() const { typedef typename internal::nested_eval::type _Nested; _Nested n(derived()); RealScalar w = n.cwiseAbs().maxCoeff(); RealScalar z = (n/w).squaredNorm(); if(z>RealScalar(0)) return n / (numext::sqrt(z)*w); else return n; } /** Normalizes the vector while avoid underflow and overflow * * \only_for_vectors * * This method is analogue to the normalize() method, but it reduces the risk of * underflow and overflow when computing the norm. * * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. * * \sa stableNorm(), stableNormalized(), normalize() */ template EIGEN_STRONG_INLINE void MatrixBase::stableNormalize() { RealScalar w = cwiseAbs().maxCoeff(); RealScalar z = (derived()/w).squaredNorm(); if(z>RealScalar(0)) derived() /= numext::sqrt(z)*w; } //---------- implementation of other norms ---------- namespace internal { template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const MatrixBase& m) { EIGEN_USING_STD_MATH(pow) return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } }; template struct lpNorm_selector { EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); } }; template struct lpNorm_selector { EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); } }; template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const MatrixBase& m) { if(Derived::SizeAtCompileTime==0 || (Derived::SizeAtCompileTime==Dynamic && m.size()==0)) return RealScalar(0); return m.cwiseAbs().maxCoeff(); } }; } // end namespace internal /** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values * of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ * norm, that is the maximum of the absolute values of the coefficients of \c *this. * * In all cases, if \c *this is empty, then the value 0 is returned. * * \note For matrices, this function does not compute the operator-norm. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink. * * \sa norm() */ template template #ifndef EIGEN_PARSED_BY_DOXYGEN inline typename NumTraits::Scalar>::Real #else MatrixBase::RealScalar #endif MatrixBase::lpNorm() const { return internal::lpNorm_selector::run(*this); } //---------- implementation of isOrthogonal / isUnitary ---------- /** \returns true if *this is approximately orthogonal to \a other, * within the precision given by \a prec. * * Example: \include MatrixBase_isOrthogonal.cpp * Output: \verbinclude MatrixBase_isOrthogonal.out */ template template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { typename internal::nested_eval::type nested(derived()); typename internal::nested_eval::type otherNested(other.derived()); return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } /** \returns true if *this is approximately an unitary matrix, * within the precision given by \a prec. In the case where the \a Scalar * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name. * * \note This can be used to check whether a family of vectors forms an orthonormal basis. * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an * orthonormal basis. * * Example: \include MatrixBase_isUnitary.cpp * Output: \verbinclude MatrixBase_isUnitary.out */ template bool MatrixBase::isUnitary(const RealScalar& prec) const { typename internal::nested_eval::type self(derived()); for(Index i = 0; i < cols(); ++i) { if(!internal::isApprox(self.col(i).squaredNorm(), static_cast(1), prec)) return false; for(Index j = 0; j < i; ++j) if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast(1), prec)) return false; } return true; } } // end namespace Eigen #endif // EIGEN_DOT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/EigenBase.h000066400000000000000000000127631506104011400236030ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_EIGENBASE_H #define EIGEN_EIGENBASE_H namespace Eigen { /** \class EigenBase * \ingroup Core_Module * * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * * In other words, an EigenBase object is an object that can be copied into a MatrixBase. * * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. * * \sa \blank \ref TopicClassHierarchy */ template struct EigenBase { // typedef typename internal::plain_matrix_type::type PlainObject; /** \brief The interface type of indices * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. * \deprecated Since Eigen 3.3, its usage is deprecated. Use Eigen::Index instead. * \sa StorageIndex, \ref TopicPreprocessorDirectives. */ typedef Eigen::Index Index; // FIXME is it needed? typedef typename internal::traits::StorageKind StorageKind; /** \returns a reference to the derived object */ EIGEN_DEVICE_FUNC Derived& derived() { return *static_cast(this); } /** \returns a const reference to the derived object */ EIGEN_DEVICE_FUNC const Derived& derived() const { return *static_cast(this); } EIGEN_DEVICE_FUNC inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } EIGEN_DEVICE_FUNC inline const Derived& const_derived() const { return *static_cast(this); } /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ EIGEN_DEVICE_FUNC inline Index rows() const { return derived().rows(); } /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ EIGEN_DEVICE_FUNC inline Index cols() const { return derived().cols(); } /** \returns the number of coefficients, which is rows()*cols(). * \sa rows(), cols(), SizeAtCompileTime. */ EIGEN_DEVICE_FUNC inline Index size() const { return rows() * cols(); } /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ template EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { derived().evalTo(dst); } /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ template EIGEN_DEVICE_FUNC inline void addTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. typename Dest::PlainObject res(rows(),cols()); evalTo(res); dst += res; } /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ template EIGEN_DEVICE_FUNC inline void subTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. typename Dest::PlainObject res(rows(),cols()); evalTo(res); dst -= res; } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ template EIGEN_DEVICE_FUNC inline void applyThisOnTheRight(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. dst = dst * this->derived(); } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ template EIGEN_DEVICE_FUNC inline void applyThisOnTheLeft(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. dst = this->derived() * dst; } }; /*************************************************************************** * Implementation of matrix base methods ***************************************************************************/ /** \brief Copies the generic expression \a other into *this. * * \details The expression must provide a (templated) evalTo(Derived& dst) const * function which does the actual job. In practice, this allows any user to write * its own special matrix without having to modify MatrixBase * * \returns a reference to *this. */ template template EIGEN_DEVICE_FUNC Derived& DenseBase::operator=(const EigenBase &other) { call_assignment(derived(), other.derived()); return derived(); } template template EIGEN_DEVICE_FUNC Derived& DenseBase::operator+=(const EigenBase &other) { call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } template template EIGEN_DEVICE_FUNC Derived& DenseBase::operator-=(const EigenBase &other) { call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_EIGENBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ForceAlignedAccess.h000066400000000000000000000112411506104011400254130ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FORCEALIGNEDACCESS_H #define EIGEN_FORCEALIGNEDACCESS_H namespace Eigen { /** \class ForceAlignedAccess * \ingroup Core_Module * * \brief Enforce aligned packet loads and stores regardless of what is requested * * \param ExpressionType the type of the object of which we are forcing aligned packet access * * This class is the return type of MatrixBase::forceAlignedAccess() * and most of the time this is the only way it is used. * * \sa MatrixBase::forceAlignedAccess() */ namespace internal { template struct traits > : public traits {}; } template class ForceAlignedAccess : public internal::dense_xpr_base< ForceAlignedAccess >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; private: ForceAlignedAccess& operator=(const ForceAlignedAccess&); }; /** \returns an expression of *this with forced aligned access * \sa forceAlignedAccessIf(),class ForceAlignedAccess */ template inline const ForceAlignedAccess MatrixBase::forceAlignedAccess() const { return ForceAlignedAccess(derived()); } /** \returns an expression of *this with forced aligned access * \sa forceAlignedAccessIf(), class ForceAlignedAccess */ template inline ForceAlignedAccess MatrixBase::forceAlignedAccess() { return ForceAlignedAccess(derived()); } /** \returns an expression of *this with forced aligned access if \a Enable is true. * \sa forceAlignedAccess(), class ForceAlignedAccess */ template template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { return derived(); // FIXME This should not work but apparently is never used } /** \returns an expression of *this with forced aligned access if \a Enable is true. * \sa forceAlignedAccess(), class ForceAlignedAccess */ template template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { return derived(); // FIXME This should not work but apparently is never used } } // end namespace Eigen #endif // EIGEN_FORCEALIGNEDACCESS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Fuzzy.h000066400000000000000000000131111506104011400230740ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_FUZZY_H #define EIGEN_FUZZY_H namespace Eigen { namespace internal { template::IsInteger> struct isApprox_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { typename internal::nested_eval::type nested(x); typename internal::nested_eval::type otherNested(y); return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; template struct isApprox_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) { return x.matrix() == y.matrix(); } }; template::IsInteger> struct isMuchSmallerThan_object_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); } }; template struct isMuchSmallerThan_object_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); } }; template::IsInteger> struct isMuchSmallerThan_scalar_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec * y); } }; template struct isMuchSmallerThan_scalar_selector { EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); } }; } // end namespace internal /** \returns \c true if \c *this is approximately equal to \a other, within the precision * determined by \a prec. * * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$ * are considered to be approximately equal within precision \f$ p \f$ if * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f] * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm * L2 norm). * * \note Because of the multiplicativeness of this comparison, one can't use this function * to check whether \c *this is approximately equal to the zero matrix or vector. * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const * RealScalar&, RealScalar) instead. * * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const */ template template bool DenseBase::isApprox( const DenseBase& other, const RealScalar& prec ) const { return internal::isApprox_selector::run(derived(), other.derived(), prec); } /** \returns \c true if the norm of \c *this is much smaller than \a other, * within the precision determined by \a prec. * * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f] * * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason, * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm * of a reference matrix of same dimensions. * * \sa isApprox(), isMuchSmallerThan(const DenseBase&, RealScalar) const */ template bool DenseBase::isMuchSmallerThan( const typename NumTraits::Real& other, const RealScalar& prec ) const { return internal::isMuchSmallerThan_scalar_selector::run(derived(), other, prec); } /** \returns \c true if the norm of \c *this is much smaller than the norm of \a other, * within the precision determined by \a prec. * * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f] * For matrices, the comparison is done using the Hilbert-Schmidt norm. * * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const */ template template bool DenseBase::isMuchSmallerThan( const DenseBase& other, const RealScalar& prec ) const { return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); } } // end namespace Eigen #endif // EIGEN_FUZZY_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/GeneralProduct.h000066400000000000000000000512031506104011400246670ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008-2011 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERAL_PRODUCT_H #define EIGEN_GENERAL_PRODUCT_H namespace Eigen { enum { Large = 2, Small = 3 }; namespace internal { template struct product_type_selector; template struct product_size_category { enum { #ifndef EIGEN_CUDA_ARCH is_large = MaxSize == Dynamic || Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD || (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD), #else is_large = 0, #endif value = is_large ? Large : Size == 1 ? 1 : Small }; }; template struct product_type { typedef typename remove_all::type _Lhs; typedef typename remove_all::type _Rhs; enum { MaxRows = traits<_Lhs>::MaxRowsAtCompileTime, Rows = traits<_Lhs>::RowsAtCompileTime, MaxCols = traits<_Rhs>::MaxColsAtCompileTime, Cols = traits<_Rhs>::ColsAtCompileTime, MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, traits<_Rhs>::MaxRowsAtCompileTime), Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, traits<_Rhs>::RowsAtCompileTime) }; // the splitting into different lines of code here, introducing the _select enums and the typedef below, // is to work around an internal compiler error with gcc 4.1 and 4.2. private: enum { rows_select = product_size_category::value, cols_select = product_size_category::value, depth_select = product_size_category::value }; typedef product_type_selector selector; public: enum { value = selector::ret, ret = selector::ret }; #ifdef EIGEN_DEBUG_PRODUCT static void debug() { EIGEN_DEBUG_VAR(Rows); EIGEN_DEBUG_VAR(Cols); EIGEN_DEBUG_VAR(Depth); EIGEN_DEBUG_VAR(rows_select); EIGEN_DEBUG_VAR(cols_select); EIGEN_DEBUG_VAR(depth_select); EIGEN_DEBUG_VAR(value); } #endif }; /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ // FIXME I'm not sure the current mapping is the ideal one. template struct product_type_selector { enum { ret = OuterProduct }; }; template struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template struct product_type_selector<1, N, 1> { enum { ret = LazyCoeffBasedProductMode }; }; template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemvProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; } // end namespace internal /*********************************************************************** * Implementation of Inner Vector Vector Product ***********************************************************************/ // FIXME : maybe the "inner product" could return a Scalar // instead of a 1x1 matrix ?? // Pro: more natural for the user // Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix // product ends up to a row-vector times col-vector product... To tackle this use // case, we could have a specialization for Block with: operator=(Scalar x); /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ /*********************************************************************** * Implementation of General Matrix Vector Product ***********************************************************************/ /* According to the shape/flags of the matrix we have to distinghish 3 different cases: * 1 - the matrix is col-major, BLAS compatible and M is large => call fast BLAS-like colmajor routine * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine * 3 - all other cases are handled using a simple loop along the outer-storage direction. * Therefore we need a lower level meta selector. * Furthermore, if the matrix is the rhs, then the product has to be transposed. */ namespace internal { template struct gemv_dense_selector; } // end namespace internal namespace internal { template struct gemv_static_vector_if; template struct gemv_static_vector_if { EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } }; template struct gemv_static_vector_if { EIGEN_STRONG_INLINE Scalar* data() { return 0; } }; template struct gemv_static_vector_if { enum { ForceAlignment = internal::packet_traits::Vectorizable, PacketSize = internal::packet_traits::size }; #if EIGEN_MAX_STATIC_ALIGN_BYTES!=0 internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } #else // Some architectures cannot align on the stack, // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return ForceAlignment ? reinterpret_cast((internal::UIntPtr(m_data.array) & ~(std::size_t(EIGEN_MAX_ALIGN_BYTES-1))) + EIGEN_MAX_ALIGN_BYTES) : m_data.array; } #endif }; // The vector is on the left => transposition template struct gemv_dense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { Transpose destT(dest); enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; gemv_dense_selector ::run(rhs.transpose(), lhs.transpose(), destT, alpha); } }; template<> struct gemv_dense_selector { template static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; typedef typename Dest::Scalar ResScalar; typedef typename Dest::RealScalar RealScalar; typedef internal::blas_traits LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; typedef internal::blas_traits RhsBlasTraits; typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) * RhsBlasTraits::extractScalarFactor(rhs); // make sure Dest is a compile-time vector type (bug 1166) typedef typename conditional::type ActualDest; enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... EvalToDestAtCompileTime = (ActualDest::InnerStrideAtCompileTime==1), ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), MightCannotUseDest = (!EvalToDestAtCompileTime) || ComplexByReal }; typedef const_blas_data_mapper LhsMapper; typedef const_blas_data_mapper RhsMapper; RhsScalar compatibleAlpha = get_factor::run(actualAlpha); if(!MightCannotUseDest) { // shortcut if we are sure to be able to use dest directly, // this ease the compiler to generate cleaner and more optimzized code for most common cases general_matrix_vector_product ::run( actualLhs.rows(), actualLhs.cols(), LhsMapper(actualLhs.data(), actualLhs.outerStride()), RhsMapper(actualRhs.data(), actualRhs.innerStride()), dest.data(), 1, compatibleAlpha); } else { gemv_static_vector_if static_dest; const bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); const bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), evalToDest ? dest.data() : static_dest.data()); if(!evalToDest) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN Index size = dest.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif if(!alphaIsCompatible) { MappedDest(actualDestPtr, dest.size()).setZero(); compatibleAlpha = RhsScalar(1); } else MappedDest(actualDestPtr, dest.size()) = dest; } general_matrix_vector_product ::run( actualLhs.rows(), actualLhs.cols(), LhsMapper(actualLhs.data(), actualLhs.outerStride()), RhsMapper(actualRhs.data(), actualRhs.innerStride()), actualDestPtr, 1, compatibleAlpha); if (!evalToDest) { if(!alphaIsCompatible) dest.matrix() += actualAlpha * MappedDest(actualDestPtr, dest.size()); else dest = MappedDest(actualDestPtr, dest.size()); } } } }; template<> struct gemv_dense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { typedef typename Lhs::Scalar LhsScalar; typedef typename Rhs::Scalar RhsScalar; typedef typename Dest::Scalar ResScalar; typedef internal::blas_traits LhsBlasTraits; typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; typedef internal::blas_traits RhsBlasTraits; typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; typedef typename internal::remove_all::type ActualRhsTypeCleaned; typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 }; gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); if(!DirectlyUseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN Index size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif Map(actualRhsPtr, actualRhs.size()) = actualRhs; } typedef const_blas_data_mapper LhsMapper; typedef const_blas_data_mapper RhsMapper; general_matrix_vector_product ::run( actualLhs.rows(), actualLhs.cols(), LhsMapper(actualLhs.data(), actualLhs.outerStride()), RhsMapper(actualRhsPtr, 1), dest.data(), dest.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) actualAlpha); } }; template<> struct gemv_dense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); // TODO if rhs is large enough it might be beneficial to make sure that dest is sequentially stored in memory, otherwise use a temp typename nested_eval::type actual_rhs(rhs); const Index size = rhs.rows(); for(Index k=0; k struct gemv_dense_selector { template static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); typename nested_eval::type actual_rhs(rhs); const Index rows = dest.rows(); for(Index i=0; i template inline const Product MatrixBase::operator*(const MatrixBase &other) const { // A note regarding the function declaration: In MSVC, this function will sometimes // not be inlined since DenseStorage is an unwindable object for dynamic // matrices and product types are holding a member to store the result. // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. enum { ProductIsValid = Derived::ColsAtCompileTime==Dynamic || OtherDerived::RowsAtCompileTime==Dynamic || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) }; // note to the lost user: // * for a dot product use: v1.dot(v2) // * for a coeff-wise product use: v1.cwiseProduct(v2) EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) #ifdef EIGEN_DEBUG_PRODUCT internal::product_type::debug(); #endif return Product(derived(), other.derived()); } /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * * The returned product will behave like any other expressions: the coefficients of the product will be * computed once at a time as requested. This might be useful in some extremely rare cases when only * a small and no coherent fraction of the result's coefficients have to be computed. * * \warning This version of the matrix product can be much much slower. So use it only if you know * what you are doing and that you measured a true speed improvement. * * \sa operator*(const MatrixBase&) */ template template const Product MatrixBase::lazyProduct(const MatrixBase &other) const { enum { ProductIsValid = Derived::ColsAtCompileTime==Dynamic || OtherDerived::RowsAtCompileTime==Dynamic || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) }; // note to the lost user: // * for a dot product use: v1.dot(v2) // * for a coeff-wise product use: v1.cwiseProduct(v2) EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) return Product(derived(), other.derived()); } } // end namespace Eigen #endif // EIGEN_PRODUCT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/GenericPacketMath.h000066400000000000000000000530651506104011400252770ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GENERIC_PACKET_MATH_H #define EIGEN_GENERIC_PACKET_MATH_H namespace Eigen { namespace internal { /** \internal * \file GenericPacketMath.h * * Default implementation for types not supported by the vectorization. * In practice these functions are provided to make easier the writing * of generic vectorized code. */ #ifndef EIGEN_DEBUG_ALIGNED_LOAD #define EIGEN_DEBUG_ALIGNED_LOAD #endif #ifndef EIGEN_DEBUG_UNALIGNED_LOAD #define EIGEN_DEBUG_UNALIGNED_LOAD #endif #ifndef EIGEN_DEBUG_ALIGNED_STORE #define EIGEN_DEBUG_ALIGNED_STORE #endif #ifndef EIGEN_DEBUG_UNALIGNED_STORE #define EIGEN_DEBUG_UNALIGNED_STORE #endif struct default_packet_traits { enum { HasHalfPacket = 0, HasAdd = 1, HasSub = 1, HasMul = 1, HasNegate = 1, HasAbs = 1, HasArg = 0, HasAbs2 = 1, HasMin = 1, HasMax = 1, HasConj = 1, HasSetLinear = 1, HasBlend = 0, HasDiv = 0, HasSqrt = 0, HasRsqrt = 0, HasExp = 0, HasLog = 0, HasLog1p = 0, HasLog10 = 0, HasPow = 0, HasSin = 0, HasCos = 0, HasTan = 0, HasASin = 0, HasACos = 0, HasATan = 0, HasSinh = 0, HasCosh = 0, HasTanh = 0, HasLGamma = 0, HasDiGamma = 0, HasZeta = 0, HasPolygamma = 0, HasErf = 0, HasErfc = 0, HasIGamma = 0, HasIGammac = 0, HasBetaInc = 0, HasRound = 0, HasFloor = 0, HasCeil = 0, HasSign = 0 }; }; template struct packet_traits : default_packet_traits { typedef T type; typedef T half; enum { Vectorizable = 0, size = 1, AlignedOnScalar = 0, HasHalfPacket = 0 }; enum { HasAdd = 0, HasSub = 0, HasMul = 0, HasNegate = 0, HasAbs = 0, HasAbs2 = 0, HasMin = 0, HasMax = 0, HasConj = 0, HasSetLinear = 0 }; }; template struct packet_traits : packet_traits { }; template struct type_casting_traits { enum { VectorizedCast = 0, SrcCoeffRatio = 1, TgtCoeffRatio = 1 }; }; /** \internal \returns static_cast(a) (coeff-wise) */ template EIGEN_DEVICE_FUNC inline TgtPacket pcast(const SrcPacket& a) { return static_cast(a); } template EIGEN_DEVICE_FUNC inline TgtPacket pcast(const SrcPacket& a, const SrcPacket& /*b*/) { return static_cast(a); } template EIGEN_DEVICE_FUNC inline TgtPacket pcast(const SrcPacket& a, const SrcPacket& /*b*/, const SrcPacket& /*c*/, const SrcPacket& /*d*/) { return static_cast(a); } /** \internal \returns a + b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet padd(const Packet& a, const Packet& b) { return a+b; } /** \internal \returns a - b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet psub(const Packet& a, const Packet& b) { return a-b; } /** \internal \returns -a (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pnegate(const Packet& a) { return -a; } /** \internal \returns conj(a) (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pconj(const Packet& a) { return numext::conj(a); } /** \internal \returns a * b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmul(const Packet& a, const Packet& b) { return a*b; } /** \internal \returns a / b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pdiv(const Packet& a, const Packet& b) { return a/b; } /** \internal \returns the min of \a a and \a b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmin(const Packet& a, const Packet& b) { return numext::mini(a, b); } /** \internal \returns the max of \a a and \a b (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmax(const Packet& a, const Packet& b) { return numext::maxi(a, b); } /** \internal \returns the absolute value of \a a */ template EIGEN_DEVICE_FUNC inline Packet pabs(const Packet& a) { using std::abs; return abs(a); } /** \internal \returns the phase angle of \a a */ template EIGEN_DEVICE_FUNC inline Packet parg(const Packet& a) { using numext::arg; return arg(a); } /** \internal \returns the bitwise and of \a a and \a b */ template EIGEN_DEVICE_FUNC inline Packet pand(const Packet& a, const Packet& b) { return a & b; } /** \internal \returns the bitwise or of \a a and \a b */ template EIGEN_DEVICE_FUNC inline Packet por(const Packet& a, const Packet& b) { return a | b; } /** \internal \returns the bitwise xor of \a a and \a b */ template EIGEN_DEVICE_FUNC inline Packet pxor(const Packet& a, const Packet& b) { return a ^ b; } /** \internal \returns the bitwise andnot of \a a and \a b */ template EIGEN_DEVICE_FUNC inline Packet pandnot(const Packet& a, const Packet& b) { return a & (!b); } /** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ template EIGEN_DEVICE_FUNC inline Packet pload(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet version of \a *from, (un-aligned load) */ template EIGEN_DEVICE_FUNC inline Packet ploadu(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ template EIGEN_DEVICE_FUNC inline Packet pset1(const typename unpacket_traits::type& a) { return a; } /** \internal \returns a packet with constant coefficients \a a[0], e.g.: (a[0],a[0],a[0],a[0]) */ template EIGEN_DEVICE_FUNC inline Packet pload1(const typename unpacket_traits::type *a) { return pset1(*a); } /** \internal \returns a packet with elements of \a *from duplicated. * For instance, for a packet of 8 elements, 4 scalars will be read from \a *from and * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]} * Currently, this function is only used for scalar * complex products. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet ploaddup(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet with elements of \a *from quadrupled. * For instance, for a packet of 8 elements, 2 scalars will be read from \a *from and * replicated to form: {from[0],from[0],from[0],from[0],from[1],from[1],from[1],from[1]} * Currently, this function is only used in matrix products. * For packet-size smaller or equal to 4, this function is equivalent to pload1 */ template EIGEN_DEVICE_FUNC inline Packet ploadquad(const typename unpacket_traits::type* from) { return pload1(from); } /** \internal equivalent to * \code * a0 = pload1(a+0); * a1 = pload1(a+1); * a2 = pload1(a+2); * a3 = pload1(a+3); * \endcode * \sa pset1, pload1, ploaddup, pbroadcast2 */ template EIGEN_DEVICE_FUNC inline void pbroadcast4(const typename unpacket_traits::type *a, Packet& a0, Packet& a1, Packet& a2, Packet& a3) { a0 = pload1(a+0); a1 = pload1(a+1); a2 = pload1(a+2); a3 = pload1(a+3); } /** \internal equivalent to * \code * a0 = pload1(a+0); * a1 = pload1(a+1); * \endcode * \sa pset1, pload1, ploaddup, pbroadcast4 */ template EIGEN_DEVICE_FUNC inline void pbroadcast2(const typename unpacket_traits::type *a, Packet& a0, Packet& a1) { a0 = pload1(a+0); a1 = pload1(a+1); } /** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet plset(const typename unpacket_traits::type& a) { return a; } /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ template EIGEN_DEVICE_FUNC inline void pstore(Scalar* to, const Packet& from) { (*to) = from; } /** \internal copy the packet \a from to \a *to, (un-aligned store) */ template EIGEN_DEVICE_FUNC inline void pstoreu(Scalar* to, const Packet& from) { (*to) = from; } template EIGEN_DEVICE_FUNC inline Packet pgather(const Scalar* from, Index /*stride*/) { return ploadu(from); } template EIGEN_DEVICE_FUNC inline void pscatter(Scalar* to, const Packet& from, Index /*stride*/) { pstore(to, from); } /** \internal tries to do cache prefetching of \a addr */ template EIGEN_DEVICE_FUNC inline void prefetch(const Scalar* addr) { #ifdef __CUDA_ARCH__ #if defined(__LP64__) // 64-bit pointer operand constraint for inlined asm asm(" prefetch.L1 [ %1 ];" : "=l"(addr) : "l"(addr)); #else // 32-bit pointer operand constraint for inlined asm asm(" prefetch.L1 [ %1 ];" : "=r"(addr) : "r"(addr)); #endif #elif (!EIGEN_COMP_MSVC) && (EIGEN_COMP_GNUC || EIGEN_COMP_CLANG || EIGEN_COMP_ICC) __builtin_prefetch(addr); #endif } /** \internal \returns the first element of a packet */ template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type pfirst(const Packet& a) { return a; } /** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ template EIGEN_DEVICE_FUNC inline Packet preduxp(const Packet* vecs) { return vecs[0]; } /** \internal \returns the sum of the elements of \a a*/ template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux(const Packet& a) { return a; } /** \internal \returns the sum of the elements of \a a by block of 4 elements. * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7} * For packet-size smaller or equal to 4, this boils down to a noop. */ template EIGEN_DEVICE_FUNC inline typename conditional<(unpacket_traits::size%8)==0,typename unpacket_traits::half,Packet>::type predux_downto4(const Packet& a) { return a; } /** \internal \returns the product of the elements of \a a*/ template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_mul(const Packet& a) { return a; } /** \internal \returns the min of the elements of \a a*/ template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min(const Packet& a) { return a; } /** \internal \returns the max of the elements of \a a*/ template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max(const Packet& a) { return a; } /** \internal \returns the reversed elements of \a a*/ template EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a) { return a; } /** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ template EIGEN_DEVICE_FUNC inline Packet pcplxflip(const Packet& a) { return Packet(a.imag(),a.real()); } /************************** * Special math functions ***************************/ /** \internal \returns the sine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psin(const Packet& a) { using std::sin; return sin(a); } /** \internal \returns the cosine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pcos(const Packet& a) { using std::cos; return cos(a); } /** \internal \returns the tan of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet ptan(const Packet& a) { using std::tan; return tan(a); } /** \internal \returns the arc sine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pasin(const Packet& a) { using std::asin; return asin(a); } /** \internal \returns the arc cosine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pacos(const Packet& a) { using std::acos; return acos(a); } /** \internal \returns the arc tangent of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet patan(const Packet& a) { using std::atan; return atan(a); } /** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psinh(const Packet& a) { using std::sinh; return sinh(a); } /** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pcosh(const Packet& a) { using std::cosh; return cosh(a); } /** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet ptanh(const Packet& a) { using std::tanh; return tanh(a); } /** \internal \returns the exp of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { using std::exp; return exp(a); } /** \internal \returns the log of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet& a) { using std::log; return log(a); } /** \internal \returns the log1p of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog1p(const Packet& a) { return numext::log1p(a); } /** \internal \returns the log10 of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog10(const Packet& a) { using std::log10; return log10(a); } /** \internal \returns the square-root of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } /** \internal \returns the reciprocal square-root of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet prsqrt(const Packet& a) { return pdiv(pset1(1), psqrt(a)); } /** \internal \returns the rounded value of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pround(const Packet& a) { using numext::round; return round(a); } /** \internal \returns the floor of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } /** \internal \returns the ceil of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } /*************************************************************************** * The following functions might not have to be overwritten for vectorized types ***************************************************************************/ /** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ // NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) template inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) { pstore(to, pset1(a)); } /** \internal \returns a * b + c (coeff-wise) */ template EIGEN_DEVICE_FUNC inline Packet pmadd(const Packet& a, const Packet& b, const Packet& c) { return padd(pmul(a, b),c); } /** \internal \returns a packet version of \a *from. * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt(const typename unpacket_traits::type* from) { if(Alignment >= unpacket_traits::alignment) return pload(from); else return ploadu(from); } /** \internal copy the packet \a from to \a *to. * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& from) { if(Alignment >= unpacket_traits::alignment) pstore(to, from); else pstoreu(to, from); } /** \internal \returns a packet version of \a *from. * Unlike ploadt, ploadt_ro takes advantage of the read-only memory path on the * hardware if available to speedup the loading of data that won't be modified * by the current computation. */ template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt_ro(const typename unpacket_traits::type* from) { return ploadt(from); } /** \internal default implementation of palign() allowing partial specialization */ template struct palign_impl { // by default data are aligned, so there is nothing to be done :) static inline void run(PacketType&, const PacketType&) {} }; /** \internal update \a first using the concatenation of the packet_size minus \a Offset last elements * of \a first and \a Offset first elements of \a second. * * This function is currently only used to optimize matrix-vector products on unligned matrices. * It takes 2 packets that represent a contiguous memory array, and returns a packet starting * at the position \a Offset. For instance, for packets of 4 elements, we have: * Input: * - first = {f0,f1,f2,f3} * - second = {s0,s1,s2,s3} * Output: * - if Offset==0 then {f0,f1,f2,f3} * - if Offset==1 then {f1,f2,f3,s0} * - if Offset==2 then {f2,f3,s0,s1} * - if Offset==3 then {f3,s0,s1,s3} */ template inline void palign(PacketType& first, const PacketType& second) { palign_impl::run(first,second); } /*************************************************************************** * Fast complex products (GCC generates a function call which is very slow) ***************************************************************************/ // Eigen+CUDA does not support complexes. #ifndef __CUDACC__ template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(a.real()*b.real() - a.imag()*b.imag(), a.imag()*b.real() + a.real()*b.imag()); } template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(a.real()*b.real() - a.imag()*b.imag(), a.imag()*b.real() + a.real()*b.imag()); } #endif /*************************************************************************** * PacketBlock, that is a collection of N packets where the number of words * in the packet is a multiple of N. ***************************************************************************/ template ::size> struct PacketBlock { Packet packet[N]; }; template EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock& /*kernel*/) { // Nothing to do in the scalar case, i.e. a 1x1 matrix. } /*************************************************************************** * Selector, i.e. vector of N boolean values used to select (i.e. blend) * words from 2 packets. ***************************************************************************/ template struct Selector { bool select[N]; }; template EIGEN_DEVICE_FUNC inline Packet pblend(const Selector::size>& ifPacket, const Packet& thenPacket, const Packet& elsePacket) { return ifPacket.select[0] ? thenPacket : elsePacket; } /** \internal \returns \a a with the first coefficient replaced by the scalar b */ template EIGEN_DEVICE_FUNC inline Packet pinsertfirst(const Packet& a, typename unpacket_traits::type b) { // Default implementation based on pblend. // It must be specialized for higher performance. Selector::size> mask; mask.select[0] = true; // This for loop should be optimized away by the compiler. for(Index i=1; i::size; ++i) mask.select[i] = false; return pblend(mask, pset1(b), a); } /** \internal \returns \a a with the last coefficient replaced by the scalar b */ template EIGEN_DEVICE_FUNC inline Packet pinsertlast(const Packet& a, typename unpacket_traits::type b) { // Default implementation based on pblend. // It must be specialized for higher performance. Selector::size> mask; // This for loop should be optimized away by the compiler. for(Index i=0; i::size-1; ++i) mask.select[i] = false; mask.select[unpacket_traits::size-1] = true; return pblend(mask, pset1(b), a); } } // end namespace internal } // end namespace Eigen #endif // EIGEN_GENERIC_PACKET_MATH_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/GlobalFunctions.h000066400000000000000000000237561506104011400250560ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2010-2016 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H #ifdef EIGEN_PARSED_BY_DOXYGEN #define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ /** \returns an expression of the coefficient-wise DOC_OP of \a x DOC_DETAILS \sa Math functions, class CwiseUnaryOp */ \ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ NAME(const Eigen::ArrayBase& x); #else #define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ (NAME)(const Eigen::ArrayBase& x) { \ return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ } #endif // EIGEN_PARSED_BY_DOXYGEN #define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ \ template \ struct NAME##_retval > \ { \ typedef const Eigen::CwiseUnaryOp, const Derived> type; \ }; \ template \ struct NAME##_impl > \ { \ static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ { \ return typename NAME##_retval >::type(x.derived()); \ } \ }; namespace Eigen { EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op,real part,\sa ArrayBase::real) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op,imaginary part,\sa ArrayBase::imag) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op,complex conjugate,\sa ArrayBase::conjugate) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op,inverse,\sa ArrayBase::inverse) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op,sine,\sa ArrayBase::sin) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op,cosine,\sa ArrayBase::cos) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op,tangent,\sa ArrayBase::tan) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op,arc-tangent,\sa ArrayBase::atan) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op,arc-sine,\sa ArrayBase::asin) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op,arc-consine,\sa ArrayBase::acos) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op,hyperbolic sine,\sa ArrayBase::sinh) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op,hyperbolic cosine,\sa ArrayBase::cosh) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op,hyperbolic tangent,\sa ArrayBase::tanh) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(lgamma,scalar_lgamma_op,natural logarithm of the gamma function,\sa ArrayBase::lgamma) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(digamma,scalar_digamma_op,derivative of lgamma,\sa ArrayBase::digamma) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf,scalar_erf_op,error function,\sa ArrayBase::erf) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc,scalar_erfc_op,complement error function,\sa ArrayBase::erfc) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op,exponential,\sa ArrayBase::exp) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op,natural logarithm,\sa Eigen::log10 DOXCOMMA ArrayBase::log) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log1p,scalar_log1p_op,natural logarithm of 1 plus the value,\sa ArrayBase::log1p) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op,base 10 logarithm,\sa Eigen::log DOXCOMMA ArrayBase::log) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op,absolute value,\sa ArrayBase::abs DOXCOMMA MatrixBase::cwiseAbs) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op,squared absolute value,\sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op,complex argument,\sa ArrayBase::arg) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op,square root,\sa ArrayBase::sqrt DOXCOMMA MatrixBase::cwiseSqrt) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(rsqrt,scalar_rsqrt_op,reciprocal square root,\sa ArrayBase::rsqrt) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op,square (power 2),\sa Eigen::abs2 DOXCOMMA Eigen::pow DOXCOMMA ArrayBase::square) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op,cube (power 3),\sa Eigen::pow DOXCOMMA ArrayBase::cube) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op,nearest integer,\sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op,nearest integer not greater than the giben value,\sa Eigen::ceil DOXCOMMA ArrayBase::floor) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op,nearest integer not less than the giben value,\sa Eigen::floor DOXCOMMA ArrayBase::ceil) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isnan,scalar_isnan_op,not-a-number test,\sa Eigen::isinf DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isnan) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isinf,scalar_isinf_op,infinite value test,\sa Eigen::isnan DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isinf) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isfinite,scalar_isfinite_op,finite value test,\sa Eigen::isinf DOXCOMMA Eigen::isnan DOXCOMMA ArrayBase::isfinite) EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op,sign (or 0),\sa ArrayBase::sign) /** \returns an expression of the coefficient-wise power of \a x to the given constant \a exponent. * * \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression (\c Derived::Scalar). * * \sa ArrayBase::pow() * * \relates ArrayBase */ #ifdef EIGEN_PARSED_BY_DOXYGEN template inline const CwiseBinaryOp,Derived,Constant > pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent); #else template inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,typename Derived::Scalar,ScalarExponent), const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,ScalarExponent,pow) >::type pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent) { return x.derived().pow(exponent); } template inline const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename Derived::Scalar,pow) pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { return x.derived().pow(exponent); } #endif /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. * * This function computes the coefficient-wise power. * * Example: \include Cwise_array_power_array.cpp * Output: \verbinclude Cwise_array_power_array.out * * \sa ArrayBase::pow() * * \relates ArrayBase */ template inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) { return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( x.derived(), exponents.derived() ); } /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. * * This function computes the coefficient-wise power between a scalar and an array of exponents. * * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). * * Example: \include Cwise_scalar_power_array.cpp * Output: \verbinclude Cwise_scalar_power_array.out * * \sa ArrayBase::pow() * * \relates ArrayBase */ #ifdef EIGEN_PARSED_BY_DOXYGEN template inline const CwiseBinaryOp,Constant,Derived> pow(const Scalar& x,const Eigen::ArrayBase& x); #else template inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,Scalar,typename Derived::Scalar), const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow) >::type pow(const Scalar& x, const Eigen::ArrayBase& exponents) { return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow)( typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); } template inline const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow) pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) { return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow)( typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); } #endif namespace internal { EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) } } // TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) #endif // EIGEN_GLOBAL_FUNCTIONS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/IO.h000066400000000000000000000156441506104011400222710ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_IO_H #define EIGEN_IO_H namespace Eigen { enum { DontAlignCols = 1 }; enum { StreamPrecision = -1, FullPrecision = -2 }; namespace internal { template std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); } /** \class IOFormat * \ingroup Core_Module * * \brief Stores a set of parameters controlling the way matrices are printed * * List of available parameters: * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. * The default is the special value \c StreamPrecision which means to use the * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point * type. * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which * allows to disable the alignment of columns, resulting in faster code. * - \b coeffSeparator string printed between two coefficients of the same row * - \b rowSeparator string printed between two rows * - \b rowPrefix string printed at the beginning of each row * - \b rowSuffix string printed at the end of each row * - \b matPrefix string printed at the beginning of the matrix * - \b matSuffix string printed at the end of the matrix * * Example: \include IOFormat.cpp * Output: \verbinclude IOFormat.out * * \sa DenseBase::format(), class WithFormat */ struct IOFormat { /** Default constructor, see class IOFormat for the meaning of the parameters */ IOFormat(int _precision = StreamPrecision, int _flags = 0, const std::string& _coeffSeparator = " ", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", const std::string& _matPrefix="", const std::string& _matSuffix="") : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) { // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline // don't add rowSpacer if columns are not to be aligned if((flags & DontAlignCols)) return; int i = int(matSuffix.length())-1; while (i>=0 && matSuffix[i]!='\n') { rowSpacer += ' '; i--; } } std::string matPrefix, matSuffix; std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; std::string coeffSeparator; int precision; int flags; }; /** \class WithFormat * \ingroup Core_Module * * \brief Pseudo expression providing matrix output with given format * * \tparam ExpressionType the type of the object on which IO stream operations are performed * * This class represents an expression with stream operators controlled by a given IOFormat. * It is the return type of DenseBase::format() * and most of the time this is the only way it is used. * * See class IOFormat for some examples. * * \sa DenseBase::format(), class IOFormat */ template class WithFormat { public: WithFormat(const ExpressionType& matrix, const IOFormat& format) : m_matrix(matrix), m_format(format) {} friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) { return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); } protected: typename ExpressionType::Nested m_matrix; IOFormat m_format; }; namespace internal { // NOTE: This helper is kept for backward compatibility with previous code specializing // this internal::significant_decimals_impl structure. In the future we should directly // call digits10() which has been introduced in July 2016 in 3.3. template struct significant_decimals_impl { static inline int run() { return NumTraits::digits10(); } }; /** \internal * print the matrix \a _m to the output stream \a s using the output format \a fmt */ template std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) { if(_m.size() == 0) { s << fmt.matPrefix << fmt.matSuffix; return s; } typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; Index width = 0; std::streamsize explicit_precision; if(fmt.precision == StreamPrecision) { explicit_precision = 0; } else if(fmt.precision == FullPrecision) { if (NumTraits::IsInteger) { explicit_precision = 0; } else { explicit_precision = significant_decimals_impl::run(); } } else { explicit_precision = fmt.precision; } std::streamsize old_precision = 0; if(explicit_precision) old_precision = s.precision(explicit_precision); bool align_cols = !(fmt.flags & DontAlignCols); if(align_cols) { // compute the largest width for(Index j = 0; j < m.cols(); ++j) for(Index i = 0; i < m.rows(); ++i) { std::stringstream sstr; sstr.copyfmt(s); sstr << m.coeff(i,j); width = std::max(width, Index(sstr.str().length())); } } s << fmt.matPrefix; for(Index i = 0; i < m.rows(); ++i) { if (i) s << fmt.rowSpacer; s << fmt.rowPrefix; if(width) s.width(width); s << m.coeff(i, 0); for(Index j = 1; j < m.cols(); ++j) { s << fmt.coeffSeparator; if (width) s.width(width); s << m.coeff(i, j); } s << fmt.rowSuffix; if( i < m.rows() - 1) s << fmt.rowSeparator; } s << fmt.matSuffix; if(explicit_precision) s.precision(old_precision); return s; } } // end namespace internal /** \relates DenseBase * * Outputs the matrix, to the given stream. * * If you wish to print the matrix with a format different than the default, use DenseBase::format(). * * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. * * \sa DenseBase::format() */ template std::ostream & operator << (std::ostream & s, const DenseBase & m) { return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); } } // end namespace Eigen #endif // EIGEN_IO_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Inverse.h000066400000000000000000000066771506104011400234030ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_INVERSE_H #define EIGEN_INVERSE_H namespace Eigen { template class InverseImpl; namespace internal { template struct traits > : traits { typedef typename XprType::PlainObject PlainObject; typedef traits BaseTraits; enum { Flags = BaseTraits::Flags & RowMajorBit }; }; } // end namespace internal /** \class Inverse * * \brief Expression of the inverse of another expression * * \tparam XprType the type of the expression we are taking the inverse * * This class represents an abstract expression of A.inverse() * and most of the time this is the only way it is used. * */ template class Inverse : public InverseImpl::StorageKind> { public: typedef typename XprType::StorageIndex StorageIndex; typedef typename XprType::PlainObject PlainObject; typedef typename XprType::Scalar Scalar; typedef typename internal::ref_selector::type XprTypeNested; typedef typename internal::remove_all::type XprTypeNestedCleaned; typedef typename internal::ref_selector::type Nested; typedef typename internal::remove_all::type NestedExpression; explicit EIGEN_DEVICE_FUNC Inverse(const XprType &xpr) : m_xpr(xpr) {} EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } protected: XprTypeNested m_xpr; }; // Generic API dispatcher template class InverseImpl : public internal::generic_xpr_base >::type { public: typedef typename internal::generic_xpr_base >::type Base; typedef typename XprType::Scalar Scalar; private: Scalar coeff(Index row, Index col) const; Scalar coeff(Index i) const; }; namespace internal { /** \internal * \brief Default evaluator for Inverse expression. * * This default evaluator for Inverse expression simply evaluate the inverse into a temporary * by a call to internal::call_assignment_no_alias. * Therefore, inverse implementers only have to specialize Assignment, ...> for * there own nested expression. * * \sa class Inverse */ template struct unary_evaluator > : public evaluator::PlainObject> { typedef Inverse InverseType; typedef typename InverseType::PlainObject PlainObject; typedef evaluator Base; enum { Flags = Base::Flags | EvalBeforeNestingBit }; unary_evaluator(const InverseType& inv_xpr) : m_result(inv_xpr.rows(), inv_xpr.cols()) { ::new (static_cast(this)) Base(m_result); internal::call_assignment_no_alias(m_result, inv_xpr); } protected: PlainObject m_result; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_INVERSE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Map.h000066400000000000000000000161071506104011400224720ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MAP_H #define EIGEN_MAP_H namespace Eigen { namespace internal { template struct traits > : public traits { typedef traits TraitsBase; enum { PlainObjectTypeInnerSize = ((traits::Flags&RowMajorBit)==RowMajorBit) ? PlainObjectType::ColsAtCompileTime : PlainObjectType::RowsAtCompileTime, InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 ? int(PlainObjectType::InnerStrideAtCompileTime) : int(StrideType::InnerStrideAtCompileTime), OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 ? (InnerStrideAtCompileTime==Dynamic || PlainObjectTypeInnerSize==Dynamic ? Dynamic : int(InnerStrideAtCompileTime) * int(PlainObjectTypeInnerSize)) : int(StrideType::OuterStrideAtCompileTime), Alignment = int(MapOptions)&int(AlignedMask), Flags0 = TraitsBase::Flags & (~NestByRefBit), Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) }; private: enum { Options }; // Expressions don't have Options }; } /** \class Map * \ingroup Core_Module * * \brief A matrix or vector expression mapping an existing array of data. * * \tparam PlainObjectType the equivalent matrix type of the mapped data * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout * of an ordinary, contiguous array. This can be overridden by specifying strides. * The type passed here must be a specialization of the Stride template, see examples below. * * This class represents a matrix or vector expression mapping an existing array of data. * It can be used to let Eigen interface without any overhead with non-Eigen data structures, * such as plain C arrays or structures from other libraries. By default, it assumes that the * data is laid out contiguously in memory. You can however override this by explicitly specifying * inner and outer strides. * * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix: * \include Map_simple.cpp * Output: \verbinclude Map_simple.out * * If you need to map non-contiguous arrays, you can do so by specifying strides: * * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time * fixed value. * \include Map_inner_stride.cpp * Output: \verbinclude Map_inner_stride.out * * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns. * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is * a short version of \c OuterStride because the default template parameter of OuterStride * is \c Dynamic * \include Map_outer_stride.cpp * Output: \verbinclude Map_outer_stride.out * * For more details and for an example of specifying both an inner and an outer stride, see class Stride. * * \b Tip: to change the array of data mapped by a Map object, you can use the C++ * placement new syntax: * * Example: \include Map_placement_new.cpp * Output: \verbinclude Map_placement_new.out * * This class is the return type of PlainObjectBase::Map() but can also be used directly. * * \sa PlainObjectBase::Map(), \ref TopicStorageOrders */ template class Map : public MapBase > { public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Map) typedef typename Base::PointerType PointerType; typedef PointerType PointerArgType; EIGEN_DEVICE_FUNC inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } EIGEN_DEVICE_FUNC inline Index outerStride() const { return int(StrideType::OuterStrideAtCompileTime) != 0 ? m_stride.outer() : int(internal::traits::OuterStrideAtCompileTime) != Dynamic ? Index(internal::traits::OuterStrideAtCompileTime) : IsVectorAtCompileTime ? (this->size() * innerStride()) : (int(Flags)&RowMajorBit) ? (this->cols() * innerStride()) : (this->rows() * innerStride()); } /** Constructor in the fixed-size case. * * \param dataPtr pointer to the array to map * \param stride optional Stride object, passing the strides. */ EIGEN_DEVICE_FUNC explicit inline Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(dataPtr)), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } /** Constructor in the dynamic-size vector case. * * \param dataPtr pointer to the array to map * \param size the size of the vector expression * \param stride optional Stride object, passing the strides. */ EIGEN_DEVICE_FUNC inline Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(dataPtr), size), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } /** Constructor in the dynamic-size matrix case. * * \param dataPtr pointer to the array to map * \param rows the number of rows of the matrix expression * \param cols the number of columns of the matrix expression * \param stride optional Stride object, passing the strides. */ EIGEN_DEVICE_FUNC inline Map(PointerArgType dataPtr, Index rows, Index cols, const StrideType& stride = StrideType()) : Base(cast_to_pointer_type(dataPtr), rows, cols), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) protected: StrideType m_stride; }; } // end namespace Eigen #endif // EIGEN_MAP_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/MapBase.h000066400000000000000000000257141506104011400232710ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2007-2010 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MAPBASE_H #define EIGEN_MAPBASE_H #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) namespace Eigen { /** \ingroup Core_Module * * \brief Base class for dense Map and Block expression with direct access * * This base class provides the const low-level accessors (e.g. coeff, coeffRef) of dense * Map and Block objects with direct access. * Typical users do not have to directly deal with this class. * * This class can be extended by through the macro plugin \c EIGEN_MAPBASE_PLUGIN. * See \link TopicCustomizing_Plugins customizing Eigen \endlink for details. * * The \c Derived class has to provide the following two methods describing the memory layout: * \code Index innerStride() const; \endcode * \code Index outerStride() const; \endcode * * \sa class Map, class Block */ template class MapBase : public internal::dense_xpr_base::type { public: typedef typename internal::dense_xpr_base::type Base; enum { RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, InnerStrideAtCompileTime = internal::traits::InnerStrideAtCompileTime, SizeAtCompileTime = Base::SizeAtCompileTime }; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef typename internal::conditional< bool(internal::is_lvalue::value), Scalar *, const Scalar *>::type PointerType; using Base::derived; // using Base::RowsAtCompileTime; // using Base::ColsAtCompileTime; // using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::IsRowMajor; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::eval; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; // bug 217 - compile error on ICC 11.1 using Base::operator=; typedef typename Base::CoeffReturnType CoeffReturnType; /** \copydoc DenseBase::rows() */ EIGEN_DEVICE_FUNC inline Index rows() const { return m_rows.value(); } /** \copydoc DenseBase::cols() */ EIGEN_DEVICE_FUNC inline Index cols() const { return m_cols.value(); } /** Returns a pointer to the first coefficient of the matrix or vector. * * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride(). * * \sa innerStride(), outerStride() */ EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } /** \copydoc PlainObjectBase::coeff(Index,Index) const */ EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index rowId, Index colId) const { return m_data[colId * colStride() + rowId * rowStride()]; } /** \copydoc PlainObjectBase::coeff(Index) const */ EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return m_data[index * innerStride()]; } /** \copydoc PlainObjectBase::coeffRef(Index,Index) const */ EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return this->m_data[colId * colStride() + rowId * rowStride()]; } /** \copydoc PlainObjectBase::coeffRef(Index) const */ EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } /** \internal */ template inline PacketScalar packet(Index rowId, Index colId) const { return internal::ploadt (m_data + (colId * colStride() + rowId * rowStride())); } /** \internal */ template inline PacketScalar packet(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return internal::ploadt(m_data + index * innerStride()); } /** \internal Constructor for fixed size matrices or vectors */ EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) checkSanity(); } /** \internal Constructor for dynamically sized vectors */ EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : m_data(dataPtr), m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), m_cols(ColsAtCompileTime == Dynamic ? vecSize : Index(ColsAtCompileTime)) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) eigen_assert(vecSize >= 0); eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); checkSanity(); } /** \internal Constructor for dynamically sized matrices */ EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : m_data(dataPtr), m_rows(rows), m_cols(cols) { eigen_assert( (dataPtr == 0) || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); checkSanity(); } #ifdef EIGEN_MAPBASE_PLUGIN #include EIGEN_MAPBASE_PLUGIN #endif protected: EIGEN_DEFAULT_COPY_CONSTRUCTOR(MapBase) EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MapBase) template EIGEN_DEVICE_FUNC void checkSanity(typename internal::enable_if<(internal::traits::Alignment>0),void*>::type = 0) const { #if EIGEN_MAX_ALIGN_BYTES>0 // innerStride() is not set yet when this function is called, so we optimistically assume the lowest plausible value: const Index minInnerStride = InnerStrideAtCompileTime == Dynamic ? 1 : Index(InnerStrideAtCompileTime); EIGEN_ONLY_USED_FOR_DEBUG(minInnerStride); eigen_assert(( ((internal::UIntPtr(m_data) % internal::traits::Alignment) == 0) || (cols() * rows() * minInnerStride * sizeof(Scalar)) < internal::traits::Alignment ) && "data is not aligned"); #endif } template EIGEN_DEVICE_FUNC void checkSanity(typename internal::enable_if::Alignment==0,void*>::type = 0) const {} PointerType m_data; const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; }; /** \ingroup Core_Module * * \brief Base class for non-const dense Map and Block expression with direct access * * This base class provides the non-const low-level accessors (e.g. coeff and coeffRef) of * dense Map and Block objects with direct access. * It inherits MapBase which defines the const variant for reading specific entries. * * \sa class Map, class Block */ template class MapBase : public MapBase { typedef MapBase ReadOnlyMapBase; public: typedef MapBase Base; typedef typename Base::Scalar Scalar; typedef typename Base::PacketScalar PacketScalar; typedef typename Base::StorageIndex StorageIndex; typedef typename Base::PointerType PointerType; using Base::derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::innerStride; using Base::outerStride; using Base::rowStride; using Base::colStride; typedef typename internal::conditional< internal::is_lvalue::value, Scalar, const Scalar >::type ScalarWithConstIfNotLvalue; EIGEN_DEVICE_FUNC inline const Scalar* data() const { return this->m_data; } EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) { return this->m_data[col * colStride() + row * rowStride()]; } EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index index) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } template inline void writePacket(Index row, Index col, const PacketScalar& val) { internal::pstoret (this->m_data + (col * colStride() + row * rowStride()), val); } template inline void writePacket(Index index, const PacketScalar& val) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) internal::pstoret (this->m_data + index * innerStride(), val); } EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : Base(dataPtr, rows, cols) {} EIGEN_DEVICE_FUNC Derived& operator=(const MapBase& other) { ReadOnlyMapBase::Base::operator=(other); return derived(); } // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, // see bugs 821 and 920. using ReadOnlyMapBase::Base::operator=; protected: EIGEN_DEFAULT_COPY_CONSTRUCTOR(MapBase) EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MapBase) }; #undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS } // end namespace Eigen #endif // EIGEN_MAPBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/MathFunctions.h000066400000000000000000001200501506104011400245300ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H // source: http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html // TODO this should better be moved to NumTraits #define EIGEN_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406L namespace Eigen { // On WINCE, std::abs is defined for int only, so let's defined our own overloads: // This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. #if EIGEN_OS_WINCE && EIGEN_COMP_MSVC && EIGEN_COMP_MSVC<=1500 long abs(long x) { return (labs(x)); } double abs(double x) { return (fabs(x)); } float abs(float x) { return (fabsf(x)); } long double abs(long double x) { return (fabsl(x)); } #endif namespace internal { /** \internal \class global_math_functions_filtering_base * * What it does: * Defines a typedef 'type' as follows: * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then * global_math_functions_filtering_base::type is a typedef for it. * - otherwise, global_math_functions_filtering_base::type is a typedef for T. * * How it's used: * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. * * How it's implemented: * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace * the typename dummy by an integer template parameter, it doesn't work anymore! */ template struct global_math_functions_filtering_base { typedef T type; }; template struct always_void { typedef void type; }; template struct global_math_functions_filtering_base ::type > { typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; }; #define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> #define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type /**************************************************************************** * Implementation of real * ****************************************************************************/ template::IsComplex> struct real_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x; } }; template struct real_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::real; return real(x); } }; template struct real_impl : real_default_impl {}; #ifdef __CUDA_ARCH__ template struct real_impl > { typedef T RealScalar; EIGEN_DEVICE_FUNC static inline T run(const std::complex& x) { return x.real(); } }; #endif template struct real_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of imag * ****************************************************************************/ template::IsComplex> struct imag_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar&) { return RealScalar(0); } }; template struct imag_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::imag; return imag(x); } }; template struct imag_impl : imag_default_impl {}; #ifdef __CUDA_ARCH__ template struct imag_impl > { typedef T RealScalar; EIGEN_DEVICE_FUNC static inline T run(const std::complex& x) { return x.imag(); } }; #endif template struct imag_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of real_ref * ****************************************************************************/ template struct real_ref_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[0]; } EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[0]; } }; template struct real_ref_retval { typedef typename NumTraits::Real & type; }; /**************************************************************************** * Implementation of imag_ref * ****************************************************************************/ template struct imag_ref_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[1]; } EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[1]; } }; template struct imag_ref_default_impl { EIGEN_DEVICE_FUNC static inline Scalar run(Scalar&) { return Scalar(0); } EIGEN_DEVICE_FUNC static inline const Scalar run(const Scalar&) { return Scalar(0); } }; template struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; template struct imag_ref_retval { typedef typename NumTraits::Real & type; }; /**************************************************************************** * Implementation of conj * ****************************************************************************/ template::IsComplex> struct conj_impl { EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { return x; } }; template struct conj_impl { EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { using std::conj; return conj(x); } }; template struct conj_retval { typedef Scalar type; }; /**************************************************************************** * Implementation of abs2 * ****************************************************************************/ template struct abs2_impl_default { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x*x; } }; template struct abs2_impl_default // IsComplex { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x.real()*x.real() + x.imag()*x.imag(); } }; template struct abs2_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return abs2_impl_default::IsComplex>::run(x); } }; template struct abs2_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of norm1 * ****************************************************************************/ template struct norm1_default_impl; template struct norm1_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { EIGEN_USING_STD_MATH(abs); return abs(x.real()) + abs(x.imag()); } }; template struct norm1_default_impl { EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { EIGEN_USING_STD_MATH(abs); return abs(x); } }; template struct norm1_impl : norm1_default_impl::IsComplex> {}; template struct norm1_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of hypot * ****************************************************************************/ template struct hypot_impl; template struct hypot_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of cast * ****************************************************************************/ template struct cast_impl { EIGEN_DEVICE_FUNC static inline NewType run(const OldType& x) { return static_cast(x); } }; // here, for once, we're plainly returning NewType: we don't want cast to do weird things. template EIGEN_DEVICE_FUNC inline NewType cast(const OldType& x) { return cast_impl::run(x); } /**************************************************************************** * Implementation of round * ****************************************************************************/ #if EIGEN_HAS_CXX11_MATH template struct round_impl { static inline Scalar run(const Scalar& x) { EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) using std::round; return round(x); } }; #else template struct round_impl { static inline Scalar run(const Scalar& x) { EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) EIGEN_USING_STD_MATH(floor); EIGEN_USING_STD_MATH(ceil); return (x > Scalar(0)) ? floor(x + Scalar(0.5)) : ceil(x - Scalar(0.5)); } }; #endif template struct round_retval { typedef Scalar type; }; /**************************************************************************** * Implementation of arg * ****************************************************************************/ #if EIGEN_HAS_CXX11_MATH template struct arg_impl { static inline Scalar run(const Scalar& x) { EIGEN_USING_STD_MATH(arg); return arg(x); } }; #else template::IsComplex> struct arg_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return (x < Scalar(0)) ? Scalar(EIGEN_PI) : Scalar(0); } }; template struct arg_default_impl { typedef typename NumTraits::Real RealScalar; EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { EIGEN_USING_STD_MATH(arg); return arg(x); } }; template struct arg_impl : arg_default_impl {}; #endif template struct arg_retval { typedef typename NumTraits::Real type; }; /**************************************************************************** * Implementation of log1p * ****************************************************************************/ namespace std_fallback { // fallback log1p implementation in case there is no log1p(Scalar) function in namespace of Scalar, // or that there is no suitable std::log1p function available template EIGEN_DEVICE_FUNC inline Scalar log1p(const Scalar& x) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) typedef typename NumTraits::Real RealScalar; EIGEN_USING_STD_MATH(log); Scalar x1p = RealScalar(1) + x; return numext::equal_strict(x1p, Scalar(1)) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) ); } } template struct log1p_impl { static inline Scalar run(const Scalar& x) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) #if EIGEN_HAS_CXX11_MATH using std::log1p; #endif using std_fallback::log1p; return log1p(x); } }; template struct log1p_retval { typedef Scalar type; }; /**************************************************************************** * Implementation of pow * ****************************************************************************/ template::IsInteger&&NumTraits::IsInteger> struct pow_impl { //typedef Scalar retval; typedef typename ScalarBinaryOpTraits >::ReturnType result_type; static EIGEN_DEVICE_FUNC inline result_type run(const ScalarX& x, const ScalarY& y) { EIGEN_USING_STD_MATH(pow); return pow(x, y); } }; template struct pow_impl { typedef ScalarX result_type; static EIGEN_DEVICE_FUNC inline ScalarX run(ScalarX x, ScalarY y) { ScalarX res(1); eigen_assert(!NumTraits::IsSigned || y >= 0); if(y & 1) res *= x; y >>= 1; while(y) { x *= x; if(y&1) res *= x; y >>= 1; } return res; } }; /**************************************************************************** * Implementation of random * ****************************************************************************/ template struct random_default_impl {}; template struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; template struct random_retval { typedef Scalar type; }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); template struct random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); } static inline Scalar run() { return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); } }; enum { meta_floor_log2_terminate, meta_floor_log2_move_up, meta_floor_log2_move_down, meta_floor_log2_bogus }; template struct meta_floor_log2_selector { enum { middle = (lower + upper) / 2, value = (upper <= lower + 1) ? int(meta_floor_log2_terminate) : (n < (1 << middle)) ? int(meta_floor_log2_move_down) : (n==0) ? int(meta_floor_log2_bogus) : int(meta_floor_log2_move_up) }; }; template::value> struct meta_floor_log2 {}; template struct meta_floor_log2 { enum { value = meta_floor_log2::middle>::value }; }; template struct meta_floor_log2 { enum { value = meta_floor_log2::middle, upper>::value }; }; template struct meta_floor_log2 { enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; }; template struct meta_floor_log2 { // no value, error at compile time }; template struct random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { if (y <= x) return x; // ScalarU is the unsigned counterpart of Scalar, possibly Scalar itself. typedef typename make_unsigned::type ScalarU; // ScalarX is the widest of ScalarU and unsigned int. // We'll deal only with ScalarX and unsigned int below thus avoiding signed // types and arithmetic and signed overflows (which are undefined behavior). typedef typename conditional<(ScalarU(-1) > unsigned(-1)), ScalarU, unsigned>::type ScalarX; // The following difference doesn't overflow, provided our integer types are two's // complement and have the same number of padding bits in signed and unsigned variants. // This is the case in most modern implementations of C++. ScalarX range = ScalarX(y) - ScalarX(x); ScalarX offset = 0; ScalarX divisor = 1; ScalarX multiplier = 1; const unsigned rand_max = RAND_MAX; if (range <= rand_max) divisor = (rand_max + 1) / (range + 1); else multiplier = 1 + range / (rand_max + 1); // Rejection sampling. do { offset = (unsigned(std::rand()) * multiplier) / divisor; } while (offset > range); return Scalar(ScalarX(x) + offset); } static inline Scalar run() { #ifdef EIGEN_MAKING_DOCS return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); #else enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value, scalar_bits = sizeof(Scalar) * CHAR_BIT, shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 }; return Scalar((std::rand() >> shift) - offset); #endif } }; template struct random_default_impl { static inline Scalar run(const Scalar& x, const Scalar& y) { return Scalar(random(x.real(), y.real()), random(x.imag(), y.imag())); } static inline Scalar run() { typedef typename NumTraits::Real RealScalar; return Scalar(random(), random()); } }; template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); } template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() { return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } // Implementatin of is* functions // std::is* do not work with fast-math and gcc, std::is* are available on MSVC 2013 and newer, as well as in clang. #if (EIGEN_HAS_CXX11_MATH && !(EIGEN_COMP_GNUC_STRICT && __FINITE_MATH_ONLY__)) || (EIGEN_COMP_MSVC>=1800) || (EIGEN_COMP_CLANG) #define EIGEN_USE_STD_FPCLASSIFY 1 #else #define EIGEN_USE_STD_FPCLASSIFY 0 #endif template EIGEN_DEVICE_FUNC typename internal::enable_if::value,bool>::type isnan_impl(const T&) { return false; } template EIGEN_DEVICE_FUNC typename internal::enable_if::value,bool>::type isinf_impl(const T&) { return false; } template EIGEN_DEVICE_FUNC typename internal::enable_if::value,bool>::type isfinite_impl(const T&) { return true; } template EIGEN_DEVICE_FUNC typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type isfinite_impl(const T& x) { #ifdef __CUDA_ARCH__ return (::isfinite)(x); #elif EIGEN_USE_STD_FPCLASSIFY using std::isfinite; return isfinite EIGEN_NOT_A_MACRO (x); #else return x<=NumTraits::highest() && x>=NumTraits::lowest(); #endif } template EIGEN_DEVICE_FUNC typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type isinf_impl(const T& x) { #ifdef __CUDA_ARCH__ return (::isinf)(x); #elif EIGEN_USE_STD_FPCLASSIFY using std::isinf; return isinf EIGEN_NOT_A_MACRO (x); #else return x>NumTraits::highest() || x::lowest(); #endif } template EIGEN_DEVICE_FUNC typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type isnan_impl(const T& x) { #ifdef __CUDA_ARCH__ return (::isnan)(x); #elif EIGEN_USE_STD_FPCLASSIFY using std::isnan; return isnan EIGEN_NOT_A_MACRO (x); #else return x != x; #endif } #if (!EIGEN_USE_STD_FPCLASSIFY) #if EIGEN_COMP_MSVC template EIGEN_DEVICE_FUNC bool isinf_msvc_helper(T x) { return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; } //MSVC defines a _isnan builtin function, but for double only EIGEN_DEVICE_FUNC inline bool isnan_impl(const long double& x) { return _isnan(x)!=0; } EIGEN_DEVICE_FUNC inline bool isnan_impl(const double& x) { return _isnan(x)!=0; } EIGEN_DEVICE_FUNC inline bool isnan_impl(const float& x) { return _isnan(x)!=0; } EIGEN_DEVICE_FUNC inline bool isinf_impl(const long double& x) { return isinf_msvc_helper(x); } EIGEN_DEVICE_FUNC inline bool isinf_impl(const double& x) { return isinf_msvc_helper(x); } EIGEN_DEVICE_FUNC inline bool isinf_impl(const float& x) { return isinf_msvc_helper(x); } #elif (defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ && EIGEN_COMP_GNUC) #if EIGEN_GNUC_AT_LEAST(5,0) #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((optimize("no-finite-math-only"))) #else // NOTE the inline qualifier and noinline attribute are both needed: the former is to avoid linking issue (duplicate symbol), // while the second prevent too aggressive optimizations in fast-math mode: #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((noinline,optimize("no-finite-math-only"))) #endif template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const long double& x) { return __builtin_isnan(x); } template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const double& x) { return __builtin_isnan(x); } template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const float& x) { return __builtin_isnan(x); } template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const double& x) { return __builtin_isinf(x); } template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const float& x) { return __builtin_isinf(x); } template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const long double& x) { return __builtin_isinf(x); } #undef EIGEN_TMP_NOOPT_ATTRIB #endif #endif // The following overload are defined at the end of this file template EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x); template EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x); template EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x); template T generic_fast_tanh_float(const T& a_x); } // end namespace internal /**************************************************************************** * Generic math functions * ****************************************************************************/ namespace numext { #ifndef __CUDA_ARCH__ template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) { EIGEN_USING_STD_MATH(min); return min EIGEN_NOT_A_MACRO (x,y); } template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) { EIGEN_USING_STD_MATH(max); return max EIGEN_NOT_A_MACRO (x,y); } #else template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) { return y < x ? y : x; } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float mini(const float& x, const float& y) { return fminf(x, y); } template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) { return x < y ? y : x; } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float maxi(const float& x, const float& y) { return fmaxf(x, y); } #endif template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) { return internal::real_ref_impl::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) { return internal::imag_ref_impl::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } EIGEN_DEVICE_FUNC inline bool abs2(bool x) { return x; } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(log1p, Scalar) log1p(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(log1p, Scalar)::run(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float log1p(const float &x) { return ::log1pf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double log1p(const double &x) { return ::log1p(x); } #endif template EIGEN_DEVICE_FUNC inline typename internal::pow_impl::result_type pow(const ScalarX& x, const ScalarY& y) { return internal::pow_impl::run(x, y); } template EIGEN_DEVICE_FUNC bool (isnan) (const T &x) { return internal::isnan_impl(x); } template EIGEN_DEVICE_FUNC bool (isinf) (const T &x) { return internal::isinf_impl(x); } template EIGEN_DEVICE_FUNC bool (isfinite)(const T &x) { return internal::isfinite_impl(x); } template EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); } template EIGEN_DEVICE_FUNC T (floor)(const T& x) { EIGEN_USING_STD_MATH(floor); return floor(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float floor(const float &x) { return ::floorf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double floor(const double &x) { return ::floor(x); } #endif template EIGEN_DEVICE_FUNC T (ceil)(const T& x) { EIGEN_USING_STD_MATH(ceil); return ceil(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float ceil(const float &x) { return ::ceilf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double ceil(const double &x) { return ::ceil(x); } #endif /** Log base 2 for 32 bits positive integers. * Conveniently returns 0 for x==0. */ inline int log2(int x) { eigen_assert(x>=0); unsigned int v(x); static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return table[(v * 0x07C4ACDDU) >> 27]; } /** \returns the square root of \a x. * * It is essentially equivalent to * \code using std::sqrt; return sqrt(x); \endcode * but slightly faster for float/double and some compilers (e.g., gcc), thanks to * specializations when SSE is enabled. * * It's usage is justified in performance critical functions, like norm/normalize. */ template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T sqrt(const T &x) { EIGEN_USING_STD_MATH(sqrt); return sqrt(x); } template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T log(const T &x) { EIGEN_USING_STD_MATH(log); return log(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float log(const float &x) { return ::logf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double log(const double &x) { return ::log(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE typename internal::enable_if::IsSigned || NumTraits::IsComplex,typename NumTraits::Real>::type abs(const T &x) { EIGEN_USING_STD_MATH(abs); return abs(x); } template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE typename internal::enable_if::IsSigned || NumTraits::IsComplex),typename NumTraits::Real>::type abs(const T &x) { return x; } #if defined(__SYCL_DEVICE_ONLY__) EIGEN_ALWAYS_INLINE float abs(float x) { return cl::sycl::fabs(x); } EIGEN_ALWAYS_INLINE double abs(double x) { return cl::sycl::fabs(x); } #endif // defined(__SYCL_DEVICE_ONLY__) #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float abs(const float &x) { return ::fabsf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double abs(const double &x) { return ::fabs(x); } template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float abs(const std::complex& x) { return ::hypotf(x.real(), x.imag()); } template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double abs(const std::complex& x) { return ::hypot(x.real(), x.imag()); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T exp(const T &x) { EIGEN_USING_STD_MATH(exp); return exp(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float exp(const float &x) { return ::expf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double exp(const double &x) { return ::exp(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T cos(const T &x) { EIGEN_USING_STD_MATH(cos); return cos(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float cos(const float &x) { return ::cosf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double cos(const double &x) { return ::cos(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T sin(const T &x) { EIGEN_USING_STD_MATH(sin); return sin(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float sin(const float &x) { return ::sinf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double sin(const double &x) { return ::sin(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T tan(const T &x) { EIGEN_USING_STD_MATH(tan); return tan(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float tan(const float &x) { return ::tanf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double tan(const double &x) { return ::tan(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T acos(const T &x) { EIGEN_USING_STD_MATH(acos); return acos(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float acos(const float &x) { return ::acosf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double acos(const double &x) { return ::acos(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T asin(const T &x) { EIGEN_USING_STD_MATH(asin); return asin(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float asin(const float &x) { return ::asinf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double asin(const double &x) { return ::asin(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T atan(const T &x) { EIGEN_USING_STD_MATH(atan); return atan(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float atan(const float &x) { return ::atanf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double atan(const double &x) { return ::atan(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T cosh(const T &x) { EIGEN_USING_STD_MATH(cosh); return cosh(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float cosh(const float &x) { return ::coshf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double cosh(const double &x) { return ::cosh(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T sinh(const T &x) { EIGEN_USING_STD_MATH(sinh); return sinh(x); } #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float sinh(const float &x) { return ::sinhf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double sinh(const double &x) { return ::sinh(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T tanh(const T &x) { EIGEN_USING_STD_MATH(tanh); return tanh(x); } #if (!defined(__CUDACC__)) && EIGEN_FAST_MATH EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float tanh(float x) { return internal::generic_fast_tanh_float(x); } #endif #ifdef __CUDACC__ template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float tanh(const float &x) { return ::tanhf(x); } template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double tanh(const double &x) { return ::tanh(x); } #endif template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T fmod(const T& a, const T& b) { EIGEN_USING_STD_MATH(fmod); return fmod(a, b); } #ifdef __CUDACC__ template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE float fmod(const float& a, const float& b) { return ::fmodf(a, b); } template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE double fmod(const double& a, const double& b) { return ::fmod(a, b); } #endif } // end namespace numext namespace internal { template EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x) { return (numext::isfinite)(numext::real(x)) && (numext::isfinite)(numext::imag(x)); } template EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x) { return (numext::isnan)(numext::real(x)) || (numext::isnan)(numext::imag(x)); } template EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x) { return ((numext::isinf)(numext::real(x)) || (numext::isinf)(numext::imag(x))) && (!(numext::isnan)(x)); } /**************************************************************************** * Implementation of fuzzy comparisons * ****************************************************************************/ template struct scalar_fuzzy_default_impl {}; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return numext::abs(x) <= numext::abs(y) * prec; } EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return numext::abs(x - y) <= numext::mini(numext::abs(x), numext::abs(y)) * prec; } EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) { return x <= y || isApprox(x, y, prec); } }; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) { return x == Scalar(0); } EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) { return x == y; } EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) { return x <= y; } }; template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return numext::abs2(x) <= numext::abs2(y) * prec * prec; } EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { return numext::abs2(x - y) <= numext::mini(numext::abs2(x), numext::abs2(y)) * prec * prec; } }; template struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; template EIGEN_DEVICE_FUNC inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); } template EIGEN_DEVICE_FUNC inline bool isApprox(const Scalar& x, const Scalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApprox(x, y, precision); } template EIGEN_DEVICE_FUNC inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); } /****************************************** *** The special case of the bool type *** ******************************************/ template<> struct random_impl { static inline bool run() { return random(0,1)==0 ? false : true; } }; template<> struct scalar_fuzzy_impl { typedef bool RealScalar; template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) { return !x; } EIGEN_DEVICE_FUNC static inline bool isApprox(bool x, bool y, bool) { return x == y; } EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) { return (!x) || y; } }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_MATHFUNCTIONS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/MathFunctionsImpl.h000066400000000000000000000064511506104011400253620ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) // Copyright (C) 2016 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATHFUNCTIONSIMPL_H #define EIGEN_MATHFUNCTIONSIMPL_H namespace Eigen { namespace internal { /** \internal \returns the hyperbolic tan of \a a (coeff-wise) Doesn't do anything fancy, just a 13/6-degree rational interpolant which is accurate up to a couple of ulp in the range [-9, 9], outside of which the tanh(x) = +/-1. This implementation works on both scalars and packets. */ template T generic_fast_tanh_float(const T& a_x) { // Clamp the inputs to the range [-9, 9] since anything outside // this range is +/-1.0f in single-precision. const T plus_9 = pset1(9.f); const T minus_9 = pset1(-9.f); // NOTE GCC prior to 6.3 might improperly optimize this max/min // step such that if a_x is nan, x will be either 9 or -9, // and tanh will return 1 or -1 instead of nan. // This is supposed to be fixed in gcc6.3, // see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867 const T x = pmax(minus_9,pmin(plus_9,a_x)); // The monomial coefficients of the numerator polynomial (odd). const T alpha_1 = pset1(4.89352455891786e-03f); const T alpha_3 = pset1(6.37261928875436e-04f); const T alpha_5 = pset1(1.48572235717979e-05f); const T alpha_7 = pset1(5.12229709037114e-08f); const T alpha_9 = pset1(-8.60467152213735e-11f); const T alpha_11 = pset1(2.00018790482477e-13f); const T alpha_13 = pset1(-2.76076847742355e-16f); // The monomial coefficients of the denominator polynomial (even). const T beta_0 = pset1(4.89352518554385e-03f); const T beta_2 = pset1(2.26843463243900e-03f); const T beta_4 = pset1(1.18534705686654e-04f); const T beta_6 = pset1(1.19825839466702e-06f); // Since the polynomials are odd/even, we need x^2. const T x2 = pmul(x, x); // Evaluate the numerator polynomial p. T p = pmadd(x2, alpha_13, alpha_11); p = pmadd(x2, p, alpha_9); p = pmadd(x2, p, alpha_7); p = pmadd(x2, p, alpha_5); p = pmadd(x2, p, alpha_3); p = pmadd(x2, p, alpha_1); p = pmul(x, p); // Evaluate the denominator polynomial p. T q = pmadd(x2, beta_6, beta_4); q = pmadd(x2, q, beta_2); q = pmadd(x2, q, beta_0); // Divide the numerator by the denominator. return pdiv(p, q); } template EIGEN_STRONG_INLINE RealScalar positive_real_hypot(const RealScalar& x, const RealScalar& y) { EIGEN_USING_STD_MATH(sqrt); RealScalar p, qp; p = numext::maxi(x,y); if(p==RealScalar(0)) return RealScalar(0); qp = numext::mini(y,x) / p; return p * sqrt(RealScalar(1) + qp*qp); } template struct hypot_impl { typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x, const Scalar& y) { EIGEN_USING_STD_MATH(abs); return positive_real_hypot(abs(x), abs(y)); } }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_MATHFUNCTIONSIMPL_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Matrix.h000066400000000000000000000451731506104011400232260ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // Copyright (C) 2008-2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIX_H #define EIGEN_MATRIX_H namespace Eigen { namespace internal { template struct traits > { private: enum { size = internal::size_at_compile_time<_Rows,_Cols>::ret }; typedef typename find_best_packet<_Scalar,size>::type PacketScalar; enum { row_major_bit = _Options&RowMajor ? RowMajorBit : 0, is_dynamic_size_storage = _MaxRows==Dynamic || _MaxCols==Dynamic, max_size = is_dynamic_size_storage ? Dynamic : _MaxRows*_MaxCols, default_alignment = compute_default_alignment<_Scalar,max_size>::value, actual_alignment = ((_Options&DontAlign)==0) ? default_alignment : 0, required_alignment = unpacket_traits::alignment, packet_access_bit = (packet_traits<_Scalar>::Vectorizable && (EIGEN_UNALIGNED_VECTORIZE || (actual_alignment>=required_alignment))) ? PacketAccessBit : 0 }; public: typedef _Scalar Scalar; typedef Dense StorageKind; typedef Eigen::Index StorageIndex; typedef MatrixXpr XprKind; enum { RowsAtCompileTime = _Rows, ColsAtCompileTime = _Cols, MaxRowsAtCompileTime = _MaxRows, MaxColsAtCompileTime = _MaxCols, Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, Options = _Options, InnerStrideAtCompileTime = 1, OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime, // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase EvaluatorFlags = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit, Alignment = actual_alignment }; }; } /** \class Matrix * \ingroup Core_Module * * \brief The matrix class, also used for vectors and row-vectors * * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen. * Vectors are matrices with one column, and row-vectors are matrices with one row. * * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). * * The first three template parameters are required: * \tparam _Scalar Numeric type, e.g. float, double, int or std::complex. * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * * The remaining template parameters are optional -- in most cases you don't have to worry about them. * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of either * \b #AutoAlign or \b #DontAlign. * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note"). * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note"). * * Eigen provides a number of typedefs covering the usual cases. Here are some examples: * * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix) * \li \c Vector4f is a vector of 4 floats (\c Matrix) * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix) * * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix) * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix) * * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix) * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix) * * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs. * * You can access elements of vectors and matrices using normal subscripting: * * \code * Eigen::VectorXd v(10); * v[0] = 0.1; * v[1] = 0.2; * v(0) = 0.3; * v(1) = 0.4; * * Eigen::MatrixXi m(10, 10); * m(0, 1) = 1; * m(0, 2) = 2; * m(0, 3) = 3; * \endcode * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. * * Some notes: * *
*
\anchor dense Dense versus sparse:
*
This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module. * * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array. * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.
* *
\anchor fixedsize Fixed-size versus dynamic-size:
*
Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time. * * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime * variables, and the array of coefficients is allocated dynamically on the heap. * * Note that \em dense matrices, be they Fixed-size or Dynamic-size, do not expand dynamically in the sense of a std::map. * If you want this behavior, see the Sparse module.
* *
\anchor maxrows _MaxRows and _MaxCols:
*
In most cases, one just leaves these parameters to the default values. * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.
*
* * ABI and storage layout * * The table below summarizes the ABI of some possible Matrix instances which is fixed thorough the lifetime of Eigen 3. * * * * * * *
Matrix typeEquivalent C structure
\code Matrix \endcode\code * struct { * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 * Eigen::Index rows, cols; * }; * \endcode
\code * Matrix * Matrix \endcode\code * struct { * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 * Eigen::Index size; * }; * \endcode
\code Matrix \endcode\code * struct { * T data[Rows*Cols]; // with (size_t(data)%A(Rows*Cols*sizeof(T)))==0 * }; * \endcode
\code Matrix \endcode\code * struct { * T data[MaxRows*MaxCols]; // with (size_t(data)%A(MaxRows*MaxCols*sizeof(T)))==0 * Eigen::Index rows, cols; * }; * \endcode
* Note that in this table Rows, Cols, MaxRows and MaxCols are all positive integers. A(S) is defined to the largest possible power-of-two * smaller to EIGEN_MAX_STATIC_ALIGN_BYTES. * * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, * \ref TopicStorageOrders */ template class Matrix : public PlainObjectBase > { public: /** \brief Base class typedef. * \sa PlainObjectBase */ typedef PlainObjectBase Base; enum { Options = _Options }; EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) typedef typename Base::PlainObject PlainObject; using Base::base; using Base::coeffRef; /** * \brief Assigns matrices to each other. * * \note This is a special case of the templated operator=. Its purpose is * to prevent a default operator= from hiding the templated operator=. * * \callgraph */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { return Base::_set(other); } /** \internal * \brief Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const DenseBase& other) { return Base::_set(other); } /* Here, doxygen failed to copy the brief information when using \copydoc */ /** * \brief Copies the generic expression \a other into *this. * \copydetails DenseBase::operator=(const EigenBase &other) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) { return Base::operator=(other); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { return Base::operator=(func); } /** \brief Default constructor. * * For fixed-size matrices, does nothing. * * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix * is called a null matrix. This constructor is the unique way to create null matrices: resizing * a matrix to 0 is not supported. * * \sa resize(Index,Index) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix() : Base() { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } // FIXME is it still needed EIGEN_DEVICE_FUNC explicit Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC Matrix(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); } EIGEN_DEVICE_FUNC Matrix& operator=(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif #ifndef EIGEN_PARSED_BY_DOXYGEN // This constructor is for both 1x1 matrices and dynamic vectors template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Matrix(const T& x) { Base::_check_template_params(); Base::template _init1(x); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) { Base::_check_template_params(); Base::template _init2(x, y); } #else /** \brief Constructs a fixed-sized matrix initialized with coefficients starting at \a data */ EIGEN_DEVICE_FUNC explicit Matrix(const Scalar *data); /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors * * This is useful for dynamic-size vectors. For fixed-size vectors, * it is redundant to pass these parameters, so one should use the default constructor * Matrix() instead. * * \warning This constructor is disabled for fixed-size \c 1x1 matrices. For instance, * calling Matrix(1) will call the initialization constructor: Matrix(const Scalar&). * For fixed-size \c 1x1 matrices it is therefore recommended to use the default * constructor Matrix() instead, especially when using one of the non standard * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). */ EIGEN_STRONG_INLINE explicit Matrix(Index dim); /** \brief Constructs an initialized 1x1 matrix with the given coefficient */ Matrix(const Scalar& x); /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor * Matrix() instead. * * \warning This constructor is disabled for fixed-size \c 1x2 and \c 2x1 vectors. For instance, * calling Matrix2f(2,1) will call the initialization constructor: Matrix(const Scalar& x, const Scalar& y). * For fixed-size \c 1x2 or \c 2x1 vectors it is therefore recommended to use the default * constructor Matrix() instead, especially when using one of the non standard * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). */ EIGEN_DEVICE_FUNC Matrix(Index rows, Index cols); /** \brief Constructs an initialized 2D vector with given coefficients */ Matrix(const Scalar& x, const Scalar& y); #endif /** \brief Constructs an initialized 3D vector with given coefficients */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; } /** \brief Constructs an initialized 4D vector with given coefficients */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) m_storage.data()[0] = x; m_storage.data()[1] = y; m_storage.data()[2] = z; m_storage.data()[3] = w; } /** \brief Copy constructor */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) { } /** \brief Copy constructor for generic expressions. * \sa MatrixBase::operator=(const EigenBase&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const EigenBase &other) : Base(other.derived()) { } EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } /////////// Geometry module /////////// template EIGEN_DEVICE_FUNC explicit Matrix(const RotationBase& r); template EIGEN_DEVICE_FUNC Matrix& operator=(const RotationBase& r); // allow to extend Matrix outside Eigen #ifdef EIGEN_MATRIX_PLUGIN #include EIGEN_MATRIX_PLUGIN #endif protected: template friend struct internal::conservative_resize_like_impl; using Base::m_storage; }; /** \defgroup matrixtypedefs Global matrix typedefs * * \ingroup Core_Module * * Eigen defines several typedef shortcuts for most common matrix and vector types. * * The general patterns are the following: * * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd * for complex double. * * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats. * * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is * a fixed-size vector of 4 complex floats. * * \sa class Matrix */ #define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##SizeSuffix##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix Vector##SizeSuffix##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix RowVector##SizeSuffix##TypeSuffix; #define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##Size##X##TypeSuffix; \ /** \ingroup matrixtypedefs */ \ typedef Matrix Matrix##X##Size##TypeSuffix; #define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cf) EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) #undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES #undef EIGEN_MAKE_TYPEDEFS #undef EIGEN_MAKE_FIXED_TYPEDEFS } // end namespace Eigen #endif // EIGEN_MATRIX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/MatrixBase.h000066400000000000000000000553541506104011400240230ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2009 Benoit Jacob // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_MATRIXBASE_H #define EIGEN_MATRIXBASE_H namespace Eigen { /** \class MatrixBase * \ingroup Core_Module * * \brief Base class for all dense matrices, vectors, and expressions * * This class is the base that is inherited by all matrix, vector, and related expression * types. Most of the Eigen API is contained in this class, and its base classes. Other important * classes for the Eigen API are Matrix, and VectorwiseOp. * * Note that some methods are defined in other modules such as the \ref LU_Module LU module * for all functions related to matrix inversions. * * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc. * * When writing a function taking Eigen objects as argument, if you want your function * to take as argument any matrix, vector, or expression, just let it take a * MatrixBase argument. As an example, here is a function printFirstRow which, given * a matrix, vector, or expression \a x, prints the first row of \a x. * * \code template void printFirstRow(const Eigen::MatrixBase& x) { cout << x.row(0) << endl; } * \endcode * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. * * \sa \blank \ref TopicClassHierarchy */ template class MatrixBase : public DenseBase { public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; using Base::derived; using Base::const_cast_derived; using Base::rows; using Base::cols; using Base::size; using Base::coeff; using Base::coeffRef; using Base::lazyAssign; using Base::eval; using Base::operator+=; using Base::operator-=; using Base::operator*=; using Base::operator/=; typedef typename Base::CoeffReturnType CoeffReturnType; typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; typedef typename Base::RowXpr RowXpr; typedef typename Base::ColXpr ColXpr; #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN /** type of the equivalent square matrix */ typedef Matrix SquareMatrixType; #endif // not EIGEN_PARSED_BY_DOXYGEN /** \returns the size of the main diagonal, which is min(rows(),cols()). * \sa rows(), cols(), SizeAtCompileTime. */ EIGEN_DEVICE_FUNC inline Index diagonalSize() const { return (numext::mini)(rows(),cols()); } typedef typename Base::PlainObject PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal the return type of MatrixBase::adjoint() */ typedef typename internal::conditional::IsComplex, CwiseUnaryOp, ConstTransposeReturnType>, ConstTransposeReturnType >::type AdjointReturnType; /** \internal Return type of eigenvalues() */ typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; /** \internal the return type of identity */ typedef CwiseNullaryOp,PlainObject> IdentityReturnType; /** \internal the return type of unit vectors */ typedef Block, SquareMatrixType>, internal::traits::RowsAtCompileTime, internal::traits::ColsAtCompileTime> BasisReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase #define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/MatrixCwiseBinaryOps.h" # ifdef EIGEN_MATRIXBASE_PLUGIN # include EIGEN_MATRIXBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS #undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const MatrixBase& other); // We cannot inherit here via Base::operator= since it is causing // trouble with MSVC. template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase& other); template EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const MatrixBase& other); template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const MatrixBase& other); template EIGEN_DEVICE_FUNC const Product operator*(const MatrixBase &other) const; template EIGEN_DEVICE_FUNC const Product lazyProduct(const MatrixBase &other) const; template Derived& operator*=(const EigenBase& other); template void applyOnTheLeft(const EigenBase& other); template void applyOnTheRight(const EigenBase& other); template EIGEN_DEVICE_FUNC const Product operator*(const DiagonalBase &diagonal) const; template EIGEN_DEVICE_FUNC typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType dot(const MatrixBase& other) const; EIGEN_DEVICE_FUNC RealScalar squaredNorm() const; EIGEN_DEVICE_FUNC RealScalar norm() const; RealScalar stableNorm() const; RealScalar blueNorm() const; RealScalar hypotNorm() const; EIGEN_DEVICE_FUNC const PlainObject normalized() const; EIGEN_DEVICE_FUNC const PlainObject stableNormalized() const; EIGEN_DEVICE_FUNC void normalize(); EIGEN_DEVICE_FUNC void stableNormalize(); EIGEN_DEVICE_FUNC const AdjointReturnType adjoint() const; EIGEN_DEVICE_FUNC void adjointInPlace(); typedef Diagonal DiagonalReturnType; EIGEN_DEVICE_FUNC DiagonalReturnType diagonal(); typedef typename internal::add_const >::type ConstDiagonalReturnType; EIGEN_DEVICE_FUNC ConstDiagonalReturnType diagonal() const; template struct DiagonalIndexReturnType { typedef Diagonal Type; }; template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; template EIGEN_DEVICE_FUNC typename DiagonalIndexReturnType::Type diagonal(); template EIGEN_DEVICE_FUNC typename ConstDiagonalIndexReturnType::Type diagonal() const; typedef Diagonal DiagonalDynamicIndexReturnType; typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; EIGEN_DEVICE_FUNC DiagonalDynamicIndexReturnType diagonal(Index index); EIGEN_DEVICE_FUNC ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; template struct TriangularViewReturnType { typedef TriangularView Type; }; template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; template EIGEN_DEVICE_FUNC typename TriangularViewReturnType::Type triangularView(); template EIGEN_DEVICE_FUNC typename ConstTriangularViewReturnType::Type triangularView() const; template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; template EIGEN_DEVICE_FUNC typename SelfAdjointViewReturnType::Type selfadjointView(); template EIGEN_DEVICE_FUNC typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; const SparseView sparseView(const Scalar& m_reference = Scalar(0), const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(); EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(Index rows, Index cols); EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index size, Index i); EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index i); EIGEN_DEVICE_FUNC static const BasisReturnType UnitX(); EIGEN_DEVICE_FUNC static const BasisReturnType UnitY(); EIGEN_DEVICE_FUNC static const BasisReturnType UnitZ(); EIGEN_DEVICE_FUNC static const BasisReturnType UnitW(); EIGEN_DEVICE_FUNC const DiagonalWrapper asDiagonal() const; const PermutationWrapper asPermutation() const; EIGEN_DEVICE_FUNC Derived& setIdentity(); EIGEN_DEVICE_FUNC Derived& setIdentity(Index rows, Index cols); bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; bool isDiagonal(const RealScalar& prec = NumTraits::dummy_precision()) const; bool isUpperTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; bool isLowerTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; template bool isOrthogonal(const MatrixBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; bool isUnitary(const RealScalar& prec = NumTraits::dummy_precision()) const; /** \returns true if each coefficients of \c *this and \a other are all exactly equal. * \warning When using floating point scalar values you probably should rather use a * fuzzy comparison such as isApprox() * \sa isApprox(), operator!= */ template EIGEN_DEVICE_FUNC inline bool operator==(const MatrixBase& other) const { return cwiseEqual(other).all(); } /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. * \warning When using floating point scalar values you probably should rather use a * fuzzy comparison such as isApprox() * \sa isApprox(), operator== */ template EIGEN_DEVICE_FUNC inline bool operator!=(const MatrixBase& other) const { return cwiseNotEqual(other).any(); } NoAlias noalias(); // TODO forceAlignedAccess is temporarily disabled // Need to find a nicer workaround. inline const Derived& forceAlignedAccess() const { return derived(); } inline Derived& forceAlignedAccess() { return derived(); } template inline const Derived& forceAlignedAccessIf() const { return derived(); } template inline Derived& forceAlignedAccessIf() { return derived(); } EIGEN_DEVICE_FUNC Scalar trace() const; template EIGEN_DEVICE_FUNC RealScalar lpNorm() const; EIGEN_DEVICE_FUNC MatrixBase& matrix() { return *this; } EIGEN_DEVICE_FUNC const MatrixBase& matrix() const { return *this; } /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } /////////// LU module /////////// inline const FullPivLU fullPivLu() const; inline const PartialPivLU partialPivLu() const; inline const PartialPivLU lu() const; inline const Inverse inverse() const; template inline void computeInverseAndDetWithCheck( ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template inline void computeInverseWithCheck( ResultType& inverse, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; Scalar determinant() const; /////////// Cholesky module /////////// inline const LLT llt() const; inline const LDLT ldlt() const; /////////// QR module /////////// inline const HouseholderQR householderQr() const; inline const ColPivHouseholderQR colPivHouseholderQr() const; inline const FullPivHouseholderQR fullPivHouseholderQr() const; inline const CompleteOrthogonalDecomposition completeOrthogonalDecomposition() const; /////////// Eigenvalues module /////////// inline EigenvaluesReturnType eigenvalues() const; inline RealScalar operatorNorm() const; /////////// SVD module /////////// inline JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; inline BDCSVD bdcSvd(unsigned int computationOptions = 0) const; /////////// Geometry module /////////// #ifndef EIGEN_PARSED_BY_DOXYGEN /// \internal helper struct to form the return type of the cross product template struct cross_product_return_type { typedef typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; typedef Matrix type; }; #endif // EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC #ifndef EIGEN_PARSED_BY_DOXYGEN inline typename cross_product_return_type::type #else inline PlainObject #endif cross(const MatrixBase& other) const; template EIGEN_DEVICE_FUNC inline PlainObject cross3(const MatrixBase& other) const; EIGEN_DEVICE_FUNC inline PlainObject unitOrthogonal(void) const; EIGEN_DEVICE_FUNC inline Matrix eulerAngles(Index a0, Index a1, Index a2) const; // put this as separate enum value to work around possible GCC 4.3 bug (?) enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1&&RowsAtCompileTime==1 ? ((internal::traits::Flags&RowMajorBit)==RowMajorBit ? Horizontal : Vertical) : ColsAtCompileTime==1 ? Vertical : Horizontal }; typedef Homogeneous HomogeneousReturnType; EIGEN_DEVICE_FUNC inline HomogeneousReturnType homogeneous() const; enum { SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 }; typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; typedef EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(ConstStartMinusOne,Scalar,quotient) HNormalizedReturnType; EIGEN_DEVICE_FUNC inline const HNormalizedReturnType hnormalized() const; ////////// Householder module /////////// void makeHouseholderInPlace(Scalar& tau, RealScalar& beta); template void makeHouseholder(EssentialPart& essential, Scalar& tau, RealScalar& beta) const; template void applyHouseholderOnTheLeft(const EssentialPart& essential, const Scalar& tau, Scalar* workspace); template void applyHouseholderOnTheRight(const EssentialPart& essential, const Scalar& tau, Scalar* workspace); ///////// Jacobi module ///////// template void applyOnTheLeft(Index p, Index q, const JacobiRotation& j); template void applyOnTheRight(Index p, Index q, const JacobiRotation& j); ///////// SparseCore module ///////// template EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type cwiseProduct(const SparseMatrixBase &other) const { return other.cwiseProduct(derived()); } ///////// MatrixFunctions module ///////// typedef typename internal::stem_function::type StemFunction; #define EIGEN_MATRIX_FUNCTION(ReturnType, Name, Description) \ /** \returns an expression of the matrix Description of \c *this. \brief This function requires the unsupported MatrixFunctions module. To compute the coefficient-wise Description use ArrayBase::##Name . */ \ const ReturnType Name() const; #define EIGEN_MATRIX_FUNCTION_1(ReturnType, Name, Description, Argument) \ /** \returns an expression of the matrix Description of \c *this. \brief This function requires the unsupported MatrixFunctions module. To compute the coefficient-wise Description use ArrayBase::##Name . */ \ const ReturnType Name(Argument) const; EIGEN_MATRIX_FUNCTION(MatrixExponentialReturnValue, exp, exponential) /** \brief Helper function for the unsupported MatrixFunctions module.*/ const MatrixFunctionReturnValue matrixFunction(StemFunction f) const; EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cosh, hyperbolic cosine) EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sinh, hyperbolic sine) EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cos, cosine) EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sin, sine) EIGEN_MATRIX_FUNCTION(MatrixSquareRootReturnValue, sqrt, square root) EIGEN_MATRIX_FUNCTION(MatrixLogarithmReturnValue, log, logarithm) EIGEN_MATRIX_FUNCTION_1(MatrixPowerReturnValue, pow, power to \c p, const RealScalar& p) EIGEN_MATRIX_FUNCTION_1(MatrixComplexPowerReturnValue, pow, power to \c p, const std::complex& p) protected: EIGEN_DEFAULT_COPY_CONSTRUCTOR(MatrixBase) EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MatrixBase) private: EIGEN_DEVICE_FUNC explicit MatrixBase(int); EIGEN_DEVICE_FUNC MatrixBase(int,int); template EIGEN_DEVICE_FUNC explicit MatrixBase(const MatrixBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} // mixing arrays and matrices is not legal template Derived& operator-=(const ArrayBase& ) {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} }; /*************************************************************************** * Implementation of matrix base methods ***************************************************************************/ /** replaces \c *this by \c *this * \a other. * * \returns a reference to \c *this * * Example: \include MatrixBase_applyOnTheRight.cpp * Output: \verbinclude MatrixBase_applyOnTheRight.out */ template template inline Derived& MatrixBase::operator*=(const EigenBase &other) { other.derived().applyThisOnTheRight(derived()); return derived(); } /** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). * * Example: \include MatrixBase_applyOnTheRight.cpp * Output: \verbinclude MatrixBase_applyOnTheRight.out */ template template inline void MatrixBase::applyOnTheRight(const EigenBase &other) { other.derived().applyThisOnTheRight(derived()); } /** replaces \c *this by \a other * \c *this. * * Example: \include MatrixBase_applyOnTheLeft.cpp * Output: \verbinclude MatrixBase_applyOnTheLeft.out */ template template inline void MatrixBase::applyOnTheLeft(const EigenBase &other) { other.derived().applyThisOnTheLeft(derived()); } } // end namespace Eigen #endif // EIGEN_MATRIXBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/NestByValue.h000066400000000000000000000065101506104011400241530ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NESTBYVALUE_H #define EIGEN_NESTBYVALUE_H namespace Eigen { namespace internal { template struct traits > : public traits {}; } /** \class NestByValue * \ingroup Core_Module * * \brief Expression which must be nested by value * * \tparam ExpressionType the type of the object of which we are requiring nesting-by-value * * This class is the return type of MatrixBase::nestByValue() * and most of the time this is the only way it is used. * * \sa MatrixBase::nestByValue() */ template class NestByValue : public internal::dense_xpr_base< NestByValue >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } template inline const PacketScalar packet(Index row, Index col) const { return m_expression.template packet(row, col); } template inline void writePacket(Index row, Index col, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(row, col, x); } template inline const PacketScalar packet(Index index) const { return m_expression.template packet(index); } template inline void writePacket(Index index, const PacketScalar& x) { m_expression.const_cast_derived().template writePacket(index, x); } EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; }; /** \returns an expression of the temporary version of *this. */ template inline const NestByValue DenseBase::nestByValue() const { return NestByValue(derived()); } } // end namespace Eigen #endif // EIGEN_NESTBYVALUE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/NoAlias.h000066400000000000000000000067761506104011400233160ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NOALIAS_H #define EIGEN_NOALIAS_H namespace Eigen { /** \class NoAlias * \ingroup Core_Module * * \brief Pseudo expression providing an operator = assuming no aliasing * * \tparam ExpressionType the type of the object on which to do the lazy assignment * * This class represents an expression with special assignment operators * assuming no aliasing between the target expression and the source expression. * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression. * It is the return type of MatrixBase::noalias() * and most of the time this is the only way it is used. * * \sa MatrixBase::noalias() */ template class StorageBase> class NoAlias { public: typedef typename ExpressionType::Scalar Scalar; explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) { call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); return m_expression; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); return m_expression; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } EIGEN_DEVICE_FUNC ExpressionType& expression() const { return m_expression; } protected: ExpressionType& m_expression; }; /** \returns a pseudo expression of \c *this with an operator= assuming * no aliasing between \c *this and the source expression. * * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag. * Currently, even though several expressions may alias, only product * expressions have this flag. Therefore, noalias() is only usefull when * the source expression contains a matrix product. * * Here are some examples where noalias is usefull: * \code * D.noalias() = A * B; * D.noalias() += A.transpose() * B; * D.noalias() -= 2 * A * B.adjoint(); * \endcode * * On the other hand the following example will lead to a \b wrong result: * \code * A.noalias() = A * B; * \endcode * because the result matrix A is also an operand of the matrix product. Therefore, * there is no alternative than evaluating A * B in a temporary, that is the default * behavior when you write: * \code * A = A * B; * \endcode * * \sa class NoAlias */ template NoAlias MatrixBase::noalias() { return NoAlias(derived()); } } // end namespace Eigen #endif // EIGEN_NOALIAS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/NumTraits.h000066400000000000000000000220221506104011400236740ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_NUMTRAITS_H #define EIGEN_NUMTRAITS_H namespace Eigen { namespace internal { // default implementation of digits10(), based on numeric_limits if specialized, // 0 for integer types, and log10(epsilon()) otherwise. template< typename T, bool use_numeric_limits = std::numeric_limits::is_specialized, bool is_integer = NumTraits::IsInteger> struct default_digits10_impl { static int run() { return std::numeric_limits::digits10; } }; template struct default_digits10_impl // Floating point { static int run() { using std::log10; using std::ceil; typedef typename NumTraits::Real Real; return int(ceil(-log10(NumTraits::epsilon()))); } }; template struct default_digits10_impl // Integer { static int run() { return 0; } }; } // end namespace internal /** \class NumTraits * \ingroup Core_Module * * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * * \tparam T the numeric type at hand * * This class stores enums, typedefs and static methods giving information about a numeric type. * * The provided data consists of: * \li A typedef \c Real, giving the "real part" type of \a T. If \a T is already real, * then \c Real is just a typedef to \a T. If \a T is \c std::complex then \c Real * is a typedef to \a U. * \li A typedef \c NonInteger, giving the type that should be used for operations producing non-integral values, * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is * only intended as a helper for code that needs to explicitly promote types. * \li A typedef \c Literal giving the type to use for numeric literals such as "2" or "0.5". For instance, for \c std::complex, Literal is defined as \c U. * Of course, this type must be fully compatible with \a T. In doubt, just use \a T here. * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex * type, and to 0 otherwise. * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, * and to \c 0 otherwise. * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. * Stay vague here. No need to do architecture-specific stuff. * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), * it returns a \a Real instead of a \a T. * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default * value by the fuzzy comparison operators. * \li highest() and lowest() functions returning the highest and lowest possible values respectively. * \li digits10() function returning the number of decimal digits that can be represented without change. This is * the analogue of std::numeric_limits::digits10 * which is used as the default implementation if specialized. */ template struct GenericNumTraits { enum { IsInteger = std::numeric_limits::is_integer, IsSigned = std::numeric_limits::is_signed, IsComplex = 0, RequireInitialization = internal::is_arithmetic::value ? 0 : 1, ReadCost = 1, AddCost = 1, MulCost = 1 }; typedef T Real; typedef typename internal::conditional< IsInteger, typename internal::conditional::type, T >::type NonInteger; typedef T Nested; typedef T Literal; EIGEN_DEVICE_FUNC static inline Real epsilon() { return numext::numeric_limits::epsilon(); } EIGEN_DEVICE_FUNC static inline int digits10() { return internal::default_digits10_impl::run(); } EIGEN_DEVICE_FUNC static inline Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } EIGEN_DEVICE_FUNC static inline T highest() { return (numext::numeric_limits::max)(); } EIGEN_DEVICE_FUNC static inline T lowest() { return IsInteger ? (numext::numeric_limits::min)() : (-(numext::numeric_limits::max)()); } EIGEN_DEVICE_FUNC static inline T infinity() { return numext::numeric_limits::infinity(); } EIGEN_DEVICE_FUNC static inline T quiet_NaN() { return numext::numeric_limits::quiet_NaN(); } }; template struct NumTraits : GenericNumTraits {}; template<> struct NumTraits : GenericNumTraits { EIGEN_DEVICE_FUNC static inline float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { EIGEN_DEVICE_FUNC static inline double dummy_precision() { return 1e-12; } }; template<> struct NumTraits : GenericNumTraits { static inline long double dummy_precision() { return 1e-15l; } }; template struct NumTraits > : GenericNumTraits > { typedef _Real Real; typedef typename NumTraits<_Real>::Literal Literal; enum { IsComplex = 1, RequireInitialization = NumTraits<_Real>::RequireInitialization, ReadCost = 2 * NumTraits<_Real>::ReadCost, AddCost = 2 * NumTraits::AddCost, MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; EIGEN_DEVICE_FUNC static inline Real epsilon() { return NumTraits::epsilon(); } EIGEN_DEVICE_FUNC static inline Real dummy_precision() { return NumTraits::dummy_precision(); } EIGEN_DEVICE_FUNC static inline int digits10() { return NumTraits::digits10(); } }; template struct NumTraits > { typedef Array ArrayType; typedef typename NumTraits::Real RealScalar; typedef Array Real; typedef typename NumTraits::NonInteger NonIntegerScalar; typedef Array NonInteger; typedef ArrayType & Nested; typedef typename NumTraits::Literal Literal; enum { IsComplex = NumTraits::IsComplex, IsInteger = NumTraits::IsInteger, IsSigned = NumTraits::IsSigned, RequireInitialization = 1, ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::AddCost, MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::MulCost }; EIGEN_DEVICE_FUNC static inline RealScalar epsilon() { return NumTraits::epsilon(); } EIGEN_DEVICE_FUNC static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } static inline int digits10() { return NumTraits::digits10(); } }; template<> struct NumTraits : GenericNumTraits { enum { RequireInitialization = 1, ReadCost = HugeCost, AddCost = HugeCost, MulCost = HugeCost }; static inline int digits10() { return 0; } private: static inline std::string epsilon(); static inline std::string dummy_precision(); static inline std::string lowest(); static inline std::string highest(); static inline std::string infinity(); static inline std::string quiet_NaN(); }; // Empty specialization for void to allow template specialization based on NumTraits::Real with T==void and SFINAE. template<> struct NumTraits {}; } // end namespace Eigen #endif // EIGEN_NUMTRAITS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/PermutationMatrix.h000066400000000000000000000522161506104011400254520ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Benoit Jacob // Copyright (C) 2009-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PERMUTATIONMATRIX_H #define EIGEN_PERMUTATIONMATRIX_H namespace Eigen { namespace internal { enum PermPermProduct_t {PermPermProduct}; } // end namespace internal /** \class PermutationBase * \ingroup Core_Module * * \brief Base class for permutations * * \tparam Derived the derived class * * This class is the base class for all expressions representing a permutation matrix, * internally stored as a vector of integers. * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have: * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f] * * Permutation matrices are square and invertible. * * Notice that in addition to the member functions and operators listed here, there also are non-member * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) * on either side. * * \sa class PermutationMatrix, class PermutationWrapper */ template class PermutationBase : public EigenBase { typedef internal::traits Traits; typedef EigenBase Base; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; typedef typename Traits::StorageIndex StorageIndex; typedef Matrix DenseMatrixType; typedef PermutationMatrix PlainPermutationType; typedef PlainPermutationType PlainObject; using Base::derived; typedef Inverse InverseReturnType; typedef void Scalar; #endif /** Copies the other permutation into *this */ template Derived& operator=(const PermutationBase& other) { indices() = other.indices(); return derived(); } /** Assignment from the Transpositions \a tr */ template Derived& operator=(const TranspositionsBase& tr) { setIdentity(tr.size()); for(Index k=size()-1; k>=0; --k) applyTranspositionOnTheRight(k,tr.coeff(k)); return derived(); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ Derived& operator=(const PermutationBase& other) { indices() = other.indices(); return derived(); } #endif /** \returns the number of rows */ inline Index rows() const { return Index(indices().size()); } /** \returns the number of columns */ inline Index cols() const { return Index(indices().size()); } /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ inline Index size() const { return Index(indices().size()); } #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); for (Index i=0; i=0 && j>=0 && i=0 && j>=0 && i void assignTranspose(const PermutationBase& other) { for (Index i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); for (Index i=0; i inline PlainPermutationType operator*(const PermutationBase& other) const { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } /** \returns the product of a permutation with another inverse permutation. * * \note \blank \note_try_to_help_rvo */ template inline PlainPermutationType operator*(const InverseImpl& other) const { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. * * \note \blank \note_try_to_help_rvo */ template friend inline PlainPermutationType operator*(const InverseImpl& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. * * This function is O(\c n) procedure allocating a buffer of \c n booleans. */ Index determinant() const { Index res = 1; Index n = size(); Matrix mask(n); mask.fill(false); Index r = 0; while(r < n) { // search for the next seed while(r=n) break; // we got one, let's follow it until we are back to the seed Index k0 = r++; mask.coeffRef(k0) = true; for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) { mask.coeffRef(k) = true; res = -res; } } return res; } protected: }; namespace internal { template struct traits > : traits > { typedef PermutationStorage StorageKind; typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; typedef _StorageIndex StorageIndex; typedef void Scalar; }; } /** \class PermutationMatrix * \ingroup Core_Module * * \brief Permutation matrix * * \tparam SizeAtCompileTime the number of rows/cols, or Dynamic * \tparam MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. * \tparam _StorageIndex the integer type of the indices * * This class represents a permutation matrix, internally stored as a vector of integers. * * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix */ template class PermutationMatrix : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: typedef const PermutationMatrix& Nested; #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; typedef typename Traits::StorageIndex StorageIndex; #endif inline PermutationMatrix() {} /** Constructs an uninitialized permutation matrix of given size. */ explicit inline PermutationMatrix(Index size) : m_indices(size) { eigen_internal_assert(size <= NumTraits::highest()); } /** Copy constructor. */ template inline PermutationMatrix(const PermutationBase& other) : m_indices(other.indices()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN /** Standard copy constructor. Defined only to prevent a default copy constructor * from hiding the other templated constructor */ inline PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} #endif /** Generic constructor from expression of the indices. The indices * array has the meaning that the permutations sends each integer i to indices[i]. * * \warning It is your responsibility to check that the indices array that you passes actually * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the * array's size. */ template explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) {} /** Convert the Transpositions \a tr to a permutation matrix */ template explicit PermutationMatrix(const TranspositionsBase& tr) : m_indices(tr.size()) { *this = tr; } /** Copies the other permutation into *this */ template PermutationMatrix& operator=(const PermutationBase& other) { m_indices = other.indices(); return *this; } /** Assignment from the Transpositions \a tr */ template PermutationMatrix& operator=(const TranspositionsBase& tr) { return Base::operator=(tr.derived()); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ PermutationMatrix& operator=(const PermutationMatrix& other) { m_indices = other.m_indices; return *this; } #endif /** const version of indices(). */ const IndicesType& indices() const { return m_indices; } /** \returns a reference to the stored array representing the permutation. */ IndicesType& indices() { return m_indices; } /**** multiplication helpers to hopefully get RVO ****/ #ifndef EIGEN_PARSED_BY_DOXYGEN template PermutationMatrix(const InverseImpl& other) : m_indices(other.derived().nestedExpression().size()) { eigen_internal_assert(m_indices.size() <= NumTraits::highest()); StorageIndex end = StorageIndex(m_indices.size()); for (StorageIndex i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) : m_indices(lhs.indices().size()) { Base::assignProduct(lhs,rhs); } #endif protected: IndicesType m_indices; }; namespace internal { template struct traits,_PacketAccess> > : traits > { typedef PermutationStorage StorageKind; typedef Map, _PacketAccess> IndicesType; typedef _StorageIndex StorageIndex; typedef void Scalar; }; } template class Map,_PacketAccess> : public PermutationBase,_PacketAccess> > { typedef PermutationBase Base; typedef internal::traits Traits; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; typedef typename IndicesType::Scalar StorageIndex; #endif inline Map(const StorageIndex* indicesPtr) : m_indices(indicesPtr) {} inline Map(const StorageIndex* indicesPtr, Index size) : m_indices(indicesPtr,size) {} /** Copies the other permutation into *this */ template Map& operator=(const PermutationBase& other) { return Base::operator=(other.derived()); } /** Assignment from the Transpositions \a tr */ template Map& operator=(const TranspositionsBase& tr) { return Base::operator=(tr.derived()); } #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ Map& operator=(const Map& other) { m_indices = other.m_indices; return *this; } #endif /** const version of indices(). */ const IndicesType& indices() const { return m_indices; } /** \returns a reference to the stored array representing the permutation. */ IndicesType& indices() { return m_indices; } protected: IndicesType m_indices; }; template class TranspositionsWrapper; namespace internal { template struct traits > { typedef PermutationStorage StorageKind; typedef void Scalar; typedef typename _IndicesType::Scalar StorageIndex; typedef _IndicesType IndicesType; enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, Flags = 0 }; }; } /** \class PermutationWrapper * \ingroup Core_Module * * \brief Class to view a vector of integers as a permutation matrix * * \tparam _IndicesType the type of the vector of integer (can be any compatible expression) * * This class allows to view any vector expression of integers as a permutation matrix. * * \sa class PermutationBase, class PermutationMatrix */ template class PermutationWrapper : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; #endif inline PermutationWrapper(const IndicesType& indices) : m_indices(indices) {} /** const version of indices(). */ const typename internal::remove_all::type& indices() const { return m_indices; } protected: typename IndicesType::Nested m_indices; }; /** \returns the matrix with the permutation applied to the columns. */ template EIGEN_DEVICE_FUNC const Product operator*(const MatrixBase &matrix, const PermutationBase& permutation) { return Product (matrix.derived(), permutation.derived()); } /** \returns the matrix with the permutation applied to the rows. */ template EIGEN_DEVICE_FUNC const Product operator*(const PermutationBase &permutation, const MatrixBase& matrix) { return Product (permutation.derived(), matrix.derived()); } template class InverseImpl : public EigenBase > { typedef typename PermutationType::PlainPermutationType PlainPermutationType; typedef internal::traits PermTraits; protected: InverseImpl() {} public: typedef Inverse InverseType; using EigenBase >::derived; #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename PermutationType::DenseMatrixType DenseMatrixType; enum { RowsAtCompileTime = PermTraits::RowsAtCompileTime, ColsAtCompileTime = PermTraits::ColsAtCompileTime, MaxRowsAtCompileTime = PermTraits::MaxRowsAtCompileTime, MaxColsAtCompileTime = PermTraits::MaxColsAtCompileTime }; #endif #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); for (Index i=0; i friend const Product operator*(const MatrixBase& matrix, const InverseType& trPerm) { return Product(matrix.derived(), trPerm.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ template const Product operator*(const MatrixBase& matrix) const { return Product(derived(), matrix.derived()); } }; template const PermutationWrapper MatrixBase::asPermutation() const { return derived(); } namespace internal { template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_PERMUTATIONMATRIX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/PlainObjectBase.h000066400000000000000000001304521506104011400247420ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_DENSESTORAGEBASE_H #define EIGEN_DENSESTORAGEBASE_H #if defined(EIGEN_INITIALIZE_MATRICES_BY_ZERO) # define EIGEN_INITIALIZE_COEFFS # define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(int i=0;i::quiet_NaN(); #else # undef EIGEN_INITIALIZE_COEFFS # define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #endif namespace Eigen { namespace internal { template struct check_rows_cols_for_overflow { template EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index, Index) { } }; template<> struct check_rows_cols_for_overflow { template EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) { // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 // we assume Index is signed Index max_index = (std::size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed bool error = (rows == 0 || cols == 0) ? false : (rows > max_index / cols); if (error) throw_std_bad_alloc(); } }; template struct conservative_resize_like_impl; template struct matrix_swap_impl; } // end namespace internal #ifdef EIGEN_PARSED_BY_DOXYGEN namespace doxygen { // This is a workaround to doxygen not being able to understand the inheritance logic // when it is hidden by the dense_xpr_base helper struct. // Moreover, doxygen fails to include members that are not documented in the declaration body of // MatrixBase if we inherits MatrixBase >, // this is why we simply inherits MatrixBase, though this does not make sense. /** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher > : public MatrixBase {}; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template struct dense_xpr_base_dispatcher > : public ArrayBase {}; } // namespace doxygen /** \class PlainObjectBase * \ingroup Core_Module * \brief %Dense storage base class for matrices and arrays. * * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. * * \tparam Derived is the derived type, e.g., a Matrix or Array * * \sa \ref TopicClassHierarchy */ template class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher #else template class PlainObjectBase : public internal::dense_xpr_base::type #endif { public: enum { Options = internal::traits::Options }; typedef typename internal::dense_xpr_base::type Base; typedef typename internal::traits::StorageKind StorageKind; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef Derived DenseType; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; using Base::MaxRowsAtCompileTime; using Base::MaxColsAtCompileTime; using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; template friend class Eigen::Map; friend class Eigen::Map; typedef Eigen::Map MapType; friend class Eigen::Map; typedef const Eigen::Map ConstMapType; #if EIGEN_MAX_ALIGN_BYTES>0 // for EIGEN_MAX_ALIGN_BYTES==0, AlignedMax==Unaligned, and many compilers generate warnings for friend-ing a class twice. friend class Eigen::Map; friend class Eigen::Map; #endif typedef Eigen::Map AlignedMapType; typedef const Eigen::Map ConstAlignedMapType; template struct StridedMapType { typedef Eigen::Map type; }; template struct StridedConstMapType { typedef Eigen::Map type; }; template struct StridedAlignedMapType { typedef Eigen::Map type; }; template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; protected: DenseStorage m_storage; public: enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits::Alignment>0) }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) EIGEN_DEVICE_FUNC Base& base() { return *static_cast(this); } EIGEN_DEVICE_FUNC const Base& base() const { return *static_cast(this); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } /** This is an overloaded version of DenseCoeffsBase::coeff(Index,Index) const * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. * * See DenseCoeffsBase::coeff(Index) const for details. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const { if(Flags & RowMajorBit) return m_storage.data()[colId + rowId * m_storage.cols()]; else // column-major return m_storage.data()[rowId + colId * m_storage.rows()]; } /** This is an overloaded version of DenseCoeffsBase::coeff(Index) const * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. * * See DenseCoeffsBase::coeff(Index) const for details. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { return m_storage.data()[index]; } /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index,Index) const * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. * * See DenseCoeffsBase::coeffRef(Index,Index) const for details. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) { if(Flags & RowMajorBit) return m_storage.data()[colId + rowId * m_storage.cols()]; else // column-major return m_storage.data()[rowId + colId * m_storage.rows()]; } /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index) const * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. * * See DenseCoeffsBase::coeffRef(Index) const for details. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_storage.data()[index]; } /** This is the const version of coeffRef(Index,Index) which is thus synonym of coeff(Index,Index). * It is provided for convenience. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const { if(Flags & RowMajorBit) return m_storage.data()[colId + rowId * m_storage.cols()]; else // column-major return m_storage.data()[rowId + colId * m_storage.rows()]; } /** This is the const version of coeffRef(Index) which is thus synonym of coeff(Index). * It is provided for convenience. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const { return m_storage.data()[index]; } /** \internal */ template EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const { return internal::ploadt (m_storage.data() + (Flags & RowMajorBit ? colId + rowId * m_storage.cols() : rowId + colId * m_storage.rows())); } /** \internal */ template EIGEN_STRONG_INLINE PacketScalar packet(Index index) const { return internal::ploadt(m_storage.data() + index); } /** \internal */ template EIGEN_STRONG_INLINE void writePacket(Index rowId, Index colId, const PacketScalar& val) { internal::pstoret (m_storage.data() + (Flags & RowMajorBit ? colId + rowId * m_storage.cols() : rowId + colId * m_storage.rows()), val); } /** \internal */ template EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& val) { internal::pstoret(m_storage.data() + index, val); } /** \returns a const pointer to the data array of this matrix */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. * * This method is intended for dynamic-size matrices, although it is legal to call it on any * matrix as long as fixed dimensions are left unchanged. If you only want to change the number * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t). * * If the current number of coefficients of \c *this exactly matches the * product \a rows * \a cols, then no memory allocation is performed and * the current values are left unchanged. In all other cases, including * shrinking, the data is reallocated and all previous values are lost. * * Example: \include Matrix_resize_int_int.cpp * Output: \verbinclude Matrix_resize_int_int.out * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index rows, Index cols) { eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,rows==RowsAtCompileTime) && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,cols==ColsAtCompileTime) && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,rows<=MaxRowsAtCompileTime) && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,cols<=MaxColsAtCompileTime) && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."); internal::check_rows_cols_for_overflow::run(rows, cols); #ifdef EIGEN_INITIALIZE_COEFFS Index size = rows*cols; bool size_changed = size != this->size(); m_storage.resize(size, rows, cols); if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #else m_storage.resize(rows*cols, rows, cols); #endif } /** Resizes \c *this to a vector of length \a size * * \only_for_vectors. This method does not work for * partially dynamic matrices when the static dimension is anything other * than 1. For example it will not work with Matrix. * * Example: \include Matrix_resize_int.cpp * Output: \verbinclude Matrix_resize_int.out * * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) */ EIGEN_DEVICE_FUNC inline void resize(Index size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) eigen_assert(((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0); #ifdef EIGEN_INITIALIZE_COEFFS bool size_changed = size != this->size(); #endif if(RowsAtCompileTime == 1) m_storage.resize(size, 1, size); else m_storage.resize(size, size, 1); #ifdef EIGEN_INITIALIZE_COEFFS if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #endif } /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange * as in the example below. * * Example: \include Matrix_resize_NoChange_int.cpp * Output: \verbinclude Matrix_resize_NoChange_int.out * * \sa resize(Index,Index) */ EIGEN_DEVICE_FUNC inline void resize(NoChange_t, Index cols) { resize(rows(), cols); } /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange * as in the example below. * * Example: \include Matrix_resize_int_NoChange.cpp * Output: \verbinclude Matrix_resize_int_NoChange.out * * \sa resize(Index,Index) */ EIGEN_DEVICE_FUNC inline void resize(Index rows, NoChange_t) { resize(rows, cols()); } /** Resizes \c *this to have the same dimensions as \a other. * Takes care of doing all the checking that's needed. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) { const OtherDerived& other = _other.derived(); internal::check_rows_cols_for_overflow::run(other.rows(), other.cols()); const Index othersize = other.rows()*other.cols(); if(RowsAtCompileTime == 1) { eigen_assert(other.rows() == 1 || other.cols() == 1); resize(1, othersize); } else if(ColsAtCompileTime == 1) { eigen_assert(other.rows() == 1 || other.cols() == 1); resize(othersize, 1); } else resize(other.rows(), other.cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * The method is intended for matrices of dynamic size. If you only want to change the number * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or * conservativeResize(Index, NoChange_t). * * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will be uninitialized. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) { internal::conservative_resize_like_impl::run(*this, rows, cols); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * As opposed to conservativeResize(Index rows, Index cols), this version leaves * the number of columns unchanged. * * In case the matrix is growing, new rows will be uninitialized. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) { // Note: see the comment in conservativeResize(Index,Index) conservativeResize(rows, cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. * * As opposed to conservativeResize(Index rows, Index cols), this version leaves * the number of rows unchanged. * * In case the matrix is growing, new columns will be uninitialized. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) { // Note: see the comment in conservativeResize(Index,Index) conservativeResize(rows(), cols); } /** Resizes the vector to \a size while retaining old values. * * \only_for_vectors. This method does not work for * partially dynamic matrices when the static dimension is anything other * than 1. For example it will not work with Matrix. * * When values are appended, they will be uninitialized. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index size) { internal::conservative_resize_like_impl::run(*this, size); } /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched. * * The method is intended for matrices of dynamic size. If you only want to change the number * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or * conservativeResize(Index, NoChange_t). * * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will copied from \c other. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) { internal::conservative_resize_like_impl::run(*this, other); } /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) { return _set(other); } /** \sa MatrixBase::lazyAssign() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) { _resize_to_match(other); return Base::lazyAssign(other.derived()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); } // Prevent user from trying to instantiate PlainObjectBase objects // by making all its constructor protected. See bug 1074. protected: EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() { // _check_template_params(); // EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ? /** \internal */ EIGEN_DEVICE_FUNC explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #endif #if EIGEN_HAS_RVALUE_REFERENCES EIGEN_DEVICE_FUNC PlainObjectBase(PlainObjectBase&& other) EIGEN_NOEXCEPT : m_storage( std::move(other.m_storage) ) { } EIGEN_DEVICE_FUNC PlainObjectBase& operator=(PlainObjectBase&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_storage, other.m_storage); return *this; } #endif /** Copy constructor */ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) : Base(), m_storage(other.m_storage) { } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) : m_storage(size, rows, cols) { // _check_template_params(); // EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } /** \sa PlainObjectBase::operator=(const EigenBase&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) : m_storage() { _check_template_params(); resizeLike(other); _set_noalias(other); } /** \sa PlainObjectBase::operator=(const EigenBase&) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) : m_storage() { _check_template_params(); resizeLike(other); *this = other.derived(); } /** \brief Copy constructor with in-place evaluation */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const ReturnByValue& other) { _check_template_params(); // FIXME this does not automatically transpose vectors if necessary resize(other.rows(), other.cols()); other.evalTo(this->derived()); } public: /** \brief Copies the generic expression \a other into *this. * \copydetails DenseBase::operator=(const EigenBase &other) */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) { _resize_to_match(other); Base::operator=(other.derived()); return this->derived(); } /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned * \a data pointers. * * Here is an example using strides: * \include Matrix_Map_stride.cpp * Output: \verbinclude Matrix_Map_stride.out * * \see class Map */ //@{ static inline ConstMapType Map(const Scalar* data) { return ConstMapType(data); } static inline MapType Map(Scalar* data) { return MapType(data); } static inline ConstMapType Map(const Scalar* data, Index size) { return ConstMapType(data, size); } static inline MapType Map(Scalar* data, Index size) { return MapType(data, size); } static inline ConstMapType Map(const Scalar* data, Index rows, Index cols) { return ConstMapType(data, rows, cols); } static inline MapType Map(Scalar* data, Index rows, Index cols) { return MapType(data, rows, cols); } static inline ConstAlignedMapType MapAligned(const Scalar* data) { return ConstAlignedMapType(data); } static inline AlignedMapType MapAligned(Scalar* data) { return AlignedMapType(data); } static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size) { return ConstAlignedMapType(data, size); } static inline AlignedMapType MapAligned(Scalar* data, Index size) { return AlignedMapType(data, size); } static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) { return ConstAlignedMapType(data, rows, cols); } static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) { return AlignedMapType(data, rows, cols); } template static inline typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) { return typename StridedConstMapType >::type(data, stride); } template static inline typename StridedMapType >::type Map(Scalar* data, const Stride& stride) { return typename StridedMapType >::type(data, stride); } template static inline typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstMapType >::type(data, size, stride); } template static inline typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) { return typename StridedMapType >::type(data, size, stride); } template static inline typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstMapType >::type(data, rows, cols, stride); } template static inline typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedMapType >::type(data, rows, cols, stride); } template static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, stride); } template static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) { return typename StridedAlignedMapType >::type(data, stride); } template static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, size, stride); } template static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) { return typename StridedAlignedMapType >::type(data, size, stride); } template static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } template static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } //@} using Base::setConstant; EIGEN_DEVICE_FUNC Derived& setConstant(Index size, const Scalar& val); EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, Index cols, const Scalar& val); using Base::setZero; EIGEN_DEVICE_FUNC Derived& setZero(Index size); EIGEN_DEVICE_FUNC Derived& setZero(Index rows, Index cols); using Base::setOnes; EIGEN_DEVICE_FUNC Derived& setOnes(Index size); EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, Index cols); using Base::setRandom; Derived& setRandom(Index size); Derived& setRandom(Index rows, Index cols); #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN #include EIGEN_PLAINOBJECTBASE_PLUGIN #endif protected: /** \internal Resizes *this in preparation for assigning \a other to it. * Takes care of doing all the checking that's needed. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size()) : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); EIGEN_ONLY_USED_FOR_DEBUG(other); #else resizeLike(other); #endif } /** * \brief Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), * it will be initialized. * * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. * * \sa operator=(const MatrixBase&), _set_noalias() * * \internal */ // aliasing is dealt once in internall::call_assignment // so at this stage we have to assume aliasing... and resising has to be done later. template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) { internal::call_assignment(this->derived(), other.derived()); return this->derived(); } /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * * \sa operator=(const MatrixBase&), _set() */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { // I don't think we need this resize call since the lazyAssign will anyways resize // and lazyAssign will be called by the assign selector. //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); return this->derived(); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) { const bool t0_is_integer_alike = internal::is_valid_index_type::value; const bool t1_is_integer_alike = internal::is_valid_index_type::value; EIGEN_STATIC_ASSERT(t0_is_integer_alike && t1_is_integer_alike, FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) resize(rows,cols); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init2(const T0& val0, const T1& val1, typename internal::enable_if::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) m_storage.data()[0] = Scalar(val0); m_storage.data()[1] = Scalar(val1); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init2(const Index& val0, const Index& val1, typename internal::enable_if< (!internal::is_same::value) && (internal::is_same::value) && (internal::is_same::value) && Base::SizeAtCompileTime==2,T1>::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) m_storage.data()[0] = Scalar(val0); m_storage.data()[1] = Scalar(val1); } // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, // then the argument is meant to be the size of the object. template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) { // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. const bool is_integer_alike = internal::is_valid_index_type::value; EIGEN_UNUSED_VARIABLE(is_integer_alike); EIGEN_STATIC_ASSERT(is_integer_alike, FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) resize(size); } // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitely converted) template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) m_storage.data()[0] = val0; } // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Index& val0, typename internal::enable_if< (!internal::is_same::value) && (internal::is_same::value) && Base::SizeAtCompileTime==1 && internal::is_convertible::value,T*>::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) m_storage.data()[0] = Scalar(val0); } // Initialize a fixed size matrix from a pointer to raw data template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Scalar* data){ this->_set_noalias(ConstMapType(data)); } // Initialize an arbitrary matrix from a dense expression template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ this->_set_noalias(other); } // Initialize an arbitrary matrix from an object convertible to the Derived type. template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Derived& other){ this->_set_noalias(other); } // Initialize an arbitrary matrix from a generic Eigen expression template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ this->derived() = other; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const ReturnByValue& other) { resize(other.rows(), other.cols()); other.evalTo(this->derived()); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const RotationBase& r) { this->derived() = r; } // For fixed-size Array template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic && Base::SizeAtCompileTime!=1 && internal::is_convertible::value && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) { Base::setConstant(val0); } // For fixed-size Array template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _init1(const Index& val0, typename internal::enable_if< (!internal::is_same::value) && (internal::is_same::value) && Base::SizeAtCompileTime!=Dynamic && Base::SizeAtCompileTime!=1 && internal::is_convertible::value && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) { Base::setConstant(val0); } template friend struct internal::matrix_swap_impl; public: #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal * \brief Override DenseBase::swap() since for dynamic-sized matrices * of same type it is enough to swap the data pointers. */ template EIGEN_DEVICE_FUNC void swap(DenseBase & other) { enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; internal::matrix_swap_impl::run(this->derived(), other.derived()); } /** \internal * \brief const version forwarded to DenseBase::swap */ template EIGEN_DEVICE_FUNC void swap(DenseBase const & other) { Base::swap(other.derived()); } EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0) && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0)) && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0)) && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0)) && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0)) && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic) && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic) && (Options & (DontAlign|RowMajor)) == Options), INVALID_MATRIX_TEMPLATE_PARAMETERS) } enum { IsPlainObjectBase = 1 }; #endif }; namespace internal { template struct conservative_resize_like_impl { static void run(DenseBase& _this, Index rows, Index cols) { if (_this.rows() == rows && _this.cols() == cols) return; EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) if ( ( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows (!Derived::IsRowMajor && _this.rows() == rows) ) // column-major and we change only the number of columns { internal::check_rows_cols_for_overflow::run(rows, cols); _this.derived().m_storage.conservativeResize(rows*cols,rows,cols); } else { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(rows,cols); const Index common_rows = numext::mini(rows, _this.rows()); const Index common_cols = numext::mini(cols, _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } } static void run(DenseBase& _this, const DenseBase& other) { if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index), // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) if ( ( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows (!Derived::IsRowMajor && _this.rows() == other.rows()) ) // column-major and we change only the number of columns { const Index new_rows = other.rows() - _this.rows(); const Index new_cols = other.cols() - _this.cols(); _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols()); if (new_rows>0) _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows); else if (new_cols>0) _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols); } else { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(other); const Index common_rows = numext::mini(tmp.rows(), _this.rows()); const Index common_cols = numext::mini(tmp.cols(), _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } } }; // Here, the specialization for vectors inherits from the general matrix case // to allow calling .conservativeResize(rows,cols) on vectors. template struct conservative_resize_like_impl : conservative_resize_like_impl { using conservative_resize_like_impl::run; static void run(DenseBase& _this, Index size) { const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1; _this.derived().m_storage.conservativeResize(size,new_rows,new_cols); } static void run(DenseBase& _this, const DenseBase& other) { if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; const Index num_new_elements = other.size() - _this.size(); const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows(); const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1; _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols); if (num_new_elements > 0) _this.tail(num_new_elements) = other.tail(num_new_elements); } }; template struct matrix_swap_impl { EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { a.base().swap(b); } }; template struct matrix_swap_impl { EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { static_cast(a).m_storage.swap(static_cast(b).m_storage); } }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_DENSESTORAGEBASE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Product.h000066400000000000000000000161031506104011400233710ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2011 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PRODUCT_H #define EIGEN_PRODUCT_H namespace Eigen { template class ProductImpl; namespace internal { template struct traits > { typedef typename remove_all::type LhsCleaned; typedef typename remove_all::type RhsCleaned; typedef traits LhsTraits; typedef traits RhsTraits; typedef MatrixXpr XprKind; typedef typename ScalarBinaryOpTraits::Scalar, typename traits::Scalar>::ReturnType Scalar; typedef typename product_promote_storage_type::ret>::ret StorageKind; typedef typename promote_index_type::type StorageIndex; enum { RowsAtCompileTime = LhsTraits::RowsAtCompileTime, ColsAtCompileTime = RhsTraits::ColsAtCompileTime, MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, // FIXME: only needed by GeneralMatrixMatrixTriangular InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. Flags = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? RowMajorBit : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 : ( ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit : NoPreferredStorageOrderBit }; }; } // end namespace internal /** \class Product * \ingroup Core_Module * * \brief Expression of the product of two arbitrary matrices or vectors * * \tparam _Lhs the type of the left-hand side expression * \tparam _Rhs the type of the right-hand side expression * * This class represents an expression of the product of two arbitrary matrices. * * The other template parameters are: * \tparam Option can be DefaultProduct, AliasFreeProduct, or LazyProduct * */ template class Product : public ProductImpl<_Lhs,_Rhs,Option, typename internal::product_promote_storage_type::StorageKind, typename internal::traits<_Rhs>::StorageKind, internal::product_type<_Lhs,_Rhs>::ret>::ret> { public: typedef _Lhs Lhs; typedef _Rhs Rhs; typedef typename ProductImpl< Lhs, Rhs, Option, typename internal::product_promote_storage_type::StorageKind, typename internal::traits::StorageKind, internal::product_type::ret>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Product) typedef typename internal::ref_selector::type LhsNested; typedef typename internal::ref_selector::type RhsNested; typedef typename internal::remove_all::type LhsNestedCleaned; typedef typename internal::remove_all::type RhsNestedCleaned; EIGEN_DEVICE_FUNC Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { eigen_assert(lhs.cols() == rhs.rows() && "invalid matrix product" && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); } EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; } EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; } protected: LhsNested m_lhs; RhsNested m_rhs; }; namespace internal { template::ret> class dense_product_base : public internal::dense_xpr_base >::type {}; /** Convertion to scalar for inner-products */ template class dense_product_base : public internal::dense_xpr_base >::type { typedef Product ProductXpr; typedef typename internal::dense_xpr_base::type Base; public: using Base::derived; typedef typename Base::Scalar Scalar; EIGEN_STRONG_INLINE operator const Scalar() const { return internal::evaluator(derived()).coeff(0,0); } }; } // namespace internal // Generic API dispatcher template class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type { public: typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; }; template class ProductImpl : public internal::dense_product_base { typedef Product Derived; public: typedef typename internal::dense_product_base Base; EIGEN_DENSE_PUBLIC_INTERFACE(Derived) protected: enum { IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), EnableCoeff = IsOneByOne || Option==LazyProduct }; public: EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const { EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); return internal::evaluator(derived()).coeff(row,col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const { EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); return internal::evaluator(derived()).coeff(i); } }; } // end namespace Eigen #endif // EIGEN_PRODUCT_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ProductEvaluators.h000066400000000000000000001435761506104011400254560ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2008-2010 Gael Guennebaud // Copyright (C) 2011 Jitse Niesen // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_PRODUCTEVALUATORS_H #define EIGEN_PRODUCTEVALUATORS_H namespace Eigen { namespace internal { /** \internal * Evaluator of a product expression. * Since products require special treatments to handle all possible cases, * we simply deffer the evaluation logic to a product_evaluator class * which offers more partial specialization possibilities. * * \sa class product_evaluator */ template struct evaluator > : public product_evaluator > { typedef Product XprType; typedef product_evaluator Base; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {} }; // Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B" // TODO we should apply that rule only if that's really helpful template struct evaluator_assume_aliasing, const CwiseNullaryOp, Plain1>, const Product > > { static const bool value = true; }; template struct evaluator, const CwiseNullaryOp, Plain1>, const Product > > : public evaluator > { typedef CwiseBinaryOp, const CwiseNullaryOp, Plain1>, const Product > XprType; typedef evaluator > Base; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs()) {} }; template struct evaluator, DiagIndex> > : public evaluator, DiagIndex> > { typedef Diagonal, DiagIndex> XprType; typedef evaluator, DiagIndex> > Base; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(Diagonal, DiagIndex>( Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), xpr.index() )) {} }; // Helper class to perform a matrix product with the destination at hand. // Depending on the sizes of the factors, there are different evaluation strategies // as controlled by internal::product_type. template< typename Lhs, typename Rhs, typename LhsShape = typename evaluator_traits::Shape, typename RhsShape = typename evaluator_traits::Shape, int ProductType = internal::product_type::value> struct generic_product_impl; template struct evaluator_assume_aliasing > { static const bool value = true; }; // This is the default evaluator implementation for products: // It creates a temporary and call generic_product_impl template struct product_evaluator, ProductTag, LhsShape, RhsShape> : public evaluator::PlainObject> { typedef Product XprType; typedef typename XprType::PlainObject PlainObject; typedef evaluator Base; enum { Flags = Base::Flags | EvalBeforeNestingBit }; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit product_evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); // FIXME shall we handle nested_eval here?, // if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.) // typedef typename internal::nested_eval::type LhsNested; // typedef typename internal::nested_eval::type RhsNested; // typedef typename internal::remove_all::type LhsNestedCleaned; // typedef typename internal::remove_all::type RhsNestedCleaned; // // const LhsNested lhs(xpr.lhs()); // const RhsNested rhs(xpr.rhs()); // // generic_product_impl::evalTo(m_result, lhs, rhs); generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); } protected: PlainObject m_result; }; // The following three shortcuts are enabled only if the scalar types match excatly. // TODO: we could enable them for different scalar types when the product is not vectorized. // Dense = Product template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> struct Assignment, internal::assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) { Index dstRows = src.rows(); Index dstCols = src.cols(); if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) dst.resize(dstRows, dstCols); // FIXME shall we handle nested_eval here? generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); } }; // Dense += Product template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> struct Assignment, internal::add_assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); // FIXME shall we handle nested_eval here? generic_product_impl::addTo(dst, src.lhs(), src.rhs()); } }; // Dense -= Product template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> struct Assignment, internal::sub_assign_op, Dense2Dense, typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> { typedef Product SrcXprType; static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) { eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); // FIXME shall we handle nested_eval here? generic_product_impl::subTo(dst, src.lhs(), src.rhs()); } }; // Dense ?= scalar * Product // TODO we should apply that rule if that's really helpful // for instance, this is not good for inner products template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis, typename Plain> struct Assignment, const CwiseNullaryOp,Plain>, const Product >, AssignFunc, Dense2Dense> { typedef CwiseBinaryOp, const CwiseNullaryOp,Plain>, const Product > SrcXprType; static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) { call_assignment_no_alias(dst, (src.lhs().functor().m_other * src.rhs().lhs())*src.rhs().rhs(), func); } }; //---------------------------------------- // Catch "Dense ?= xpr + Product<>" expression to save one temporary // FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct template struct evaluator_assume_aliasing::Scalar>, const OtherXpr, const Product >, DenseShape > { static const bool value = true; }; template struct evaluator_assume_aliasing::Scalar>, const OtherXpr, const Product >, DenseShape > { static const bool value = true; }; template struct assignment_from_xpr_op_product { template static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const InitialFunc& /*func*/) { call_assignment_no_alias(dst, src.lhs(), Func1()); call_assignment_no_alias(dst, src.rhs(), Func2()); } }; #define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP,BINOP,ASSIGN_OP2) \ template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename DstScalar, typename SrcScalar, typename OtherScalar,typename ProdScalar> \ struct Assignment, const OtherXpr, \ const Product >, internal::ASSIGN_OP, Dense2Dense> \ : assignment_from_xpr_op_product, internal::ASSIGN_OP, internal::ASSIGN_OP2 > \ {} EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_sum_op,add_assign_op); EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_sum_op,add_assign_op); EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_sum_op,sub_assign_op); EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_difference_op,sub_assign_op); EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_difference_op,sub_assign_op); EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_difference_op,add_assign_op); //---------------------------------------- template struct generic_product_impl { template static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); } template static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); } template static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } }; /*********************************************************************** * Implementation of outer dense * dense vector product ***********************************************************************/ // Column major result template void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) { evaluator rhsEval(rhs); typename nested_eval::type actual_lhs(lhs); // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored // FIXME not very good if rhs is real and lhs complex while alpha is real too const Index cols = dst.cols(); for (Index j=0; j void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) { evaluator lhsEval(lhs); typename nested_eval::type actual_rhs(rhs); // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored // FIXME not very good if lhs is real and rhs complex while alpha is real too const Index rows = dst.rows(); for (Index i=0; i struct generic_product_impl { template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; typedef typename Product::Scalar Scalar; // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; struct adds { Scalar m_scale; explicit adds(const Scalar& s) : m_scale(s) {} template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += m_scale * src; } }; template static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major()); } template static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major()); } template static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major()); } template static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major()); } }; // This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo template struct generic_product_impl_base { typedef typename Product::Scalar Scalar; template static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } template static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } template static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } template static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } }; template struct generic_product_impl : generic_product_impl_base > { typedef typename nested_eval::type LhsNested; typedef typename nested_eval::type RhsNested; typedef typename Product::Scalar Scalar; enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; typedef typename internal::remove_all::type>::type MatrixType; template static EIGEN_STRONG_INLINE void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { LhsNested actual_lhs(lhs); RhsNested actual_rhs(rhs); internal::gemv_dense_selector::HasUsableDirectAccess) >::run(actual_lhs, actual_rhs, dst, alpha); } }; template struct generic_product_impl { typedef typename Product::Scalar Scalar; template static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { // Same as: dst.noalias() = lhs.lazyProduct(rhs); // but easier on the compiler side call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op()); } template static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { // dst.noalias() += lhs.lazyProduct(rhs); call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op()); } template static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) { // dst.noalias() -= lhs.lazyProduct(rhs); call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op()); } // Catch "dst {,+,-}= (s*A)*B" and evaluate it lazily by moving out the scalar factor: // dst {,+,-}= s * (A.lazyProduct(B)) // This is a huge benefit for heap-allocated matrix types as it save one costly allocation. // For them, this strategy is also faster than simply by-passing the heap allocation through // stack allocation. // For fixed sizes matrices, this is less obvious, it is sometimes x2 faster, but sometimes x3 slower, // and the behavior depends also a lot on the compiler... so let's be conservative and enable them for dynamic-size only, // that is when coming from generic_product_impl<...,GemmProduct> in file GeneralMatrixMatrix.h template static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void eval_dynamic(Dst& dst, const CwiseBinaryOp, const CwiseNullaryOp, Plain1>, Xpr2>& lhs, const Rhs& rhs, const Func &func) { call_assignment_no_alias(dst, lhs.lhs().functor().m_other * lhs.rhs().lazyProduct(rhs), func); } // Here, we we always have LhsT==Lhs, but we need to make it a template type to make the above // overload more specialized. template static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void eval_dynamic(Dst& dst, const LhsT& lhs, const Rhs& rhs, const Func &func) { call_assignment_no_alias(dst, lhs.lazyProduct(rhs), func); } // template // static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) // { dst.noalias() += alpha * lhs.lazyProduct(rhs); } }; // This specialization enforces the use of a coefficient-based evaluation strategy template struct generic_product_impl : generic_product_impl {}; // Case 2: Evaluate coeff by coeff // // This is mostly taken from CoeffBasedProduct.h // The main difference is that we add an extra argument to the etor_product_*_impl::run() function // for the inner dimension of the product, because evaluator object do not know their size. template struct etor_product_coeff_impl; template struct etor_product_packet_impl; template struct product_evaluator, ProductTag, DenseShape, DenseShape> : evaluator_base > { typedef Product XprType; typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit product_evaluator(const XprType& xpr) : m_lhs(xpr.lhs()), m_rhs(xpr.rhs()), m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. m_innerDim(xpr.lhs().cols()) { EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::AddCost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); #if 0 std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n"; std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n"; std::cerr << "LhsAlignment= " << LhsAlignment << "\n"; std::cerr << "RhsAlignment= " << RhsAlignment << "\n"; std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n"; std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n"; std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n"; std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n"; std::cerr << "Alignment= " << Alignment << "\n"; std::cerr << "Flags= " << Flags << "\n"; #endif } // Everything below here is taken from CoeffBasedProduct.h typedef typename internal::nested_eval::type LhsNested; typedef typename internal::nested_eval::type RhsNested; typedef typename internal::remove_all::type LhsNestedCleaned; typedef typename internal::remove_all::type RhsNestedCleaned; typedef evaluator LhsEtorType; typedef evaluator RhsEtorType; enum { RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime }; typedef typename find_best_packet::type LhsVecPacketType; typedef typename find_best_packet::type RhsVecPacketType; enum { LhsCoeffReadCost = LhsEtorType::CoeffReadCost, RhsCoeffReadCost = RhsEtorType::CoeffReadCost, CoeffReadCost = InnerSize==0 ? NumTraits::ReadCost : InnerSize == Dynamic ? HugeCost : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + (InnerSize - 1) * NumTraits::AddCost, Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, LhsFlags = LhsEtorType::Flags, RhsFlags = RhsEtorType::Flags, LhsRowMajor = LhsFlags & RowMajorBit, RhsRowMajor = RhsFlags & RowMajorBit, LhsVecPacketSize = unpacket_traits::size, RhsVecPacketSize = unpacket_traits::size, // Here, we don't care about alignment larger than the usable packet size. LhsAlignment = EIGEN_PLAIN_ENUM_MIN(LhsEtorType::Alignment,LhsVecPacketSize*int(sizeof(typename LhsNestedCleaned::Scalar))), RhsAlignment = EIGEN_PLAIN_ENUM_MIN(RhsEtorType::Alignment,RhsVecPacketSize*int(sizeof(typename RhsNestedCleaned::Scalar))), SameType = is_same::value, CanVectorizeRhs = bool(RhsRowMajor) && (RhsFlags & PacketAccessBit) && (ColsAtCompileTime!=1), CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) && (RowsAtCompileTime!=1), EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : (bool(RhsRowMajor) && !CanVectorizeLhs), Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) | (EvalToRowMajor ? RowMajorBit : 0) // TODO enable vectorization for mixed types | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0) | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0), LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)), RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)), Alignment = bool(CanVectorizeLhs) ? (LhsOuterStrideBytes<=0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment) : bool(CanVectorizeRhs) ? (RhsOuterStrideBytes<=0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment) : 0, /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. */ CanVectorizeInner = SameType && LhsRowMajor && (!RhsRowMajor) && (LhsFlags & RhsFlags & ActualPacketAccessBit) && (InnerSize % packet_traits::size == 0) }; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const { return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); } /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, * which is why we don't set the LinearAccessBit. * TODO: this seems possible when the result is a vector */ EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const { const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); } template const PacketType packet(Index row, Index col) const { PacketType res; typedef etor_product_packet_impl PacketImpl; PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); return res; } template const PacketType packet(Index index) const { const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; return packet(row,col); } protected: typename internal::add_const_on_value_type::type m_lhs; typename internal::add_const_on_value_type::type m_rhs; LhsEtorType m_lhsImpl; RhsEtorType m_rhsImpl; // TODO: Get rid of m_innerDim if known at compile time Index m_innerDim; }; template struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape> : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape> { typedef Product XprType; typedef Product BaseProduct; typedef product_evaluator Base; enum { Flags = Base::Flags | EvalBeforeNestingBit }; EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(BaseProduct(xpr.lhs(),xpr.rhs())) {} }; /**************************************** *** Coeff based product, Packet path *** ****************************************/ template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) { etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); res = pmadd(pset1(lhs.coeff(row, Index(UnrollingIndex-1))), rhs.template packet(Index(UnrollingIndex-1), col), res); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) { etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); res = pmadd(lhs.template packet(row, Index(UnrollingIndex-1)), pset1(rhs.coeff(Index(UnrollingIndex-1), col)), res); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) { res = pmul(pset1(lhs.coeff(row, Index(0))),rhs.template packet(Index(0), col)); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) { res = pmul(lhs.template packet(row, Index(0)), pset1(rhs.coeff(Index(0), col))); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) { res = pset1(typename unpacket_traits::type(0)); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) { res = pset1(typename unpacket_traits::type(0)); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) { res = pset1(typename unpacket_traits::type(0)); for(Index i = 0; i < innerDim; ++i) res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); } }; template struct etor_product_packet_impl { static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) { res = pset1(typename unpacket_traits::type(0)); for(Index i = 0; i < innerDim; ++i) res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); } }; /*************************************************************************** * Triangular products ***************************************************************************/ template struct triangular_product_impl; template struct generic_product_impl : generic_product_impl_base > { typedef typename Product::Scalar Scalar; template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { triangular_product_impl ::run(dst, lhs.nestedExpression(), rhs, alpha); } }; template struct generic_product_impl : generic_product_impl_base > { typedef typename Product::Scalar Scalar; template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); } }; /*************************************************************************** * SelfAdjoint products ***************************************************************************/ template struct selfadjoint_product_impl; template struct generic_product_impl : generic_product_impl_base > { typedef typename Product::Scalar Scalar; template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); } }; template struct generic_product_impl : generic_product_impl_base > { typedef typename Product::Scalar Scalar; template static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) { selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); } }; /*************************************************************************** * Diagonal products ***************************************************************************/ template struct diagonal_product_evaluator_base : evaluator_base { typedef typename ScalarBinaryOpTraits::ReturnType Scalar; public: enum { CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost, MatrixFlags = evaluator::Flags, DiagFlags = evaluator::Flags, _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor, _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), _SameTypes = is_same::value, // FIXME currently we need same types, but in the future the next rule should be the one //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0), Alignment = evaluator::Alignment, AsScalarProduct = (DiagonalType::SizeAtCompileTime==1) || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::RowsAtCompileTime==1 && ProductOrder==OnTheLeft) || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==1 && ProductOrder==OnTheRight) }; diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) : m_diagImpl(diag), m_matImpl(mat) { EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const { if(AsScalarProduct) return m_diagImpl.coeff(0) * m_matImpl.coeff(idx); else return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); } protected: template EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const { return internal::pmul(m_matImpl.template packet(row, col), internal::pset1(m_diagImpl.coeff(id))); } template EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const { enum { InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator::Alignment)) // FIXME hardcoded 16!! }; return internal::pmul(m_matImpl.template packet(row, col), m_diagImpl.template packet(id)); } evaluator m_diagImpl; evaluator m_matImpl; }; // diagonal * dense template struct product_evaluator, ProductTag, DiagonalShape, DenseShape> : diagonal_product_evaluator_base, OnTheLeft> { typedef diagonal_product_evaluator_base, OnTheLeft> Base; using Base::m_diagImpl; using Base::m_matImpl; using Base::coeff; typedef typename Base::Scalar Scalar; typedef Product XprType; typedef typename XprType::PlainObject PlainObject; enum { StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(xpr.rhs(), xpr.lhs().diagonal()) { } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); } #ifndef __CUDACC__ template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case. // See also similar calls below. return this->template packet_impl(row,col, row, typename internal::conditional::type()); } template EIGEN_STRONG_INLINE PacketType packet(Index idx) const { return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } #endif }; // dense * diagonal template struct product_evaluator, ProductTag, DenseShape, DiagonalShape> : diagonal_product_evaluator_base, OnTheRight> { typedef diagonal_product_evaluator_base, OnTheRight> Base; using Base::m_diagImpl; using Base::m_matImpl; using Base::coeff; typedef typename Base::Scalar Scalar; typedef Product XprType; typedef typename XprType::PlainObject PlainObject; enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) : Base(xpr.lhs(), xpr.rhs().diagonal()) { } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const { return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); } #ifndef __CUDACC__ template EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { return this->template packet_impl(row,col, col, typename internal::conditional::type()); } template EIGEN_STRONG_INLINE PacketType packet(Index idx) const { return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); } #endif }; /*************************************************************************** * Products with permutation matrices ***************************************************************************/ /** \internal * \class permutation_matrix_product * Internal helper class implementing the product between a permutation matrix and a matrix. * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h */ template struct permutation_matrix_product; template struct permutation_matrix_product { typedef typename nested_eval::type MatrixType; typedef typename remove_all::type MatrixTypeCleaned; template static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) { MatrixType mat(xpr); const Index n = Side==OnTheLeft ? mat.rows() : mat.cols(); // FIXME we need an is_same for expression that is not sensitive to constness. For instance // is_same_xpr, Block >::value should be true. //if(is_same::value && extract_data(dst) == extract_data(mat)) if(is_same_dense(dst, mat)) { // apply the permutation inplace Matrix mask(perm.size()); mask.fill(false); Index r = 0; while(r < perm.size()) { // search for the next seed while(r=perm.size()) break; // we got one, let's follow it until we are back to the seed Index k0 = r++; Index kPrev = k0; mask.coeffRef(k0) = true; for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k)) { Block(dst, k) .swap(Block (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); mask.coeffRef(k) = true; kPrev = k; } } } else { for(Index i = 0; i < n; ++i) { Block (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i) = Block (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i); } } } }; template struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { permutation_matrix_product::run(dst, lhs, rhs); } }; template struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { permutation_matrix_product::run(dst, rhs, lhs); } }; template struct generic_product_impl, Rhs, PermutationShape, MatrixShape, ProductTag> { template static void evalTo(Dest& dst, const Inverse& lhs, const Rhs& rhs) { permutation_matrix_product::run(dst, lhs.nestedExpression(), rhs); } }; template struct generic_product_impl, MatrixShape, PermutationShape, ProductTag> { template static void evalTo(Dest& dst, const Lhs& lhs, const Inverse& rhs) { permutation_matrix_product::run(dst, rhs.nestedExpression(), lhs); } }; /*************************************************************************** * Products with transpositions matrices ***************************************************************************/ // FIXME could we unify Transpositions and Permutation into a single "shape"?? /** \internal * \class transposition_matrix_product * Internal helper class implementing the product between a permutation matrix and a matrix. */ template struct transposition_matrix_product { typedef typename nested_eval::type MatrixType; typedef typename remove_all::type MatrixTypeCleaned; template static inline void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr) { MatrixType mat(xpr); typedef typename TranspositionType::StorageIndex StorageIndex; const Index size = tr.size(); StorageIndex j = 0; if(!is_same_dense(dst,mat)) dst = mat; for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { transposition_matrix_product::run(dst, lhs, rhs); } }; template struct generic_product_impl { template static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) { transposition_matrix_product::run(dst, rhs, lhs); } }; template struct generic_product_impl, Rhs, TranspositionsShape, MatrixShape, ProductTag> { template static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) { transposition_matrix_product::run(dst, lhs.nestedExpression(), rhs); } }; template struct generic_product_impl, MatrixShape, TranspositionsShape, ProductTag> { template static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) { transposition_matrix_product::run(dst, rhs.nestedExpression(), lhs); } }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_PRODUCT_EVALUATORS_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Random.h000066400000000000000000000143531506104011400231760ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_RANDOM_H #define EIGEN_RANDOM_H namespace Eigen { namespace internal { template struct scalar_random_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) inline const Scalar operator() () const { return random(); } }; template struct functor_traits > { enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; } // end namespace internal /** \returns a random matrix expression * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * \not_reentrant * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. * * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * See DenseBase::NullaryExpr(Index, const CustomNullaryOp&) for an example using C++11 random generators. * * \sa DenseBase::setRandom(), DenseBase::Random(Index), DenseBase::Random() */ template inline const typename DenseBase::RandomReturnType DenseBase::Random(Index rows, Index cols) { return NullaryExpr(rows, cols, internal::scalar_random_op()); } /** \returns a random vector expression * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors * \not_reentrant * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Random() should be used * instead. * * Example: \include MatrixBase_random_int.cpp * Output: \verbinclude MatrixBase_random_int.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary vector whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random() */ template inline const typename DenseBase::RandomReturnType DenseBase::Random(Index size) { return NullaryExpr(size, internal::scalar_random_op()); } /** \returns a fixed-size random matrix or vector expression * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * * Example: \include MatrixBase_random.cpp * Output: \verbinclude MatrixBase_random.out * * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * * \not_reentrant * * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random(Index) */ template inline const typename DenseBase::RandomReturnType DenseBase::Random() { return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); } /** Sets all coefficients in this expression to random values. * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * \not_reentrant * * Example: \include MatrixBase_setRandom.cpp * Output: \verbinclude MatrixBase_setRandom.out * * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index) */ template inline Derived& DenseBase::setRandom() { return *this = Random(rows(), cols()); } /** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * \only_for_vectors * \not_reentrant * * Example: \include Matrix_setRandom_int.cpp * Output: \verbinclude Matrix_setRandom_int.out * * \sa DenseBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setRandom(Index newSize) { resize(newSize); return setRandom(); } /** Resizes to the given size, and sets all coefficients in this expression to random values. * * Numbers are uniformly spread through their whole definition range for integer types, * and in the [-1:1] range for floating point scalar types. * * \not_reentrant * * \param rows the new number of rows * \param cols the new number of columns * * Example: \include Matrix_setRandom_int_int.cpp * Output: \verbinclude Matrix_setRandom_int_int.out * * \sa DenseBase::setRandom(), setRandom(Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& PlainObjectBase::setRandom(Index rows, Index cols) { resize(rows, cols); return setRandom(); } } // end namespace Eigen #endif // EIGEN_RANDOM_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Redux.h000066400000000000000000000426741506104011400230540ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REDUX_H #define EIGEN_REDUX_H namespace Eigen { namespace internal { // TODO // * implement other kind of vectorization // * factorize code /*************************************************************************** * Part 1 : the logic deciding a strategy for vectorization and unrolling ***************************************************************************/ template struct redux_traits { public: typedef typename find_best_packet::type PacketType; enum { PacketSize = unpacket_traits::size, InnerMaxSize = int(Derived::IsRowMajor) ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime }; enum { MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) && (functor_traits::PacketAccess), MayLinearVectorize = bool(MightVectorize) && (int(Derived::Flags)&LinearAccessBit), MaySliceVectorize = bool(MightVectorize) && int(InnerMaxSize)>=3*PacketSize }; public: enum { Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal) : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) : int(DefaultTraversal) }; public: enum { Cost = Derived::SizeAtCompileTime == Dynamic ? HugeCost : Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) }; public: enum { Unrolling = Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling }; #ifdef EIGEN_DEBUG_ASSIGN static void debug() { std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; std::cerr.setf(std::ios::hex, std::ios::basefield); EIGEN_DEBUG_VAR(Derived::Flags) std::cerr.unsetf(std::ios::hex); EIGEN_DEBUG_VAR(InnerMaxSize) EIGEN_DEBUG_VAR(PacketSize) EIGEN_DEBUG_VAR(MightVectorize) EIGEN_DEBUG_VAR(MayLinearVectorize) EIGEN_DEBUG_VAR(MaySliceVectorize) EIGEN_DEBUG_VAR(Traversal) EIGEN_DEBUG_VAR(UnrollingLimit) EIGEN_DEBUG_VAR(Unrolling) std::cerr << std::endl; } #endif }; /*************************************************************************** * Part 2 : unrollers ***************************************************************************/ /*** no vectorization ***/ template struct redux_novec_unroller { enum { HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), redux_novec_unroller::run(mat,func)); } }; template struct redux_novec_unroller { enum { outer = Start / Derived::InnerSizeAtCompileTime, inner = Start % Derived::InnerSizeAtCompileTime }; typedef typename Derived::Scalar Scalar; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); } }; // This is actually dead code and will never be called. It is required // to prevent false warnings regarding failed inlining though // for 0 length run() will never be called at all. template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } }; /*** vectorization ***/ template struct redux_vec_unroller { enum { PacketSize = redux_traits::PacketSize, HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) { return func.packetOp( redux_vec_unroller::run(mat,func), redux_vec_unroller::run(mat,func) ); } }; template struct redux_vec_unroller { enum { index = Start * redux_traits::PacketSize, outer = index / int(Derived::InnerSizeAtCompileTime), inner = index % int(Derived::InnerSizeAtCompileTime), alignment = Derived::Alignment }; typedef typename Derived::Scalar Scalar; typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) { return mat.template packetByOuterInner(outer, inner); } }; /*************************************************************************** * Part 3 : implementation of all cases ***************************************************************************/ template::Traversal, int Unrolling = redux_traits::Unrolling > struct redux_impl; template struct redux_impl { typedef typename Derived::Scalar Scalar; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res; res = mat.coeffByOuterInner(0, 0); for(Index i = 1; i < mat.innerSize(); ++i) res = func(res, mat.coeffByOuterInner(0, i)); for(Index i = 1; i < mat.outerSize(); ++i) for(Index j = 0; j < mat.innerSize(); ++j) res = func(res, mat.coeffByOuterInner(i, j)); return res; } }; template struct redux_impl : public redux_novec_unroller {}; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename redux_traits::PacketType PacketScalar; static Scalar run(const Derived &mat, const Func& func) { const Index size = mat.size(); const Index packetSize = redux_traits::PacketSize; const int packetAlignment = unpacket_traits::alignment; enum { alignment0 = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Derived::Alignment) }; const Index alignedStart = internal::first_default_aligned(mat.nestedExpression()); const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); const Index alignedEnd2 = alignedStart + alignedSize2; const Index alignedEnd = alignedStart + alignedSize; Scalar res; if(alignedSize) { PacketScalar packet_res0 = mat.template packet(alignedStart); if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop { PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) { packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); } packet_res0 = func.packetOp(packet_res0,packet_res1); if(alignedEnd>alignedEnd2) packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); } res = func.predux(packet_res0); for(Index index = 0; index < alignedStart; ++index) res = func(res,mat.coeff(index)); for(Index index = alignedEnd; index < size; ++index) res = func(res,mat.coeff(index)); } else // too small to vectorize anything. // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. { res = mat.coeff(0); for(Index index = 1; index < size; ++index) res = func(res,mat.coeff(index)); } return res; } }; // NOTE: for SliceVectorizedTraversal we simply bypass unrolling template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename redux_traits::PacketType PacketType; EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); const Index outerSize = mat.outerSize(); enum { packetSize = redux_traits::PacketSize }; const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; Scalar res; if(packetedInnerSize) { PacketType packet_res = mat.template packet(0,0); for(Index j=0; j(j,i)); res = func.predux(packet_res); for(Index j=0; j::run(mat, func); } return res; } }; template struct redux_impl { typedef typename Derived::Scalar Scalar; typedef typename redux_traits::PacketType PacketScalar; enum { PacketSize = redux_traits::PacketSize, Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); if (VectorizedSize > 0) { Scalar res = func.predux(redux_vec_unroller::run(mat,func)); if (VectorizedSize != Size) res = func(res,redux_novec_unroller::run(mat,func)); return res; } else { return redux_novec_unroller::run(mat,func); } } }; // evaluator adaptor template class redux_evaluator { public: typedef _XprType XprType; EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} typedef typename XprType::Scalar Scalar; typedef typename XprType::CoeffReturnType CoeffReturnType; typedef typename XprType::PacketScalar PacketScalar; typedef typename XprType::PacketReturnType PacketReturnType; enum { MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator Flags = evaluator::Flags & ~DirectAccessBit, IsRowMajor = XprType::IsRowMajor, SizeAtCompileTime = XprType::SizeAtCompileTime, InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, CoeffReadCost = evaluator::CoeffReadCost, Alignment = evaluator::Alignment }; EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const { return m_evaluator.coeff(row, col); } EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const { return m_evaluator.coeff(index); } template PacketType packet(Index row, Index col) const { return m_evaluator.template packet(row, col); } template PacketType packet(Index index) const { return m_evaluator.template packet(index); } EIGEN_DEVICE_FUNC CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } template PacketType packetByOuterInner(Index outer, Index inner) const { return m_evaluator.template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } const XprType & nestedExpression() const { return m_xpr; } protected: internal::evaluator m_evaluator; const XprType &m_xpr; }; } // end namespace internal /*************************************************************************** * Part 4 : public API ***************************************************************************/ /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be * an associative operator. Both current C++98 and C++11 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ template template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::redux(const Func& func) const { eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); typedef typename internal::redux_evaluator ThisEvaluator; ThisEvaluator thisEval(derived()); return internal::redux_impl::run(thisEval, func); } /** \returns the minimum of all coefficients of \c *this. * \warning the result is undefined if \c *this contains NaN. */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { return derived().redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of \c *this. * \warning the result is undefined if \c *this contains NaN. */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { return derived().redux(Eigen::internal::scalar_max_op()); } /** \returns the sum of all coefficients of \c *this * * If \c *this is empty, then the value 0 is returned. * * \sa trace(), prod(), mean() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); return derived().redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this * * \sa trace(), prod(), sum() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { #ifdef __INTEL_COMPILER #pragma warning push #pragma warning ( disable : 2259 ) #endif return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); #ifdef __INTEL_COMPILER #pragma warning pop #endif } /** \returns the product of all coefficients of *this * * Example: \include MatrixBase_prod.cpp * Output: \verbinclude MatrixBase_prod.out * * \sa sum(), mean(), trace() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); return derived().redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. * * \c *this can be any matrix, not necessarily square. * * \sa diagonal(), sum() */ template EIGEN_STRONG_INLINE typename internal::traits::Scalar MatrixBase::trace() const { return derived().diagonal().sum(); } } // end namespace Eigen #endif // EIGEN_REDUX_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Ref.h000066400000000000000000000310541506104011400224670ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2012 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REF_H #define EIGEN_REF_H namespace Eigen { namespace internal { template struct traits > : public traits > { typedef _PlainObjectType PlainObjectType; typedef _StrideType StrideType; enum { Options = _Options, Flags = traits >::Flags | NestByRefBit, Alignment = traits >::Alignment }; template struct match { enum { IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime, HasDirectAccess = internal::has_direct_access::ret, StorageOrderMatch = IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), // NOTE, this indirection of evaluator::Alignment is needed // to workaround a very strange bug in MSVC related to the instantiation // of has_*ary_operator in evaluator. // This line is surprisingly very sensitive. For instance, simply adding parenthesis // as "DerivedAlignment = (int(evaluator::Alignment))," will make MSVC fail... DerivedAlignment = int(evaluator::Alignment), AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (DerivedAlignment >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment ScalarTypeMatch = internal::is_same::value, MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; typedef typename internal::conditional::type type; }; }; template struct traits > : public traits {}; } template class RefBase : public MapBase { typedef typename internal::traits::PlainObjectType PlainObjectType; typedef typename internal::traits::StrideType StrideType; public: typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() : int(Flags)&RowMajorBit ? this->cols() : this->rows(); } EIGEN_DEVICE_FUNC RefBase() : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, StrideType::InnerStrideAtCompileTime==Dynamic?0:StrideType::InnerStrideAtCompileTime) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(RefBase) protected: typedef Stride StrideBase; template EIGEN_DEVICE_FUNC void construct(Expression& expr) { EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(PlainObjectType,Expression); if(PlainObjectType::RowsAtCompileTime==1) { eigen_assert(expr.rows()==1 || expr.cols()==1); ::new (static_cast(this)) Base(expr.data(), 1, expr.size()); } else if(PlainObjectType::ColsAtCompileTime==1) { eigen_assert(expr.rows()==1 || expr.cols()==1); ::new (static_cast(this)) Base(expr.data(), expr.size(), 1); } else ::new (static_cast(this)) Base(expr.data(), expr.rows(), expr.cols()); if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); else ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); } StrideBase m_stride; }; /** \class Ref * \ingroup Core_Module * * \brief A matrix or vector expression mapping an existing expression * * \tparam PlainObjectType the equivalent matrix type of the mapped data * \tparam Options specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), * but accepts a variable outer stride (leading dimension). * This can be overridden by specifying strides. * The type passed here must be a specialization of the Stride template, see examples below. * * This class provides a way to write non-template functions taking Eigen objects as parameters while limiting the number of copies. * A Ref<> object can represent either a const expression or a l-value: * \code * // in-out argument: * void foo1(Ref x); * * // read-only const argument: * void foo2(const Ref& x); * \endcode * * In the in-out case, the input argument must satisfy the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. * Likewise, a Ref can reference any column-major dense matrix expression of float whose column's elements are contiguously stored with * the possibility to have a constant space in-between each column, i.e. the inner stride must be equal to 1, but the outer stride (or leading dimension) * can be greater than the number of rows. * * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. * Here are some examples: * \code * MatrixXf A; * VectorXf a; * foo1(a.head()); // OK * foo1(A.col()); // OK * foo1(A.row()); // Compilation error because here innerstride!=1 * foo2(A.row()); // Compilation error because A.row() is a 1xN object while foo2 is expecting a Nx1 object * foo2(A.row().transpose()); // The row is copied into a contiguous temporary * foo2(2*a); // The expression is evaluated into a temporary * foo2(A.col().segment(2,4)); // No temporary * \endcode * * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameters. * Here is an example accepting an innerstride!=1: * \code * // in-out argument: * void foo3(Ref > x); * foo3(A.row()); // OK * \endcode * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involve more * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overload internally calling a * template function, e.g.: * \code * // in the .h: * void foo(const Ref& A); * void foo(const Ref >& A); * * // in the .cpp: * template void foo_impl(const TypeOfA& A) { * ... // crazy code goes here * } * void foo(const Ref& A) { foo_impl(A); } * void foo(const Ref >& A) { foo_impl(A); } * \endcode * * * \sa PlainObjectBase::Map(), \ref TopicStorageOrders */ template class Ref : public RefBase > { private: typedef internal::traits Traits; template EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase& expr, typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Ref) #ifndef EIGEN_PARSED_BY_DOXYGEN template EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); Base::construct(expr.derived()); } template EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) #else /** Implicit constructor from any dense expression */ template inline Ref(DenseBase& expr) #endif { EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); EIGEN_STATIC_ASSERT(!Derived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); Base::construct(expr.const_cast_derived()); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Ref) }; // this is the const ref version template class Ref : public RefBase > { typedef internal::traits Traits; public: typedef RefBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; // std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; construct(expr.derived(), typename Traits::template match::type()); } EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy } template EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { construct(other.derived(), typename Traits::template match::type()); } protected: template EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) { Base::construct(expr); } template EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) { internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); Base::construct(m_object); } protected: TPlainObjectType m_object; }; } // end namespace Eigen #endif // EIGEN_REF_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Replicate.h000066400000000000000000000127331506104011400236660ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REPLICATE_H #define EIGEN_REPLICATE_H namespace Eigen { namespace internal { template struct traits > : traits { typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic ? Dynamic : RowFactor * MatrixType::RowsAtCompileTime, ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic ? Dynamic : ColFactor * MatrixType::ColsAtCompileTime, //FIXME we don't propagate the max sizes !!! MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, // FIXME enable DirectAccess with negative strides? Flags = IsRowMajor ? RowMajorBit : 0 }; }; } /** * \class Replicate * \ingroup Core_Module * * \brief Expression of the multiple replication of a matrix or vector * * \tparam MatrixType the type of the object we are replicating * \tparam RowFactor number of repetitions at compile time along the vertical direction, can be Dynamic. * \tparam ColFactor number of repetitions at compile time along the horizontal direction, can be Dynamic. * * This class represents an expression of the multiple replication of a matrix or vector. * It is the return type of DenseBase::replicate() and most of the time * this is the only way it is used. * * \sa DenseBase::replicate() */ template class Replicate : public internal::dense_xpr_base< Replicate >::type { typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) typedef typename internal::remove_all::type NestedExpression; template EIGEN_DEVICE_FUNC inline explicit Replicate(const OriginalMatrixType& matrix) : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); } template EIGEN_DEVICE_FUNC inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor) : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) } EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } EIGEN_DEVICE_FUNC const _MatrixTypeNested& nestedExpression() const { return m_matrix; } protected: MatrixTypeNested m_matrix; const internal::variable_if_dynamic m_rowFactor; const internal::variable_if_dynamic m_colFactor; }; /** * \return an expression of the replication of \c *this * * Example: \include MatrixBase_replicate.cpp * Output: \verbinclude MatrixBase_replicate.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate */ template template const Replicate DenseBase::replicate() const { return Replicate(derived()); } /** * \return an expression of the replication of each column (or row) of \c *this * * Example: \include DirectionWise_replicate_int.cpp * Output: \verbinclude DirectionWise_replicate_int.out * * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate */ template const typename VectorwiseOp::ReplicateReturnType VectorwiseOp::replicate(Index factor) const { return typename VectorwiseOp::ReplicateReturnType (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); } } // end namespace Eigen #endif // EIGEN_REPLICATE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/ReturnByValue.h000066400000000000000000000101501506104011400245140ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009-2010 Gael Guennebaud // Copyright (C) 2009-2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_RETURNBYVALUE_H #define EIGEN_RETURNBYVALUE_H namespace Eigen { namespace internal { template struct traits > : public traits::ReturnType> { enum { // We're disabling the DirectAccess because e.g. the constructor of // the Block-with-DirectAccess expression requires to have a coeffRef method. // Also, we don't want to have to implement the stride stuff. Flags = (traits::ReturnType>::Flags | EvalBeforeNestingBit) & ~DirectAccessBit }; }; /* The ReturnByValue object doesn't even have a coeff() method. * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators */ template struct nested_eval, n, PlainObject> { typedef typename traits::ReturnType type; }; } // end namespace internal /** \class ReturnByValue * \ingroup Core_Module * */ template class ReturnByValue : public internal::dense_xpr_base< ReturnByValue >::type, internal::no_assignment_operator { public: typedef typename internal::traits::ReturnType ReturnType; typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) template EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } EIGEN_DEVICE_FUNC inline Index rows() const { return static_cast(this)->rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return static_cast(this)->cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN #define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT class Unusable{ Unusable(const Unusable&) {} Unusable& operator=(const Unusable&) {return *this;} }; const Unusable& coeff(Index) const { return *reinterpret_cast(this); } const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } #undef Unusable #endif }; template template Derived& DenseBase::operator=(const ReturnByValue& other) { other.evalTo(derived()); return derived(); } namespace internal { // Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that // when a ReturnByValue expression is assigned, the evaluator is not constructed. // TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world template struct evaluator > : public evaluator::ReturnType> { typedef ReturnByValue XprType; typedef typename internal::traits::ReturnType PlainObject; typedef evaluator Base; EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : m_result(xpr.rows(), xpr.cols()) { ::new (static_cast(this)) Base(m_result); xpr.evalTo(m_result); } protected: PlainObject m_result; }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_RETURNBYVALUE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Reverse.h000066400000000000000000000156411506104011400233720ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob // Copyright (C) 2009 Ricard Marxer // Copyright (C) 2009-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_REVERSE_H #define EIGEN_REVERSE_H namespace Eigen { namespace internal { template struct traits > : traits { typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) }; }; template struct reverse_packet_cond { static inline PacketType run(const PacketType& x) { return preverse(x); } }; template struct reverse_packet_cond { static inline PacketType run(const PacketType& x) { return x; } }; } // end namespace internal /** \class Reverse * \ingroup Core_Module * * \brief Expression of the reverse of a vector or matrix * * \tparam MatrixType the type of the object of which we are taking the reverse * \tparam Direction defines the direction of the reverse operation, can be Vertical, Horizontal, or BothDirections * * This class represents an expression of the reverse of a vector. * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() * and most of the time this is the only way it is used. * * \sa MatrixBase::reverse(), VectorwiseOp::reverse() */ template class Reverse : public internal::dense_xpr_base< Reverse >::type { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) typedef typename internal::remove_all::type NestedExpression; using Base::IsRowMajor; protected: enum { PacketSize = internal::packet_traits::size, IsColMajor = !IsRowMajor, ReverseRow = (Direction == Vertical) || (Direction == BothDirections), ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, ReversePacket = (Direction == BothDirections) || ((Direction == Vertical) && IsColMajor) || ((Direction == Horizontal) && IsRowMajor) }; typedef internal::reverse_packet_cond reverse_packet; public: EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } EIGEN_DEVICE_FUNC inline Index innerStride() const { return -m_matrix.innerStride(); } EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } protected: typename MatrixType::Nested m_matrix; }; /** \returns an expression of the reverse of *this. * * Example: \include MatrixBase_reverse.cpp * Output: \verbinclude MatrixBase_reverse.out * */ template inline typename DenseBase::ReverseReturnType DenseBase::reverse() { return ReverseReturnType(derived()); } //reverse const overload moved DenseBase.h due to a CUDA compiler bug /** This is the "in place" version of reverse: it reverses \c *this. * * In most cases it is probably better to simply use the reversed expression * of a matrix. However, when reversing the matrix data itself is really needed, * then this "in-place" version is probably the right choice because it provides * the following additional benefits: * - less error prone: doing the same operation with .reverse() requires special care: * \code m = m.reverse().eval(); \endcode * - this API enables reverse operations without the need for a temporary * - it allows future optimizations (cache friendliness, etc.) * * \sa VectorwiseOp::reverseInPlace(), reverse() */ template inline void DenseBase::reverseInPlace() { if(cols()>rows()) { Index half = cols()/2; leftCols(half).swap(rightCols(half).reverse()); if((cols()%2)==1) { Index half2 = rows()/2; col(half).head(half2).swap(col(half).tail(half2).reverse()); } } else { Index half = rows()/2; topRows(half).swap(bottomRows(half).reverse()); if((rows()%2)==1) { Index half2 = cols()/2; row(half).head(half2).swap(row(half).tail(half2).reverse()); } } } namespace internal { template struct vectorwise_reverse_inplace_impl; template<> struct vectorwise_reverse_inplace_impl { template static void run(ExpressionType &xpr) { Index half = xpr.rows()/2; xpr.topRows(half).swap(xpr.bottomRows(half).colwise().reverse()); } }; template<> struct vectorwise_reverse_inplace_impl { template static void run(ExpressionType &xpr) { Index half = xpr.cols()/2; xpr.leftCols(half).swap(xpr.rightCols(half).rowwise().reverse()); } }; } // end namespace internal /** This is the "in place" version of VectorwiseOp::reverse: it reverses each column or row of \c *this. * * In most cases it is probably better to simply use the reversed expression * of a matrix. However, when reversing the matrix data itself is really needed, * then this "in-place" version is probably the right choice because it provides * the following additional benefits: * - less error prone: doing the same operation with .reverse() requires special care: * \code m = m.reverse().eval(); \endcode * - this API enables reverse operations without the need for a temporary * * \sa DenseBase::reverseInPlace(), reverse() */ template void VectorwiseOp::reverseInPlace() { internal::vectorwise_reverse_inplace_impl::run(_expression().const_cast_derived()); } } // end namespace Eigen #endif // EIGEN_REVERSE_H bbuchfink-diamond-08b3cbc/src/lib/Eigen/src/Core/Select.h000066400000000000000000000136041506104011400231730ustar00rootroot00000000000000// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2010 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SELECT_H #define EIGEN_SELECT_H namespace Eigen { /** \class Select * \ingroup Core_Module * * \brief Expression of a coefficient wise version of the C++ ternary operator ?: * * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix * \param ThenMatrixType the type of the \em then expression * \param ElseMatrixType the type of the \em else expression * * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:. * It is the return type of DenseBase::select() and most of the time this is the only way it is used. * * \sa DenseBase::select(const DenseBase&, const DenseBase&) const */ namespace internal { template struct traits > : traits { typedef typename traits::Scalar Scalar; typedef Dense StorageKind; typedef typename traits::XprKind XprKind; typedef typename ConditionMatrixType::Nested ConditionMatrixNested; typedef typename ThenMatrixType::Nested ThenMatrixNested; typedef typename ElseMatrixType::Nested ElseMatrixNested; enum { RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime, ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit }; }; } template class Select : public internal::dense_xpr_base< Select >::type, internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base