         cudaDeviceSynchronize();
         timer.stop();
         stats.align_time += timer.seconds();
+
+        if (0)
+        {
+            const diagonal_type hit = merged_hits[0];
+            const uint32 read_id  = hit.y;
+            const uint32 text_pos = hit.x;
+
+            const thrust::device_ptr<const uint32> read_index( reads.read_index() );
+            const thrust::device_ptr<const uint32> read_stream( reads.read_stream() );
+            const uint2  read_range = make_uint2( read_index[ read_id ], read_index[ read_id+1 ] );
+
+            PackedStream<thrust::device_ptr<const uint32>,uint8,4u,false> packed_reads( read_stream );
+            char read_string[256];
+            dna_to_string(
+                packed_reads.begin() + read_range.x,
+                read_range.y - read_range.x,
+                read_string );
+
+            PackedStream<thrust::device_ptr<const uint32>,uint8,2u,true> packed_genome( thrust::device_ptr<const uint32>( genome.stream() ) );
+            char genome_string[256];
+            dna_to_string(
+                packed_genome.begin() + text_pos - 15,
+                read_range.y - read_range.x + 31,
+                genome_string );
+
+            fprintf(stderr, "hit: (%u, %u) @ %u\n", read_id, text_pos );
+            fprintf(stderr, "  (%u, %u)\n", read_range.x, read_range.y );
+            fprintf(stderr, "  %s\n", read_string);
+            fprintf(stderr, "  %s\n", genome_string);
+        }
+
+        // compute the best score for each read
+        const uint32 n_distinct = cuda::reduce_by_key(
+            n_merged,
+            thrust::make_transform_iterator( nvbio::plain_view( merged_hits ), component_functor<diagonal_type>( 1u ) ),
+            nvbio::plain_view( scores ),
+            nvbio::plain_view( out_reads ),
+            nvbio::plain_view( out_scores ),
+            thrust::maximum<int16>(),
+            temp_storage );
+
+        // count how many reads have a score >= -5
+        const uint32 n_aligned = cuda::reduce(
+            n_distinct,
+            thrust::make_transform_iterator( nvbio::plain_view( out_scores ), above_threshold( -20 ) ),
+            thrust::plus<uint32>(),
+            temp_storage );
+
+        stats.aligned += n_aligned;
     }
 }
 

    float   locate_time;
    float   align_time;
    uint64  reads;
    uint64  queries;
    uint64  matches;
    uint64  occurrences;
    uint64  merged;
};

// build a set of q-grams from a given string, together with their sorted counterpart

#include <nvbio/basic/console.h>
#include <nvbio/basic/vector.h>
#include <nvbio/basic/shared_pointer.h>
#include <nvbio/basic/dna.h>
#include <nvbio/strings/string_set.h>
#include <nvbio/strings/infix.h>
#include <nvbio/strings/seeds.h>
