[med-svn] [Git][med-team/bowtie2][upstream] New upstream version 2.5.5

Steffen Möller (@moeller) gitlab at salsa.debian.org
Sun Feb 22 15:33:39 GMT 2026



Steffen Möller pushed to branch upstream at Debian Med / bowtie2


Commits:
ea626081 by Steffen Moeller at 2026-02-22T15:11:40+00:00
New upstream version 2.5.5
- - - - -


28 changed files:

- .github/workflows/random-tests.yml
- .github/workflows/simple-tests.yml
- BOWTIE2_VERSION
- CMakeLists.txt
- MANUAL
- MANUAL.markdown
- Makefile
- NEWS
- README.md
- aligner_seed.cpp
- aligner_seed.h
- aligner_seed2.h
- aligner_sw_driver.cpp
- aligner_sw_driver.h
- aln_sink.h
- bowtie2-build
- bowtie2-inspect
- bowtie_main.cpp
- bt2_search.cpp
- doc/manual.html
- doc/website/manual.ssi
- doc/website/recent_news.ssi
- doc/website/rhsidebar.ssi
- group_walk.h
- opts.h
- pat.cpp
- pat.h
- processor_support.h


Changes:

=====================================
.github/workflows/random-tests.yml
=====================================
@@ -45,14 +45,14 @@ jobs:
           make clean; make -j4 allall
           export NUM_CORES=1
           make random-test
-  linux-avx2:
+  linux-noavx2:
     runs-on: ubuntu-latest
     needs: linux
     steps:
       - uses: actions/checkout at v2
-      - name: Run random tests using avx2
+      - name: Run random tests without using avx2
         run: |
-          export SSE_AVX2=1
+          export SSE_AVX2=0
           make clean; make -j4 allall
           export NUM_CORES=1
           make random-test


=====================================
.github/workflows/simple-tests.yml
=====================================
@@ -44,14 +44,14 @@ jobs:
         run: |
           make clean; make -j4 allall
           make simple-test
-  linux-avx2:
+  linux-noavx2:
     runs-on: ubuntu-latest
     needs: linux
     steps:
       - uses: actions/checkout at v2
-      - name: Run simple tests using AVX2
+      - name: Run simple tests without using AVX2
         run: |
-          export SSE_AVX2=1
+          export SSE_AVX2=0
           make clean; make -j4 allall
           make simple-test
   macos:


=====================================
BOWTIE2_VERSION
=====================================
@@ -1 +1 @@
-2.5.4
+2.5.5


=====================================
CMakeLists.txt
=====================================
@@ -1,10 +1,10 @@
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
 
 cmake_policy(SET CMP0048 NEW)
 cmake_policy(SET CMP0005 NEW)
 
 file(STRINGS ${CMAKE_SOURCE_DIR}/BOWTIE2_VERSION PROJECT_VERSION)
-project(bowtie2 LANGUAGES CXX VERSION ${PROJECT_VERSION})
+project(bowtie2 LANGUAGES C CXX VERSION ${PROJECT_VERSION})
 
 enable_testing()
 
@@ -29,13 +29,14 @@ set(USE_SAIS ${USE_SAIS})
 set(WITH_THREAD_PROFILING ${WITH_THREAD_PROFILING})
 set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
 set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -g3 -Wall")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -funroll-loops")
 set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
 
-include_directories(${SOURCE_DIR}/third_party)
 
+include_directories(${CMAKE_SOURCE_DIR}/third_party)
+message("${CMAKE_SOURCE_DIR}/third_party")
 if (MINGW)
   option(BOWTIE_MM "Memory mapped files not supported on Windows" OFF)
   option(BOWTIE_SHARED_MEM "Shared memory not supported on Windows" OFF)
@@ -194,22 +195,34 @@ if (USE_SRA)
   find_package(Perl REQUIRED)
   find_program(MAKE_EXE NAMES gmake nmake make)
 
+  # ExternalProject_add(ncbi_vdb_project
+  #   URL https://github.com/ncbi/ncbi-vdb/archive/refs/tags/${NCBI_VDB_VER}.tar.gz
+  #   PREFIX ${CMAKE_CURRENT_BINARY_DIR}/ncbi-vdb-${NCBI_VDB_VER}
+  #   BUILD_IN_SOURCE 0
+  #   # CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --without-debug
+  #   BUILD_COMMAND cmake .  -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS}
+  #   # BUILD_COMMAND ${MAKE_EXE}
+  #   INSTALL_COMMAND ${MAKE_EXE} install
+  #   )
+
   ExternalProject_add(ncbi_vdb_project
-    URL https://github.com/ncbi/ncbi-vdb/archive/${NCBI_VDB_VER}.tar.gz
+    URL https://github.com/ncbi/ncbi-vdb/archive/refs/tags/${NCBI_VDB_VER}.tar.gz
     PREFIX ${CMAKE_CURRENT_BINARY_DIR}/ncbi-vdb-${NCBI_VDB_VER}
     BUILD_IN_SOURCE 1
-    CONFIGURE_COMMAND ./configure --prefix="${THIRD_PARTY_LIBS}" --without-debug
-    BUILD_COMMAND ${MAKE_EXE}
-    INSTALL_COMMAND ${MAKE_EXE} install
+    # CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --without-debug
+    CONFIGURE_COMMAND cd build && cmake ..  -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS}
+    BUILD_COMMAND cmake --build build
+    INSTALL_COMMAND cmake --install build
     )
 
   ExternalProject_add(ngs_project
-    URL https://github.com/ncbi/sra-tools/archive/${SRA_TOOLS_VER}.tar.gz
+    URL https://github.com/ncbi/sra-tools/archive/refs/tags/${SRA_TOOLS_VER}.tar.gz
     PREFIX ${CMAKE_CURRENT_BINARY_DIR}/sra-tools-${SRA_TOOLS_VER}
     BUILD_IN_SOURCE 1
-    CONFIGURE_COMMAND ./configure --prefix=${THIRD_PARTY_LIBS} --with-ncbi-vdb-prefix=${THIRD_PARTY_LIBS} --enable-static --without-debug
-    BUILD_COMMAND ${MAKE_EXE}
-    INSTALL_COMMAND ${MAKE_EXE} install
+    CONFIGURE_COMMAND cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DVDB_INCDIR=${THIRD_PARTY_LIBS}/include -DVDB_LIBDIR=${THIRD_PARTY_LIBS}/lib64 -DCMAKE_INSTALL_PREFIX=${THIRD_PARTY_LIBS} -DBUILD_TOOLS_INTERNAL=ON -DBUILD_TOOLS_LOADERS=OFF -DBUILD_TOOLS_TEST_TOOLS=OFF
+    BUILD_COMMAND cmake --build build
+
+    INSTALL_COMMAND cmake --install build
     DEPENDS ncbi_vdb_project
     )
 


=====================================
MANUAL
=====================================
@@ -23,12 +23,12 @@ many other tools, some of which are listed here.
 If you use Bowtie 2 for your published research, please cite our work.
 Papers describing Bowtie 2 are:
 
--   Langmead B, Wilks C, Antonescu V, Charles R. Scaling read aligners
-    to hundreds of threads on general-purpose processors.
-    Bioinformatics. 2018 Jul 18. doi: 10.1093/bioinformatics/bty648.
+- Langmead B, Wilks C, Antonescu V, Charles R. Scaling read aligners to
+  hundreds of threads on general-purpose processors. Bioinformatics.
+  2018 Jul 18. doi: 10.1093/bioinformatics/bty648.
 
--   Langmead B, Salzberg SL. Fast gapped-read alignment with Bowtie 2.
-    Nature Methods. 2012 Mar 4;9(4):357-9. doi: 10.1038/nmeth.1923.
+- Langmead B, Salzberg SL. Fast gapped-read alignment with Bowtie 2.
+  Nature Methods. 2012 Mar 4;9(4):357-9. doi: 10.1038/nmeth.1923.
 
 How is Bowtie 2 different from Bowtie 1?
 
@@ -155,15 +155,15 @@ and gzipped inputs.
 To build bowtie2-build with libsais first make sure that the libsais
 submodule is available. This can be done in one of the following ways:
 
--   first time cloning bowtie2 --
-    git clone --recursive https://github.com/BenLangmead/bowtie2.git
--   existing checkout of bowtie2 --
-    git submodule init && git submodule update
+- first time cloning bowtie2 --
+  git clone --recursive https://github.com/BenLangmead/bowtie2.git
+- existing checkout of bowtie2 --
+  git submodule init && git submodule update
 
 Issue the following command line to build libsais:
 
--   with OpenMP support -- [g]make libsais USE_SAIS_OPENMP=1
--   without OpenMP support -- [g]make libsais USE_SAIS=1
+- with OpenMP support -- [g]make libsais USE_SAIS_OPENMP=1
+- without OpenMP support -- [g]make libsais USE_SAIS=1
 
 The choice of using OpenMP will determine whether or not the algorithm
 runs multithreaded. The [-p/--threads] argument to bowtie2-build will be
@@ -171,15 +171,15 @@ ignored when libsais is compiled without OpenMP support.
 
 Finally, building the bowtie2-build executable:
 
--   with OpenMP support -- [g]make bowtie2-build-s USE_SAIS_OPENMP=1
--   without OpenMP support -- [g]make bowtie2-build-s USE_SAIS=1
+- with OpenMP support -- [g]make bowtie2-build-s USE_SAIS_OPENMP=1
+- without OpenMP support -- [g]make bowtie2-build-s USE_SAIS=1
 
 Building with CMake
 
 To build Bowtie2 with SRA and libsais support issue the following
 command:
 
--   cmake . -D USE_SRA=1 -D USE_SAIS=1 && cmake --build .
+- cmake . -D USE_SRA=1 -D USE_SAIS=1 && cmake --build .
 
 CMake will take care of building and linking against the specified
 dependencies.
@@ -688,20 +688,20 @@ record for such a read, but no alignment will be reported and the YF:i
 SAM optional field will be set to indicate the reason the read was
 filtered.
 
--   YF:Z:LN: the read was filtered because it had length less than or
-    equal to the number of seed mismatches set with the -N option.
--   YF:Z:NS: the read was filtered because it contains a number of
-    ambiguous characters (usually N or .) greater than the ceiling
-    specified with --n-ceil.
--   YF:Z:SC: the read was filtered because the read length and the match
-    bonus (set with --ma) are such that the read can't possibly earn an
-    alignment score greater than or equal to the threshold set with
-    --score-min
--   YF:Z:QC: the read was filtered because it was marked as failing
-    quality control and the user specified the --qc-filter option. This
-    only happens when the input is in Illumina's QSEQ format (i.e. when
-    --qseq is specified) and the last (11th) field of the read's QSEQ
-    record contains 1.
+- YF:Z:LN: the read was filtered because it had length less than or
+  equal to the number of seed mismatches set with the -N option.
+- YF:Z:NS: the read was filtered because it contains a number of
+  ambiguous characters (usually N or .) greater than the ceiling
+  specified with --n-ceil.
+- YF:Z:SC: the read was filtered because the read length and the match
+  bonus (set with --ma) are such that the read can't possibly earn an
+  alignment score greater than or equal to the threshold set with
+  --score-min
+- YF:Z:QC: the read was filtered because it was marked as failing
+  quality control and the user specified the --qc-filter option. This
+  only happens when the input is in Illumina's QSEQ format (i.e. when
+  --qseq is specified) and the last (11th) field of the read's QSEQ
+  record contains 1.
 
 If a read could be filtered for more than one reason, the value YF:Z
 flag will reflect only one of those reasons.
@@ -1247,6 +1247,18 @@ offsets and searches for more alignments. A read is considered to have
 repetitive seeds if the total number of seed hits divided by the number
 of seeds that aligned at least once is greater than 300. Default: 2.
 
+    -d/--deterministic-seeds
+
+Consider all seeds in order (no subsampling). Can be used to augment -a
+or -k with deterministic behavior. This option significantly speeds up
+-a while also reducing memory consumption. It is not however always
+strictly better than standalone [-a] when considering the number of
+repeated alignments found.
+
+Note: In order to use this option exact upfront and 1mm upfront behavior
+have to be disabled using the following options: [--no-exact-upfront]
+and --no-1mm-upfront.
+
 Paired-end options
 
     -I/--minins <int>


=====================================
MANUAL.markdown
=====================================
@@ -1514,6 +1514,23 @@ searches for more alignments.  A read is considered to have repetitive seeds if
 the total number of seed hits divided by the number of seeds that aligned at
 least once is greater than 300.  Default: 2.
 
