mb_lookup.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:27k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: mb_lookup.c,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 18:08:17  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.33
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: mb_lookup.c,v 1000.4 2004/06/01 18:08:17 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's offical duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Ilya Dondoshansky
  35.  *
  36.  */
  37. /** @file mb_lookup.c
  38.  * Functions responsible for the creation of a lookup table
  39.  * @todo FIXME @sa mb_lookup.h
  40.  */
  41. static char const rcsid[] = 
  42.     "$Id: mb_lookup.c,v 1000.4 2004/06/01 18:08:17 gouriano Exp $";
  43. #include <algo/blast/core/blast_options.h>
  44. #include <algo/blast/core/blast_def.h>
  45. #include <algo/blast/core/mb_lookup.h>
  46. #include "blast_inline.h"
  47. MBLookupTable* MBLookupTableDestruct(MBLookupTable* mb_lt)
  48. {
  49.    if (!mb_lt)
  50.       return NULL;
  51.    if (mb_lt->hashtable)
  52.       sfree(mb_lt->hashtable);
  53.    if (mb_lt->next_pos)
  54.       sfree(mb_lt->next_pos);
  55.    if (mb_lt->next_pos2)
  56.       sfree(mb_lt->next_pos2);
  57.    sfree(mb_lt->pv_array);
  58.    sfree(mb_lt);
  59.    return mb_lt;
  60. }
  61. /** Convert weight, template length and template type from input options into
  62.     an MBTemplateType enum
  63. */
  64. static DiscTemplateType GetDiscTemplateType(Int2 weight, Uint1 length, 
  65.                                      DiscWordType type)
  66. {
  67.    if (weight == 11) {
  68.       if (length == 16) {
  69.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  70.             return TEMPL_11_16;
  71.          else if (type == MB_WORD_OPTIMAL)
  72.             return TEMPL_11_16_OPT;
  73.       } else if (length == 18) {
  74.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  75.             return TEMPL_11_18;
  76.          else if (type == MB_WORD_OPTIMAL)
  77.             return TEMPL_11_18_OPT;
  78.       } else if (length == 21) {
  79.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  80.             return TEMPL_11_21;
  81.          else if (type == MB_WORD_OPTIMAL)
  82.             return TEMPL_11_21_OPT;
  83.       }
  84.    } else if (weight == 12) {
  85.       if (length == 16) {
  86.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  87.             return TEMPL_12_16;
  88.          else if (type == MB_WORD_OPTIMAL)
  89.             return TEMPL_12_16_OPT;
  90.       } else if (length == 18) {
  91.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  92.             return TEMPL_12_18;
  93.          else if (type == MB_WORD_OPTIMAL)
  94.             return TEMPL_12_18_OPT;
  95.       } else if (length == 21) {
  96.          if (type == MB_WORD_CODING || type == MB_TWO_TEMPLATES)
  97.             return TEMPL_12_21;
  98.          else if (type == MB_WORD_OPTIMAL)
  99.             return TEMPL_12_21_OPT;
  100.       }
  101.    }
  102.    return TEMPL_CONTIGUOUS; /* All unsupported cases default to 0 */
  103. }
  104. #define SMALL_QUERY_CUTOFF 15000
  105. #define LARGE_QUERY_CUTOFF 800000
  106. /* Documentation in mb_lookup.h */
  107. Int2 MB_LookupTableNew(BLAST_SequenceBlk* query, ListNode* location,
  108.         MBLookupTable** mb_lt_ptr,
  109.         const LookupTableOptions* lookup_options)
  110. {
  111.    Int4 query_length;
  112.    Uint1* seq,* pos;
  113.    Int4 index;
  114.    Int4 ecode;
  115.    Int4 mask;
  116.    Int4 ecode1, ecode2;
  117.    Uint1 val, nuc_mask = 0xfc;
  118.    MBLookupTable* mb_lt;
  119.    Int4 masked_word_count = 0;
  120.    PV_ARRAY_TYPE *pv_array=NULL;
  121.    Int4 pv_shift, pv_array_bts, pv_size, pv_index;
  122.    Int2 word_length, extra_length;
  123.    Int4 last_offset;
  124.    Int4 table_entries;
  125. #ifdef USE_HASH_TABLE
  126.    Int4 hash_shift, hash_mask, crc, size, length;
  127.    Uint1* hash_buf;
  128. #endif
  129.    DiscTemplateType template_type;
  130.    Boolean amb_cond;
  131.    Boolean two_templates = 
  132.       (lookup_options->mb_template_type == MB_TWO_TEMPLATES);
  133.    Int2 bytes_in_word;
  134.    Uint1 width;
  135.    Int4 from, to;
  136.    ListNode* loc;
  137.    Int4 longest_chain = 0;
  138.    Int4 pcount, pcount1=0;
  139.    
  140.    if (!location) {
  141.      /* Empty sequence location provided */
  142.      *mb_lt_ptr = NULL;
  143.      return -1;
  144.    }
  145.    template_type = GetDiscTemplateType(lookup_options->word_size,
  146.                       lookup_options->mb_template_length, 
  147.                       (DiscWordType)lookup_options->mb_template_type);
  148.    query_length = query->length;
  149.    mb_lt = (MBLookupTable*) calloc(1, sizeof(MBLookupTable));
  150.     
  151.    bytes_in_word = (lookup_options->word_size + 1)/ 4;
  152.    if (bytes_in_word < 3) 
  153.       width = 2;
  154.    else
  155.       width = 3;
  156.    mb_lt->template_type = template_type;
  157.    mb_lt->two_templates = two_templates;
  158.    if (two_templates)
  159.       /* For now leave only one possibility for the second template */
  160.       mb_lt->second_template_type = template_type + 1;
  161. #ifdef USE_HASH_TABLE
  162.    /* Make hash table size the smallest power of 2 greater than query length */
  163.    for (length=query_length,size=1; length>0; length=length>>1,size++);
  164.    mb_lt->hashsize = 1<<size;
  165.    hash_shift = (32 - size)/2;
  166.    hash_mask = mb_lt->hashsize - 1;
  167.    pv_shift = 0;
  168. #else
  169.    if (width == 2) {
  170.       mb_lt->hashsize = 1 << 16;
  171.       pv_shift = 0;
  172.    }
  173.    else {
  174.       /* determine the approximate number of hashtable entries */
  175.       table_entries = 0;
  176.       for (loc = location; loc; loc = loc->next) {
  177.          from = ((SSeqRange*) loc->ptr)->left;
  178.          to = ((SSeqRange*) loc->ptr)->right;
  179.          table_entries += (to - from);
  180.       }
  181.       /* To fit in the external cache of latter-day micro-
  182.          processors, the PV array must be compressed. pv_shift
  183.  below is the power of two that the array size is
  184.  divided by. The target PV array size is 128 kBytes.
  185.  If the query is too small or too large, the compression 
  186.  should be higher. Small queries don't reuse the PV array,
  187.  and large queries saturate it. In either case, cache
  188.  is better used on other data. */
  189.       if (lookup_options->word_size == 11 && lookup_options->mb_template_length > 0) {
  190.          mb_lt->hashsize = 1 << 22;
  191.          if( table_entries <= SMALL_QUERY_CUTOFF ||
  192.      table_entries >= LARGE_QUERY_CUTOFF )
  193.             pv_shift = 3;
  194.  else
  195.             pv_shift = 2;
  196.       }
  197.       else {
  198.          mb_lt->hashsize = 1 << 24;
  199.          if( table_entries <= SMALL_QUERY_CUTOFF ||
  200.      table_entries >= LARGE_QUERY_CUTOFF )
  201.             pv_shift = 5;
  202.  else
  203.             pv_shift = 4;
  204.       }
  205.    }
  206. #endif
  207.    if (lookup_options->mb_template_length > 0) {
  208.       mb_lt->discontiguous = TRUE;
  209.       mb_lt->compressed_wordsize = width + 1;
  210.       word_length = mb_lt->word_length = COMPRESSION_RATIO*(width+1);
  211.       mb_lt->template_length = lookup_options->mb_template_length;
  212.       extra_length = mb_lt->template_length - word_length;
  213.       mb_lt->mask = (Int4) (-1);
  214.       mask = (1 << (8*(width+1) - 2)) - 1;
  215.    } else {
  216.       mb_lt->compressed_wordsize = width;
  217.       word_length = COMPRESSION_RATIO*width;
  218.       mb_lt->word_length = lookup_options->word_size;
  219.       mb_lt->template_length = COMPRESSION_RATIO*width;
  220.       mb_lt->mask = mb_lt->hashsize - 1;
  221.       mask = (1 << (8*width - 2)) - 1;
  222.       extra_length = 0;
  223.    }
  224.    /* Scan step must be set in lookup_options; even if it is not, still 
  225.       try to set it reasonably in mb_lt - it can't remain 0 */
  226.    if (lookup_options->scan_step)
  227.       mb_lt->scan_step = lookup_options->scan_step;
  228.    else
  229.       mb_lt->scan_step = COMPRESSION_RATIO;
  230.    mb_lt->full_byte_scan = (mb_lt->scan_step % COMPRESSION_RATIO == 0);
  231.    if ((mb_lt->hashtable = (Int4*) 
  232.         calloc(mb_lt->hashsize, sizeof(Int4))) == NULL) {
  233.       MBLookupTableDestruct(mb_lt);
  234.       return -1;
  235.    }
  236.    if ((mb_lt->next_pos = (Int4*) 
  237.         calloc((query_length+1), sizeof(Int4))) == NULL) {
  238.       MBLookupTableDestruct(mb_lt);
  239.       return -1;
  240.    }
  241.    if (two_templates) {
  242.       if ((mb_lt->hashtable2 = (Int4*) 
  243.            calloc(mb_lt->hashsize, sizeof(Int4))) == NULL) {
  244.          MBLookupTableDestruct(mb_lt);
  245.          return -1;
  246.       }
  247.       if ((mb_lt->next_pos2 = (Int4*) 
  248.            calloc((query_length+1), sizeof(Int4))) == NULL) {
  249.          MBLookupTableDestruct(mb_lt);
  250.          return -1;
  251.       }
  252.    }
  253.    for (loc = location; loc; loc = loc->next) {
  254.       /* We want index to be always pointing to the start of the word.
  255.          Since sequence pointer points to the end of the word, subtract
  256.          word length from the loop boundaries. 
  257.       */
  258.       from = ((SSeqRange*) loc->ptr)->left;
  259.       to = ((SSeqRange*) loc->ptr)->right - word_length;
  260.       seq = query->sequence_start + from;
  261.       pos = seq + word_length;
  262.       
  263.       ecode = 0;
  264.       /* Also add 1 to all indices, because lookup table indices count 
  265.          from 1. */
  266.       from -= word_length - 2;
  267.       last_offset = to - extra_length + 2;
  268.       amb_cond = TRUE;
  269.       for (index = from; index <= last_offset; index++) {
  270.          val = *++seq;
  271.          if ((val & nuc_mask) != 0) { /* ambiguity or gap */
  272.             ecode = 0;
  273.             pos = seq + word_length;
  274.          } else {
  275.             /* get next base */
  276.             ecode = ((ecode & mask) << 2) + val;
  277.             if (seq >= pos) {
  278.                if (extra_length) {
  279.                   switch (template_type) {
  280.                   case TEMPL_11_18: case TEMPL_12_18:
  281.                      amb_cond = !GET_AMBIG_CONDITION_18(seq);
  282.                      break;
  283.                   case TEMPL_11_18_OPT: case TEMPL_12_18_OPT:
  284.                      amb_cond = !GET_AMBIG_CONDITION_18_OPT(seq);
  285.                      break;
  286.                   case TEMPL_11_21: case TEMPL_12_21:
  287.                      amb_cond = !GET_AMBIG_CONDITION_21(seq);
  288.                      break;
  289.                   case TEMPL_11_21_OPT: case TEMPL_12_21_OPT:
  290.                      amb_cond = !GET_AMBIG_CONDITION_21_OPT(seq);
  291.                      break;
  292.                   default:
  293.                      break;
  294.                   }
  295.                }
  296.                      
  297.                if (amb_cond) {
  298.                   switch (template_type) {
  299.                   case TEMPL_11_16:
  300.                      ecode1 = GET_WORD_INDEX_11_16(ecode);
  301.                      break;
  302.                   case TEMPL_12_16:
  303.                      ecode1 = GET_WORD_INDEX_12_16(ecode);
  304.                      break;
  305.                   case TEMPL_11_16_OPT:
  306.                      ecode1 = GET_WORD_INDEX_11_16_OPT(ecode);
  307.                      break;
  308.                   case TEMPL_12_16_OPT:
  309.                      ecode1 = GET_WORD_INDEX_12_16_OPT(ecode);
  310.                      break;
  311.                   case TEMPL_11_18:
  312.                      ecode1 = (GET_WORD_INDEX_11_18(ecode)) |
  313.                                (GET_EXTRA_CODE_18(seq));
  314.                      break;
  315.                   case TEMPL_12_18:
  316.                      ecode1 = (GET_WORD_INDEX_12_18(ecode)) |
  317.                                (GET_EXTRA_CODE_18(seq));
  318.                      break;
  319.                   case TEMPL_11_18_OPT:
  320.                      ecode1 = (GET_WORD_INDEX_11_18_OPT(ecode)) |
  321.                                (GET_EXTRA_CODE_18_OPT(seq));
  322.                      break;
  323.                   case TEMPL_12_18_OPT:
  324.                      ecode1 = (GET_WORD_INDEX_12_18_OPT(ecode)) |
  325.                                (GET_EXTRA_CODE_18_OPT(seq));
  326.                      break;
  327.                   case TEMPL_11_21:
  328.                      ecode1 = (GET_WORD_INDEX_11_21(ecode)) |
  329.                                (GET_EXTRA_CODE_21(seq));
  330.                      break;
  331.                   case TEMPL_12_21:
  332.                      ecode1 = (GET_WORD_INDEX_12_21(ecode)) |
  333.                                (GET_EXTRA_CODE_21(seq));
  334.                      break;
  335.                   case TEMPL_11_21_OPT:
  336.                      ecode1 = (GET_WORD_INDEX_11_21_OPT(ecode)) |
  337.                                (GET_EXTRA_CODE_21_OPT(seq));
  338.                      break;
  339.                   case TEMPL_12_21_OPT:
  340.                      ecode1 = (GET_WORD_INDEX_12_21_OPT(ecode)) |
  341.                                (GET_EXTRA_CODE_21_OPT(seq));
  342.                      break;
  343.                   default: /* Contiguous word */
  344.                      ecode1 = ecode;
  345.                      break;
  346.                   }
  347.                      
  348. #ifdef USE_HASH_TABLE                     
  349.                   hash_buf = (Uint1*)&ecode1;
  350.                   CRC32(crc, hash_buf);
  351.                   ecode1 = (crc>>hash_shift) & hash_mask;
  352. #endif
  353.                   if (two_templates) {
  354.                      switch (template_type) {
  355.                      case TEMPL_11_16:
  356.                         ecode2 = GET_WORD_INDEX_11_16_OPT(ecode);
  357.                         break;
  358.                      case TEMPL_12_16:
  359.                         ecode2 = GET_WORD_INDEX_12_16_OPT(ecode);
  360.                         break;
  361.                      case TEMPL_11_18:
  362.                         ecode2 = (GET_WORD_INDEX_11_18_OPT(ecode)) |
  363.                            (GET_EXTRA_CODE_18_OPT(seq));
  364.                         break;
  365.                      case TEMPL_12_18:
  366.                         ecode2 = (GET_WORD_INDEX_12_18_OPT(ecode)) |
  367.                            (GET_EXTRA_CODE_18_OPT(seq));
  368.                         break;
  369.                      case TEMPL_11_21:
  370.                         ecode2 = (GET_WORD_INDEX_11_21_OPT(ecode)) |
  371.                            (GET_EXTRA_CODE_21_OPT(seq));
  372.                         break;
  373.                      case TEMPL_12_21:
  374.                         ecode2 = (GET_WORD_INDEX_12_21_OPT(ecode)) |
  375.                            (GET_EXTRA_CODE_21_OPT(seq));
  376.                         break;
  377.                      default:
  378.                         ecode2 = 0; break;
  379.                      }
  380.                      
  381. #ifdef USE_HASH_TABLE                     
  382.                      hash_buf = (Uint1*)&ecode2;
  383.                      CRC32(crc, hash_buf);
  384.                      ecode2 = (crc>>hash_shift) & hash_mask;
  385. #endif
  386.                      if (mb_lt->hashtable[ecode1] == 0 || 
  387.                          mb_lt->hashtable2[ecode2] == 0)
  388.                         mb_lt->num_unique_pos_added++;
  389.                      mb_lt->next_pos2[index] = mb_lt->hashtable2[ecode2];
  390.                      mb_lt->hashtable2[ecode2] = index;
  391.                   } else {
  392.                      if (mb_lt->hashtable[ecode1] == 0)
  393.                         mb_lt->num_unique_pos_added++;
  394.                   }
  395.                   mb_lt->next_pos[index] = mb_lt->hashtable[ecode1];
  396.                   mb_lt->hashtable[ecode1] = index;
  397.                }
  398.             }
  399.          }
  400.       }
  401.    }
  402.    mb_lt->pv_array_bts = pv_array_bts = PV_ARRAY_BTS + pv_shift; 
  403. #ifdef QUESTION_PV_ARRAY_USE
  404.    if (mb_lt->num_unique_pos_added < 
  405.        (PV_ARRAY_FACTOR*(mb_lt->hashsize>>pv_shift))) {
  406. #endif
  407.       pv_size = mb_lt->hashsize>>pv_array_bts;
  408.       /* Size measured in PV_ARRAY_TYPE's */
  409.       pv_array = calloc(PV_ARRAY_BYTES, pv_size);
  410.       for (index=0; index<mb_lt->hashsize; index++) {
  411.          if (mb_lt->hashtable[index] != 0 ||
  412.              (two_templates && mb_lt->hashtable2[index] != 0))
  413.             pv_array[index>>pv_array_bts] |= 
  414.                (((PV_ARRAY_TYPE) 1)<<(index&PV_ARRAY_MASK));
  415.       }
  416.       mb_lt->pv_array = pv_array;
  417. #ifdef QUESTION_PV_ARRAY_USE
  418.    }
  419. #endif
  420.    /* Now remove the hash entries that have too many positions */
  421. #if 0
  422.    if (lookup_options->max_positions>0) {
  423. #endif
  424.       for (pv_index = 0; pv_index < pv_size; ++pv_index) {
  425.          if (pv_array[pv_index]) {
  426.             for (ecode = pv_index<<pv_array_bts; 
  427.                  ecode < (pv_index+1)<<pv_array_bts; ++ecode) {
  428.                for (index=mb_lt->hashtable[ecode], pcount=0; 
  429.                     index>0; index=mb_lt->next_pos[index], pcount++);
  430.                if (two_templates) {
  431.                   for (index=mb_lt->hashtable2[ecode], pcount1=0; 
  432.                        index>0; index=mb_lt->next_pos2[index], pcount1++);
  433.                }
  434.                if ((pcount=MAX(pcount,pcount1))>lookup_options->max_positions) {
  435.                   mb_lt->hashtable[ecode] = 0;
  436.                   if (two_templates)
  437.                      mb_lt->hashtable2[ecode] = 0;
  438. #ifdef ERR_POST_EX_DEFINED
  439.                   ErrPostEx(SEV_WARNING, 0, 0, "%lx - %d", ecode, pcount);
  440. #endif
  441.                   masked_word_count++;
  442.                }
  443.                longest_chain = MAX(longest_chain, pcount);
  444.             }
  445.          }
  446.       }
  447.       if (masked_word_count) {
  448. #ifdef ERR_POST_EX_DEFINED
  449.  ErrPostEx(SEV_WARNING, 0, 0, "Masked %d %dmers", masked_word_count,
  450.    4*width);
  451. #endif
  452.       }
  453. #if 0
  454.    }
  455. #endif
  456.    mb_lt->longest_chain = longest_chain;
  457.    *mb_lt_ptr = mb_lt;
  458.    return 0;
  459. }
  460. Int4 MB_AG_ScanSubject(const LookupTableWrap* lookup_wrap,
  461.        const BLAST_SequenceBlk* subject, Int4 start_offset,
  462.        Uint4* q_offsets, Uint4* s_offsets, Int4 max_hits,  
  463.        Int4* end_offset)
  464. {
  465.    MBLookupTable* mb_lt = (MBLookupTable*) lookup_wrap->lut;
  466.    Uint1* s;
  467.    Uint1* abs_start;
  468.    Int4  index=0, s_off;
  469.    
  470.    Int4 q_off;
  471.    PV_ARRAY_TYPE *pv_array = mb_lt->pv_array;
  472.    Int4 total_hits = 0;
  473.    Int4 compressed_wordsize, compressed_scan_step, word_size;
  474.    Boolean full_byte_scan = mb_lt->full_byte_scan;
  475.    Uint1 pv_array_bts = mb_lt->pv_array_bts;
  476.    
  477.    /* Since the test for number of hits here is done after adding them, 
  478.       subtract the longest chain length from the allowed offset array size. */
  479.    max_hits -= mb_lt->longest_chain;
  480.    abs_start = subject->sequence;
  481.    s = abs_start + start_offset/COMPRESSION_RATIO;
  482.    compressed_scan_step = mb_lt->scan_step / COMPRESSION_RATIO;
  483.    compressed_wordsize = mb_lt->compressed_wordsize;
  484.    word_size = compressed_wordsize*COMPRESSION_RATIO;
  485.    index = 0;
  486.    
  487.    /* NB: s in this function always points to the start of the word!
  488.     */
  489.    if (full_byte_scan) {
  490.       Uint1* s_end = abs_start + subject->length/COMPRESSION_RATIO - 
  491.          compressed_wordsize;
  492.       for ( ; s <= s_end; s += compressed_scan_step) {
  493.          BlastNaLookupInitIndex(compressed_wordsize, s, &index);
  494.          
  495.          if (NA_PV_TEST(pv_array, index, pv_array_bts)) {
  496.             q_off = mb_lt->hashtable[index];
  497.             s_off = (s - abs_start)*COMPRESSION_RATIO;
  498.             if (q_off && (total_hits >= max_hits))
  499.                break;
  500.             while (q_off) {
  501.                q_offsets[total_hits] = q_off - 1;
  502.                s_offsets[total_hits++] = s_off;
  503.                q_off = mb_lt->next_pos[q_off];
  504.             }
  505.          }
  506.       }
  507.       *end_offset = (s - abs_start)*COMPRESSION_RATIO;
  508.    } else {
  509.       Int4 last_offset = subject->length - word_size;
  510.       Uint1 bit;
  511.       Int4 adjusted_index;
  512.       for (s_off = start_offset; s_off <= last_offset; 
  513.            s_off += mb_lt->scan_step) {
  514.          s = abs_start + (s_off / COMPRESSION_RATIO);
  515.          bit = 2*(s_off % COMPRESSION_RATIO);
  516.          /* Compute index for a word made of full bytes */
  517.          s = BlastNaLookupInitIndex(compressed_wordsize, s, &index);
  518.          /* Adjust the word index by the base within a byte */
  519.          adjusted_index = BlastNaLookupAdjustIndex(s, index, mb_lt->mask,
  520.                                                    bit);
  521.          if (NA_PV_TEST(pv_array, adjusted_index, pv_array_bts)) {
  522.             q_off = mb_lt->hashtable[adjusted_index];
  523.             if (q_off && (total_hits >= max_hits))
  524.                break;
  525.             while (q_off) {
  526.                q_offsets[total_hits] = q_off - 1;
  527.                s_offsets[total_hits++] = s_off; 
  528.                q_off = mb_lt->next_pos[q_off];
  529.             }
  530.          }
  531.       }
  532.       *end_offset = s_off;
  533.    }
  534.    return total_hits;
  535. }
  536. Int4 MB_ScanSubject(const LookupTableWrap* lookup,
  537.        const BLAST_SequenceBlk* subject, Int4 start_offset, 
  538.        Uint4* q_offsets, Uint4* s_offsets, Int4 max_hits,
  539.        Int4* end_offset) 
  540. {
  541.    Uint1* abs_start,* s_end;
  542.    Uint1* s;
  543.    Int4 hitsfound = 0;
  544.    Uint4 query_offset, subject_offset;
  545.    Int4 index;
  546.    MBLookupTable* mb_lt = (MBLookupTable*) lookup->lut;
  547.    Uint4* q_ptr = q_offsets,* s_ptr = s_offsets;
  548.    PV_ARRAY_TYPE *pv_array = mb_lt->pv_array;
  549.    Uint1 pv_array_bts = mb_lt->pv_array_bts;
  550.    Int4 compressed_wordsize = mb_lt->compressed_wordsize;
  551. #ifdef DEBUG_LOG
  552.    FILE *logfp0 = fopen("new0.log", "a");
  553. #endif   
  554.    /* Since the test for number of hits here is done after adding them, 
  555.       subtract the longest chain length from the allowed offset array size.
  556.    */
  557.    max_hits -= mb_lt->longest_chain;
  558.    abs_start = subject->sequence;
  559.    s = abs_start + start_offset/COMPRESSION_RATIO;
  560.    s_end = abs_start + (*end_offset)/COMPRESSION_RATIO;
  561.    s = BlastNaLookupInitIndex(mb_lt->compressed_wordsize, s, &index);
  562.    /* In the following code, s points to the byte right after the end of 
  563.       the word. */
  564.    while (s <= s_end) {
  565.       if (NA_PV_TEST(pv_array, index, pv_array_bts)) {
  566.          query_offset = mb_lt->hashtable[index];
  567.          subject_offset = 
  568.             ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO;
  569.          if (query_offset && (hitsfound >= max_hits))
  570.             break;
  571.          while (query_offset) {
  572. #ifdef DEBUG_LOG
  573.             fprintf(logfp0, "%ldt%ldt%ldn", query_offset, 
  574.                     subject_offset, index);
  575. #endif
  576.             *(q_ptr++) = query_offset - 1;
  577.             *(s_ptr++) = subject_offset;
  578.             ++hitsfound;
  579.             query_offset = mb_lt->next_pos[query_offset];
  580.          }
  581.       }
  582.       /* Compute the next value of the lookup index 
  583.          (shifting sequence by a full byte) */
  584.       index = BlastNaLookupComputeIndex(FULL_BYTE_SHIFT, mb_lt->mask, 
  585.                                         s++, index);
  586.    }
  587.    *end_offset = 
  588.      ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO;
  589. #ifdef DEBUG_LOG
  590.    fclose(logfp0);
  591. #endif
  592.    return hitsfound;
  593. }
  594. Int4 MB_DiscWordScanSubject(const LookupTableWrap* lookup, 
  595.        const BLAST_SequenceBlk* subject, Int4 start_offset,
  596.        Uint4* q_offsets, Uint4* s_offsets, Int4 max_hits, 
  597.        Int4* end_offset)
  598. {
  599.    Uint1* s;
  600.    Uint1* s_start,* abs_start,* s_end;
  601.    Int4 hitsfound = 0;
  602.    Uint4 query_offset, subject_offset;
  603.    Int4 word, index, index2=0;
  604.    MBLookupTable* mb_lt = (MBLookupTable*) lookup->lut;
  605.    Uint4* q_ptr = q_offsets,* s_ptr = s_offsets;
  606.    Boolean full_byte_scan = mb_lt->full_byte_scan;
  607.    Boolean two_templates = mb_lt->two_templates;
  608.    Uint1 template_type = mb_lt->template_type;
  609.    Uint1 second_template_type = mb_lt->second_template_type;
  610.    PV_ARRAY_TYPE *pv_array = mb_lt->pv_array;
  611.    Uint1 pv_array_bts = mb_lt->pv_array_bts;
  612.    Int4 compressed_wordsize = mb_lt->compressed_wordsize;
  613. #ifdef DEBUG_LOG
  614.    FILE *logfp0 = fopen("new0.log", "a");
  615. #endif   
  616.    
  617.    /* Since the test for number of hits here is done after adding them, 
  618.       subtract the longest chain length from the allowed offset array size. */
  619.    max_hits -= mb_lt->longest_chain;
  620.    abs_start = subject->sequence;
  621.    s_start = abs_start + start_offset/COMPRESSION_RATIO;
  622.    s_end = abs_start + (*end_offset)/COMPRESSION_RATIO;
  623.    s = BlastNaLookupInitIndex(mb_lt->compressed_wordsize, s_start, &word);
  624.    /* s now points to the byte right after the end of the current word */
  625.    if (full_byte_scan) {
  626.      while (s <= s_end) {
  627.        index = ComputeDiscontiguousIndex(s, word, template_type);
  628.        if (two_templates) {
  629.           index2 = ComputeDiscontiguousIndex(s, word, second_template_type);
  630.        }
  631.        if (NA_PV_TEST(pv_array, index, pv_array_bts)) {
  632.           query_offset = mb_lt->hashtable[index];
  633.           subject_offset = 
  634.              ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO;
  635.           if (query_offset && (hitsfound >= max_hits))
  636.              break;
  637.           while (query_offset) {
  638. #ifdef DEBUG_LOG
  639.              fprintf(logfp0, "%ldt%ldt%ldn", query_offset, 
  640.                      subject_offset, index);
  641. #endif
  642.              *(q_ptr++) = query_offset - 1;
  643.              *(s_ptr++) = subject_offset;
  644.              ++hitsfound;
  645.              query_offset = mb_lt->next_pos[query_offset];
  646.           }
  647.        }
  648.        if (two_templates && NA_PV_TEST(pv_array, index2, pv_array_bts)) {
  649.           query_offset = mb_lt->hashtable2[index2];
  650.           subject_offset = 
  651.              ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO;
  652.           if (query_offset && (hitsfound >= max_hits))
  653.              break;
  654.           while (query_offset) {
  655.              q_offsets[hitsfound] = query_offset - 1;
  656.              s_offsets[hitsfound++] = subject_offset;
  657.              query_offset = mb_lt->next_pos2[query_offset];
  658.           }
  659.        }
  660.        word = BlastNaLookupComputeIndex(FULL_BYTE_SHIFT, 
  661.                            mb_lt->mask, s++, word);
  662.      }
  663.    } else {
  664.       Int4 scan_shift = 2*mb_lt->scan_step;
  665.       Uint1 bit = 2*(start_offset % COMPRESSION_RATIO);
  666.       Int4 adjusted_word;
  667.       while (s <= s_end) {
  668.          /* Adjust the word index by the base within a byte */
  669.          adjusted_word = BlastNaLookupAdjustIndex(s, word, mb_lt->mask,
  670.                                          bit);
  671.    
  672.          index = ComputeDiscontiguousIndex_1b(s, adjusted_word, bit,
  673.                     template_type);
  674.        
  675.          if (two_templates)
  676.             index2 = ComputeDiscontiguousIndex_1b(s, adjusted_word, bit,
  677.                         second_template_type);
  678.          if (NA_PV_TEST(pv_array, index, pv_array_bts)) {
  679.             query_offset = mb_lt->hashtable[index];
  680.             subject_offset = 
  681.                ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO
  682.                + bit/2;
  683.             if (query_offset && (hitsfound >= max_hits))
  684.                break;
  685.             while (query_offset) {
  686. #ifdef DEBUG_LOG
  687.                fprintf(logfp0, "%ldt%ldt%ldn", query_offset, 
  688.                        subject_offset, index);
  689. #endif
  690.                *(q_ptr++) = query_offset - 1;
  691.                *(s_ptr++) = subject_offset;
  692.                ++hitsfound;
  693.                query_offset = mb_lt->next_pos[query_offset];
  694.             }
  695.          }
  696.          if (two_templates && NA_PV_TEST(pv_array, index2, pv_array_bts)) {
  697.             query_offset = mb_lt->hashtable2[index2];
  698.             subject_offset = 
  699.                ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO
  700.                + bit/2;
  701.             if (query_offset && (hitsfound >= max_hits))
  702.                break;
  703.             while (query_offset) {
  704.                q_offsets[hitsfound] = query_offset - 1;
  705.                s_offsets[hitsfound++] = subject_offset;
  706.                query_offset = mb_lt->next_pos2[query_offset];
  707.             }
  708.          }
  709.          bit += scan_shift;
  710.          if (bit >= FULL_BYTE_SHIFT) {
  711.             /* Advance to the next full byte */
  712.             bit -= FULL_BYTE_SHIFT;
  713.             word = BlastNaLookupComputeIndex(FULL_BYTE_SHIFT, 
  714.                                 mb_lt->mask, s++, word);
  715.          }
  716.       }
  717.    }
  718.    *end_offset = 
  719.      ((s - abs_start) - compressed_wordsize)*COMPRESSION_RATIO;
  720. #ifdef DEBUG_LOG
  721.    fclose(logfp0);
  722. #endif
  723.    return hitsfound;
  724. }