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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_extend.c,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:07:13  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.64
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: blast_extend.c,v 1000.2 2004/06/01 18:07:13 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 blast_extend.c
  38.  * Functions to initialize structures used for BLAST extension
  39.  */
  40. static char const rcsid[] = 
  41.     "$Id: blast_extend.c,v 1000.2 2004/06/01 18:07:13 gouriano Exp $";
  42. #include <algo/blast/core/blast_extend.h>
  43. #include <algo/blast/core/blast_options.h>
  44. #include <algo/blast/core/blast_lookup.h>
  45. #include <algo/blast/core/mb_lookup.h>
  46. #include <algo/blast/core/blast_util.h> /* for NCBI2NA_UNPACK_BASE macros */
  47. #include "blast_inline.h"
  48. #define MIN_INIT_HITLIST_SIZE 100
  49. /* Description in blast_extend.h */
  50. BlastInitHitList* BLAST_InitHitListNew(void)
  51. {
  52.    BlastInitHitList* init_hitlist = (BlastInitHitList*)
  53.       calloc(1, sizeof(BlastInitHitList));
  54.    init_hitlist->allocated = MIN_INIT_HITLIST_SIZE;
  55.    init_hitlist->init_hsp_array = (BlastInitHSP*)
  56.       malloc(MIN_INIT_HITLIST_SIZE*sizeof(BlastInitHSP));
  57.    return init_hitlist;
  58. }
  59. void BlastInitHitListReset(BlastInitHitList* init_hitlist)
  60. {
  61.    Int4 index;
  62.    for (index = 0; index < init_hitlist->total; ++index)
  63.       sfree(init_hitlist->init_hsp_array[index].ungapped_data);
  64.    init_hitlist->total = 0;
  65. }
  66. BlastInitHitList* BLAST_InitHitListFree(BlastInitHitList* init_hitlist)
  67. {
  68.    BlastInitHitListReset(init_hitlist);
  69.    sfree(init_hitlist->init_hsp_array);
  70.    sfree(init_hitlist);
  71.    return NULL;
  72. }
  73. /** Allocates memory for the BLAST_DiagTable*. This function also 
  74.  * sets many of the parametes such as diag_array_length etc.
  75.  * @param qlen Length of the query [in]
  76.  * @param multiple_hits Specifies whether multiple hits method is used [in]
  77.  * @param window_size The max. distance between two hits that are extended [in]
  78.  * @return The allocated BLAST_DiagTable structure
  79. */
  80. static BLAST_DiagTable*
  81. BLAST_DiagTableNew (Int4 qlen, Boolean multiple_hits, Int4 window_size)
  82. {
  83.         BLAST_DiagTable* diag_table;
  84.         Int4 diag_array_length;
  85.         diag_table= (BLAST_DiagTable*) calloc(1, sizeof(BLAST_DiagTable));
  86.         if (diag_table)
  87.         {
  88.                 diag_array_length = 1;
  89.                 /* What power of 2 is just longer than the query? */
  90.                 while (diag_array_length < (qlen+window_size))
  91.                 {
  92.                         diag_array_length = diag_array_length << 1;
  93.                 }
  94.                 /* These are used in the word finders to shift and mask
  95.                 rather than dividing and taking the remainder. */
  96.                 diag_table->diag_array_length = diag_array_length;
  97.                 diag_table->diag_mask = diag_array_length-1;
  98.                 diag_table->multiple_hits = multiple_hits;
  99.                 diag_table->offset = window_size;
  100.                 diag_table->window = window_size;
  101.         }
  102.         return diag_table;
  103. }
  104. /* Description in blast_extend.h */
  105. Int2 BlastExtendWordNew(Uint4 query_length,
  106.    const BlastInitialWordOptions* word_options,
  107.    Uint4 subject_length, Blast_ExtendWord** ewp_ptr)
  108. {
  109.    Blast_ExtendWord* ewp;
  110.    Int4 index, i;
  111.    *ewp_ptr = ewp = (Blast_ExtendWord*) calloc(1, sizeof(Blast_ExtendWord));
  112.    if (!ewp) {
  113.       return -1;
  114.    }
  115.    if (word_options->container_type == eMbStacks) {
  116.       double search_space;
  117.       Int4 stack_size, num_stacks;
  118.       MB_StackTable* stack_table;
  119.       ewp->stack_table = stack_table = 
  120.          (MB_StackTable*) malloc(sizeof(MB_StackTable));
  121.       search_space = 
  122.          ((double) query_length) * subject_length;
  123.       num_stacks = MIN(1 + (Int4) (sqrt(search_space)/100), 500);
  124.       stack_size = 5000/num_stacks;
  125.       stack_table->stack_index = (Int4*) calloc(num_stacks, sizeof(Int4));
  126.       stack_table->stack_size = (Int4*) malloc(num_stacks*sizeof(Int4));
  127.       stack_table->estack = 
  128.          (MB_Stack**) malloc(num_stacks*sizeof(MB_Stack*));
  129.       for (index=0; index<num_stacks; index++) {
  130.          stack_table->estack[index] = 
  131.             (MB_Stack*) malloc(stack_size*sizeof(MB_Stack));
  132.          stack_table->stack_size[index] = stack_size;
  133.       }
  134.       stack_table->num_stacks = num_stacks;
  135.    } else {
  136.       Boolean multiple_hits = (word_options->window_size > 0);
  137.       Int4* buffer;
  138.       BLAST_DiagTable* diag_table;
  139.       ewp->diag_table = diag_table = 
  140.          BLAST_DiagTableNew(query_length, multiple_hits, 
  141.                             word_options->window_size);
  142.       /* Allocate the buffer to be used for diagonal array. */
  143.       buffer = 
  144.          (Int4*) calloc(diag_table->diag_array_length, sizeof(DiagStruct));
  145.       
  146.       if (buffer == NULL) {
  147.          sfree(ewp);
  148.          return -1;
  149.       }
  150.          
  151.       diag_table->diag_array= (DiagStruct*) buffer;
  152.       for(i=0;i<diag_table->diag_array_length;i++){
  153.          diag_table->diag_array[i].diag_level=0;
  154.          diag_table->diag_array[i].last_hit = -diag_table->window;
  155.       }
  156.    }
  157.    *ewp_ptr = ewp;
  158.    
  159.    return 0;
  160. }
  161. Boolean BLAST_SaveInitialHit(BlastInitHitList* init_hitlist, 
  162.                   Int4 q_off, Int4 s_off, BlastUngappedData* ungapped_data) 
  163. {
  164.    BlastInitHSP* match_array;
  165.    Int4 num, num_avail;
  166.    num = init_hitlist->total;
  167.    num_avail = init_hitlist->allocated;
  168.    match_array = init_hitlist->init_hsp_array;
  169.    if (num>=num_avail) {
  170.       if (init_hitlist->do_not_reallocate) 
  171.          return FALSE;
  172.       num_avail *= 2;
  173.       match_array = (BlastInitHSP*) 
  174.          realloc(match_array, num_avail*sizeof(BlastInitHSP));
  175.       if (!match_array) {
  176.          init_hitlist->do_not_reallocate = TRUE;
  177.          return FALSE;
  178.       } else {
  179.          init_hitlist->allocated = num_avail;
  180.          init_hitlist->init_hsp_array = match_array;
  181.       }
  182.    }
  183.    match_array[num].q_off = q_off;
  184.    match_array[num].s_off = s_off;
  185.    match_array[num].ungapped_data = ungapped_data;
  186.    init_hitlist->total++;
  187.    return TRUE;
  188. }
  189. /** Traditional Mega BLAST initial word extension
  190.  * @param query The query sequence [in]
  191.  * @param subject The subject sequence [in]
  192.  * @param lookup Lookup table structure [in]
  193.  * @param word_params The parameters related to initial word extension [in]
  194.  * @param matrix the substitution matrix for ungapped extension [in]
  195.  * @param ewp The structure containing word extension information [in]
  196.  * @param q_off The offset in the query sequence [in]
  197.  * @param s_off The offset in the subject sequence [in]
  198.  * @param init_hitlist The structure containing information about all 
  199.  *                     initial hits [in] [out]
  200.  * @return Has this hit been extended? 
  201.  */
  202. static Boolean
  203. MB_ExtendInitialHit(BLAST_SequenceBlk* query, 
  204.    BLAST_SequenceBlk* subject, LookupTableWrap* lookup,
  205.    const BlastInitialWordParameters* word_params, 
  206.    Int4** matrix, Blast_ExtendWord* ewp, Int4 q_off, Int4 s_off,
  207.    BlastInitHitList* init_hitlist) 
  208. {
  209.    Int4 index, index1, step;
  210.    MBLookupTable* mb_lt = (MBLookupTable*) lookup->lut;
  211.    MB_Stack* estack;
  212.    Int4 diag, stack_top;
  213.    Int4 window, word_extra_length, scan_step;
  214.    Boolean new_hit, hit_ready = FALSE, two_hits, do_ungapped_extension;
  215.    BLAST_DiagTable* diag_table = ewp->diag_table;
  216.    MB_StackTable* stack_table = ewp->stack_table;
  217.    BlastUngappedData* ungapped_data = NULL;
  218.    const BlastInitialWordOptions* word_options = word_params->options;
  219.    Int4 s_pos;
  220.    window = word_options->window_size;
  221.    word_extra_length = 
  222.       mb_lt->word_length - COMPRESSION_RATIO*mb_lt->compressed_wordsize;
  223.    scan_step = mb_lt->scan_step;
  224.    two_hits = (window > 0);
  225.    do_ungapped_extension = word_options->ungapped_extension;
  226.    if (diag_table) {
  227.       DiagStruct* diag_array = diag_table->diag_array;
  228.       DiagStruct* diag_array_elem;
  229.       Int4 diag_mask;
  230.       Int4 offset, s_pos;
  231.       diag_mask = diag_table->diag_mask;
  232.       offset = diag_table->offset;
  233.       s_pos = s_off + offset;
  234.       diag = (s_off + diag_table->diag_array_length - q_off) & diag_mask;
  235.       diag_array_elem = &diag_array[diag];
  236.       step = s_pos - diag_array_elem->last_hit;
  237.       if (step <= 0)
  238.          return FALSE;
  239.       if (!two_hits) {
  240.          /* Single hit version */
  241.          new_hit = (step > scan_step);
  242.          hit_ready = (new_hit && (word_extra_length == 0)) || 
  243.             (!new_hit && 
  244.              (step + diag_array_elem->diag_level == word_extra_length));
  245.       } else {
  246.          /* Two hit version */
  247.          if (diag_array_elem->diag_level > word_extra_length) {
  248.             /* Previous hit already saved */
  249.             new_hit = (step > scan_step);
  250.          } else {
  251.             new_hit = (step > window);
  252.             hit_ready = (diag_array_elem->diag_level == word_extra_length) &&
  253.                !new_hit;
  254.          }
  255.       }
  256.       if (hit_ready) {
  257.          if (do_ungapped_extension) {
  258.             /* Perform ungapped extension */
  259.             BlastnWordUngappedExtend(query, subject, matrix, q_off, s_off, 
  260.                word_params->cutoff_score, -word_params->x_dropoff, 
  261.                &ungapped_data);
  262.             s_pos = ungapped_data->length - 1 + ungapped_data->s_start 
  263.                + diag_table->offset;
  264.             diag_array_elem->diag_level += 
  265.                s_pos - diag_array_elem->last_hit;
  266.             diag_array_elem->last_hit = s_pos;
  267.          } else {
  268.             ungapped_data = NULL;
  269.             diag_array_elem->diag_level += step;
  270.             diag_array_elem->last_hit = s_pos;
  271.          }
  272.          if (!ungapped_data || 
  273.              ungapped_data->score >= word_params->cutoff_score) {
  274.             BLAST_SaveInitialHit(init_hitlist, q_off, s_off, ungapped_data);
  275.          } else {
  276.             sfree(ungapped_data);
  277.             /* Set diag_level to 0, indicating that any hit after this will 
  278.                be new */
  279.             diag_array_elem->diag_level = 0;
  280.          }
  281.       } else if (step > 0) {
  282.          /* First hit in the 2-hit case or a direct extension of the 
  283.             previous hit - update the last hit information only */
  284.          if (new_hit)
  285.             diag_array_elem->diag_level = 0;
  286.          else
  287.             diag_array_elem->diag_level += step;
  288.          diag_array_elem->last_hit = s_pos;
  289.       }
  290.       
  291.    } else {
  292.       /* Use stacks instead of the diagonal array */
  293.       index1 = (s_off - q_off) % stack_table->num_stacks;
  294.       if (index1<0)
  295.          index1 += stack_table->num_stacks;
  296.       estack = stack_table->estack[index1];
  297.       stack_top = stack_table->stack_index[index1] - 1;
  298.       
  299.       for (index = 0; index <= stack_top; ) {
  300.          step = s_off - estack[index].level;
  301.          if (estack[index].diag == s_off - q_off) {
  302.             if (step <= 0) {
  303.                stack_table->stack_index[index1] = stack_top + 1;
  304.                return FALSE;
  305.             }
  306.             if (!two_hits) {
  307.                /* Single hit version */
  308.                new_hit = (step > scan_step);
  309.                hit_ready = (!new_hit && 
  310.                   (step + estack[index].length == word_extra_length)) ||
  311.                   (new_hit && (word_extra_length == 0));
  312.             } else {
  313.                /* Two hit version */
  314.                if (estack[index].length > word_extra_length) {
  315.                   /* Previous hit already saved */
  316.                   new_hit = (step > scan_step);
  317.                } else {
  318.                   new_hit = (step > window);
  319.                   hit_ready = (estack[index].length == word_extra_length) &&
  320.                      !new_hit;
  321.                }
  322.             }
  323.             if (hit_ready) {
  324.                if (do_ungapped_extension) {
  325.                   /* Perform ungapped extension */
  326.                   BlastnWordUngappedExtend(query, subject, matrix, 
  327.                       q_off, s_off, word_params->cutoff_score, 
  328.                       -word_params->x_dropoff, &ungapped_data);
  329.                   s_pos = ungapped_data->length - 1 + 
  330.                      ungapped_data->s_start;
  331.                   estack[index].length += s_pos - estack[index].level;
  332.                   estack[index].level = s_pos;
  333.                } else {
  334.                   ungapped_data = NULL;
  335.                   estack[index].length += step;
  336.                   estack[index].level = s_off;
  337.                }
  338.                if (!ungapped_data || 
  339.                    ungapped_data->score >= word_params->cutoff_score) {
  340.                   BLAST_SaveInitialHit(init_hitlist, q_off, s_off, 
  341.                                        ungapped_data);
  342.                } else {
  343.                   sfree(ungapped_data);
  344.                   /* Set hit length back to 0 after ungapped extension 
  345.                      failure */
  346.                   estack[index].length = 0;
  347.                }
  348.             } else {
  349.                /* First hit in the 2-hit case or a direct extension of the 
  350.                   previous hit - update the last hit information only */
  351.                if (new_hit)
  352.                   estack[index].length = 0;
  353.                else
  354.                   estack[index].length += step;
  355.                estack[index].level = s_off;
  356.             }
  357.             /* In case the size of this stack changed */
  358.             stack_table->stack_index[index1] = stack_top + 1;  
  359.             return hit_ready;
  360.          } else if (step <= scan_step || (step <= window && 
  361.                       estack[index].length >= word_extra_length)) {
  362.             /* Hit from a different diagonal, and it can be continued */
  363.             index++;
  364.          } else {
  365.             /* Hit from a different diagonal that does not continue: remove
  366.                it from the stack */
  367.             estack[index] = estack[stack_top];
  368.             --stack_top;
  369.          }
  370.       }
  371.       /* Need an extra slot on the stack for this hit */
  372.       if (++stack_top >= stack_table->stack_size[index1]) {
  373.          /* Stack about to overflow - reallocate memory */
  374.          MB_Stack* ptr;
  375.          if (!(ptr = (MB_Stack*)realloc(estack,
  376.                      2*stack_table->stack_size[index1]*sizeof(MB_Stack)))) {
  377.             return FALSE;
  378.          } else {
  379.             stack_table->stack_size[index1] *= 2;
  380.             estack = stack_table->estack[index1] = ptr;
  381.          }
  382.       }
  383.       /* Start a new hit */
  384.       estack[stack_top].diag = s_off - q_off;
  385.       estack[stack_top].level = s_off;
  386.       estack[stack_top].length = 0;
  387.       stack_table->stack_index[index1] = stack_top + 1;
  388.       /* Save the hit if it already qualifies */
  389.       if (!two_hits && (word_extra_length == 0)) {
  390.          hit_ready = TRUE;
  391.          if (do_ungapped_extension) {
  392.             /* Perform ungapped extension */
  393.             BlastnWordUngappedExtend(query, subject, matrix, q_off, s_off, 
  394.                word_params->cutoff_score, -word_params->x_dropoff, 
  395.                &ungapped_data);
  396.             estack[stack_top].level = ungapped_data->length - 1 + 
  397.                ungapped_data->s_start;
  398.             estack[stack_top].length = ungapped_data->length;
  399.          } else {
  400.             ungapped_data = NULL;
  401.          }
  402.          if (!ungapped_data || 
  403.              ungapped_data->score >= word_params->cutoff_score) {
  404.             BLAST_SaveInitialHit(init_hitlist, q_off, s_off, 
  405.                                  ungapped_data);
  406.          } else {
  407.             sfree(ungapped_data);
  408.             /* Set hit length back to 0 after ungapped extension 
  409.                failure */
  410.             estack[index].length = 0;
  411.          }
  412.       }
  413.    }
  414.    return hit_ready;
  415. }
  416. /** Update the word extension structure after scanning of each subject sequence
  417.  * @param ewp The structure holding word extension information [in] [out]
  418.  * @param subject_length The length of the subject sequence that has just been
  419.  *        processed [in]
  420.  */
  421. static Int2 BlastNaExtendWordExit(Blast_ExtendWord* ewp, Int4 subject_length)
  422. {
  423.    BLAST_DiagTable* diag_table;
  424.    Int4 diag_array_length, i;
  425.    if (!ewp)
  426.       return -1;
  427.    diag_table = ewp->diag_table;
  428.       
  429.    if (diag_table->offset >= INT4_MAX/2) {
  430.       diag_array_length = diag_table->diag_array_length;
  431.       for(i=0;i<diag_array_length;i++) {
  432.  diag_table->diag_array[i].diag_level=0;
  433.  diag_table->diag_array[i].last_hit = -diag_table->window;
  434.       }
  435.    }
  436.       
  437.    if (diag_table->offset < INT4_MAX/2) {
  438.       diag_table->offset += subject_length + diag_table->window;
  439.    } else {
  440.       diag_table->offset = 0;
  441.    }
  442.    return 0;
  443. }
  444. /** Update the MegaBlast word extension structure after scanning of each 
  445.  *  subject sequence.
  446.  * @param ewp The structure holding word extension information [in] [out]
  447.  * @param subject_length The length of the subject sequence that has just been
  448.  *        processed [in]
  449.  */
  450. static Int2 MB_ExtendWordExit(Blast_ExtendWord* ewp, Int4 subject_length)
  451. {
  452.    if (!ewp)
  453.       return -1;
  454.    if (ewp->diag_table) {
  455.       return BlastNaExtendWordExit(ewp, subject_length);
  456.    } else { 
  457.       memset(ewp->stack_table->stack_index, 0, 
  458.              ewp->stack_table->num_stacks*sizeof(Int4));
  459.    }
  460.    return 0;
  461. }
  462. /* Description in blast_extend.h */
  463. Boolean
  464. BlastnWordUngappedExtend(BLAST_SequenceBlk* query, 
  465.    BLAST_SequenceBlk* subject, Int4** matrix, 
  466.    Int4 q_off, Int4 s_off, Int4 cutoff, Int4 X, 
  467.    BlastUngappedData** ungapped_data)
  468. {
  469.    Uint1* q;
  470.    Int4 sum, score;
  471.    Uint1 ch;
  472.    Uint1* subject0,* sf,* q_beg,* q_end,* s_end,* s,* start;
  473.    Int2 remainder, base;
  474.    Int4 q_avail, s_avail;
  475.    
  476.    base = 3 - (s_off % 4);
  477.    
  478.    subject0 = subject->sequence;
  479.    q_avail = query->length - q_off;
  480.    s_avail = subject->length - s_off;
  481.    q = q_beg = q_end = query->sequence + q_off;
  482.    s = s_end = subject0 + s_off/COMPRESSION_RATIO;
  483.    if (q_off < s_off) {
  484.       start = subject0 + (s_off-q_off)/COMPRESSION_RATIO;
  485.       remainder = 3 - ((s_off-q_off)%COMPRESSION_RATIO);
  486.    } else {
  487.       start = subject0;
  488.       remainder = 3;
  489.    }
  490.    
  491.    /* Find where positive scoring starts & ends within the word hit */
  492.    score = 0;
  493.    sum = 0;
  494.    /* extend to the left */
  495.    while ((s > start) || (s == start && base < remainder)) {
  496.       if (base == 3) {
  497.          s--;
  498.          base = 0;
  499.       } else {
  500.          ++base;
  501.       }
  502.       ch = *s;
  503.       if ((sum += matrix[*--q][NCBI2NA_UNPACK_BASE(ch, base)]) > 0) {
  504.          q_beg = q;
  505.          score += sum;
  506.          sum = 0;
  507.       } else if (sum < X) {
  508.          break;
  509.       }
  510.    }
  511.    
  512.    if (score >= cutoff && !ungapped_data) 
  513.       return FALSE;
  514.    
  515.    if (ungapped_data) {
  516.       *ungapped_data = (BlastUngappedData*) 
  517.          malloc(sizeof(BlastUngappedData));
  518.       (*ungapped_data)->q_start = q_beg - query->sequence;
  519.       (*ungapped_data)->s_start = 
  520.          s_off - (q_off - (*ungapped_data)->q_start);
  521.    }
  522.    if (q_avail < s_avail) {
  523.       sf = subject0 + (s_off + q_avail)/COMPRESSION_RATIO;
  524.       remainder = 3 - ((s_off + q_avail)%COMPRESSION_RATIO);
  525.    } else {
  526.       sf = subject0 + (subject->length)/COMPRESSION_RATIO;
  527.       remainder = 3 - ((subject->length)%COMPRESSION_RATIO);
  528.    }
  529.    /* extend to the right */
  530.    q = q_end;
  531.    s = s_end;
  532.    sum = 0;
  533.    base = 3 - (s_off % COMPRESSION_RATIO);
  534.    
  535.    while (s < sf || (s == sf && base > remainder)) {
  536.       ch = *s;
  537.       if ((sum += matrix[*q++][NCBI2NA_UNPACK_BASE(ch, base)]) > 0) {
  538.          q_end = q;
  539.          score += sum;
  540.          sum = 0;
  541.       } else if (sum < X)
  542.          break;
  543.       if (base == 0) {
  544.          base = 3;
  545.          s++;
  546.       } else
  547.          base--;
  548.    }
  549.    
  550.    if (ungapped_data) {
  551.       (*ungapped_data)->length = q_end - q_beg;
  552.       (*ungapped_data)->score = score;
  553.       (*ungapped_data)->frame = 0;
  554.    }
  555.    
  556.    return (score < cutoff);
  557. }
  558. /** Perform ungapped extension given an offset pair, and save the initial 
  559.  * hit information if the hit qualifies. This function assumes that the
  560.  * exact match has already been extended to the word size parameter.
  561.  * @param query The query sequence [in]
  562.  * @param subject The subject sequence [in]
  563.  * @param min_step Distance at which new word hit lies within the previously
  564.  *                 extended hit. Non-zero only when ungapped extension is not
  565.  *                 performed, e.g. for contiguous megablast. [in]
  566.  * @param word_params The parameters related to initial word extension [in]
  567.  * @param matrix the substitution matrix for ungapped extension [in]
  568.  * @param ewp The structure containing word extension information [in]
  569.  * @param q_off The offset in the query sequence [in]
  570.  * @param s_end The offset in the subject sequence where this hit ends [in]
  571.  * @param s_off The offset in the subject sequence [in]
  572.  * @param init_hitlist The structure containing information about all 
  573.  *                     initial hits [in] [out]
  574.  * @return Has this hit been extended? 
  575.  */
  576. static Boolean
  577. BlastnExtendInitialHit(BLAST_SequenceBlk* query, 
  578.    BLAST_SequenceBlk* subject, Uint4 min_step,
  579.    const BlastInitialWordParameters* word_params, 
  580.    Int4** matrix, Blast_ExtendWord* ewp, Int4 q_off, Int4 s_end,
  581.    Int4 s_off, BlastInitHitList* init_hitlist)
  582. {
  583.    Int4 diag, real_diag;
  584.    Int4 s_pos, last_hit;
  585.    BLAST_DiagTable*     diag_table;
  586.    BlastUngappedData* ungapped_data;
  587.    const BlastInitialWordOptions* word_options = word_params->options;
  588.    Int4 window_size = word_options->window_size;
  589.    Boolean hit_ready;
  590.    Boolean new_hit = FALSE, second_hit = FALSE;
  591.    Int4 step;
  592.    DiagStruct* diag_array_elem;
  593.    diag_table = ewp->diag_table;
  594.    diag = s_off + diag_table->diag_array_length - q_off;
  595.    real_diag = diag & diag_table->diag_mask;
  596.    diag_array_elem = &diag_table->diag_array[real_diag];
  597.    s_pos = s_end + diag_table->offset;
  598.    last_hit = diag_array_elem->last_hit;
  599.    step = s_pos - last_hit;
  600.    if (step <= 0)
  601.       /* This is a hit on a diagonal that has already been explored 
  602.          further down */
  603.       return 0;
  604.    if (window_size == 0 ||
  605.        (diag_array_elem->diag_level == 1)) {
  606.       /* Single hit version or previous hit was already a second hit */
  607.       new_hit = (step > (Int4)min_step);
  608.    } else {
  609.       /* Previous hit was the first hit */
  610.       new_hit = (step > window_size);
  611.       second_hit = (step > 0 && step <= window_size);
  612.    }
  613.    hit_ready = ((window_size == 0) && new_hit) || second_hit;
  614.    if (hit_ready) {
  615.       if (word_options->ungapped_extension) {
  616.          /* Perform ungapped extension */
  617.          BlastnWordUngappedExtend(query, subject, matrix, q_off, s_off, 
  618.             word_params->cutoff_score, -word_params->x_dropoff, 
  619.             &ungapped_data);
  620.       
  621.          diag_array_elem->last_hit = 
  622.             ungapped_data->length + ungapped_data->s_start 
  623.             + diag_table->offset;
  624.       } else {
  625.          ungapped_data = NULL;
  626.          diag_array_elem->last_hit = s_pos;
  627.       }
  628.       if (!ungapped_data || 
  629.           ungapped_data->score >= word_params->cutoff_score) {
  630.          BLAST_SaveInitialHit(init_hitlist, q_off, s_off, ungapped_data);
  631.          /* Set diag_level to 1, indicating that this hit has already been 
  632.             saved */
  633.          diag_array_elem->diag_level = 1;
  634.       } else {
  635.          sfree(ungapped_data);
  636.          /* Set diag_level to 0, indicating that any hit after this will 
  637.             be new */
  638.          diag_array_elem->diag_level = 0;
  639.       }
  640.    } else {
  641.       /* First hit in the 2-hit case or a direct extension of the previous 
  642.          hit - update the last hit information only */
  643.       diag_array_elem->last_hit = s_pos;
  644.       if (new_hit)
  645.          diag_array_elem->diag_level = 0;
  646.    }
  647.    return hit_ready;
  648. }
  649. /* Description in blast_extend.h */
  650. Int2 BlastNaWordFinder(BLAST_SequenceBlk* subject, 
  651.        BLAST_SequenceBlk* query,
  652.        LookupTableWrap* lookup_wrap,
  653.        Int4** matrix,
  654.        const BlastInitialWordParameters* word_params,
  655.        Blast_ExtendWord* ewp,
  656.        Uint4* q_offsets,
  657.        Uint4* s_offsets,
  658.        Int4 max_hits,
  659.        BlastInitHitList* init_hitlist, 
  660.              BlastUngappedStats* ungapped_stats)
  661. {
  662.    LookupTable* lookup = (LookupTable*) lookup_wrap->lut;
  663.    Uint1* s_start = subject->sequence;
  664.    Uint1* abs_start = s_start;
  665.    Int4 i;
  666.    Uint1* s;
  667.    Uint1* q_start = query->sequence;
  668.    Int4 hitsfound, total_hits = 0;
  669.    Int4 hits_extended = 0;
  670.    Uint4 word_size, compressed_wordsize, reduced_word_length;
  671.    Uint4 extra_bytes_needed;
  672.    Uint2 extra_bases, left, right;
  673.    Uint1* q;
  674.    Int4 start_offset, last_start, next_start, last_end;
  675.    Uint1 max_bases;
  676.    word_size = COMPRESSION_RATIO*lookup->wordsize;
  677.    last_start = subject->length - word_size;
  678.    start_offset = 0;
  679.    compressed_wordsize = lookup->reduced_wordsize;
  680.    extra_bytes_needed = lookup->wordsize - compressed_wordsize;
  681.    reduced_word_length = COMPRESSION_RATIO*compressed_wordsize;
  682.    extra_bases = lookup->word_length - word_size;
  683.    last_end = subject->length - word_size;
  684.    while (start_offset <= last_start) {
  685.       /* Pass the last word ending offset */
  686.       next_start = last_end;
  687.       hitsfound = BlastNaScanSubject(lookup_wrap, subject, start_offset, 
  688.                      q_offsets, s_offsets, max_hits, &next_start); 
  689.       
  690.       total_hits += hitsfound;
  691.       for (i = 0; i < hitsfound; ++i) {
  692.          /* Here it is guaranteed that subject offset is divisible by 4,
  693.             because we only extend to the right, so scanning stride must be
  694.             equal to 4. */
  695.          s = abs_start + (s_offsets[i])/COMPRESSION_RATIO;
  696.          q = q_start + q_offsets[i];
  697.     
  698.          /* Check for extra bytes if required for longer words. */
  699.          if (extra_bytes_needed && 
  700.              !BlastNaCompareExtraBytes(q+reduced_word_length, 
  701.                  s+compressed_wordsize, extra_bytes_needed))
  702.             continue;
  703.          /* mini extension to the left */
  704.          max_bases = 
  705.             MIN(COMPRESSION_RATIO, MIN(q_offsets[i], s_offsets[i]));
  706.          left = BlastNaMiniExtendLeft(q, s-1, max_bases);
  707.          /* mini extension to the right */
  708.          max_bases =
  709.             MIN(COMPRESSION_RATIO, 
  710.                 MIN(subject->length - s_offsets[i] - lookup->wordsize,
  711.                     query->length - q_offsets[i] - word_size));
  712.          right = 0;
  713.          if (max_bases > 0) {
  714.             s += lookup->wordsize;
  715.             q += word_size;
  716.             right = BlastNaMiniExtendRight(q, s, max_bases);
  717.          }
  718.          if (left + right >= extra_bases) {
  719.             /* Check if this diagonal has already been explored. */
  720.             if (BlastnExtendInitialHit(query, subject, 0, 
  721.                    word_params, matrix, ewp, q_offsets[i], 
  722.                    s_offsets[i] + word_size + right, 
  723.                    s_offsets[i], init_hitlist))
  724.                ++hits_extended;
  725.          }
  726.       }
  727.       start_offset = next_start;
  728.    }
  729.    BlastNaExtendWordExit(ewp, subject->length);
  730.    Blast_UngappedStatsUpdate(ungapped_stats, total_hits, hits_extended, 
  731.                              init_hitlist->total);
  732.    return 0;
  733. /** Extend an exact match in both directions up to the provided 
  734.  * maximal length. 
  735.  * @param q_start Pointer to the start of the extension in query [in]
  736.  * @param s_start Pointer to the start of the extension in subject [in]
  737.  * @param max_bases_left At most how many bases to extend to the left [in]
  738.  * @param max_bases_right At most how many bases to extend to the right [in]
  739.  * @param max_length The length of the required exact match [in]
  740.  * @param extend_partial_byte Should partial byte extension be perfomed?[in]
  741.  * @param extended_right How far has extension succeeded to the right? [out]
  742.  * @return TRUE if extension successful 
  743.  */
  744. static Boolean 
  745. BlastNaExactMatchExtend(Uint1* q_start, Uint1* s_start, 
  746.    Uint4 max_bases_left, Uint4 max_bases_right, Uint4 max_length, 
  747.    Boolean extend_partial_byte, Uint4* extended_right)
  748. {
  749.    Uint4 length;
  750.    Uint1* q,* s;
  751.    
  752.    *extended_right = 0;
  753.    length = 0;
  754.    /* Extend to the right; start from the firstt byte (it must be the 
  755.       first one that's guaranteed to match by the lookup table hit). */
  756.    q = q_start;
  757.    s = s_start;
  758.    while (length < max_length && max_bases_right >= COMPRESSION_RATIO) {
  759.       if (*s != PACK_WORD(q))
  760.          break;
  761.       length += COMPRESSION_RATIO;
  762.       ++s;
  763.       q += COMPRESSION_RATIO;
  764.       max_bases_right -= COMPRESSION_RATIO;
  765.    }
  766.    if (extend_partial_byte) {
  767.       if (max_bases_right > 0) {
  768.          length += BlastNaMiniExtendRight(q, s, 
  769.                       (Uint1) MIN(max_bases_right, COMPRESSION_RATIO));
  770.       }
  771.    }
  772.    *extended_right = length;
  773.    if (length >= max_length)
  774.       return TRUE;
  775.    if (max_bases_left < max_length - length)
  776.       return FALSE;
  777.    else
  778.       max_bases_left = max_length - length;
  779.    /* Extend to the left; start with the byte just before the first. */
  780.    q = q_start - COMPRESSION_RATIO;
  781.    s = s_start - 1;
  782.    while (length < max_length && max_bases_left >= COMPRESSION_RATIO) {
  783.       if (*s != PACK_WORD(q))
  784.          break;
  785.       length += COMPRESSION_RATIO;
  786.       --s;
  787.       q -= COMPRESSION_RATIO;
  788.       max_bases_left -= COMPRESSION_RATIO;
  789.    }
  790.    if (length >= max_length)
  791.       return TRUE;
  792.    if (extend_partial_byte && max_bases_left > 0) {
  793.       length += BlastNaMiniExtendLeft(q+COMPRESSION_RATIO, s, 
  794.                    (Uint1) MIN(max_bases_left, COMPRESSION_RATIO));
  795.    }
  796.    return (length >= max_length);
  797. }
  798. /** Extend the lookup table exact match hit in both directions and 
  799.  * update the diagonal structure.
  800.  * @param q_offsets Array of query offsets [in]
  801.  * @param s_offsets Array of subject offsets [in]
  802.  * @param num_hits Size of the above arrays [in]
  803.  * @param word_params Parameters for word extension [in]
  804.  * @param lookup_wrap Lookup table wrapper structure [in]
  805.  * @param query Query sequence data [in]
  806.  * @param subject Subject sequence data [in]
  807.  * @param matrix Scoring matrix for ungapped extension [in]
  808.  * @param ewp Word extension structure containing information about the 
  809.  *            extent of already processed hits on each diagonal [in]
  810.  * @param init_hitlist Structure to keep the extended hits. 
  811.  *                     Must be allocated outside of this function [in] [out]
  812.  * @return Number of hits extended. 
  813.  */
  814. static Int4 
  815. BlastNaExtendRightAndLeft(Uint4* q_offsets, Uint4* s_offsets, Int4 num_hits, 
  816.                           const BlastInitialWordParameters* word_params,
  817.                           LookupTableWrap* lookup_wrap,
  818.                           BLAST_SequenceBlk* query, BLAST_SequenceBlk* subject,
  819.                           Int4** matrix, Blast_ExtendWord* ewp, 
  820.                           BlastInitHitList* init_hitlist)
  821. {
  822.    Int4 index;
  823.    Uint4 query_length = query->length;
  824.    Uint4 subject_length = subject->length;
  825.    Uint1* q_start = query->sequence;
  826.    Uint1* s_start = subject->sequence;
  827.    Uint4 word_length = 0;
  828.    Uint4 q_off, s_off;
  829.    Uint4 max_bases_left, max_bases_right;
  830.    Uint4 extended_right;
  831.    Uint4 shift;
  832.    Uint1* q, *s;
  833.    Uint4 min_step = 0;
  834.    Boolean do_ungapped_extension = word_params->options->ungapped_extension;
  835.    Boolean variable_wordsize = 
  836.       (Boolean) word_params->options->variable_wordsize;
  837.    Int4 hits_extended = 0;
  838.    if (lookup_wrap->lut_type == MB_LOOKUP_TABLE) {
  839.       MBLookupTable* lut = (MBLookupTable*)lookup_wrap->lut;
  840.       word_length = lut->word_length;
  841.       if(!do_ungapped_extension && !lut->discontiguous)
  842.          min_step = lut->scan_step;
  843.    } else {
  844.       LookupTable* lut = (LookupTable*)lookup_wrap->lut;
  845.       word_length = lut->word_length;
  846.    }
  847.    for (index = 0; index < num_hits; ++index) {
  848.       /* Adjust offsets to the start of the next full byte in the
  849.          subject sequence */
  850.       shift = (COMPRESSION_RATIO - s_offsets[index]%COMPRESSION_RATIO)
  851.          % COMPRESSION_RATIO;
  852.       q_off = q_offsets[index] + shift;
  853.       s_off = s_offsets[index] + shift;
  854.       s = s_start + s_off/COMPRESSION_RATIO;
  855.       q = q_start + q_off;
  856.       
  857.       max_bases_left = 
  858.          MIN(word_length, MIN(q_off, s_off));
  859.       max_bases_right = MIN(word_length, 
  860.                             MIN(query_length-q_off, subject_length-s_off));
  861.       
  862.       if (BlastNaExactMatchExtend(q, s, max_bases_left, 
  863.                                   max_bases_right, word_length, 
  864.                                   (Boolean) !variable_wordsize, &extended_right)) 
  865.       {
  866.          /* Check if this diagonal has already been explored and save
  867.             the hit if needed. */
  868.          if (BlastnExtendInitialHit(query, subject, min_step,
  869.                                 word_params, matrix, ewp, q_offsets[index], 
  870.                                 s_off + extended_right, s_offsets[index], 
  871.                                 init_hitlist))
  872.             ++hits_extended;
  873.       }
  874.    }
  875.    return hits_extended;
  876. }
  877. /* Description in blast_extend.h */
  878. Int2 MB_WordFinder(BLAST_SequenceBlk* subject,
  879.    BLAST_SequenceBlk* query,
  880.    LookupTableWrap* lookup_wrap,
  881.    Int4** matrix, 
  882.    const BlastInitialWordParameters* word_params,
  883.    Blast_ExtendWord* ewp,
  884.    Uint4* q_offsets,
  885.    Uint4* s_offsets,
  886.    Int4 max_hits,
  887.    BlastInitHitList* init_hitlist, 
  888.          BlastUngappedStats* ungapped_stats)
  889. {
  890.    const BlastInitialWordOptions* word_options = word_params->options;
  891.    /* Pointer to the beginning of the first word of the subject sequence */
  892.    MBLookupTable* mb_lt = (MBLookupTable*) lookup_wrap->lut;
  893.    Int4 hitsfound=0;
  894.    Int4 total_hits=0, index;
  895.    Int4 start_offset, next_start, last_start, last_end;
  896.    Int4 subject_length = subject->length;
  897.    Boolean ag_blast;
  898.    Int4 hits_extended = 0;
  899.    ag_blast = (Boolean) (word_options->extension_method == eRightAndLeft);
  900.    start_offset = 0;
  901.    if (mb_lt->discontiguous) {
  902.       last_start = subject_length - mb_lt->template_length;
  903.       last_end = last_start + mb_lt->word_length;
  904.    } else {
  905.       last_end = subject_length;
  906.       if (ag_blast) {
  907.          last_start = 
  908.             last_end - COMPRESSION_RATIO*mb_lt->compressed_wordsize;
  909.       } else {
  910.          last_start = last_end - mb_lt->word_length;
  911.       }
  912.    }
  913.    /* start_offset points to the beginning of the word */
  914.    while ( start_offset <= last_start ) {
  915.       /* Set the last argument's value to the end of the last word,
  916.          without the extra bases for the discontiguous case */
  917.       next_start = last_end;
  918.       if (mb_lt->discontiguous) {
  919.          hitsfound = MB_DiscWordScanSubject(lookup_wrap, subject, start_offset,
  920.             q_offsets, s_offsets, max_hits, &next_start);
  921.       } else if (!ag_blast) {
  922.          hitsfound = MB_ScanSubject(lookup_wrap, subject, start_offset, 
  923.     q_offsets, s_offsets, max_hits, &next_start);
  924.       } else {
  925.          hitsfound = MB_AG_ScanSubject(lookup_wrap, subject, start_offset, 
  926.     q_offsets, s_offsets, max_hits, &next_start);
  927.       }
  928.       if (ag_blast) {
  929.          hits_extended += 
  930.             BlastNaExtendRightAndLeft(q_offsets, s_offsets, hitsfound, 
  931.                                    word_params, lookup_wrap, query, subject, 
  932.                                    matrix, ewp, init_hitlist);
  933.       } else {
  934.          for (index = 0; index < hitsfound; ++index) {
  935.             if (MB_ExtendInitialHit(query, subject, lookup_wrap, word_params,
  936.                                     matrix, ewp, q_offsets[index], 
  937.                                     s_offsets[index], init_hitlist))
  938.                ++hits_extended;
  939.          }
  940.       }
  941.       /* next_start returned from the ScanSubject points to the beginning
  942.          of the word */
  943.       start_offset = next_start;
  944.       total_hits += hitsfound;
  945.    }
  946.    MB_ExtendWordExit(ewp, subject_length);
  947.    Blast_UngappedStatsUpdate(ungapped_stats, total_hits, hits_extended, 
  948.                              init_hitlist->total);
  949.    return 0;
  950. }
  951. /* Description in blast_extend.h */
  952. Int2 BlastNaWordFinder_AG(BLAST_SequenceBlk* subject, 
  953.   BLAST_SequenceBlk* query,
  954.   LookupTableWrap* lookup_wrap, 
  955.   Int4** matrix,
  956.   const BlastInitialWordParameters* word_params,
  957.   Blast_ExtendWord* ewp,
  958.   Uint4* q_offsets,
  959.   Uint4* s_offsets,
  960.   Int4 max_hits,
  961.   BlastInitHitList* init_hitlist, 
  962.            BlastUngappedStats* ungapped_stats)
  963. {
  964.    Int4 hitsfound, total_hits = 0;
  965.    Int4 start_offset, end_offset, next_start;
  966.    LookupTable* lookup = (LookupTable*) lookup_wrap->lut;
  967.    Int4 hits_extended = 0;
  968.    start_offset = 0;
  969.    end_offset = subject->length - COMPRESSION_RATIO*lookup->reduced_wordsize;
  970.    /* start_offset points to the beginning of the word; end_offset is the
  971.       beginning of the last word */
  972.    while (start_offset <= end_offset) {
  973.       hitsfound = BlastNaScanSubject_AG(lookup_wrap, subject, start_offset, 
  974.                      q_offsets, s_offsets, max_hits, &next_start); 
  975.       
  976.       total_hits += hitsfound;
  977.       hits_extended += 
  978.          BlastNaExtendRightAndLeft(q_offsets, s_offsets, hitsfound, 
  979.                                 word_params, lookup_wrap, query, subject, 
  980.                                 matrix, ewp, init_hitlist);
  981.       start_offset = next_start;
  982.    }
  983.    BlastNaExtendWordExit(ewp, subject->length);
  984.    Blast_UngappedStatsUpdate(ungapped_stats, total_hits, hits_extended, 
  985.                              init_hitlist->total);
  986.    return 0;
  987. /** Deallocate memory for the diagonal table structure */
  988. static BLAST_DiagTable* BlastDiagTableFree(BLAST_DiagTable* diag_table)
  989. {
  990.    if (diag_table) {
  991.       sfree(diag_table->diag_array);
  992.       sfree(diag_table);
  993.    }
  994.    return NULL;
  995. }
  996. /** Deallocate memory for the stack table structure */
  997. static MB_StackTable* MBStackTableFree(MB_StackTable* stack_table)
  998. {
  999.    Int4 index;
  1000.    if (!stack_table)
  1001.       return NULL;
  1002.    for (index = 0; index < stack_table->num_stacks; ++index)
  1003.       sfree(stack_table->estack[index]);
  1004.    sfree(stack_table->estack);
  1005.    sfree(stack_table->stack_index);
  1006.    sfree(stack_table->stack_size);
  1007.    sfree(stack_table);
  1008.    return NULL;
  1009. }
  1010. Blast_ExtendWord* BlastExtendWordFree(Blast_ExtendWord* ewp)
  1011. {
  1012.    BlastDiagTableFree(ewp->diag_table);
  1013.    MBStackTableFree(ewp->stack_table);
  1014.    sfree(ewp);
  1015.    return NULL;
  1016. }
  1017. void 
  1018. BlastSaveInitHsp(BlastInitHitList* ungapped_hsps, Int4 q_start, Int4 s_start, 
  1019.    Int4 q_off, Int4 s_off, Int4 len, Int4 score)
  1020. {
  1021.   BlastUngappedData* ungapped_data = NULL;
  1022.   ungapped_data = (BlastUngappedData*) malloc(sizeof(BlastUngappedData));
  1023.   ungapped_data->q_start = q_start;
  1024.   ungapped_data->s_start = s_start;
  1025.   ungapped_data->length  = len;
  1026.   ungapped_data->score   = score;
  1027.   ungapped_data->frame   = 0;
  1028.   BLAST_SaveInitialHit(ungapped_hsps, q_off, s_off, ungapped_data);
  1029.   return;
  1030. }