+</td></tr>
+<tr><td id="bowtie2-options-d">
+
+    -d/--deterministic-seeds
+
+</td><td>
+
+Consider all seeds in order (no subsampling). Can be used to augment
+[`-a`] or [`-k`] with deterministic behavior. This option
+significantly speeds up [`-a`] while also reducing memory consumption.
+It is not however always strictly better than standalone `[-a]` when
+considering the number of repeated alignments found.
+
+Note: In order to use this option exact upfront and 1mm upfront behavior
+have to be disabled using the following options: [`--no-exact-upfront`]
+and [`--no-1mm-upfront`].
+
 </td></tr>
 </table>
 


=====================================
Makefile
=====================================
@@ -59,6 +59,8 @@ endif
 ifeq (1, $(WINDOWS))
   BOWTIE_MM :=
   BOWTIE_SHARED_MEM :=
+  # and no support for advanced vectorization either
+  SSE_AVX2 := 0
 endif
 
 MACOS :=
@@ -72,17 +74,21 @@ ifneq (,$(findstring Darwin,$(shell uname)))
   endif
 endif
 
+# do we have a 256-bit variant of the executable?
+ENABLE_V256 := 0
+
 BITS := 32
 ARCH ?= $(shell uname -m)
 ifneq (,$(findstring $(ARCH), x86_64 amd64))
   BITS := 64
-  ifeq (1, $(SSE_AVX2))
-	SSE_FLAG := -mavx2 -faligned-new -DSSE_AVX2
-  else
-	SSE_FLAG := -msse2
-  endif
-
+  SSE_FLAG := -msse2
   POPCNT_CAPABILITY ?= 1
+  ifneq (0, $(SSE_AVX2))
+    ENABLE_V256 := 1
+    V256_FLAG := -march=x86-64-v3 -mtune=znver3 -faligned-new -DSSE_AVX2 -DPOPCNT_CAPABILITY
+    # tell 128-bit version to check for v256 capability and use it, if found
+    SSE_FLAG += -DENABLE_x86_64_v3
+  endif
 else ifneq (,$(findstring $(ARCH), aarch64 arm64 s390x powerpc64 powerpc64le ppc64 ppc64le))
   BITS := 64
   SSE_FLAG :=
@@ -229,29 +235,45 @@ else ifeq (0,$(shell $(CXX) -E -fsanitize=undefined btypes.h > /dev/null 2>&1; e
   SANITIZER_FLAGS := -fsanitize=undefined
 endif
 
-DEBUG_FLAGS    := -O0 -g3 $(SSE_FLAG)
-RELEASE_FLAGS  := -O3 $(SSE_FLAG) -funroll-loops -g3
+DEBUG_FLAGS    := -O0 -g3
+RELEASE_FLAGS  := -O3 -funroll-loops -g3
 NOASSERT_FLAGS := -DNDEBUG
 FILE_FLAGS     := -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 DEBUG_DEFS     = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(CXXFLAGS)\""
 RELEASE_DEFS   = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(CXXFLAGS)\""
 
-BOWTIE2_BIN_LIST := bowtie2-build-s \
+ifeq (1, $(ENABLE_V256))
+  V256_DEBUG_DEFS     = -DCOMPILER_OPTIONS="\"$(DEBUG_FLAGS) $(CXXFLAGS) $(V256_FLAG)\""
+  V256_RELEASE_DEFS   = -DCOMPILER_OPTIONS="\"$(RELEASE_FLAGS) $(CXXFLAGS) $(V256_FLAG)\""
+endif
+
+
+BOWTIE2_BIN_BOTH_LIST := bowtie2-build-s \
   bowtie2-build-l \
   bowtie2-align-s \
-  bowtie2-align-l \
-  bowtie2-inspect-s \
-  bowtie2-inspect-l
-BOWTIE2_BIN_LIST_DBG := bowtie2-build-s-debug \
+  bowtie2-align-l
+BOWTIE2_BIN_BOTH_LIST_DBG := bowtie2-build-s-debug \
   bowtie2-build-l-debug \
   bowtie2-align-s-debug \
-  bowtie2-align-l-debug \
-  bowtie2-inspect-s-debug \
-  bowtie2-inspect-l-debug
-BOWTIE2_BIN_LIST_SAN := bowtie2-build-s-sanitized \
+  bowtie2-align-l-debug
+BOWTIE2_BIN_BOTH_LIST_SAN := bowtie2-build-s-sanitized \
   bowtie2-build-l-sanitized \
   bowtie2-align-s-sanitized \
-  bowtie2-align-l-sanitized \
+  bowtie2-align-l-sanitized
+
+ifeq (1, $(ENABLE_V256))
+  BOWTIE2_BIN_BOTH_LIST += bowtie2-align-s-v256 bowtie2-align-l-v256
+  BOWTIE2_BIN_BOTH_LIST_DBG += bowtie2-align-s-debug-v256 bowtie2-align-l-debug-v256
+  BOWTIE2_BIN_BOTH_LIST_SAN += bowtie2-align-s-sanitized-v256 bowtie2-align-l-sanitized-v256
+endif
+
+BOWTIE2_BIN_LIST := $(BOWTIE2_BIN_BOTH_LIST) \
+  bowtie2-inspect-s \
+  bowtie2-inspect-l
+BOWTIE2_BIN_LIST_DBG := $(BOWTIE2_BIN_BOTH_LIST_DBG) \
+  bowtie2-inspect-s-debug \
+  bowtie2-inspect-l-debug
+BOWTIE2_BIN_LIST_SAN := $(BOWTIE2_BIN_BOTH_LIST_SAN) \
   bowtie2-inspect-s-sanitized \
   bowtie2-inspect-l-sanitized
 ifndef SANITIZER_FLAGS
@@ -309,9 +331,9 @@ endif
 
 all: $(BOWTIE2_BIN_LIST) ;
 allall: $(BOWTIE2_BIN_LIST) $(BOWTIE2_BIN_LIST_DBG) $(BOWTIE2_BIN_LIST_SAN) ;
-both: bowtie2-align-s bowtie2-build-s bowtie2-align-l bowtie2-build-l ;
-both-debug: bowtie2-align-s-debug bowtie2-build-s-debug bowtie2-align-l-debug bowtie2-build-l-debug ;
-both-sanitized: bowtie2-align-s-sanitized bowtie2-build-s-sanitized bowtie2-align-l-sanitized bowtie2-build-l-sanitized ;
+both: $(BOWTIE2_BIN_BOTH_LIST) ;
+both-debug: $(BOWTIE2_BIN_BOTH_LIST_DBG) ;
+both-sanitized: $(BOWTIE2_BIN_BOTH_LIST_SAN) ;
 
 DEFS := -fno-strict-aliasing \
   -DBOWTIE2_VERSION="\"`cat BOWTIE2_VERSION`\"" \
@@ -377,7 +399,7 @@ bowtie2-build-l-debug: bt2_build.cpp $(SHARED_CPPS) $(HEADERS)
 bowtie2-align-s-sanitized bowtie2-align-s: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
 	$(CXX) $(RELEASE_FLAGS) $(RELEASE_DEFS) $(CXXFLAGS) \
 		$(DEFS) -DBOWTIE2 $(NOASSERT_FLAGS) \
-		$(CPPFLAGS) \
+		$(CPPFLAGS) $(SSE_FLAG) \
 		-o $@ $< \
 		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
 		$(LDFLAGS) $(LDLIBS)
@@ -385,7 +407,7 @@ bowtie2-align-s-sanitized bowtie2-align-s: bt2_search.cpp $(SEARCH_CPPS) $(SHARE
 bowtie2-align-l-sanitized bowtie2-align-l: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
 	$(CXX) $(RELEASE_FLAGS) $(RELEASE_DEFS) $(CXXFLAGS) \
 		$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX $(NOASSERT_FLAGS)  \
-		$(CPPFLAGS) \
+		$(CPPFLAGS) $(SSE_FLAG) \
 		-o $@ $< \
 		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
 		$(LDFLAGS) $(LDLIBS)
@@ -394,7 +416,7 @@ bowtie2-align-s-debug: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $
 	$(CXX) $(DEBUG_FLAGS) \
 		$(DEBUG_DEFS) $(CXXFLAGS) \
 		$(DEFS) -DBOWTIE2  \
-		$(CPPFLAGS) \
+		$(CPPFLAGS) $(SSE_FLAG) \
 		-o $@ $< \
 		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
 		$(LDFLAGS) $(LDLIBS)
@@ -403,11 +425,52 @@ bowtie2-align-l-debug: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $
 	$(CXX) $(DEBUG_FLAGS) \
 		$(DEBUG_DEFS) $(CXXFLAGS) \
 		$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX  \
-		$(CPPFLAGS) \
+		$(CPPFLAGS) $(SSE_FLAG) \
+		-o $@ $< \
+		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+		$(LDFLAGS) $(LDLIBS)
+
+ifeq (1,$(ENABLE_V256))
+#
+# bowtie2-align v256 targets
+#
+
+bowtie2-align-s-sanitized-v256 bowtie2-align-s-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+	$(CXX) $(RELEASE_FLAGS) $(V256_RELEASE_DEFS) $(CXXFLAGS) \
+		$(DEFS) -DBOWTIE2 $(NOASSERT_FLAGS) \
+		$(CPPFLAGS) $(V256_FLAG) \
 		-o $@ $< \
 		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
 		$(LDFLAGS) $(LDLIBS)
 
+bowtie2-align-l-sanitized-v256 bowtie2-align-l-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+	$(CXX) $(RELEASE_FLAGS) $(V256_RELEASE_DEFS) $(CXXFLAGS) \
+		$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX $(NOASSERT_FLAGS)  \
+		$(CPPFLAGS) $(V256_FLAG) \
+		-o $@ $< \
+		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+		$(LDFLAGS) $(LDLIBS)
+
+bowtie2-align-s-debug-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+	$(CXX) $(DEBUG_FLAGS) \
+		$(V256_DEBUG_DEFS) $(CXXFLAGS) \
+		$(DEFS) -DBOWTIE2  \
+		$(CPPFLAGS) $(V256_FLAG) \
+		-o $@ $< \
+		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+		$(LDFLAGS) $(LDLIBS)
+
+bowtie2-align-l-debug-v256: bt2_search.cpp $(SEARCH_CPPS) $(SHARED_CPPS) $(HEADERS) $(SEARCH_FRAGMENTS)
+	$(CXX) $(DEBUG_FLAGS) \
+		$(V256_DEBUG_DEFS) $(CXXFLAGS) \
+		$(DEFS) -DBOWTIE2 -DBOWTIE_64BIT_INDEX  \
+		$(CPPFLAGS) $(V256_FLAG) \
+		-o $@ $< \
+		$(SHARED_CPPS) $(SEARCH_CPPS_MAIN) \
+		$(LDFLAGS) $(LDLIBS)
+
+endif
+
 #
 # bowtie2-inspect targets
 #


=====================================
NEWS
=====================================
@@ -18,6 +18,17 @@ Please report any issues to the Bowtie 2 Github page or using the Sourceforge bu
 
 Version Release History
 =======================
+## Version 2.5.5 - Feb 16, 2026 ##
+
+### bowtie2 ###
+    * Added `-d` command line option that makes `-a`/`-k`
+      deterministic in the way alignments are reported. This
+      deterministic mode runs much significantly faster than `-a` and
+      consumes less memory.  It not yet strictly better than `-a` when
+      considering alignments found. (PR #520, 521)
+    * Add support for selecting AVX version at runtime on x86_64/amd64
+      CPUs. (PR #515)
+
 
 ## Version 2.5.4 - May 16, 2024 ##
 


=====================================
README.md
=====================================
@@ -2,7 +2,9 @@
 <!-- badges: start -->
 ![Random Tests](https://github.com/BenLangmead/bowtie2/actions/workflows/random-tests.yml/badge.svg)
 ![Simple Tests](https://github.com/BenLangmead/bowtie2/actions/workflows/simple-tests.yml/badge.svg)
-[![Version](https://img.shields.io/badge/version-2.5.4-green.svg)](https://shields.io/)
+[![Version](https://img.shields.io/badge/version-2.5.5-green.svg)](https://shields.io/)
+[![European Galaxy server](https://img.shields.io/badge/usegalaxy-.eu-brightgreen?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAASCAYAAABB7B6eAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAACC2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjE8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx0aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+MjwvdGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KD0UqkwAAAn9JREFUOBGlVEuLE0EQruqZiftwDz4QYT1IYM8eFkHFw/4HYX+GB3/B4l/YP+CP8OBNTwpCwFMQXAQPKtnsg5nJZpKdni6/6kzHvAYDFtRUT71f3UwAEbkLch9ogQxcBwRKMfAnM1/CBwgrbxkgPAYqlBOy1jfovlaPsEiWPROZmqmZKKzOYCJb/AbdYLso9/9B6GppBRqCrjSYYaquZq20EUKAzVpjo1FzWRDVrNay6C/HDxT92wXrAVCH3ASqq5VqEtv1WZ13Mdwf8LFyyKECNbgHHAObWhScf4Wnj9CbQpPzWYU3UFoX3qkhlG8AY2BTQt5/EA7qaEPQsgGLWied0A8VKrHAsCC1eJ6EFoUd1v6GoPOaRAtDPViUr/wPzkIFV9AaAZGtYB568VyJfijV+ZBzlVZJ3W7XHB2RESGe4opXIGzRTdjcAupOK09RA6kzr1NTrTj7V1ugM4VgPGWEw+e39CxO6JUw5XhhKihmaDacU2GiR0Ohcc4cZ+Kq3AjlEnEeRSazLs6/9b/kh4eTC+hngE3QQD7Yyclxsrf3cpxsPXn+cFdenF9aqlBXMXaDiEyfyfawBz2RqC/O9WF1ysacOpytlUSoqNrtfbS642+4D4CS9V3xb4u8P/ACI4O810efRu6KsC0QnjHJGaq4IOGUjWTo/YDZDB3xSIxcGyNlWcTucb4T3in/3IaueNrZyX0lGOrWndstOr+w21UlVFokILjJLFhPukbVY8OmwNQ3nZgNJNmKDccusSb4UIe+gtkI+9/bSLJDjqn763f5CQ5TLApmICkqwR0QnUPKZFIUnoozWcQuRbC0Km02knj0tPYx63furGs3x/iPnz83zJDVNtdP3QAAAABJRU5ErkJggg==)](https://usegalaxy.eu/root?tool_id=bowtie2)
+[![US Galaxy server](https://img.shields.io/badge/usegalaxy-.org-orange?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAASCAYAAABB7B6eAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAACC2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjE8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx0aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+MjwvdGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KD0UqkwAAAn9JREFUOBGlVEuLE0EQruqZiftwDz4QYT1IYM8eFkHFw/4HYX+GB3/B4l/YP+CP8OBNTwpCwFMQXAQPKtnsg5nJZpKdni6/6kzHvAYDFtRUT71f3UwAEbkLch9ogQxcBwRKMfAnM1/CBwgrbxkgPAYqlBOy1jfovlaPsEiWPROZmqmZKKzOYCJb/AbdYLso9/9B6GppBRqCrjSYYaquZq20EUKAzVpjo1FzWRDVrNay6C/HDxT92wXrAVCH3ASqq5VqEtv1WZ13Mdwf8LFyyKECNbgHHAObWhScf4Wnj9CbQpPzWYU3UFoX3qkhlG8AY2BTQt5/EA7qaEPQsgGLWied0A8VKrHAsCC1eJ6EFoUd1v6GoPOaRAtDPViUr/wPzkIFV9AaAZGtYB568VyJfijV+ZBzlVZJ3W7XHB2RESGe4opXIGzRTdjcAupOK09RA6kzr1NTrTj7V1ugM4VgPGWEw+e39CxO6JUw5XhhKihmaDacU2GiR0Ohcc4cZ+Kq3AjlEnEeRSazLs6/9b/kh4eTC+hngE3QQD7Yyclxsrf3cpxsPXn+cFdenF9aqlBXMXaDiEyfyfawBz2RqC/O9WF1ysacOpytlUSoqNrtfbS642+4D4CS9V3xb4u8P/ACI4O810efRu6KsC0QnjHJGaq4IOGUjWTo/YDZDB3xSIxcGyNlWcTucb4T3in/3IaueNrZyX0lGOrWndstOr+w21UlVFokILjJLFhPukbVY8OmwNQ3nZgNJNmKDccusSb4UIe+gtkI+9/bSLJDjqn763f5CQ5TLApmICkqwR0QnUPKZFIUnoozWcQuRbC0Km02knj0tPYx63furGs3x/iPnz83zJDVNtdP3QAAAABJRU5ErkJggg==)](https://usegalaxy.org/root?tool_id=bowtie2)
 <!-- [![Build Status](https://travis-ci.org/BenLangmead/bowtie2.svg?branch=master)](https://travis-ci.org/BenLangmead/bowtie2) -->
 [![License: GPL v3](https://img.shields.io/badge/license-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
 <!--badges: end -->


=====================================
aligner_seed.cpp
=====================================
@@ -600,6 +600,7 @@ void SeedAligner::searchAllSeeds(
 	const Ebwt* ebwtBw,          // BWT' index
 	const Read& read,            // read to align
 	const Scoring& pens,         // scoring scheme
+	size_t ncut_f,               // min seed quality for BWT 
 	AlignmentCacheIface& cache,  // local cache for seed alignments
 	SeedResults& sr,             // holds all the seed hits
 	SeedSearchMetrics& met,      // metrics
@@ -613,6 +614,7 @@ void SeedAligner::searchAllSeeds(
 	ebwtBw_ = ebwtBw;
 	sc_ = &pens;
 	read_ = &read;
+	ncut_f_ = ncut_f;
 	bwops_ = bwedits_ = 0;
 	uint64_t possearches = 0, seedsearches = 0, intrahits = 0, interhits = 0, ooms = 0;
 
@@ -1582,6 +1584,8 @@ SeedAligner::reportHit(
 	uint16_t len,                      // length of hit
 	DoublyLinkedList<Edit> *prevEdit)  // previous edit
 {
+	if ( (botf - topf) > ncut_f_) return; // low quality seed, just ignore
+
 	const BTDnaString& seq = cache.getSeq();
 
 	// Add information about the seed hit to AlignmentCache.  This


=====================================
aligner_seed.h
=====================================
@@ -1688,6 +1688,7 @@ public:
 		const Ebwt* ebwtBw,         // BWT' index
 		const Read& read,           // read to align
 		const Scoring& pens,        // scoring scheme
+		size_t ncut_f,              // min seed quality for BWT 
 		AlignmentCacheIface& cache, // local seed alignment cache
 		SeedResults& hits,          // holds all the seed hits
 		SeedSearchMetrics& met,     // metrics
@@ -1834,6 +1835,8 @@ protected:
 	
 	const Read* read_;         // read whose seeds are currently being aligned
 	
+	size_t ncut_f_;            // min seed quality for BWT 
+
 	EList<Edit> edits_;        // temporary place to sort edits
 	EList<uint32_t> offIdx2off_;// offset idx to read offset map, set up instantiateSeeds()
 	uint64_t bwops_;           // Burrows-Wheeler operations


=====================================
aligner_seed2.h
=====================================
@@ -2158,7 +2158,7 @@ public:
 		for(size_t i = 0; i < sas_.size(); i++) {
 			size_t en = sink[i].botf - sink[i].topf;
 			sas_[i].init(sink[i].topf, EListSlice<TIndexOffU, 16>(offs_, ei, en));
-			gws_[i].init(ebwtFw, ref, sas_[i], rnd, met);
+			gws_[i].init(ebwtFw, ref, sas_[i], met);
 			ei += en;
 		}
 	}
@@ -2509,7 +2509,7 @@ protected:
 		sas_.resize(1);
 		gws_.resize(1);
 		sas_[0].init(topf, EListSlice<TIndexOffU, 16>(offs_, 0, botf - topf));
-		gws_[0].init(ebwtFw, ref, sas_[0], rnd, met);
+		gws_[0].init(ebwtFw, ref, sas_[0], met);
 	}
 	
 	DescentPartialResolvedAlignmentSink palsink_;


=====================================
aligner_sw_driver.cpp
=====================================
@@ -68,6 +68,7 @@ bool SwDriver::eeSaTups(
 	SeedResults& sh,             // seed hits to extend into full alignments
 	const Ebwt& ebwt,            // BWT
 	const BitPairReference& ref, // Reference strings
+	bool deterministicSeeds,     // Should I disable the random seed selection? 
 	RandomSource& rnd,           // pseudo-random generator
 	WalkMetrics& wlm,            // group walk left metrics
 	SwMetrics& swmSeed,          // metrics for seed extensions
@@ -88,6 +89,7 @@ bool SwDriver::eeSaTups(
 	nobj += sh.mm1EEHits().size();
     nobj = min(nobj, maxelt);
 	gws_.ensure(nobj);
+	useCurrIdx = false;
 	rands_.ensure(nobj);
 	satpos_.ensure(nobj);
 	eehits_.ensure(nobj);
@@ -188,7 +190,6 @@ bool SwDriver::eeSaTups(
                         ebwt,               // forward Bowtie index
                         ref,                // reference sequences
                         sa,                 // SATuple
-                        rnd,                // pseudo-random generator
                         wlm);               // metrics
                     assert(gws_.back().repOk(sa));
                     nelt_out += width;
@@ -277,7 +278,6 @@ bool SwDriver::eeSaTups(
                     ebwt, // forward Bowtie index
                     ref,  // reference sequences
                     sa,   // SATuple
-                    rnd,  // pseudo-random generator
                     wlm); // metrics
                 assert(gws_.back().repOk(sa));
                 nelt_out += width;
@@ -487,7 +487,9 @@ void SwDriver::extend(
  * Given seed results, set up all of our state for resolving and keeping
  * track of reference offsets for hits.
  */
-void SwDriver::prioritizeSATups(
+
+// non-deterministic, fill in rands_
+void SwDriver::prioritizeSATupsRands(
 	const Read& read,            // read
 	SeedResults& sh,             // seed hits to extend into full alignments
 	const Ebwt& ebwtFw,          // BWT
@@ -510,6 +512,7 @@ void SwDriver::prioritizeSATups(
 	const int matei = (read.mate <= 1 ? 0 : 1);
 	satups_.clear();
 	gws_.clear();
+	useCurrIdx = false;
 	rands_.clear();
 	rands2_.clear();
 	satpos_.clear();
@@ -620,7 +623,6 @@ void SwDriver::prioritizeSATups(
 				ebwtFw, // forward Bowtie index
 				ref,    // reference sequences
 				sa,     // SA tuples: ref hit, salist range
-				rnd,    // pseudo-random generator
 				wlm);   // metrics
 			assert(gws_.back().initialized());
 			rands_.expand();
@@ -665,7 +667,6 @@ void SwDriver::prioritizeSATups(
 			ebwtFw, // forward Bowtie index
 			ref,    // reference sequences
 			sa,     // SA tuples: ref hit, salist range
-			rnd,    // pseudo-random generator
 			wlm);   // metrics
 		assert(gws_.back().initialized());
 		rands_.expand();
@@ -725,7 +726,6 @@ void SwDriver::prioritizeSATups(
 			ebwtFw, // forward Bowtie index
 			ref,    // reference sequences
 			sa,     // SA tuples: ref hit, salist range
-			rnd,    // pseudo-random generator
 			wlm);   // metrics
 		assert(gws_.back().initialized());
 		// Initialize random selector
@@ -737,6 +737,172 @@ void SwDriver::prioritizeSATups(
 	return;
 }
 
+// deterministic, use only a single gws element, will use just-in-time init later
+void SwDriver::prioritizeSATupsIdxs(
+	const Read& read,            // read
+	SeedResults& sh,             // seed hits to extend into full alignments
+	const Ebwt& ebwtFw,          // BWT
+	const Ebwt* ebwtBw,          // BWT
+	const BitPairReference& ref, // Reference strings
+	int seedmms,                 // # mismatches allowed in seed
+	size_t maxelt,               // max elts we'll consider
+	bool doExtend,               // do extension of seed hits?
+	AlignmentCacheIface& ca,     // alignment cache for seed hits
+	WalkMetrics& wlm,            // group walk left metrics
+	PerReadMetrics& prm,         // per-read metrics
+	size_t& nelt_out)            // out: # elements total
+{
+	const size_t nonz = sh.nonzeroOffsets(); // non-zero positions
+	const int matei = (read.mate <= 1 ? 0 : 1);
+	satups_.clear();
+	gws_.resize(1);    // will use a single element in deterministic mode
+	useCurrIdx = true;
+	satpos_.clear();
+
+	size_t nrange = 0, nelt = 0;
+	for(size_t i = 0; i < nonz; i++) {
+		bool fw = true;
+		uint32_t offidx = 0, rdoff = 0, seedlen = 0;
+		QVal qv = sh.hitsByRank(i, offidx, rdoff, fw, seedlen);
+		assert(qv.valid());
+		assert(!qv.empty());
+		assert(qv.repOk(ca.current()));
+		ca.queryQval(qv, satups_, nrange, nelt);
+		for(size_t j = 0; j < satups_.size(); j++) {
+			const size_t sz = satups_[j].size();
+			// Check whether this hit occurs inside the extended boundaries of
+			// another hit we already processed for this read.
+			if(seedmms == 0) {
+				// See if we're covered by a previous extended seed hit
+				EList<ExtendRange>& range =
+					fw ? seedExRangeFw_[matei] : seedExRangeRc_[matei];
+				bool skip = false;
+				for(size_t k = 0; k < range.size(); k++) {
+					size_t p5 = range[k].off;
+					size_t len = range[k].len;
+					if(p5 <= rdoff && p5 + len >= (rdoff + seedlen)) {
+						if(sz <= range[k].sz) {
+							skip = true;
+							break;
+						}
+					}
+				}
+				if(skip) {
+					assert_gt(nrange, 0);
+					nrange--;
+					assert_geq(nelt, sz);
+					nelt -= sz;
+					continue; // Skip this seed
+				}
+			}
+			satpos_.expand();
+			SATupleAndPos& satpos = satpos_.back();
+			satpos.sat = satups_[j];
+			satpos.origSz = sz;
+			satpos.pos.init(fw, offidx, rdoff, seedlen);
+			satpos.nlex = satpos.nrex = 0;
+#ifndef NDEBUG
+			tmp_rdseq_.clear();
+			uint64_t key = satpos.sat.key.seq;
+			for(size_t k = 0; k < seedlen; k++) {
+				int c = (int)(key & 3);
+				tmp_rdseq_.append(c);
+				key >>= 2;
+			}
+			tmp_rdseq_.reverse();
+#endif
+			size_t nlex = 0, nrex = 0;
+			if(doExtend) {
+				extend(
+					read,
+					ebwtFw,
+					ebwtBw,
+					satpos.sat.topf,
+					(TIndexOffU)(satpos.sat.topf + sz),
+					satpos.sat.topb,
+					(TIndexOffU)(satpos.sat.topb + sz),
+					fw,
+					rdoff,
+					seedlen,
+					prm,
+					nlex,
+					nrex);
+			}
+			satpos.nlex = nlex;
+			satpos.nrex = nrex;
+			if(seedmms == 0 && (nlex > 0 || nrex > 0)) {
+				assert_geq(rdoff, (fw ? nlex : nrex));
+				size_t p5 = rdoff - (fw ? nlex : nrex);
+				EList<ExtendRange>& range =
+					fw ? seedExRangeFw_[matei] : seedExRangeRc_[matei];
+				range.expand();
+				range.back().off = p5;
+				range.back().len = seedlen + nlex + nrex;
+				range.back().sz = sz;
+			}
+		}
+		satups_.clear();
+	}
+	assert_eq(nrange, satpos_.size());
+	// sort satpos_, since we want to consider the high-quality (smaller size) seeds first
+	satpos_.sort();
+	gws_.ensure(nrange);
+
+	size_t nelt_added = 0;
+	// We may not want to keep all of the ranges
+	// so check if we hit max before we run of them
+	size_t sp_el = 0;
+	for(sp_el = 0; (sp_el < nrange) && (nelt_added < maxelt); sp_el++) {
+		const SATupleAndPos& satpos = satpos_[sp_el];
+		nelt_added += satpos.sat.size();
+#ifndef NDEBUG
+		for(size_t k = 0; k < sp_el; k++) {
+			assert(!(satpos_[k] == satpos_[sp_el]));
+		}
+#endif
+	}
+	if (sp_el < nrange) {
+		// did not use all elements, truncate
+		satpos_.resize(sp_el);
+	}
+
+	nelt_out = nelt_added;
+	return;
+}
+
+// just the selector
+void SwDriver::prioritizeSATups(
+	const Read& read,            // read
+	SeedResults& sh,             // seed hits to extend into full alignments
+	const Ebwt& ebwtFw,          // BWT
+	const Ebwt* ebwtBw,          // BWT
+	const BitPairReference& ref, // Reference strings
+	int seedmms,                 // # mismatches allowed in seed
+	size_t maxelt,               // max elts we'll consider
+	bool doExtend,               // do extension of seed hits?
+	bool deterministicSeeds,     // Should I disable the random seed selection? 
+	bool lensq,                  // square length in weight calculation
+	bool szsq,                   // square range size in weight calculation
+	size_t nsm,                  // if range as <= nsm elts, it's "small"
+	AlignmentCacheIface& ca,     // alignment cache for seed hits
+	RandomSource& rnd,           // pseudo-random generator
+	WalkMetrics& wlm,            // group walk left metrics
+	PerReadMetrics& prm,         // per-read metrics
+	size_t& nelt_out,            // out: # elements total
+	bool all)                    // report all hits?
+{
+	if (deterministicSeeds) {
+		prioritizeSATupsIdxs(read, sh, ebwtFw, ebwtBw, ref,
+				seedmms, maxelt, doExtend,
+				ca, wlm, prm, nelt_out);
+	} else {
+		prioritizeSATupsRands(read, sh, ebwtFw, ebwtBw, ref,
+				seedmms, maxelt, doExtend, lensq, szsq, nsm,
+				ca, rnd, wlm, prm, nelt_out, all);
+	}
+	return;
+}
+
 enum {
 	FOUND_NONE = 0,
 	FOUND_EE,
@@ -780,6 +946,7 @@ int SwDriver::extendSeeds(
 	size_t cpow2,                // interval between diagonals to checkpoint
 	bool doTri,                  // triangular mini-fills?
 	int tighten,                 // -M score tightening mode
+	bool deterministicSeeds,     // Should I disable the random seed selection? 
 	AlignmentCacheIface& ca,     // alignment cache for seed hits
 	RandomSource& rnd,           // pseudo-random source
 	WalkMetrics& wlm,            // group walk left metrics
@@ -831,13 +998,14 @@ int SwDriver::extendSeeds(
 					sh,           // seed hits to extend into full alignments
 					ebwtFw,       // BWT
 					ref,          // Reference strings
+					deterministicSeeds, // Should I disable the random seed selection? 
 					rnd,          // pseudo-random generator
 					wlm,          // group walk left metrics
 					swmSeed,      // seed-extend metrics
 					nelt,         // out: # elements total
                     maxIters,     // max # to report
 					all);         // report all hits?
-				assert_eq(gws_.size(), rands_.size());
+				assert_eq(satpos_.size(), rands_.size());
 				assert_eq(gws_.size(), satpos_.size());
 			} else {
 				eeMode = false;
@@ -861,6 +1029,7 @@ int SwDriver::extendSeeds(
 					seedmms,       // # seed mismatches allowed
 					maxIters,      // max rows to consider per position
 					doExtend,      // extend out seeds
+					deterministicSeeds, // Should I disable the random seed selection? 
 					true,          // square extended length
 					true,          // square SA range size
 					nsm,           // smallness threshold
@@ -870,8 +1039,10 @@ int SwDriver::extendSeeds(
 					prm,           // per-read metrics
 					nelt,          // out: # elements total
 					all);          // report all hits?
-				assert_eq(gws_.size(), rands_.size());
-				assert_eq(gws_.size(), satpos_.size());
+				if (!useCurrIdx) {
+					assert_eq(satpos_.size(), rands_.size());
+					assert_eq(gws_.size(), satpos_.size());
+				}
 				neltLeft = nelt;
 				firstExtend = false;
 			}
@@ -880,33 +1051,57 @@ int SwDriver::extendSeeds(
 				break;
 			}
 		}
-		for(size_t i = 0; i < gws_.size(); i++) {
+		const size_t maxi = satpos_.size();
+		for(size_t i = 0; i < maxi; i++) {
 			if(eeMode && eehits_[i].score < minsc) {
 				return EXTEND_PERFECT_SCORE;
 			}
-			bool is_small       = satpos_[i].sat.size() < nsm;
-			bool fw             = satpos_[i].pos.fw;
-			uint32_t rdoff      = satpos_[i].pos.rdoff;
-			uint32_t seedhitlen = satpos_[i].pos.seedlen;
+			// In deterministic mode, we can reuse the same gws_ element
+			GroupWalk2S<TSlice, 16> &gws = gws_[useCurrIdx? 0 : i];
+
+			const SATupleAndPos& satpos = satpos_[i];
+			const size_t sat_size     = satpos.sat.size();
+			// when we are not subsampling(useCurrIdx), treat them all as if they were small
+			const bool is_small       = useCurrIdx ? true : (sat_size < nsm);
+			const bool fw             = satpos.pos.fw;
+			uint32_t rdoff      = satpos.pos.rdoff;
+			uint32_t seedhitlen = satpos.pos.seedlen;
 			if(!fw) {
 				// 'rdoff' and 'offidx' are with respect to the 5' end of
 				// the read.  Here we convert rdoff to be with respect to
 				// the upstream (3') end of ther read.
 				rdoff = (uint32_t)(rdlen - rdoff - seedhitlen);
 			}
+			if (useCurrIdx) {
+				// since we are reusing the same element, just-in-time initialization
+				SARangeWithOffs<TSlice> sa;
+				sa.topf = satpos.sat.topf;
+				sa.len = satpos.sat.key.len;
+				sa.offs = satpos.sat.offs;
+				gws.reset();
+				gws.init(
+					ebwtFw, // forward Bowtie index
+					ref,    // reference sequences
+					sa,     // SA tuples: ref hit, salist range
+					wlm);   // metrics
+				assert(gws.initialized());
+			}
 			bool first = true;
+			size_t currIdx = 0; // only used when useCurrIdx==true
 			// If the range is small, investigate all elements now.  If the
 			// range is large, just investigate one and move on - we might come
 			// back to this range later.
 			size_t riter = 0;
-			while(!rands_[i].done() && (first || is_small || eeMode)) {
-				assert(!gws_[i].done());
+			while( (useCurrIdx? (currIdx<sat_size) : (!rands_[i].done()) ) && 
+			        (first || is_small || eeMode) ) {
+				assert(!gws.done());
 				riter++;
 				if(minsc == perfectScore) {
 					if(!eeMode || eehits_[i].score < perfectScore) {
 						return EXTEND_PERFECT_SCORE;
 					}
 				} else if(eeMode && eehits_[i].score < minsc) {
+					assert(!useCurrIdx);
 					break;
 				}
 				if(prm.nExDps >= maxDp || prm.nMateDps >= maxDp) {
@@ -922,13 +1117,14 @@ int SwDriver::extendSeeds(
 				first = false;
 				// Resolve next element offset
 				WalkResult wr;
-				size_t elt = rands_[i].next(rnd);
+				// auto-increment after use
+				size_t elt = useCurrIdx ? (currIdx++) : rands_[i].next(rnd);
 				//cerr << "elt=" << elt << endl;
 				SARangeWithOffs<TSlice> sa;
-				sa.topf = satpos_[i].sat.topf;
-				sa.len = satpos_[i].sat.key.len;
-				sa.offs = satpos_[i].sat.offs;
-				gws_[i].advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
+				sa.topf = satpos.sat.topf;
+				sa.len = satpos.sat.key.len;
+				sa.offs = satpos.sat.offs;
+				gws.advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
 				eltsDone++;
 				if(!eeMode) {
 					assert_gt(neltLeft, 0);
@@ -952,7 +1148,7 @@ int SwDriver::extendSeeds(
 				}
 #ifndef NDEBUG
 				if(!eeMode && !straddled) { // Check that seed hit matches reference
-					uint64_t key = satpos_[i].sat.key.seq;
+					uint64_t key = satpos.sat.key.seq;
 					for(size_t k = 0; k < wr.elt.len; k++) {
 						int c = ref.getBase(tidx, toff + wr.elt.len - k - 1);
 						assert_leq(c, 3);
@@ -1289,8 +1485,10 @@ int SwDriver::extendSeeds(
 				// At this point we know that we aren't bailing, and will
 				// continue to resolve seed hits.  
 
-			} // while(!gws_[i].done())
-		}
+			} // while(!gws.done())
+		} // for maxi
+
+		if (useCurrIdx) break; // always one-pass, when using useCurrIdx
 	}
 	// Short-circuited because a limit, e.g. -k, -m or -M, was exceeded
 	return EXTEND_EXHAUSTED_CANDIDATES;
@@ -1419,6 +1617,7 @@ int SwDriver::extendSeedsPaired(
 	size_t cpow2,                // interval between diagonals to checkpoint
 	bool doTri,                  // triangular mini-fills?
 	int tighten,                 // -M score tightening mode
+	bool deterministicSeeds,     // Should I disable the random seed selection? 
 	AlignmentCacheIface& ca,     // alignment cache for seed hits
 	RandomSource& rnd,           // pseudo-random source
 	WalkMetrics& wlm,            // group walk left metrics
@@ -1511,18 +1710,19 @@ int SwDriver::extendSeedsPaired(
 					sh,           // seed hits to extend into full alignments
 					ebwtFw,       // BWT
 					ref,          // Reference strings
+					deterministicSeeds, // Should I disable the random seed selection? 
 					rnd,          // pseudo-random generator
 					wlm,          // group walk left metrics
 					swmSeed,      // seed-extend metrics
 					nelt,         // out: # elements total
                     maxIters,     // max elts to report
 					all);         // report all hits
-				assert_eq(gws_.size(), rands_.size());
+				assert_eq(satpos_.size(), rands_.size());
 				assert_eq(gws_.size(), satpos_.size());
 				neltLeft = nelt;
 				// Initialize list that contains the mate-finding failure
 				// streak for each range
-				mateStreaks_.resize(gws_.size());
+				mateStreaks_.resize(satpos_.size());
 				mateStreaks_.fill(0);
 			} else {
 				eeMode = false;
@@ -1548,6 +1748,7 @@ int SwDriver::extendSeedsPaired(
 					seedmms,       // # seed mismatches allowed
 					maxIters,      // max rows to consider per position
 					doExtend,      // extend out seeds
+					deterministicSeeds, // Should I disable the random seed selection? 
 					true,          // square extended length
 					true,          // square SA range size
 					nsm,           // smallness threshold
@@ -1557,11 +1758,13 @@ int SwDriver::extendSeedsPaired(
 					prm,           // per-read metrics
 					nelt,          // out: # elements total
 					all);          // report all hits?
-				assert_eq(gws_.size(), rands_.size());
-				assert_eq(gws_.size(), satpos_.size());
+				if (!useCurrIdx) {
+					assert_eq(satpos_.size(), rands_.size());
+					assert_eq(gws_.size(), satpos_.size());
+				}
 				neltLeft = nelt;
 				firstExtend = false;
-				mateStreaks_.resize(gws_.size());
+				mateStreaks_.resize(satpos_.size());
 				mateStreaks_.fill(0);
 			}
 			if(neltLeft == 0) {
@@ -1569,30 +1772,55 @@ int SwDriver::extendSeedsPaired(
 				break;
 			}
 		}
-		for(size_t i = 0; i < gws_.size(); i++) {
+		const size_t maxi = satpos_.size();
+		for(size_t i = 0; i < maxi; i++) {
 			if(eeMode && eehits_[i].score < minsc) {
 				return EXTEND_PERFECT_SCORE;
 			}
-			bool is_small       = satpos_[i].sat.size() < nsm;
-			bool fw             = satpos_[i].pos.fw;
-			uint32_t rdoff      = satpos_[i].pos.rdoff;
-			uint32_t seedhitlen = satpos_[i].pos.seedlen;
+			// In deterministic mode, we can reuse the same gws_ element
+			GroupWalk2S<TSlice, 16> &gws = gws_[useCurrIdx? 0 : i];
+
+			const SATupleAndPos& satpos = satpos_[i];
+			const size_t sat_size     = satpos.sat.size();
+			// when we are not subsampling(useCurrIdx), treat them all as if they were small
+			const bool is_small       = useCurrIdx ? true : (sat_size < nsm);
+			const bool fw             = satpos.pos.fw;
+			uint32_t rdoff      = satpos.pos.rdoff;
+			uint32_t seedhitlen = satpos.pos.seedlen;
 			if(!fw) {
 				// 'rdoff' and 'offidx' are with respect to the 5' end of
 				// the read.  Here we convert rdoff to be with respect to
 				// the upstream (3') end of ther read.
 				rdoff = (uint32_t)(rdlen - rdoff - seedhitlen);
 			}
+			if (useCurrIdx) {
+				// since we are reusing the same element, just-in-time initialization
+				SARangeWithOffs<TSlice> sa;
+				sa.topf = satpos.sat.topf;
+				sa.len = satpos.sat.key.len;
+				sa.offs = satpos.sat.offs;
+				gws.reset();
+				gws.init(
+					ebwtFw, // forward Bowtie index
+					ref,    // reference sequences
+					sa,     // SA tuples: ref hit, salist range
+					wlm);   // metrics
+				assert(gws.initialized());
+			}
 			bool first = true;
+			size_t currIdx = 0; // only used when useCurrIdx==true
 			// If the range is small, investigate all elements now.  If the
 			// range is large, just investigate one and move on - we might come
 			// back to this range later.
-			while(!rands_[i].done() && (first || is_small || eeMode)) {
+			size_t riter = 0;
+			while( (useCurrIdx? (currIdx<sat_size) : (!rands_[i].done()) ) && 
+			        (first || is_small || eeMode) ) {
 				if(minsc == perfectScore) {
 					if(!eeMode || eehits_[i].score < perfectScore) {
 						return EXTEND_PERFECT_SCORE;
 					}
 				} else if(eeMode && eehits_[i].score < minsc) {
+					assert(!useCurrIdx);
 					break;
 				}
 				if(prm.nExDps >= maxDp || prm.nMateDps >= maxDp) {
@@ -1615,21 +1843,26 @@ int SwDriver::extendSeedsPaired(
 				}
 				if(mateStreaks_[i] >= maxMateStreak) {
 					// Don't try this seed range anymore
-					rands_[i].setDone();
-					assert(rands_[i].done());
+					if (useCurrIdx) {
+					       currIdx = sat_size;
+					} else {
+						rands_[i].setDone();
+						assert(rands_[i].done());
+					}
 					break;
 				}
 				prm.nExIters++;
 				first = false;
-				assert(!gws_[i].done());
+				assert(!gws.done());
 				// Resolve next element offset
 				WalkResult wr;
-				size_t elt = rands_[i].next(rnd);
+				// auto-increment after use
+				size_t elt = useCurrIdx ? (currIdx++) : rands_[i].next(rnd);
 				SARangeWithOffs<TSlice> sa;
-				sa.topf = satpos_[i].sat.topf;
-				sa.len = satpos_[i].sat.key.len;
-				sa.offs = satpos_[i].sat.offs;
-				gws_[i].advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
+				sa.topf = satpos.sat.topf;
+				sa.len = satpos.sat.key.len;
+				sa.offs = satpos.sat.offs;
+				gws.advanceElement((TIndexOffU)elt, ebwtFw, ref, sa, gwstate_, wr, wlm, prm);
 				eltsDone++;
 				assert_gt(neltLeft, 0);
 				neltLeft--;
@@ -1651,7 +1884,7 @@ int SwDriver::extendSeedsPaired(
 				}
 #ifndef NDEBUG
 				if(!eeMode && !straddled) { // Check that seed hit matches reference
-					uint64_t key = satpos_[i].sat.key.seq;
+					uint64_t key = satpos.sat.key.seq;
 					for(size_t k = 0; k < wr.elt.len; k++) {
 						int c = ref.getBase(tidx, toff + wr.elt.len - k - 1);
 						assert_leq(c, 3);
@@ -2396,7 +2629,9 @@ int SwDriver::extendSeedsPaired(
 				// At this point we know that we aren't bailing, and will continue to resolve seed hits.  
 
 			} // while(!gw.done())
-		} // for(size_t i = 0; i < gws_.size(); i++)
+		} // for(size_t i = 0; i < maxi; i++)
+
+		if (useCurrIdx) break; // always one-pass, when using useCurrIdx
 	}
 	return EXTEND_EXHAUSTED_CANDIDATES;
 }


=====================================
aligner_sw_driver.h
=====================================
@@ -346,6 +346,7 @@ public:
 		size_t cpow2,                // interval between diagonals to checkpoint
 		bool doTri,                  // triangular mini-fills
 		int tighten,                 // -M score tightening mode
+		bool deterministicSeeds,     // Should I disable the random seed selection? 
 		AlignmentCacheIface& ca,     // alignment cache for seed hits
 		RandomSource& rnd,           // pseudo-random source
 		WalkMetrics& wlm,            // group walk left metrics
@@ -403,6 +404,7 @@ public:
 		size_t cpow2,                // interval between diagonals to checkpoint
 		bool doTri,                  // triangular mini-fills
 		int tighten,                 // -M score tightening mode
+		bool deterministicSeeds,     // Should I disable the random seed selection? 
 		AlignmentCacheIface& cs,     // alignment cache for seed hits
 		RandomSource& rnd,           // pseudo-random source
 		WalkMetrics& wlm,            // group walk left metrics
@@ -447,6 +449,7 @@ protected:
 		SeedResults& sh,             // seed hits to extend into full alignments
 		const Ebwt& ebwt,            // BWT
 		const BitPairReference& ref, // Reference strings
+		bool deterministicSeeds,     // Should I disable the random seed selection? 
 		RandomSource& rnd,           // pseudo-random generator
 		WalkMetrics& wlm,            // group walk left metrics
 		SwMetrics& swmSeed,          // metrics for seed extensions
@@ -478,6 +481,7 @@ protected:
 		int seedmms,                 // # seed mismatches allowed
 		size_t maxelt,               // max elts we'll consider
 		bool doExtend,               // extend out seeds
+		bool deterministicSeeds,     // Should I disable the random seed selection? 
 		bool lensq,                  // square extended length
 		bool szsq,                   // square SA range size
 		size_t nsm,                  // if range as <= nsm elts, it's "small"
@@ -488,9 +492,45 @@ protected:
 		size_t& nelt_out,            // out: # elements total
 		bool all);                   // report all hits?
 
+	void prioritizeSATupsRands(
+		const Read& rd,              // read
+		SeedResults& sh,             // seed hits to extend into full alignments
+		const Ebwt& ebwtFw,          // BWT
+		const Ebwt* ebwtBw,          // BWT'
+		const BitPairReference& ref, // Reference strings
+		int seedmms,                 // # seed mismatches allowed
+		size_t maxelt,               // max elts we'll consider
+		bool doExtend,               // extend out seeds
+		bool lensq,                  // square extended length
+		bool szsq,                   // square SA range size
+		size_t nsm,                  // if range as <= nsm elts, it's "small"
+		AlignmentCacheIface& ca,     // alignment cache for seed hits
+		RandomSource& rnd,           // pseudo-random generator
+		WalkMetrics& wlm,            // group walk left metrics
+		PerReadMetrics& prm,         // per-read metrics
+		size_t& nelt_out,            // out: # elements total
+		bool all);                   // report all hits?
+
+	void prioritizeSATupsIdxs(
+		const Read& rd,              // read
+		SeedResults& sh,             // seed hits to extend into full alignments
+		const Ebwt& ebwtFw,          // BWT
+		const Ebwt* ebwtBw,          // BWT'
+		const BitPairReference& ref, // Reference strings
+		int seedmms,                 // # seed mismatches allowed
+		size_t maxelt,               // max elts we'll consider
+		bool doExtend,               // extend out seeds
+		AlignmentCacheIface& ca,     // alignment cache for seed hits
+		WalkMetrics& wlm,            // group walk left metrics
+		PerReadMetrics& prm,         // per-read metrics
+		size_t& nelt_out);           // out: # elements total
+
 	Random1toN               rand_;    // random number generators
-	EList<Random1toN, 16>    rands_;   // random number generators
-	EList<Random1toN, 16>    rands2_;  // random number generators
+
+	bool                     useCurrIdx; // use currIdx if true, rands_ else
+	EList<Random1toN, 16>    rands_;   // random number generators (needed when non-deterministic)
+
+	EList<Random1toN, 16>    rands2_;  // random number generators, internal temp
 	EList<EEHit, 16>         eehits_;  // holds end-to-end hits
 	EList<SATupleAndPos, 16> satpos_;  // holds SATuple, SeedPos pairs
 	EList<SATupleAndPos, 16> satpos2_; // holds SATuple, SeedPos pairs


=====================================
aln_sink.h
=====================================
@@ -858,6 +858,10 @@ public:
 		return oq_;
 	}
 
+	/**
+	 * Now many possible reference names do we handle
+	 */
+	size_t num_refnames() const { return refnames_.size();}
 protected:
 
 	OutputQueue&       oq_;           // output queue


=====================================
bowtie2-build
=====================================
@@ -25,6 +25,7 @@ import gzip
 import inspect
 import logging
 import argparse
+import platform
 import subprocess
 
 
@@ -115,6 +116,9 @@ def main():
         if tot_size > small_index_max_size:
             build_bin_spec = os.path.join(ex_path, build_bin_l)
 
+    if "Windows" in platform.platform():
+        build_bin_spec += '.exe'
+
     if not os.path.exists(build_bin_spec):
         sys.stderr.write(
             "{0} does not exist, try running `[g]make {0}'\n".format(


=====================================
bowtie2-inspect
=====================================
@@ -26,6 +26,7 @@ import inspect
 import logging
 import argparse
 import subprocess
+import platform
 from collections import deque
 
 def main():
@@ -61,7 +62,7 @@ def main():
         inspect_bin_l += '-debug'
 
     if script_options.sanitized:
-        inpsect_bin_spec += '-sanitized'
+        inspect_bin_spec += '-sanitized'
         inspect_bin_l += '-sanitized'
 
     if script_options.large_index:
@@ -73,6 +74,9 @@ def main():
         if large_idx_exists and not small_idx_exists:
             inspect_bin_spec = os.path.join(ex_path,inspect_bin_l)
 
+    if "Windows" in platform.platform():
+        inspect_bin_spec += '.exe'
+
     argv.appendleft('basic-0')
     argv.appendleft('--wrapper')
     argv.appendleft(inspect_bin_spec)


=====================================
bowtie_main.cpp
=====================================
@@ -24,12 +24,38 @@
 #include "tokenize.h"
 #include "ds.h"
 
+#ifdef ENABLE_x86_64_v3
+#include <unistd.h>
+#endif
+
 using namespace std;
 
 extern "C" {
 	int bowtie(int argc, const char **argv);
 }
 
+#ifdef ENABLE_x86_64_v3
+void check_x86_64_v3(int argc, const char **argv) {
+	if (__builtin_cpu_supports ("x86-64-v3") && (argc<126)) {
+		const char* new_argv[128]; // should always be enough, but above check enforces it, too
+		const char * org_path = argv[0];
+		// Append -v256 to the original path 
+		const int fn_len = strlen(org_path);
+		char *new_path = (char*) malloc(fn_len+16);
+		memcpy(new_path,org_path,fn_len);
+		strncpy(new_path+fn_len,"-v256",15);
+
+		for (int i=1; i<=argc; i++) new_argv[i] = argv[i]; // all but first the same, also copy final NULL
+		new_argv[0] = new_path;
+		// now replace the executable with new variant
+		// assuming the executable exists... execvp will gracefully fail else, which is OK
+		execvp(new_argv[0], (char *const *)new_argv);
+		// we should never get out of the above call
+		fprintf(stderr,"[WARNING] Failed to launch x86-64-v3 version, staying with default\n");
+	}
+}
+#endif
+
 /**
  * Bowtie main function.  It is placed in a separate source file to
  * make it slightly easier to compile Bowtie as a library.
@@ -40,6 +66,9 @@ extern "C" {
  * bowtie.
  */
 int main(int argc, const char **argv) {
+#ifdef ENABLE_x86_64_v3
+	check_x86_64_v3(argc, argv);
+#endif
 	if(argc > 2 && strcmp(argv[1], "-A") == 0) {
 		const char *file = argv[2];
 		ifstream in;


=====================================
bt2_search.cpp
=====================================
@@ -1,3 +1,4 @@
+
 /*
  * Copyright 2011, Ben Langmead <langmea at cs.jhu.edu>
  *
@@ -85,6 +86,7 @@ static string metricsFile;// output file to put alignment metrics in
 static bool metricsStderr;// output file to put alignment metrics in
 static bool metricsPerRead; // report a metrics tuple for every read
 static bool allHits;      // for multihits, report just one
+static bool deterministicSeeds;      // for low quality seeds, enable subsampling
 static bool showVersion;  // just print version and quit?
 static int ipause;        // pause before maching?
 static uint64_t qUpto;    // max # of queries to read
@@ -101,6 +103,8 @@ static string thread_stealing_dir; // keep track of pids in this directory
 static bool thread_stealing;// true iff thread stealing is in use
 static int outType;       // style of output
 static bool noRefNames;   // true -> print reference indexes; not names
+static uint32_t lowseeds; // size of seed range above which a seed is considered low quality, and thus discarded (0 disables the cut)
+static uint32_t lowseedsDivider; // how much should I divide the lowseeds parameter by, if 0 use abs value
 static uint32_t khits;    // number of hits per read; >1 is much slower
 static uint32_t mhits;    // don't report any hits if there are > mhits
 static int partitionSz;   // output a partitioning key in first field
@@ -278,6 +282,24 @@ static void set_format(int &current_format, file_format format) {
 	}
 }
 
+int set_default_thread_count() {
+	int num_threads = 1;
+	const char *omp_num_threads = NULL;
+	if ((omp_num_threads = getenv("OMP_NUM_THREADS")) != NULL) {
+		try {
+			num_threads = std::stoi(omp_num_threads);
+		} catch (std::invalid_argument const &ex) {
+			std::cerr << "Error: " << ex.what() << std::endl;
+			exit(EXIT_FAILURE);
+		} catch (std::out_of_range const &ex) {
+			std::cerr << "Error: " << ex.what() << std::endl;
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	return num_threads;
+}
+
 static void resetOptions() {
 	mates1.clear();
 	mates2.clear();
@@ -297,6 +319,7 @@ static void resetOptions() {
 	metricsStderr       = false;	// print metrics to stderr (in addition to --metrics-file if it's specified
 	metricsPerRead      = false;	// report a metrics tuple for every read?
 	allHits		    = false;	// for multihits, report just one
+	deterministicSeeds  = false;    // for low quality seeds, enable subsampling
 	showVersion	    = false;	// just print version and quit?
 	ipause		    = 0;	// pause before maching?
 	qUpto               = 0xffffffffffffffff; // max # of queries to read
@@ -307,13 +330,15 @@ static void resetOptions() {
 	solexaQuals	    = false;	// quality strings are solexa quals, not phred, and subtract 64 (not 33)
 	phred64Quals	    = false;	// quality chars are phred, but must subtract 64 (not 33)
 	integerQuals	    = false;	// quality strings are space-separated strings of integers, not ASCII
-	nthreads	    = 1;	// number of pthreads operating concurrently
+	nthreads	    = set_default_thread_count();	// number of pthreads operating concurrently
 	thread_ceiling	    = 0;	// max # threads user asked for
 	thread_stealing_dir = "";	// keep track of pids in this directory
 	thread_stealing	    = false;	// true iff thread stealing is in use
 	FNAME_SIZE	    = 4096;
 	outType		    = OUTPUT_SAM;	// style of output
 	noRefNames	    = false;	// true -> print reference indexes; not names
+	lowseeds	    = 0;	// size of seed range above which a seed is considered low quality, and thus discarded (0 disables the cut)
+	lowseedsDivider	    = 0;	// how much should I divide the lowseeds parameter by, if 0 use the abs value
 	khits		    = 1;	// number of hits per read; >1 is much slower
 	mhits		    = 50;	// stop after finding this many alignments+1
 	partitionSz	    = 0;	// output a partitioning key in first field
@@ -476,7 +501,7 @@ static void resetOptions() {
 #endif
 }
 
-static const char *short_options = "bfF:qbzhcu:rv:s:aP:t3:5:w:p:k:M:1:2:I:X:CQ:N:i:L:U:x:S:g:O:D:R:";
+static const char *short_options = "bfF:qbzhcu:rv:s:adP:t3:5:w:p:k:l:M:1:2:I:X:CQ:N:i:L:U:x:S:g:O:D:R:";
 
 static struct option long_options[] = {
 	{(char*)"verbose",                     no_argument,        0,                   ARG_VERBOSE},
@@ -509,6 +534,7 @@ static struct option long_options[] = {
 	{(char*)"help",                        no_argument,        0,                   'h'},
 	{(char*)"threads",                     required_argument,  0,                   'p'},
 	{(char*)"khits",                       required_argument,  0,                   'k'},
+	{(char*)"lowseeds",                    required_argument,  0,                   'l'},
 	{(char*)"minins",                      required_argument,  0,                   'I'},
 	{(char*)"maxins",                      required_argument,  0,                   'X'},
 	{(char*)"quals",                       required_argument,  0,                   'Q'},
@@ -626,6 +652,8 @@ static struct option long_options[] = {
 	{(char*)"no-exact-upfront",            no_argument,        0,                   ARG_EXACT_UPFRONT_NO},
 	{(char*)"no-1mm-upfront",              no_argument,        0,                   ARG_1MM_UPFRONT_NO},
 	{(char*)"1mm-minlen",                  required_argument,  0,                   ARG_1MM_MINLEN},
+	{(char*)"deterministic-seeds",         no_argument,        0,                   'd'},
+	{(char*)"no-deterministic-seeds",      no_argument,        0,                   ARG_DET_SEEDS_NO},
 	{(char*)"seed-off",                    required_argument,  0,                   'O'},
 	{(char*)"seed-boost",                  required_argument,  0,                   ARG_SEED_BOOST_THRESH},
 	{(char*)"read-times",                  no_argument,        0,                   ARG_READ_TIMES},
@@ -824,11 +852,15 @@ static void printUsage(ostream& out) {
 	    << "   OR" << endl
 	    << "  -k <int>           report up to <int> alns per read; MAPQ not meaningful" << endl
 	    << "   OR" << endl
-	    << "  -a/--all           report all alignments; very slow, MAPQ not meaningful" << endl
+	    << "  -a/--all           report all alignments; very slow without -l, MAPQ not meaningful" << endl
 	    << endl
 	    << " Effort:" << endl
+	    << "  -l/--lowseeds <n>  ignore any low quality seeds with ranges over threshold" << endl
+	    << "                     (0=no cut, if percentage, mili or nano, relative to idx size)" << endl
 	    << "  -D <int>           give up extending after <int> failed extends in a row (15)" << endl
 	    << "  -R <int>           for reads w/ repetitive seeds, try <int> sets of seeds (2)" << endl
+	    << "  -d/--deterministic-seeds" << endl
+	    << "                     Consider all seeds in order (no subsampling, best with -a)" << endl
 	    << endl
 	    << " Paired-end:" << endl
 	    << "  -I/--minins <int>  minimum fragment length (0)" << endl
@@ -952,6 +984,19 @@ T parse(const char *s) {
 	return tmp;
 }
 
+/**
+ * Parse a T string 'str',
+ * provide first char after the parse (\0 if all string consumed)
+ */
+template<typename T>
+T parse(const char *s, char &remainder) {
+	T tmp;
+	stringstream ss(s);
+	ss >> tmp;
+	ss >> remainder;
+	return tmp;
+}
+
 /**
  * Parse a pair of Ts from a string, 'str', delimited with 'delim'.
  */
@@ -1286,6 +1331,30 @@ static void parseOption(int next_option, const char *arg) {
 		saw_k = true;
 		break;
 	}
+	case 'l': {
+		char remainder = 0;
+		lowseedsDivider = 0;
+		lowseeds = parse<size_t>(arg, remainder);
+		if (remainder=='%') {
+			// User requested percentage of DB
+			lowseedsDivider = 100;
+		} else if (remainder=='m') {
+			// User requested mili of DB
+			lowseedsDivider = 1000;
+		} else if (remainder=='n') {
+			// User requested nano of DB
+			lowseedsDivider = 1000000;
+		} else if (remainder==0) {
+			// We got an absolute value
+                        lowseedsDivider = 0;
+		} else {
+			cerr << "Warning: -l argument had training chars "
+			     << "that were not parsed" << endl;
+		}
+		break;
+	}
+	case 'd': deterministicSeeds = true; break;
+	case ARG_DET_SEEDS_NO: deterministicSeeds = false; break;
 	case ARG_VERBOSE: gVerbose = 1; break;
 	case ARG_STARTVERBOSE: startVerbose = true; break;
 	case ARG_QUIET: gQuiet = true; break;
@@ -1706,6 +1775,16 @@ static void parseOptions(int argc, const char **argv) {
 		assert_gt(mhits, 0);
 		msample = true;
 	}
+	if (deterministicSeeds) {
+		if ( doExactUpFront || do1mmUpFront || (mhits!=0) ) {
+			cerr << "Warning: -d cannot be used with --exact-upfront, --1mm-upfront or -m." << endl;
+			throw 1;
+		}
+		if ( !allHits ) {
+			cerr << "Error: -d can only be used with -a." << endl;
+			throw 1;
+		}
+	}
 	if (format == UNKNOWN)
 		set_format(format, FASTQ);
 	if(mates1.size() != mates2.size()) {
@@ -1714,7 +1793,7 @@ static void parseOptions(int argc, const char **argv) {
 		     << "sequences must be specified with -1 and -2." << endl;
 		throw 1;
 	}
-	if(interleaved && (format != FASTA && format != FASTQ)) {
+	if(interleaved && (format != FASTA && format != FASTQ && format != BAM)) {
 		cerr << "Error: --interleaved only works in combination with FASTA (-f) and FASTQ (-q) formats." << endl;
 		throw 1;
 	}
@@ -3022,6 +3101,12 @@ static void multiseedSearchWorker(void *vp) {
 	AlnSink&                msink    = *multiseed_msink;
 	OutFileBuf*             metricsOfb = multiseed_metricsOfb;
 
+	const size_t lowseeds_ncut = (lowseeds>0) ?
+			((lowseedsDivider!=0) ? ((msink.num_refnames() * lowseeds + (lowseedsDivider-1))/lowseedsDivider) // round up, avoid 0
+					      : lowseeds
+			) :
+			std::numeric_limits<size_t>::max(); // never filter by size
+
 	{
 #ifdef PER_THREAD_TIMING
 		uint64_t ncpu_changeovers = 0;
@@ -3505,6 +3590,7 @@ static void multiseedSearchWorker(void *vp) {
 									cpow2,          // checkpointer interval, log2
 									doTri,          // triangular mini-fills?
 									tighten,        // -M score tightening mode
+									deterministicSeeds, // Should I disable the random seed selection? 
 									ca,             // seed alignment cache
 									rnd,            // pseudo-random source
 									wlm,            // group walk left metrics
@@ -3547,6 +3633,7 @@ static void multiseedSearchWorker(void *vp) {
 									cpow2,          // checkpointer interval, log2
 									doTri,          // triangular mini-fills
 									tighten,        // -M score tightening mode
+									deterministicSeeds, // Should I disable the random seed selection? 
 									ca,             // seed alignment cache
 									rnd,            // pseudo-random source
 									wlm,            // group walk left metrics
@@ -3687,6 +3774,7 @@ static void multiseedSearchWorker(void *vp) {
 									cpow2,          // checkpointer interval, log2
 									doTri,          // triangular mini-fills?
 									tighten,        // -M score tightening mode
+									deterministicSeeds, // Should I disable the random seed selection? 
 									ca,             // seed alignment cache
 									rnd,            // pseudo-random source
 									wlm,            // group walk left metrics
@@ -3729,6 +3817,7 @@ static void multiseedSearchWorker(void *vp) {
 									cpow2,          // checkpointer interval, log2
 									doTri,          // triangular mini-fills?
 									tighten,        // -M score tightening mode
+									deterministicSeeds, // Should I disable the random seed selection? 
 									ca,             // seed alignment cache
 									rnd,            // pseudo-random source
 									wlm,            // group walk left metrics
@@ -3865,6 +3954,7 @@ static void multiseedSearchWorker(void *vp) {
 								ebwtBw,           // BWT' index
 								*rds[mate],       // read
 								sc,               // scoring scheme
+								lowseeds_ncut,    // cut no seed quality
 								ca,               // alignment cache
 								shs[mate],        // store seed hits here
 								sdm,              // metrics
@@ -3963,6 +4053,7 @@ static void multiseedSearchWorker(void *vp) {
 										cpow2,          // checkpointer interval, log2
 										doTri,          // triangular mini-fills?
 										tighten,        // -M score tightening mode
+										deterministicSeeds, // Should I disable the random seed selection? 
 										ca,             // seed alignment cache
 										rnd,            // pseudo-random source
 										wlm,            // group walk left metrics
@@ -4005,6 +4096,7 @@ static void multiseedSearchWorker(void *vp) {
 										cpow2,          // checkpointer interval, log2
 										doTri,          // triangular mini-fills?
 										tighten,        // -M score tightening mode
+										deterministicSeeds, // Should I disable the random seed selection? 
 										ca,             // seed alignment cache
 										rnd,            // pseudo-random source
 										wlm,            // group walk left metrics
@@ -4716,8 +4808,14 @@ static void multiseedSearch(
 	EList<int> tids;
 	EList<std::thread*> threads(nthreads);
 	EList<thread_tracking_pair> tps;
+	// The condition_variable synchronization can be problematic
+	// in certain situations.
+	// Disabling it and using the polling-based lock-free mechanism can help there
+	// The (relative) polling cost is much higher for low thread count, so use that as a treshold
+	bool readahead_useCVLocks = nthreads<=16; // Note: We may want to consider other factors, too
+
 	// Important: Need at least nthreads+1 elements, more is OK
-	PatternSourceReadAheadFactory readahead_factory(patsrc,pp,4*nthreads+1);
+	PatternSourceReadAheadFactory readahead_factory(patsrc,pp,4*nthreads+1,readahead_useCVLocks);
 	multiseed_readahead_factory = &readahead_factory;
 
 	tps.resize(std::max(nthreads, thread_ceiling));


=====================================
doc/manual.html
=====================================
@@ -6,6 +6,9 @@
   <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
   <title>Bowtie 2 Manual</title>
   <style>
+    /* Default styles provided by pandoc.
+    ** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
+    */
     code{white-space: pre-wrap;}
     span.smallcaps{font-variant: small-caps;}
     div.columns{display: flex; gap: min(4vw, 1.5em);}
@@ -1778,6 +1781,25 @@ number of seed hits divided by the number of seeds that aligned at least
 once is greater than 300. Default: 2.</p>
 </td>
 </tr>
+<tr>
+<td id="bowtie2-options-d">
+<pre><code>-d/--deterministic-seeds</code></pre>
+</td>
+<td>
+<p>Consider all seeds in order (no subsampling). Can be used to augment
+<a href="#bowtie2-options-a"><code>-a</code></a> or <a
+href="#bowtie2-options-k"><code>-k</code></a> with deterministic
+behavior. This option significantly speeds up <a
+href="#bowtie2-options-a"><code>-a</code></a> while also reducing memory
+consumption. It is not however always strictly better than standalone
+<code>[-a]</code> when considering the number of repeated alignments
+found.</p>
+<p>Note: In order to use this option exact upfront and 1mm upfront
+behavior have to be disabled using the following options:
+[<code>--no-exact-upfront</code>] and <a
+href="#bowtie2-options-no-1mm-upfront"><code>--no-1mm-upfront</code></a>.</p>
+</td>
+</tr>
 </table>
 <h4 id="paired-end-options">Paired-end options</h4>
 <table>


=====================================
doc/website/manual.ssi
=====================================
@@ -1747,6 +1747,25 @@ number of seed hits divided by the number of seeds that aligned at least
 once is greater than 300. Default: 2.</p>
 </td>
 </tr>
+<tr>
+<td id="bowtie2-options-d">
+<pre><code>-d/--deterministic-seeds</code></pre>
+</td>
+<td>
+<p>Consider all seeds in order (no subsampling). Can be used to augment
+<a href="#bowtie2-options-a"><code>-a</code></a> or <a
+href="#bowtie2-options-k"><code>-k</code></a> with deterministic
+behavior. This option significantly speeds up <a
+href="#bowtie2-options-a"><code>-a</code></a> while also reducing memory
+consumption. It is not however always strictly better than standalone
+<code>[-a]</code> when considering the number of repeated alignments
+found.</p>
+<p>Note: In order to use this option exact upfront and 1mm upfront
+behavior have to be disabled using the following options:
+[<code>--no-exact-upfront</code>] and <a
+href="#bowtie2-options-no-1mm-upfront"><code>--no-1mm-upfront</code></a>.</p>
+</td>
+</tr>
 </table>
 <h4 id="paired-end-options">Paired-end options</h4>
 <table>
@@ -3087,5 +3106,3 @@ format, run:</p>
 href="http://samtools.sourceforge.net/mpileup.shtml">Calling SNPs/INDELs
 with SAMtools/BCFtools</a> for more details and variations on this
 process.</p>
-<!-- fasta-continuous option does not exist but was added to prevent
-warnings due to the case insensitive nature of markdown URLs -->


=====================================
doc/website/recent_news.ssi
=====================================
@@ -1,3 +1,19 @@
+<h2 id="version-2.5.5---feb-16-2026">Version 2.5.5 - Feb 16, 2026</h2>
+<h3 id="bowtie2">bowtie2</h3>
+<ul>
+  <li>Added <code><a href="manual.shtml#bowtie2-options-d">-d/--deterministic-mode</a></code>command
+      line option that
+      makes <code><a href="manual.shtml#bowtie2-options-a">-a</a>/<a href="manual.shtml#bowtie2-options-k">-k</a></code>
+      deterministic in the way alignments are reported. This
+      deterministic mode runs much significantly faster
+      than <a href="manual.shtml#bowtie2-options-a">-a</a> and
+      consumes less memory.  It not yet strictly better
+      than <a href="manual.shtml#bowtie2-options-a">-a</a> when
+      considering alignments found. (PR #520, 521)</li>
+  <li>Add support for selecting AVX version at runtime on x86_64/amd64
+      CPUs. (PR #515)</li>
+</ul>
+
 <h2 id="version-2.5.4---may-16-2024">Version 2.5.4 - May 16, 2024</h2>
 <h3 id="bowtie2">bowtie2</h3>
 <ul>


=====================================
doc/website/rhsidebar.ssi
=====================================
@@ -18,10 +18,10 @@
         </tr>
       <tr>
       <td>
-        <a href="https://sourceforge.net/projects/bowtie-bio/files/bowtie2/2.5.4">Bowtie2 v2.5.4</a>
+        <a href="https://sourceforge.net/projects/bowtie-bio/files/bowtie2/2.5.4">Bowtie2 v2.5.5</a>
       </td>
       <td align="right">
-        05/16/24 
+        02/16/26 
       </td>
       </tr>
       <tr>


=====================================
group_walk.h
=====================================
@@ -1106,7 +1106,6 @@ public:
 		const Ebwt& ebwtFw,         // forward Bowtie index for walking left
 		const BitPairReference& ref,// bitpair-encoded reference
 		SARangeWithOffs<T>& sa,     // SA range with offsets
-		RandomSource& rnd,          // pseudo-random generator for sampling rows
 		WalkMetrics& met)           // update metrics here
 	{
 		reset();


=====================================
opts.h
=====================================
@@ -163,6 +163,7 @@ enum {
 	ARG_SRA_ACC,                // --sra-acc
         ARG_SAM_APPEND_COMMENT,     // --sam-append-comment
         ARG_SAM_OPT_CONFIG,         // --sam-opt-config
+        ARG_DET_SEEDS_NO,           // --no-deterministic-seeds
 };
 
 #endif


=====================================
pat.cpp
=====================================
@@ -55,7 +55,7 @@ static uint32_t genRandSeed(
 	size_t qlen = qry.length();
 	// Throw all the characters of the read into the random seed
 	for(size_t i = 0; i < qlen; i++) {
-		int p = (int)qry[i];
+	        int p = (int)qry[i];
 		assert_leq(p, 4);
 		size_t off = ((i & 15) << 1);
 		rseed ^= ((uint32_t)p << off);
@@ -302,20 +302,28 @@ pair<bool, int> DualPatternComposer::nextBatch(PerThreadReadBuf& pt) {
  * the read and quality input, create a list of pattern sources to
  * dispense them.
  */
-PatternComposer* PatternComposer::setupPatternComposer(
-	const EList<string>& si,   // singles, from argv
-	const EList<string>& m1,   // mate1's, from -1 arg
-	const EList<string>& m2,   // mate2's, from -2 arg
-	const EList<string>& m12,  // both mates on each line, from --12 arg
-	const EList<string>& q,    // qualities associated with singles
-	const EList<string>& q1,   // qualities associated with m1
-	const EList<string>& q2,   // qualities associated with m2
+PatternComposer *PatternComposer::setupPatternComposer(
+    const EList<string> &si,  // singles, from argv
+    const EList<string> &m1,  // mate1's, from -1 arg
+    const EList<string> &m2,  // mate2's, from -2 arg
+    const EList<string> &m12, // both mates on each line, from --12 arg
+    const EList<string> &q,   // qualities associated with singles
+    const EList<string> &q1,  // qualities associated with m1
+    const EList<string> &q2,  // qualities associated with m2
 #ifdef USE_SRA
-	const EList<string>& sra_accs, // SRA accessions
+    const EList<string> &sra_accs, // SRA accessions
 #endif
-	PatternParams& p,    // read-in parameters
-	bool verbose)              // be talkative?
+    PatternParams &p, // read-in parameters
+    bool verbose)     // be talkative?
 {
+        // We save the value of PatternParams::align_paired_reads
+        // so that `--align-paired-reads` works as expected.
+        bool align_paired_reads = p.align_paired_reads;
+        // This serves as an indicator to the BAM pattern source
+        // that we intend on parsing paired reads from separate files
+        p.align_paired_reads = true;
+
+
 	EList<PatternSource*>* a  = new EList<PatternSource*>();
 	EList<PatternSource*>* b  = new EList<PatternSource*>();
 	// Create list of pattern sources for paired reads appearing
@@ -331,11 +339,11 @@ PatternComposer* PatternComposer::setupPatternComposer(
 		}
 		a->push_back(PatternSource::patsrcFromStrings(p, *qs));
 		b->push_back(NULL);
-		p.interleaved = false;
 		if(!p.fileParallel) {
 			break;
 		}
-	}
+        }
+        p.interleaved = false;
 
 #ifdef USE_SRA
 	for(size_t i = 0; i < sra_accs.size(); i++) {
@@ -354,8 +362,7 @@ PatternComposer* PatternComposer::setupPatternComposer(
 		}
 	}
 #endif
-
-	// Create list of pattern sources for paired reads
+        // Create list of pattern sources for paired reads
 	for(size_t i = 0; i < m1.size(); i++) {
 		const EList<string>* qs = &m1;
 		EList<string> tmpSeq;
@@ -391,7 +398,11 @@ PatternComposer* PatternComposer::setupPatternComposer(
 	// All mates/mate files must be paired
 	assert_eq(a->size(), b->size());
 
-	// Create list of pattern sources for the unpaired reads
+        // Create list of pattern sources for the unpaired reads
+        p.align_paired_reads = align_paired_reads;
+        if (p.align_paired_reads) {
+                p.interleaved = true;
+        }
 	for(size_t i = 0; i < si.size(); i++) {
 		const EList<string>* qs = &si;
 		PatternSource* patsrc = NULL;
@@ -1370,7 +1381,8 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
 			i = i + sizeof(l_name) + l_name + sizeof(uint32_t);
 		}
 		first_ = false;
-	}
+        }
+
 	while (readi < pt.max_buf_) {
 		if (i >= alignment_batch.size()) {
 			return make_pair(false, readi);
@@ -1397,19 +1409,26 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
 		i += sizeof(block_size);
 		memcpy(&flag, &alignment_batch[0] + i + offset[BAMField::flag], sizeof(flag));
 		if (currentlyBigEndian())
-			flag = endianSwapU16(flag);
-		EList<Read>& readbuf = (pp_.align_paired_reads && (flag & 0x80)) != 0 ? pt.bufb_ : pt.bufa_;
+                        flag = endianSwapU16(flag);
+
+                if (interleaved_) {
+                        batch_a = (flag & 0x80) != 0 ? false : true;
+                }
+
+                EList<Read> &readbuf = batch_a ? pt.bufa_ : pt.bufb_;
+
 		if ((flag & 0x4) == 0) {
 			readbuf[readi].readOrigBuf.clear();
 			i += block_size;
 			continue;
 		}
-		if (!pp_.align_paired_reads && ((flag & 0x40) != 0 || (flag & 0x80) != 0)) {
+		if (!align_paired_reads_ && (flag & 0x1) != 0) {
 			readbuf[readi].readOrigBuf.clear();
 			i += block_size;
 			continue;
 		}
-		if (pp_.align_paired_reads && ((flag & 0x40) == 0 && (flag & 0x80) == 0)) {
+                if (align_paired_reads_ &&
+                    ((batch_a && ((flag & 0x40) == 0)) || (!batch_a && (flag & 0x80) == 0))) {
 			readbuf[readi].readOrigBuf.clear();
 			i += block_size;
 			continue;
@@ -1418,7 +1437,7 @@ std::pair<bool, int> BAMPatternSource::get_alignments(PerThreadReadBuf& pt, bool
 		readbuf[readi].readOrigBuf.resize(block_size);
 		memcpy(readbuf[readi].readOrigBuf.wbuf(), &alignment_batch[0] + i, block_size);
 		i += block_size;
-		readi += (pp_.align_paired_reads &&
+		readi += (interleaved_ &&
 			  pt.bufb_[readi].readOrigBuf.length() == 0) ? 0 : 1;
 	}
 


=====================================
pat.h
=====================================
@@ -851,22 +851,16 @@ class BAMPatternSource : public CFilePatternSource {
 	};
 
 public:
-
-	BAMPatternSource(
-		const EList<std::string>& infiles,
-		const PatternParams& p) :
-		CFilePatternSource(infiles, p),
-		first_(true),
-		alignment_batch(0),
-		alignment_offset(0),
-		delta_(0),
-		pp_(p)
-		{
-			stream.zalloc = Z_NULL;
-			stream.zfree = Z_NULL;
-			stream.opaque = Z_NULL;
-			alignment_batch.reserve(1 << 16);
-		}
+  BAMPatternSource(const EList<std::string> &infiles, const PatternParams &p)
+      : CFilePatternSource(infiles, p), first_(true), alignment_batch(0),
+      alignment_offset(0), delta_(0), pp_(p), interleaved_(pp_.interleaved),
+      align_paired_reads_(pp_.align_paired_reads)
+	{
+		stream.zalloc = Z_NULL;
+		stream.zfree = Z_NULL;
+		stream.opaque = Z_NULL;
+		alignment_batch.reserve(1 << 16);
+	}
 
 	virtual void reset() {
 		first_ = true;
@@ -913,7 +907,9 @@ private:
 	size_t delta_;
 	z_stream stream;
 
-	PatternParams pp_;
+        PatternParams pp_;
+        bool interleaved_;
+        bool align_paired_reads_;
 };
 
 /**
@@ -1298,10 +1294,10 @@ public:
 
 	PatternSourceReadAheadFactory(
 		PatternComposer& composer,
-		const PatternParams& pp, size_t n) :
+		const PatternParams& pp, size_t n, bool useCV) :
 		psfact_(composer,pp),
-		psq_ready_(),
-		psq_idle_(psfact_,n),
+		psq_ready_(useCV),
+		psq_idle_(useCV,psfact_,n),
 		asynct_(readAsync, this) {}
 
 	~PatternSourceReadAheadFactory() {
@@ -1325,9 +1321,75 @@ public:
 private:
 
 	template <typename T>
-	class LockedQueue {
+	class LockedQueueCV {
 	public:
-		virtual ~LockedQueue() {}
+		virtual ~LockedQueueCV() {}
+
+		bool empty() {
+			bool ret = false;
+			{
+				std::unique_lock<std::mutex> lk(m_);
+				ret = q_.empty();
+			}
+			return ret;
+		}
+
+		void push(T& ps) {
+			std::unique_lock<std::mutex> lk(m_);
+			q_.push(ps);
+			cv_.notify_all();
+		}
+
+		// wait for data, if none in the queue
+		T pop() {
+			T ret;
+			{
+				std::unique_lock<std::mutex> lk(m_);
+				cv_.wait(lk, [this] { return !q_.empty();});
+				ret = q_.front();
+				q_.pop();
+			}
+			return ret;
+		}
+
+	protected:
+		std::mutex m_;
+		std::condition_variable cv_;
+		std::queue<T> q_;
+	};
+
+	class LockedPSQueueCV : public LockedQueueCV<PatternSourcePerThread*> {
+	public:
+		LockedPSQueueCV(PatternSourcePerThreadFactory& psfact, size_t n) : 
+			LockedQueueCV<PatternSourcePerThread*>() {
+			for (size_t i=0; i<n; i++) {
+				q_.push(psfact.create());
+			}
+		}
+
+		virtual ~LockedPSQueueCV() {
+			while (!q_.empty()) {
+				delete q_.front();
+				q_.pop();
+			}
+		}
+	};
+
+	class LockedREQueueCV : public LockedQueueCV<ReadElement> {
+	public:
+		virtual ~LockedREQueueCV() {
+			// we actually own ps while in the queue
+			while (!q_.empty()) {
+				delete q_.front().ps;
+				q_.pop();
+			}
+		}
+	};
+
+	template <typename T>
+	class LockedQueueMC {
+	public:
+		virtual ~LockedQueueMC() {}
 
 		bool empty() {
 			return q_.size_approx() == 0;
@@ -1346,21 +1408,19 @@ private:
 		}
 
 	protected:
-		// std::mutex m_;
-		// std::condition_variable cv_;
 		ConcurrentQueue<T> q_;
 	};
 
-	class LockedPSQueue: public LockedQueue<PatternSourcePerThread*> {
+	class LockedPSQueueMC: public LockedQueueMC<PatternSourcePerThread*> {
 	public:
-		LockedPSQueue(PatternSourcePerThreadFactory& psfact, size_t n) : 
-			LockedQueue<PatternSourcePerThread*>() {
+		LockedPSQueueMC(PatternSourcePerThreadFactory& psfact, size_t n) : 
+			LockedQueueMC<PatternSourcePerThread*>() {
 			for (size_t i=0; i<n; i++) {
 				q_.enqueue(psfact.create());
 			}
 		}
 
-		virtual ~LockedPSQueue() {
+		virtual ~LockedPSQueueMC() {
 			PatternSourcePerThread *item;
 
 			while (q_.size_approx() != 0) {
@@ -1371,9 +1431,9 @@ private:
 
 	};
 
-	class LockedREQueue : public LockedQueue<ReadElement> {
+	class LockedREQueueMC : public LockedQueueMC<ReadElement> {
 	public:
-		virtual ~LockedREQueue() {
+		virtual ~LockedREQueueMC() {
 			// we actually own ps while in the queue
 			ReadElement item;
 
@@ -1385,6 +1445,60 @@ private:
 		}
 	};
 
+	template <typename T, typename Q1, typename Q2>
+	class LockedQueueDuo {
+	public:
+		LockedQueueDuo(Q1 *pq1, Q2 *pq2) 
+		: pq1_(pq1), pq2_(pq2)
+		{
+			assert( (pq1_!=NULL) || (pq2_!=NULL) );
+		}
+
+		virtual ~LockedQueueDuo() {
+			if (pq1_!=NULL) delete pq1_;
+			if (pq2_!=NULL) delete pq2_;
+		}
+
+		bool empty() {
+			return (pq1_!=NULL) ? pq1_->empty() : pq2_->empty();
+		}
+
+		void push(T& ps) {
+			if (pq1_!=NULL) {
+				pq1_->push(ps);
+			} else {
+				pq2_->push(ps);
+			}
+		}
+
+		T pop() {
+			return (pq1_!=NULL) ? pq1_->pop() : pq2_->pop();
+		}
+
+	protected:
+		// owned, and exactly one should be not NULL
+		Q1 *pq1_;
+		Q2 *pq2_;
+	};
+
+	class LockedPSQueue: public LockedQueueDuo<PatternSourcePerThread*, LockedPSQueueCV, LockedPSQueueMC> {
+	public:
+		LockedPSQueue(bool useCV, PatternSourcePerThreadFactory& psfact, size_t n) : 
+			LockedQueueDuo<PatternSourcePerThread*, LockedPSQueueCV, LockedPSQueueMC>(
+				useCV ? new LockedPSQueueCV(psfact,n) : NULL,
+				useCV ? NULL : new LockedPSQueueMC(psfact,n)
+			) {}
+	};
+
+	class LockedREQueue: public LockedQueueDuo<ReadElement, LockedREQueueCV, LockedREQueueMC> {
+	public:
+		LockedREQueue(bool useCV) : 
+			LockedQueueDuo<ReadElement, LockedREQueueCV, LockedREQueueMC>(
+				useCV ? new LockedREQueueCV() : NULL,
+				useCV ? NULL : new LockedREQueueMC()
+			) {}
+	};
+
         static void readAsync(PatternSourceReadAheadFactory *obj) {
 		LockedREQueue &psq_ready = obj->psq_ready_;
 		LockedPSQueue &psq_idle = obj->psq_idle_;


=====================================
processor_support.h
=====================================
@@ -31,6 +31,9 @@ public:
     ProcessorSupport() { }
     bool POPCNTenabled()
     {
+#if defined(SSE_AVX2)
+       return true; // POPCNT is part of AVX2, so always present; no need to check
+#else
     // from: Intel® 64 and IA-32 Architectures Software Developer’s Manual, 325462-036US,March 2013
     //Before an application attempts to use the POPCNT instruction, it must check that the
     //processor supports SSE4.2
@@ -58,6 +61,7 @@ public:
         return false;
     }
     return true;
+#endif
     }
 
 #endif // POPCNT_CAPABILITY



View it on GitLab: https://salsa.debian.org/med-team/bowtie2/-/commit/ea62608187cc1b15ab7a2fc42d537fcaa06f0efe

-- 
View it on GitLab: https://salsa.debian.org/med-team/bowtie2/-/commit/ea62608187cc1b15ab7a2fc42d537fcaa06f0efe
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260222/6785aa93/attachment-0001.htm>


More information about the debian-med-commit mailing list