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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_hits.c,v $
  4.  * PRODUCTION Revision 1000.7  2004/06/01 18:07:22  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.101
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: blast_hits.c,v 1000.7 2004/06/01 18:07:22 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_hits.c
  38.  * BLAST functions for saving hits after the (preliminary) gapped alignment
  39.  */
  40. static char const rcsid[] = 
  41.     "$Id: blast_hits.c,v 1000.7 2004/06/01 18:07:22 gouriano Exp $";
  42. #include <algo/blast/core/blast_options.h>
  43. #include <algo/blast/core/blast_extend.h>
  44. #include <algo/blast/core/blast_hits.h>
  45. #include <algo/blast/core/blast_util.h>
  46. /********************************************************************************
  47.           Functions manipulating BlastHSP's
  48. ********************************************************************************/
  49. BlastHSP* Blast_HSPFree(BlastHSP* hsp)
  50. {
  51.    if (!hsp)
  52.       return NULL;
  53.    hsp->gap_info = GapEditBlockDelete(hsp->gap_info);
  54.    sfree(hsp);
  55.    return NULL;
  56. }
  57. BlastHSP* Blast_HSPNew(void)
  58. {
  59.      BlastHSP* new_hsp = (BlastHSP*) calloc(1, sizeof(BlastHSP));
  60.      return new_hsp;
  61. }
  62. /*
  63.    Comments in blast_hits.h
  64. */
  65. Int2
  66. Blast_HSPInit(Int4 query_start, Int4 query_end, Int4 subject_start, Int4 subject_end,
  67.           Int4 query_gapped_start, Int4 subject_gapped_start, 
  68.           Int4 query_context, Int2 subject_frame, Int4 score, 
  69.           GapEditBlock* *gap_edit, BlastHSP* *ret_hsp)
  70. {
  71.    BlastHSP* new_hsp = Blast_HSPNew();
  72.    *ret_hsp = NULL;
  73.    if (new_hsp == NULL)
  74. return -1;
  75.    new_hsp->query.offset = query_start;
  76.    new_hsp->subject.offset = subject_start;
  77.    new_hsp->query.length = query_end - query_start;
  78.    new_hsp->subject.length = subject_end - subject_start;
  79.    new_hsp->query.end = query_end;
  80.    new_hsp->subject.end = subject_end;
  81.    new_hsp->query.gapped_start = query_gapped_start;
  82.    new_hsp->subject.gapped_start = subject_gapped_start;
  83.    new_hsp->context = query_context;
  84.    new_hsp->subject.frame = subject_frame;
  85.    new_hsp->score = score;
  86.    if (gap_edit && *gap_edit)
  87.    { /* If this is non-NULL transfer ownership. */
  88.         new_hsp->gap_info = *gap_edit;
  89.         *gap_edit = NULL;
  90.    }
  91.    *ret_hsp = new_hsp;
  92.    return 0;
  93. }
  94. /*
  95.  Comments in blast_hits.h
  96. */
  97. Int2
  98. Blast_HSPReset(Int4 query_start, Int4 query_end, Int4 subject_start, Int4 subject_end,
  99.           Int4 score, GapEditBlock* *gap_edit, BlastHSP* hsp)
  100. {
  101.    if (hsp == NULL)
  102.      return -1;
  103.    hsp->score = score;
  104.    hsp->query.offset = query_start;
  105.    hsp->subject.offset = subject_start;
  106.    hsp->query.length = query_end - query_start;
  107.    hsp->subject.length = subject_end - subject_start;
  108.    hsp->query.end = query_end;
  109.    hsp->subject.end = subject_end;
  110.    if (gap_edit && *gap_edit)
  111.    { /* If this is non-NULL transfer ownership. */
  112.         hsp->gap_info = *gap_edit;
  113.         *gap_edit = NULL;
  114.    }
  115.    return 0;
  116. }
  117. void Blast_HSPPHIGetEvalue(BlastHSP* hsp, BlastScoreBlk* sbp)
  118. {
  119.    double paramC;
  120.    double Lambda;
  121.    Int8 pattern_space;
  122.   
  123.    if (!hsp || !sbp)
  124.       return;
  125.    paramC = sbp->kbp[0]->paramC;
  126.    Lambda = sbp->kbp[0]->Lambda;
  127.    pattern_space = sbp->effective_search_sp;
  128.    hsp->evalue = pattern_space*paramC*(1+Lambda*hsp->score)*
  129.                     exp(-Lambda*hsp->score);
  130. }
  131. Boolean Blast_HSPReevaluateWithAmbiguities(BlastHSP* hsp, 
  132.            Uint1* query_start, Uint1* subject_start, 
  133.            const BlastHitSavingOptions* hit_options, 
  134.            const BlastScoringParameters* score_params, 
  135.            BlastQueryInfo* query_info, BlastScoreBlk* sbp)
  136. {
  137.    BlastScoringOptions *score_options = score_params->options;
  138.    Int4 sum, score, gap_open, gap_extend;
  139.    Int4** matrix;
  140.    Uint1* query,* subject;
  141.    Uint1* new_q_start,* new_s_start,* new_q_end,* new_s_end;
  142.    Int4 index;
  143.    Int2 factor = 1;
  144.    Uint1 mask = 0x0f;
  145.    GapEditScript* esp,* last_esp = NULL,* prev_esp,* first_esp = NULL;
  146.    Boolean delete_hsp;
  147.    Int8 searchsp_eff;
  148.    Int4 last_esp_num = 0;
  149.    Int4 align_length;
  150.    Blast_KarlinBlk* kbp;
  151.    Boolean gapped_calculation = score_options->gapped_calculation;
  152.    /* NB: this function is called only for BLASTn, so we know where the 
  153.       Karlin block is */
  154.    kbp = sbp->kbp_std[hsp->context];
  155.    searchsp_eff = query_info->eff_searchsp_array[hsp->context];
  156.    if (score_params->gap_open == 0 && score_params->gap_extend == 0) {
  157.       if (score_params->reward % 2 == 1) 
  158.          factor = 2;
  159.       gap_open = 0;
  160.       gap_extend = 
  161.          (score_params->reward - 2*score_params->penalty) * factor / 2;
  162.    } else {
  163.       gap_open = score_params->gap_open;
  164.       gap_extend = score_params->gap_extend;
  165.    }
  166.    matrix = sbp->matrix;
  167.    query = query_start + hsp->query.offset; 
  168.    subject = subject_start + hsp->subject.offset;
  169.    score = 0;
  170.    sum = 0;
  171.    new_q_start = new_q_end = query;
  172.    new_s_start = new_s_end = subject;
  173.    index = 0;
  174.    
  175.    if (!gapped_calculation) {
  176.       for (index = 0; index < hsp->subject.length; ++index) {
  177.          sum += factor*matrix[*query & mask][*subject];
  178.          query++;
  179.          subject++;
  180.          if (sum < 0) {
  181.             if (BLAST_KarlinStoE_simple(score, kbp, searchsp_eff)
  182.                 > hit_options->expect_value) {
  183.                /* Start from new offset */
  184.                new_q_start = query;
  185.                new_s_start = subject;
  186.                score = sum = 0;
  187.             } else {
  188.                /* Stop here */
  189.                break;
  190.             }
  191.          } else if (sum > score) {
  192.             /* Remember this point as the best scoring end point */
  193.             score = sum;
  194.             new_q_end = query;
  195.             new_s_end = subject;
  196.          }
  197.       }
  198.    } else {
  199.       esp = hsp->gap_info->esp;
  200.       prev_esp = NULL;
  201.       last_esp = first_esp = esp;
  202.       last_esp_num = 0;
  203.       
  204.       while (esp) {
  205.          if (esp->op_type == eGapAlignSub) {
  206.             sum += factor*matrix[*query & mask][*subject];
  207.             query++;
  208.             subject++;
  209.             index++;
  210.          } else if (esp->op_type == eGapAlignDel) {
  211.             sum -= gap_open + gap_extend * esp->num;
  212.             subject += esp->num;
  213.             index += esp->num;
  214.          } else if (esp->op_type == eGapAlignIns) {
  215.             sum -= gap_open + gap_extend * esp->num;
  216.             query += esp->num;
  217.             index += esp->num;
  218.          }
  219.          
  220.          if (sum < 0) {
  221.             if (BLAST_KarlinStoE_simple(score, kbp, searchsp_eff)
  222.                 > hit_options->expect_value) {
  223.                /* Start from new offset */
  224.                new_q_start = query;
  225.                new_s_start = subject;
  226.                score = sum = 0;
  227.                if (index < esp->num) {
  228.                   esp->num -= index;
  229.                   first_esp = esp;
  230.                   index = 0;
  231.                } else {
  232.                   first_esp = esp->next;
  233.                }
  234.                /* Unlink the bad part of the esp chain 
  235.                   so it can be freed later */
  236.                if (prev_esp)
  237.                   prev_esp->next = NULL;
  238.                last_esp = NULL;
  239.             } else {
  240.                /* Stop here */
  241.                break;
  242.             }
  243.          } else if (sum > score) {
  244.             /* Remember this point as the best scoring end point */
  245.             score = sum;
  246.             last_esp = esp;
  247.             last_esp_num = index;
  248.             new_q_end = query;
  249.             new_s_end = subject;
  250.          }
  251.          if (index >= esp->num) {
  252.             index = 0;
  253.             prev_esp = esp;
  254.             esp = esp->next;
  255.          }
  256.       } /* loop on edit scripts */
  257.    } /* if (gapped_calculation) */
  258.    score /= factor;
  259.    
  260.    delete_hsp = FALSE;
  261.    hsp->score = score;
  262.    hsp->evalue = 
  263.       BLAST_KarlinStoE_simple(score, kbp, searchsp_eff);
  264.    if (hsp->evalue > hit_options->expect_value) {
  265.       delete_hsp = TRUE;
  266.    } else {
  267.       hsp->query.length = new_q_end - new_q_start;
  268.       hsp->subject.length = new_s_end - new_s_start;
  269.       hsp->query.offset = new_q_start - query_start;
  270.       hsp->query.end = hsp->query.offset + hsp->query.length;
  271.       hsp->subject.offset = new_s_start - subject_start;
  272.       hsp->subject.end = hsp->subject.offset + hsp->subject.length;
  273.       if (gapped_calculation) {
  274.          /* Make corrections in edit block and free any parts that
  275.             are no longer needed */
  276.          if (first_esp != hsp->gap_info->esp) {
  277.             GapEditScriptDelete(hsp->gap_info->esp);
  278.             hsp->gap_info->esp = first_esp;
  279.          }
  280.          if (last_esp->next != NULL) {
  281.             GapEditScriptDelete(last_esp->next);
  282.             last_esp->next = NULL;
  283.          }
  284.          last_esp->num = last_esp_num;
  285.       }
  286.       Blast_HSPGetNumIdentities(query_start, subject_start, hsp, 
  287.          gapped_calculation, &hsp->num_ident, &align_length);
  288.       /* Check if this HSP passes the percent identity test */
  289.       if (((double)hsp->num_ident) / align_length * 100 < 
  290.           hit_options->percent_identity)
  291.          delete_hsp = TRUE;
  292.    }
  293.    
  294.    if (delete_hsp) { /* This HSP is now below the cutoff */
  295.       if (gapped_calculation && first_esp != NULL && 
  296.           first_esp != hsp->gap_info->esp)
  297.          GapEditScriptDelete(first_esp);
  298.    }
  299.   
  300.    return delete_hsp;
  301. Int2
  302. Blast_HSPGetNumIdentities(Uint1* query, Uint1* subject, 
  303.    BlastHSP* hsp, Boolean is_gapped, Int4* num_ident_ptr, 
  304.    Int4* align_length_ptr)
  305. {
  306.    Int4 i, num_ident, align_length, q_off, s_off;
  307.    Uint1* q,* s;
  308.    GapEditBlock* gap_info;
  309.    GapEditScript* esp;
  310.    gap_info = hsp->gap_info;
  311.    if (!gap_info && is_gapped)
  312.       return -1;
  313.    q_off = hsp->query.offset;
  314.    s_off = hsp->subject.offset;
  315.    if (!subject || !query)
  316.       return -1;
  317.    q = &query[q_off];
  318.    s = &subject[s_off];
  319.    num_ident = 0;
  320.    align_length = 0;
  321.    if (!gap_info) {
  322.       /* Ungapped case */
  323.       align_length = hsp->query.length; 
  324.       for (i=0; i<align_length; i++) {
  325.          if (*q++ == *s++)
  326.             num_ident++;
  327.       }
  328.    } else {
  329.       for (esp = gap_info->esp; esp; esp = esp->next) {
  330.          align_length += esp->num;
  331.          switch (esp->op_type) {
  332.          case eGapAlignSub:
  333.             for (i=0; i<esp->num; i++) {
  334.                if (*q++ == *s++)
  335.                   num_ident++;
  336.             }
  337.             break;
  338.          case eGapAlignDel:
  339.             s += esp->num;
  340.             break;
  341.          case eGapAlignIns:
  342.             q += esp->num;
  343.             break;
  344.          default: 
  345.             s += esp->num;
  346.             q += esp->num;
  347.             break;
  348.          }
  349.       }
  350.    }
  351.    *align_length_ptr = align_length;
  352.    *num_ident_ptr = num_ident;
  353.    return 0;
  354. }
  355. Int2
  356. Blast_HSPGetOOFNumIdentities(Uint1* query, Uint1* subject, 
  357.    BlastHSP* hsp, Uint1 program, 
  358.    Int4* num_ident_ptr, Int4* align_length_ptr)
  359. {
  360.    Int4 i, num_ident, align_length;
  361.    Uint1* q,* s;
  362.    GapEditScript* esp;
  363.    if (!hsp->gap_info || !subject || !query)
  364.       return -1;
  365.    if (program == blast_type_tblastn ||
  366.        program == blast_type_rpstblastn) {
  367.        q = &query[hsp->query.offset];
  368.        s = &subject[hsp->subject.offset];
  369.    } else {
  370.        s = &query[hsp->query.offset];
  371.        q = &subject[hsp->subject.offset];
  372.    }
  373.    num_ident = 0;
  374.    align_length = 0;
  375.    for (esp = hsp->gap_info->esp; esp; esp = esp->next) {
  376.       switch (esp->op_type) {
  377.       case eGapAlignSub: /* Substitution */
  378.          align_length += esp->num;
  379.          for (i=0; i<esp->num; i++) {
  380.             if (*q == *s)
  381.                num_ident++;
  382.             ++q;
  383.             s += CODON_LENGTH;
  384.          }
  385.          break;
  386.       case eGapAlignIns: /* Insertion */
  387.          align_length += esp->num;
  388.          s += esp->num * CODON_LENGTH;
  389.          break;
  390.       case eGapAlignDel: /* Deletion */
  391.          align_length += esp->num;
  392.          q += esp->num;
  393.          break;
  394.       case eGapAlignDel2: /* Gap of two nucleotides. */
  395.          s -= 2;
  396.          break;
  397.       case eGapAlignDel1: /* Gap of one nucleotide. */
  398.          s -= 1;
  399.          break;
  400.       case eGapAlignIns1: /* Insertion of one nucleotide. */
  401.          s += 1;
  402.          break;
  403.       case eGapAlignIns2: /* Insertion of two nucleotides. */
  404.          s += 2;
  405.          break;
  406.       default: 
  407.          s += esp->num * CODON_LENGTH;
  408.          q += esp->num;
  409.          break;
  410.       }
  411.    }
  412.    *align_length_ptr = align_length;
  413.    *num_ident_ptr = num_ident;
  414.    return 0;
  415. }
  416. /** TRUE if c is between a and b; f between d and f. Determines if the
  417.  * coordinates are already in an HSP that has been evaluated. 
  418.  */
  419. #define CONTAINED_IN_HSP(a,b,c,d,e,f) (((a <= c && b >= c) && (d <= f && e >= f)) ? TRUE : FALSE)
  420. /** Checks if the first HSP is contained in the second. */
  421. static Boolean Blast_HSPContained(BlastHSP* hsp1, BlastHSP* hsp2)
  422. {
  423.    Boolean hsp_start_is_contained=FALSE, hsp_end_is_contained=FALSE;
  424.    if (hsp1->score > hsp2->score)
  425.       return FALSE;
  426.    if (CONTAINED_IN_HSP(hsp2->query.offset, hsp2->query.end, hsp1->query.offset, hsp2->subject.offset, hsp2->subject.end, hsp1->subject.offset) == TRUE) {
  427.       hsp_start_is_contained = TRUE;
  428.    }
  429.    if (CONTAINED_IN_HSP(hsp2->query.offset, hsp2->query.end, hsp1->query.end, hsp2->subject.offset, hsp2->subject.end, hsp1->subject.end) == TRUE) {
  430.       hsp_end_is_contained = TRUE;
  431.    }
  432.    
  433.    return (hsp_start_is_contained && hsp_end_is_contained);
  434. }
  435. /** Comparison callback function for sorting HSPs by score */
  436. static int
  437. score_compare_hsps(const void* v1, const void* v2)
  438. {
  439.    BlastHSP* h1,* h2;
  440.    
  441.    h1 = *((BlastHSP**) v1);
  442.    h2 = *((BlastHSP**) v2);
  443.    /* No need to check e-values, because for the same subject sequence e-value
  444.       is always inverse proportional to score. However e-values are less 
  445.       sensitive, since they both can be 0, when scores are large but 
  446.       different. */
  447.    if (h1->score > h2->score)
  448.       return -1;
  449.    else if (h1->score < h2->score)
  450.       return 1;
  451.    /* Tie-breakers: decreasing subject offsets; decreasing subject ends, 
  452.       decreasing query offsets, decreasing query ends */
  453.    else if (h1->subject.offset > h2->subject.offset)
  454.       return -1;
  455.    else if (h1->subject.offset < h2->subject.offset)
  456.       return 1;
  457.    else if (h1->subject.end > h2->subject.end)
  458.       return -1;
  459.    else if (h1->subject.end < h2->subject.end)
  460.       return 1;
  461.    else if (h1->query.offset > h2->query.offset)
  462.       return -1;
  463.    else if (h1->query.offset < h2->query.offset)
  464.       return 1;
  465.    else if (h1->query.end > h2->query.end)
  466.       return -1;
  467.    else if (h1->query.end < h2->query.end)
  468.       return 1;
  469.    return 0;
  470. }
  471. #define FUZZY_EVALUE_COMPARE_FACTOR 1e-6
  472. /** Compares 2 real numbers up to a fixed precision */
  473. static int fuzzy_evalue_comp(double evalue1, double evalue2)
  474. {
  475.    if (evalue1 < (1-FUZZY_EVALUE_COMPARE_FACTOR)*evalue2)
  476.       return -1;
  477.    else if (evalue1 > (1+FUZZY_EVALUE_COMPARE_FACTOR)*evalue2)
  478.       return 1;
  479.    else 
  480.       return 0;
  481. }
  482. /** Comparison callback function for sorting HSPs by e-value and score, before
  483.     saving BlastHSPList in a BlastHitList. E-value has priority over score, 
  484.     because lower scoring HSPs might have lower e-values, if they are linked
  485.     with sum statistics.
  486.     E-values are compared only up to a certain precision. */
  487. static int
  488. evalue_compare_hsps(const void* v1, const void* v2)
  489. {
  490.    BlastHSP* h1,* h2;
  491.    int retval = 0;
  492.    h1 = *((BlastHSP**) v1);
  493.    h2 = *((BlastHSP**) v2);
  494.    
  495.    if ((retval = fuzzy_evalue_comp(h1->evalue, h2->evalue)) != 0)
  496.       return retval;
  497.    return score_compare_hsps(v1, v2);
  498. }
  499. /** Comparison callback function for sorting HSPs by diagonal and flagging
  500.  * the HSPs contained in or identical to other HSPs for future deletion.
  501. */
  502. static int
  503. diag_uniq_compare_hsps(const void* v1, const void* v2)
  504. {
  505.    BlastHSP* h1,* h2;
  506.    BlastHSP** hp1,** hp2;
  507.    
  508.    hp1 = (BlastHSP**) v1;
  509.    hp2 = (BlastHSP**) v2;
  510.    h1 = *hp1;
  511.    h2 = *hp2;
  512.    
  513.    if (h1==NULL && h2==NULL) return 0;
  514.    else if (h1==NULL) return 1;
  515.    else if (h2==NULL) return -1;
  516.    
  517.    /* Separate different queries and/or strands */
  518.    if (h1->context < h2->context)
  519.       return -1;
  520.    else if (h1->context > h2->context)
  521.       return 1;
  522.    
  523.    /* Check if one HSP is contained in the other, if so, 
  524.       leave only the longer one, given it has lower evalue */
  525.    if (h1->query.offset >= h2->query.offset && 
  526.        h1->query.end <= h2->query.end &&  
  527.        h1->subject.offset >= h2->subject.offset && 
  528.        h1->subject.end <= h2->subject.end && 
  529.        h1->score <= h2->score) { 
  530.       (*hp1)->score = 0;
  531.    } else if (h1->query.offset <= h2->query.offset &&  
  532.               h1->query.end >= h2->query.end &&  
  533.               h1->subject.offset <= h2->subject.offset && 
  534.               h1->subject.end >= h2->subject.end && 
  535.               h1->score >= h2->score) { 
  536.       (*hp2)->score = 0;
  537.    }
  538.    
  539.    return (h1->query.offset - h1->subject.offset) -
  540.       (h2->query.offset - h2->subject.offset);
  541. }
  542. static int
  543. null_compare_hsps(const void* v1, const void* v2)
  544. {
  545.    BlastHSP* h1,* h2;
  546.    
  547.    h1 = *((BlastHSP**) v1);
  548.    h2 = *((BlastHSP**) v2);
  549.    
  550.    if ((h1 && h2) || (!h1 && !h2))
  551.       return 0;
  552.    else if (!h1) return 1;
  553.    else return -1;
  554. }
  555. /** Comparison callback for sorting HSPs by diagonal. Do not compare
  556.  * diagonals for HSPs from different contexts. The absolute value of the
  557.  * return is the diagonal difference between the HSPs.
  558.  */
  559. static int
  560. diag_compare_hsps(const void* v1, const void* v2)
  561. {
  562.    BlastHSP* h1,* h2;
  563.    h1 = *((BlastHSP**) v1);
  564.    h2 = *((BlastHSP**) v2);
  565.    
  566.    if (h1->context < h2->context)
  567.       return INT4_MIN;
  568.    else if (h1->context > h2->context)
  569.       return INT4_MAX;
  570.    return (h1->query.offset - h1->subject.offset) - 
  571.       (h2->query.offset - h2->subject.offset);
  572. }
  573. /** An auxiliary structure used for merging HSPs */
  574. typedef struct BlastHSPSegment {
  575.    Int4 q_start, q_end;
  576.    Int4 s_start, s_end;
  577.    struct BlastHSPSegment* next;
  578. } BlastHSPSegment;
  579. #define OVERLAP_DIAG_CLOSE 10
  580. /** Merge the two HSPs if they intersect.
  581.  * @param hsp1 The first HSP; also contains the result of merge. [in] [out]
  582.  * @param hsp2 The second HSP [in]
  583.  * @param start The starting offset of the subject coordinates where the 
  584.  *               intersection is possible [in]
  585. */
  586. static Boolean
  587. Blast_HSPsMerge(BlastHSP* hsp1, BlastHSP* hsp2, Int4 start)
  588. {
  589.    BlastHSPSegment* segments1,* segments2,* new_segment1,* new_segment2;
  590.    GapEditScript* esp1,* esp2,* esp;
  591.    Int4 end = start + DBSEQ_CHUNK_OVERLAP - 1;
  592.    Int4 min_diag, max_diag, num1, num2, dist = 0, next_dist = 0;
  593.    Int4 diag1_start, diag1_end, diag2_start, diag2_end;
  594.    Int4 index;
  595.    Uint1 intersection_found;
  596.    EGapAlignOpType op_type = eGapAlignSub;
  597.    if (!hsp1->gap_info || !hsp2->gap_info) {
  598.       /* Assume that this is an ungapped alignment, hence simply compare 
  599.          diagonals. Do not merge if they are on different diagonals */
  600.       if (diag_compare_hsps(&hsp1, &hsp2) == 0 &&
  601.           hsp1->query.end >= hsp2->query.offset) {
  602.          hsp1->query.end = hsp2->query.end;
  603.          hsp1->subject.end = hsp2->subject.end;
  604.          hsp1->query.length = hsp1->query.end - hsp1->query.offset;
  605.          hsp1->subject.length = hsp1->subject.end - hsp1->subject.offset;
  606.          return TRUE;
  607.       } else
  608.          return FALSE;
  609.    }
  610.    /* Find whether these HSPs have an intersection point */
  611.    segments1 = (BlastHSPSegment*) calloc(1, sizeof(BlastHSPSegment));
  612.    
  613.    esp1 = hsp1->gap_info->esp;
  614.    esp2 = hsp2->gap_info->esp;
  615.    
  616.    segments1->q_start = hsp1->query.offset;
  617.    segments1->s_start = hsp1->subject.offset;
  618.    while (segments1->s_start < start) {
  619.       if (esp1->op_type == eGapAlignIns)
  620.          segments1->q_start += esp1->num;
  621.       else if (segments1->s_start + esp1->num < start) {
  622.          if (esp1->op_type == eGapAlignSub) { 
  623.             segments1->s_start += esp1->num;
  624.             segments1->q_start += esp1->num;
  625.          } else if (esp1->op_type == eGapAlignDel)
  626.             segments1->s_start += esp1->num;
  627.       } else 
  628.          break;
  629.       esp1 = esp1->next;
  630.    }
  631.    /* Current esp is the first segment within the overlap region */
  632.    segments1->s_end = segments1->s_start + esp1->num - 1;
  633.    if (esp1->op_type == eGapAlignSub)
  634.       segments1->q_end = segments1->q_start + esp1->num - 1;
  635.    else
  636.       segments1->q_end = segments1->q_start;
  637.    
  638.    new_segment1 = segments1;
  639.    
  640.    for (esp = esp1->next; esp; esp = esp->next) {
  641.       new_segment1->next = (BlastHSPSegment*)
  642.          calloc(1, sizeof(BlastHSPSegment));
  643.       new_segment1->next->q_start = new_segment1->q_end + 1;
  644.       new_segment1->next->s_start = new_segment1->s_end + 1;
  645.       new_segment1 = new_segment1->next;
  646.       if (esp->op_type == eGapAlignSub) {
  647.          new_segment1->q_end += esp->num - 1;
  648.          new_segment1->s_end += esp->num - 1;
  649.       } else if (esp->op_type == eGapAlignIns) {
  650.          new_segment1->q_end += esp->num - 1;
  651.          new_segment1->s_end = new_segment1->s_start;
  652.       } else {
  653.          new_segment1->s_end += esp->num - 1;
  654.          new_segment1->q_end = new_segment1->q_start;
  655.       }
  656.    }
  657.    
  658.    /* Now create the second segments list */
  659.    
  660.    segments2 = (BlastHSPSegment*) calloc(1, sizeof(BlastHSPSegment));
  661.    segments2->q_start = hsp2->query.offset;
  662.    segments2->s_start = hsp2->subject.offset;
  663.    segments2->q_end = segments2->q_start + esp2->num - 1;
  664.    segments2->s_end = segments2->s_start + esp2->num - 1;
  665.    
  666.    new_segment2 = segments2;
  667.    
  668.    for (esp = esp2->next; esp && new_segment2->s_end < end; 
  669.         esp = esp->next) {
  670.       new_segment2->next = (BlastHSPSegment*)
  671.          calloc(1, sizeof(BlastHSPSegment));
  672.       new_segment2->next->q_start = new_segment2->q_end + 1;
  673.       new_segment2->next->s_start = new_segment2->s_end + 1;
  674.       new_segment2 = new_segment2->next;
  675.       if (esp->op_type == eGapAlignIns) {
  676.          new_segment2->s_end = new_segment2->s_start;
  677.          new_segment2->q_end = new_segment2->q_start + esp->num - 1;
  678.       } else if (esp->op_type == eGapAlignDel) {
  679.          new_segment2->s_end = new_segment2->s_start + esp->num - 1;
  680.          new_segment2->q_end = new_segment2->q_start;
  681.       } else if (esp->op_type == eGapAlignSub) {
  682.          new_segment2->s_end = new_segment2->s_start + esp->num - 1;
  683.          new_segment2->q_end = new_segment2->q_start + esp->num - 1;
  684.       }
  685.    }
  686.    
  687.    new_segment1 = segments1;
  688.    new_segment2 = segments2;
  689.    intersection_found = 0;
  690.    num1 = num2 = 0;
  691.    while (new_segment1 && new_segment2 && !intersection_found) {
  692.       if (new_segment1->s_end < new_segment2->s_start || 
  693.           new_segment1->q_end < new_segment2->q_start) {
  694.          new_segment1 = new_segment1->next;
  695.          num1++;
  696.          continue;
  697.       }
  698.       if (new_segment2->s_end < new_segment1->s_start || 
  699.           new_segment2->q_end < new_segment1->q_start) {
  700.          new_segment2 = new_segment2->next;
  701.          num2++;
  702.          continue;
  703.       }
  704.       diag1_start = new_segment1->s_start - new_segment1->q_start;
  705.       diag2_start = new_segment2->s_start - new_segment2->q_start;
  706.       diag1_end = new_segment1->s_end - new_segment1->q_end;
  707.       diag2_end = new_segment2->s_end - new_segment2->q_end;
  708.       
  709.       if (diag1_start == diag1_end && diag2_start == diag2_end &&  
  710.           diag1_start == diag2_start) {
  711.          /* Both segments substitutions, on same diagonal */
  712.          intersection_found = 1;
  713.          dist = new_segment2->s_end - new_segment1->s_start + 1;
  714.          break;
  715.       } else if (diag1_start != diag1_end && diag2_start != diag2_end) {
  716.          /* Both segments gaps - must intersect */
  717.          intersection_found = 3;
  718.          op_type = eGapAlignIns;
  719.          dist = new_segment2->s_end - new_segment1->s_start + 1;
  720.          next_dist = new_segment2->q_end - new_segment1->q_start - dist + 1;
  721.          if (new_segment2->q_end - new_segment1->q_start < dist) {
  722.             dist = new_segment2->q_end - new_segment1->q_start + 1;
  723.             op_type = eGapAlignDel;
  724.             next_dist = new_segment2->s_end - new_segment1->s_start - dist + 1;
  725.          }
  726.          break;
  727.       } else if (diag1_start != diag1_end) {
  728.          max_diag = MAX(diag1_start, diag1_end);
  729.          min_diag = MIN(diag1_start, diag1_end);
  730.          if (diag2_start >= min_diag && diag2_start <= max_diag) {
  731.             intersection_found = 2;
  732.             dist = diag2_start - min_diag + 1;
  733.             if (new_segment1->s_end == new_segment1->s_start)
  734.                next_dist = new_segment2->s_end - new_segment1->s_end + 1;
  735.             else
  736.                next_dist = new_segment2->q_end - new_segment1->q_end + 1;
  737.             break;
  738.          }
  739.       } else if (diag2_start != diag2_end) {
  740.          max_diag = MAX(diag2_start, diag2_end);
  741.          min_diag = MIN(diag2_start, diag2_end);
  742.          if (diag1_start >= min_diag && diag1_start <= max_diag) {
  743.             intersection_found = 2;
  744.             next_dist = max_diag - diag1_start + 1;
  745.             if (new_segment2->s_end == new_segment2->s_start)
  746.                dist = new_segment2->s_start - new_segment1->s_start + 1;
  747.             else
  748.                dist = new_segment2->q_start - new_segment1->q_start + 1;
  749.             break;
  750.          }
  751.       }
  752.       if (new_segment1->s_end <= new_segment2->s_end) {
  753.          new_segment1 = new_segment1->next;
  754.          num1++;
  755.       } else {
  756.          new_segment2 = new_segment2->next;
  757.          num2++;
  758.       }
  759.    }
  760.    
  761.    sfree(segments1);
  762.    sfree(segments2);
  763.    if (intersection_found) {
  764.       esp = NULL;
  765.       for (index = 0; index < num1-1; index++)
  766.          esp1 = esp1->next;
  767.       for (index = 0; index < num2-1; index++) {
  768.          esp = esp2;
  769.          esp2 = esp2->next;
  770.       }
  771.       if (intersection_found < 3) {
  772.          if (num1 > 0)
  773.             esp1 = esp1->next;
  774.          if (num2 > 0) {
  775.             esp = esp2;
  776.             esp2 = esp2->next;
  777.          }
  778.       }
  779.       switch (intersection_found) {
  780.       case 1:
  781.          esp1->num = dist;
  782.          esp1->next = esp2->next;
  783.          esp2->next = NULL;
  784.          break;
  785.       case 2:
  786.          esp1->num = dist;
  787.          esp2->num = next_dist;
  788.          esp1->next = esp2;
  789.          if (esp)
  790.             esp->next = NULL;
  791.          break;
  792.       case 3:
  793.          esp1->num += dist;
  794.          esp2->op_type = op_type;
  795.          esp2->num = next_dist;
  796.          esp1->next = esp2;
  797.          if (esp)
  798.             esp->next = NULL;
  799.          break;
  800.       default: break;
  801.       }
  802.       hsp1->query.end = hsp2->query.end;
  803.       hsp1->subject.end = hsp2->subject.end;
  804.       hsp1->query.length = hsp1->query.end - hsp1->query.offset;
  805.       hsp1->subject.length = hsp1->subject.end - hsp1->subject.offset;
  806.    }
  807.    return (Boolean) intersection_found;
  808. }
  809. /********************************************************************************
  810.           Functions manipulating BlastHSPList's
  811. ********************************************************************************/
  812. BlastHSPList* Blast_HSPListFree(BlastHSPList* hsp_list)
  813. {
  814.    Int4 index;
  815.    if (!hsp_list)
  816.       return hsp_list;
  817.    for (index = 0; index < hsp_list->hspcnt; ++index) {
  818.       Blast_HSPFree(hsp_list->hsp_array[index]);
  819.    }
  820.    sfree(hsp_list->hsp_array);
  821.    sfree(hsp_list);
  822.    return NULL;
  823. }
  824. BlastHSPList* Blast_HSPListNew(Int4 hsp_max)
  825. {
  826.    BlastHSPList* hsp_list = (BlastHSPList*) calloc(1, sizeof(BlastHSPList));
  827.    const Int4 k_default_allocated=100;
  828.    /* hsp_max is max number of HSP's ever allowed, INT4_MAX taken as infinity. */
  829.    hsp_list->hsp_max = INT4_MAX; 
  830.    if (hsp_max > 0)
  831.       hsp_list->hsp_max = hsp_max;
  832.    hsp_list->allocated = MIN(k_default_allocated, hsp_list->hsp_max);
  833.    hsp_list->hsp_array = (BlastHSP**) 
  834.       calloc(hsp_list->allocated, sizeof(BlastHSP*));
  835.    return hsp_list;
  836. }
  837. /** Duplicate HSPList's contents, copying only pointers to individual HSPs */
  838. static BlastHSPList* Blast_HSPListDup(BlastHSPList* hsp_list)
  839. {
  840.    BlastHSPList* new_hsp_list = (BlastHSPList*) 
  841.       BlastMemDup(hsp_list, sizeof(BlastHSPList));
  842.    new_hsp_list->hsp_array = (BlastHSP**) 
  843.       BlastMemDup(hsp_list->hsp_array, hsp_list->allocated*sizeof(BlastHSP*));
  844.    new_hsp_list->allocated = hsp_list->allocated;
  845.    return new_hsp_list;
  846. }
  847. /* Comments in blast_hits.h
  848.  */
  849. Int2 
  850. Blast_HSPListSaveHSP(BlastHSPList* hsp_list, BlastHSP* new_hsp)
  851. {
  852.    BlastHSP** hsp_array;
  853.    Int4 highscore, lowscore, score = 0;
  854.    Int4 hspcnt, new_index, old_index;
  855.    Int4 hsp_allocated; /* how many hsps are in the array. */
  856.    hspcnt = hsp_list->hspcnt;
  857.    hsp_allocated = hsp_list->allocated;
  858.    
  859.    /* Check if list is already full, then reallocate. */
  860.    if (hspcnt >= hsp_allocated-1 && hsp_list->do_not_reallocate == FALSE)
  861.    {
  862.       Int4 new_allocated = MIN(2*hsp_list->allocated, hsp_list->hsp_max);
  863.       if (new_allocated <= hsp_list->hsp_max) {
  864.          hsp_array = (BlastHSP**)
  865.             realloc(hsp_list->hsp_array, new_allocated*sizeof(BlastHSP*));
  866.          if (hsp_array == NULL)
  867.          {
  868. #ifdef ERR_POST_EX_DEFINED
  869.             ErrPostEx(SEV_WARNING, 0, 0, 
  870.                "UNABLE to reallocate in Blast_SaveHsp,"
  871.                " continuing with fixed array of %ld HSP's", 
  872.                       (long) hsp_allocated);
  873. #endif
  874.             hsp_list->do_not_reallocate = TRUE; 
  875.          } else {
  876.             hsp_list->hsp_array = hsp_array;
  877.             hsp_list->allocated = new_allocated;
  878.             hsp_allocated = new_allocated;
  879.          }
  880.       } else {
  881.          hsp_list->do_not_reallocate = TRUE; 
  882.       }
  883.    }
  884.    hsp_array = hsp_list->hsp_array;
  885.    /* If we are saving ALL HSP's, simply save and sort later. */
  886.    if (hsp_list->do_not_reallocate == FALSE)
  887.    {
  888.       hsp_array[hsp_list->hspcnt] = new_hsp;
  889.       (hsp_list->hspcnt)++;
  890.       return 0;
  891.    }
  892.    /* Use a binary search to insert the HSP. */
  893.    score = new_hsp->score;
  894.     
  895.    if (hspcnt != 0) {
  896.       highscore = hsp_array[0]->score;
  897.       lowscore = hsp_array[hspcnt-1]->score;
  898.    } else {
  899.       highscore = 0;
  900.       lowscore = 0;
  901.    }
  902.    if (score >= highscore) {
  903.       new_index = 0;
  904.    } else if (score <= lowscore) {
  905.       new_index = hspcnt;
  906.    } else {
  907.       const Int4 k_MaxIter=30;
  908.       Int4 index;
  909.       Int4 low_index = 0;
  910.       Int4 high_index = hspcnt-1;
  911.       new_index = (low_index+high_index)/2;
  912.       old_index = new_index;
  913.       
  914.       for (index=0; index<k_MaxIter; index++)
  915.       {
  916.          if (score > hsp_array[new_index]->score)
  917.             high_index = new_index;
  918.          else
  919.             low_index = new_index;
  920.          new_index = (low_index+high_index)/2;
  921.          if (new_index == old_index) { 
  922.             /* Perform this check as new_index get rounded DOWN above.*/
  923.             if (score < hsp_array[new_index]->score)
  924.                new_index++;
  925.             break;
  926.          }
  927.          old_index = new_index;
  928.       }
  929.    }
  930.    if (hspcnt >= hsp_allocated-1) {
  931.       if (new_index >= hspcnt) { 
  932.          /* this HSP is less significant than others on a full list.*/
  933.          sfree(new_hsp);
  934.          return 0;
  935.       } else { /* Delete the last HSP on the list. */
  936.          hspcnt = hsp_list->hspcnt--;
  937.          sfree(hsp_array[hspcnt-1]);
  938.       }
  939.    }
  940.    hsp_list->hspcnt++;
  941.    memmove((hsp_array+new_index+1), (hsp_array+new_index), (hspcnt-new_index)*sizeof(hsp_array[0]));
  942.    hsp_array[new_index] = new_hsp;
  943.    
  944.    return 0;
  945. }
  946. void 
  947. Blast_HSPListSetFrames(Uint1 program_number, BlastHSPList* hsp_list, 
  948.                  Boolean is_ooframe)
  949. {
  950.    BlastHSP* hsp;
  951.    Int4 index;
  952.    if (!hsp_list)
  953.       return;
  954.    for (index=0; index<hsp_list->hspcnt; index++) {
  955.       hsp = hsp_list->hsp_array[index];
  956.       if (is_ooframe && program_number == blast_type_blastx) {
  957.          /* Query offset is in mixed-frame coordinates */
  958.          hsp->query.frame = hsp->query.offset % CODON_LENGTH + 1;
  959.          if ((hsp->context % NUM_FRAMES) >= CODON_LENGTH)
  960.             hsp->query.frame = -hsp->query.frame;
  961.       } else {
  962.          hsp->query.frame = BLAST_ContextToFrame(program_number, hsp->context);
  963.       }
  964.       
  965.       /* Correct offsets in the edit block too */
  966.       if (hsp->gap_info) {
  967.          hsp->gap_info->frame1 = hsp->query.frame;
  968.          hsp->gap_info->frame2 = hsp->subject.frame;
  969.       }
  970.    }
  971. }
  972. Int2 Blast_HSPListGetEvalues(Uint1 program, BlastQueryInfo* query_info,
  973.         BlastHSPList* hsp_list, Boolean gapped_calculation, 
  974.         BlastScoreBlk* sbp)
  975. {
  976.    BlastHSP* hsp;
  977.    BlastHSP** hsp_array;
  978.    Blast_KarlinBlk** kbp;
  979.    Int4 hsp_cnt;
  980.    Int4 index;
  981.    
  982.    if (hsp_list == NULL)
  983.       return 1;
  984.    
  985.    if (gapped_calculation)
  986.       kbp = sbp->kbp_gap_std;
  987.    else
  988.       kbp = sbp->kbp_std;
  989.    
  990.    hsp_cnt = hsp_list->hspcnt;
  991.    hsp_array = hsp_list->hsp_array;
  992.    for (index=0; index<hsp_cnt; index++) {
  993.       hsp = hsp_array[index];
  994.       ASSERT(hsp != NULL);
  995.       /* Get effective search space from the score block, or from the 
  996.          query information block, in order of preference */
  997.       if (sbp->effective_search_sp) {
  998.          hsp->evalue = BLAST_KarlinStoE_simple(hsp->score, kbp[hsp->context],
  999.                           sbp->effective_search_sp);
  1000.       } else {
  1001.          hsp->evalue = 
  1002.             BLAST_KarlinStoE_simple(hsp->score, kbp[hsp->context],
  1003.                query_info->eff_searchsp_array[hsp->context]);
  1004.       }
  1005.    }
  1006.    
  1007.    return 0;
  1008. }
  1009. void Blast_HSPListPHIGetEvalues(BlastHSPList* hsp_list, BlastScoreBlk* sbp)
  1010. {
  1011.    Int4 index;
  1012.    BlastHSP* hsp;
  1013.    for (index = 0; index < hsp_list->hspcnt; ++index) {
  1014.       hsp = hsp_list->hsp_array[index];
  1015.       Blast_HSPPHIGetEvalue(hsp, sbp);
  1016.    }
  1017. }
  1018. Int2 Blast_HSPListReapByEvalue(BlastHSPList* hsp_list, 
  1019.         BlastHitSavingOptions* hit_options)
  1020. {
  1021.    BlastHSP* hsp;
  1022.    BlastHSP** hsp_array;
  1023.    Int4 hsp_cnt = 0;
  1024.    Int4 index;
  1025.    double cutoff;
  1026.    
  1027.    if (hsp_list == NULL)
  1028.       return 1;
  1029.    cutoff = hit_options->expect_value;
  1030.    hsp_array = hsp_list->hsp_array;
  1031.    for (index = 0; index < hsp_list->hspcnt; index++) {
  1032.       hsp = hsp_array[index];
  1033.       ASSERT(hsp != NULL);
  1034.       
  1035.       if (hsp->evalue > cutoff) {
  1036.          hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  1037.       } else {
  1038.          if (index > hsp_cnt)
  1039.             hsp_array[hsp_cnt] = hsp_array[index];
  1040.          hsp_cnt++;
  1041.       }
  1042.    }
  1043.       
  1044.    hsp_list->hspcnt = hsp_cnt;
  1045.    return 0;
  1046. }
  1047. /* See description in blast_hits.h */
  1048. Int2
  1049. Blast_HSPListPurgeNullHSPs(BlastHSPList* hsp_list)
  1050. {
  1051.         Int4 index, index1; /* loop indices. */
  1052.         Int4 hspcnt; /* total number of HSP's to iterate over. */
  1053.         BlastHSP** hsp_array;  /* hsp_array to purge. */
  1054. if (hsp_list == NULL || hsp_list->hspcnt == 0)
  1055. return 0;
  1056.         hsp_array = hsp_list->hsp_array;
  1057.         hspcnt = hsp_list->hspcnt;
  1058. index1 = 0;
  1059. for (index=0; index<hspcnt; index++)
  1060. {
  1061. if (hsp_array[index] != NULL)
  1062. {
  1063. hsp_array[index1] = hsp_array[index];
  1064. index1++;
  1065. }
  1066. }
  1067. for (index=index1; index<hspcnt; index++)
  1068. {
  1069. hsp_array[index] = NULL;
  1070. }
  1071. hsp_list->hspcnt = index1;
  1072.         return 0;
  1073. }
  1074. /** Are the two HSPs within a given diagonal distance of each other? */
  1075. #define MB_HSP_CLOSE(q1, q2, s1, s2, c) (ABS(((q1)-(s1)) - ((q2)-(s2))) < (c))
  1076. #define MIN_DIAG_DIST 60
  1077. /** Sort the HSPs in an HSP list by diagonal and remove redundant HSPs */
  1078. static Int2
  1079. Blast_HSPListUniqSort(BlastHSPList* hsp_list)
  1080. {
  1081.    Int4 index, new_hspcnt, index1, q_off, s_off, q_end, s_end, index2;
  1082.    BlastHSP** hsp_array = hsp_list->hsp_array;
  1083.    Boolean shift_needed = FALSE;
  1084.    Int4 context;
  1085.    double evalue;
  1086.    qsort(hsp_array, hsp_list->hspcnt, sizeof(BlastHSP*), 
  1087.          diag_uniq_compare_hsps);
  1088.    /* Delete all HSPs that were flagged in qsort */
  1089.    for (index = 0; index < hsp_list->hspcnt; ++index) {
  1090.       if (hsp_array[index]->score == 0) {
  1091.          hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  1092.       }
  1093.    }      
  1094.    /* Move all nulled out HSPs to the end */
  1095.    qsort(hsp_array, hsp_list->hspcnt, sizeof(BlastHSP*),
  1096.          null_compare_hsps);
  1097.    for (index=1, new_hspcnt=0; index<hsp_list->hspcnt; index++) {
  1098.       if (!hsp_array[index])
  1099.          break;
  1100.       q_off = hsp_array[index]->query.offset;
  1101.       s_off = hsp_array[index]->subject.offset;
  1102.       q_end = hsp_array[index]->query.end;
  1103.       s_end = hsp_array[index]->subject.end;
  1104.       evalue = hsp_array[index]->evalue;
  1105.       context = hsp_array[index]->context;
  1106.       for (index1 = new_hspcnt; index1 >= 0 && 
  1107.            hsp_array[index1]->context == context && new_hspcnt-index1 < 10 && 
  1108.            MB_HSP_CLOSE(q_off, hsp_array[index1]->query.offset,
  1109.                         s_off, hsp_array[index1]->subject.offset, 
  1110.                         MIN_DIAG_DIST);
  1111.            index1--) {
  1112.          if (q_off >= hsp_array[index1]->query.offset && 
  1113.              s_off >= hsp_array[index1]->subject.offset && 
  1114.              q_end <= hsp_array[index1]->query.end && 
  1115.              s_end <= hsp_array[index1]->subject.end &&
  1116.              evalue >= hsp_array[index1]->evalue) {
  1117.             hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  1118.             break;
  1119.          } else if (q_off <= hsp_array[index1]->query.offset && 
  1120.              s_off <= hsp_array[index1]->subject.offset && 
  1121.              q_end >= hsp_array[index1]->query.end && 
  1122.              s_end >= hsp_array[index1]->subject.end &&
  1123.              evalue <= hsp_array[index1]->evalue) {
  1124.             hsp_array[index1] = Blast_HSPFree(hsp_array[index1]);
  1125.             shift_needed = TRUE;
  1126.          }
  1127.       }
  1128.       
  1129.       /* If some lower indexed HSPs have been removed, shift the subsequent 
  1130.          HSPs */
  1131.       if (shift_needed) {
  1132.          /* Find the first non-NULL HSP, going backwards */
  1133.          while (index1 >= 0 && !hsp_array[index1])
  1134.             index1--;
  1135.          /* Go forward, and shift any non-NULL HSPs */
  1136.          for (index2 = ++index1; index1 <= new_hspcnt; index1++) {
  1137.             if (hsp_array[index1])
  1138.                hsp_array[index2++] = hsp_array[index1];
  1139.          }
  1140.          new_hspcnt = index2 - 1;
  1141.          shift_needed = FALSE;
  1142.       }
  1143.       if (hsp_array[index] != NULL)
  1144.          hsp_array[++new_hspcnt] = hsp_array[index];
  1145.    }
  1146.    /* Set all HSP pointers that will not be used any more to NULL */
  1147.    memset(&hsp_array[new_hspcnt+1], 0, 
  1148.   (hsp_list->hspcnt - new_hspcnt - 1)*sizeof(BlastHSP*));
  1149.    hsp_list->hspcnt = new_hspcnt + 1;
  1150.    return 0;
  1151. }
  1152. Int2 
  1153. Blast_HSPListReevaluateWithAmbiguities(BlastHSPList* hsp_list,
  1154.    BLAST_SequenceBlk* query_blk, BLAST_SequenceBlk* subject_blk, 
  1155.    const BlastHitSavingOptions* hit_options, BlastQueryInfo* query_info, 
  1156.    BlastScoreBlk* sbp, const BlastScoringParameters* score_params, 
  1157.    const BlastSeqSrc* seq_src)
  1158. {
  1159.    BlastHSP** hsp_array,* hsp;
  1160.    Uint1* query_start,* subject_start = NULL;
  1161.    Int4 index, context, hspcnt;
  1162.    Boolean purge, delete_hsp;
  1163.    Int2 status = 0;
  1164.    GetSeqArg seq_arg;
  1165.    Boolean gapped_calculation = score_params->options->gapped_calculation;
  1166.    if (!hsp_list)
  1167.       return status;
  1168.    hspcnt = hsp_list->hspcnt;
  1169.    hsp_array = hsp_list->hsp_array;
  1170.    memset((void*) &seq_arg, 0, sizeof(seq_arg));
  1171.    /* In case of no traceback, return without doing anything */
  1172.    if (!hsp_list->traceback_done && gapped_calculation) {
  1173.       if (hsp_list->hspcnt > 1)
  1174.          status = Blast_HSPListUniqSort(hsp_list);
  1175.       return status;
  1176.    }
  1177.    if (hsp_list->hspcnt == 0)
  1178.       /* All HSPs have been deleted */
  1179.       return status;
  1180.    /* Retrieve the unpacked subject sequence and save it in the 
  1181.       sequence_start element of the subject structure.
  1182.       NB: for the BLAST 2 Sequences case, the uncompressed sequence must 
  1183.       already be there */
  1184.    if (seq_src) {
  1185.       seq_arg.oid = subject_blk->oid;
  1186.       seq_arg.encoding = BLASTNA_ENCODING;
  1187.       BLASTSeqSrcGetSequence(seq_src, (void*) &seq_arg);
  1188.       subject_blk->sequence_start = seq_arg.seq->sequence_start;
  1189.       subject_blk->sequence = seq_arg.seq->sequence_start + 1;
  1190.    }
  1191.    /* The sequence in blastna encoding is now stored in sequence_start */
  1192.    subject_start = subject_blk->sequence_start + 1;
  1193.    purge = FALSE;
  1194.    for (index=0; index<hspcnt; index++) {
  1195.       if (hsp_array[index] == NULL)
  1196.          continue;
  1197.       else
  1198.          hsp = hsp_array[index];
  1199.       context = hsp->context;
  1200.       query_start = query_blk->sequence + query_info->context_offsets[context];
  1201.       delete_hsp = 
  1202.          Blast_HSPReevaluateWithAmbiguities(hsp, query_start, subject_start,
  1203.             hit_options, score_params, query_info, sbp);
  1204.       
  1205.       if (delete_hsp) { /* This HSP is now below the cutoff */
  1206.          hsp_array[index] = Blast_HSPFree(hsp_array[index]);
  1207.          purge = TRUE;
  1208.       }
  1209.    }
  1210.     
  1211.    if (purge) {
  1212.       Blast_HSPListPurgeNullHSPs(hsp_list);
  1213.    }
  1214.    
  1215.    /* Check for HSP inclusion once more */
  1216.    if (hsp_list->hspcnt > 1)
  1217.       status = Blast_HSPListUniqSort(hsp_list);
  1218.    BlastSequenceBlkFree(seq_arg.seq);
  1219.    subject_blk->sequence = NULL;
  1220.    return status;
  1221. }
  1222. /** Combine two HSP lists, without altering the individual HSPs, and without 
  1223.  * reallocating the HSP array. 
  1224.  * @param hsp_list New HSP list [in]
  1225.  * @param combined_hsp_list Old HSP list, to which new HSPs are added [in] [out]
  1226.  * @param new_hspcnt How many HSPs to save in the combined list? The extra ones
  1227.  *                   are freed. The best scoring HSPs are saved. This argument
  1228.  *                   cannot be greater than the allocated size of the 
  1229.  *                   combined list's HSP array. [in]
  1230.  */
  1231. static void 
  1232. Blast_HSPListsCombineByScore(BlastHSPList* hsp_list, 
  1233.                              BlastHSPList* combined_hsp_list,
  1234.                              Int4 new_hspcnt)
  1235. {
  1236.    Int4 index, index1, index2;
  1237.    BlastHSP** new_hsp_array;
  1238.    ASSERT(new_hspcnt <= combined_hsp_list->allocated);
  1239.    if (new_hspcnt >= hsp_list->hspcnt + combined_hsp_list->hspcnt) {
  1240.       /* All HSPs from both arrays are saved */
  1241.       for (index=combined_hsp_list->hspcnt, index1=0; 
  1242.            index1<hsp_list->hspcnt; index1++) {
  1243.          if (hsp_list->hsp_array[index1] != NULL)
  1244.             combined_hsp_list->hsp_array[index++] = hsp_list->hsp_array[index1];
  1245.       }
  1246.    } else {
  1247.       /* Not all HSPs are be saved; sort both arrays by score and save only
  1248.          the new_hspcnt best ones. 
  1249.          For the merged set of HSPs, allocate array the same size as in the 
  1250.          old HSP list. */
  1251.       new_hsp_array = (BlastHSP**) 
  1252.          malloc(combined_hsp_list->allocated*sizeof(BlastHSP*));
  1253.       qsort(combined_hsp_list->hsp_array, combined_hsp_list->hspcnt, 
  1254.            sizeof(BlastHSP*), score_compare_hsps);
  1255.       qsort(hsp_list->hsp_array, hsp_list->hspcnt, sizeof(BlastHSP*),
  1256.             score_compare_hsps);
  1257.       index1 = index2 = 0;
  1258.       for (index = 0; index < new_hspcnt; ++index) {
  1259.          if (index1 < combined_hsp_list->hspcnt &&
  1260.              (index2 >= hsp_list->hspcnt ||
  1261.              (combined_hsp_list->hsp_array[index1]->score >= 
  1262.              hsp_list->hsp_array[index2]->score))) {
  1263.             new_hsp_array[index] = combined_hsp_list->hsp_array[index1];
  1264.             ++index1;
  1265.          } else {
  1266.             new_hsp_array[index] = hsp_list->hsp_array[index2];
  1267.             ++index2;
  1268.          }
  1269.       }
  1270.       /* Free the extra HSPs that could not be saved */
  1271.       for ( ; index1 < combined_hsp_list->hspcnt; ++index1) {
  1272.          combined_hsp_list->hsp_array[index1] = 
  1273.             Blast_HSPFree(combined_hsp_list->hsp_array[index1]);
  1274.       }
  1275.       for ( ; index2 < hsp_list->hspcnt; ++index2) {
  1276.          hsp_list->hsp_array[index2] = 
  1277.             Blast_HSPFree(hsp_list->hsp_array[index2]);
  1278.       }
  1279.       /* Point combined_hsp_list's HSP array to the new one */
  1280.       sfree(combined_hsp_list->hsp_array);
  1281.       combined_hsp_list->hsp_array = new_hsp_array;
  1282.    }
  1283.    
  1284.    combined_hsp_list->hspcnt = index;
  1285.    /* Second HSP list now does not own any HSPs */
  1286.    hsp_list->hspcnt = 0;
  1287. }
  1288. Int2 Blast_HSPListAppend(BlastHSPList* hsp_list,
  1289.         BlastHSPList** combined_hsp_list_ptr, Int4 hsp_num_max)
  1290. {
  1291.    BlastHSPList* combined_hsp_list = *combined_hsp_list_ptr;
  1292.    BlastHSP** new_hsp_array;
  1293.    Int4 new_hspcnt;
  1294.    if (!hsp_list || hsp_list->hspcnt == 0)
  1295.       return 0;
  1296.    /* If no previous HSP list, just return a copy of the new one. */
  1297.    if (!combined_hsp_list) {
  1298.       *combined_hsp_list_ptr = Blast_HSPListDup(hsp_list);
  1299.       hsp_list->hspcnt = 0;
  1300.       return 0;
  1301.    }
  1302.    /* Just append new list to the end of the old list, in case of 
  1303.       multiple frames of the subject sequence */
  1304.    new_hspcnt = MIN(combined_hsp_list->hspcnt + hsp_list->hspcnt, 
  1305.                     hsp_num_max);
  1306.    if (new_hspcnt > combined_hsp_list->allocated && 
  1307.        !combined_hsp_list->do_not_reallocate) {
  1308.       Int4 new_allocated = MIN(2*new_hspcnt, hsp_num_max);
  1309.       new_hsp_array = (BlastHSP**) 
  1310.          realloc(combined_hsp_list->hsp_array, 
  1311.                  new_allocated*sizeof(BlastHSP*));
  1312.       
  1313.       if (new_hsp_array) {
  1314.          combined_hsp_list->allocated = new_allocated;
  1315.          combined_hsp_list->hsp_array = new_hsp_array;
  1316.       } else {
  1317.          combined_hsp_list->do_not_reallocate = TRUE;
  1318.          new_hspcnt = combined_hsp_list->allocated;
  1319.       }
  1320.    }
  1321.    if (combined_hsp_list->allocated == hsp_num_max)
  1322.       combined_hsp_list->do_not_reallocate = TRUE;
  1323.    Blast_HSPListsCombineByScore(hsp_list, combined_hsp_list, new_hspcnt);
  1324.    return 0;
  1325. }
  1326. Int2 Blast_HSPListsMerge(BlastHSPList* hsp_list, 
  1327.                    BlastHSPList** combined_hsp_list_ptr,
  1328.                    Int4 hsp_num_max, Int4 start, Boolean merge_hsps)
  1329. {
  1330.    BlastHSPList* combined_hsp_list = *combined_hsp_list_ptr;
  1331.    BlastHSP* hsp, *hsp_var;
  1332.    BlastHSP** hspp1,** hspp2;
  1333.    Int4 index, index1;
  1334.    Int4 hspcnt1, hspcnt2, new_hspcnt = 0;
  1335.    BlastHSP** new_hsp_array;
  1336.   
  1337.    if (!hsp_list || hsp_list->hspcnt == 0)
  1338.       return 0;
  1339.    /* If no previous HSP list, just return a copy of the new one. */
  1340.    if (!combined_hsp_list) {
  1341.       *combined_hsp_list_ptr = Blast_HSPListDup(hsp_list);
  1342.       hsp_list->hspcnt = 0;
  1343.       return 0;
  1344.    }
  1345.    /* Merge the two HSP lists for successive chunks of the subject sequence */
  1346.    hspcnt1 = hspcnt2 = 0;
  1347.    /* Put all HSPs that intersect the overlap region at the front of the
  1348.       respective HSP arrays. */
  1349.    for (index = 0; index < combined_hsp_list->hspcnt; index++) {
  1350.       hsp = combined_hsp_list->hsp_array[index];
  1351.       if (hsp->subject.end > start) {
  1352.          /* At least part of this HSP lies in the overlap strip. */
  1353.          hsp_var = combined_hsp_list->hsp_array[hspcnt1];
  1354.          combined_hsp_list->hsp_array[hspcnt1] = hsp;
  1355.          combined_hsp_list->hsp_array[index] = hsp_var;
  1356.          ++hspcnt1;
  1357.       }
  1358.    }
  1359.    for (index = 0; index < hsp_list->hspcnt; index++) {
  1360.       hsp = hsp_list->hsp_array[index];
  1361.       if (hsp->subject.offset < start + DBSEQ_CHUNK_OVERLAP) {
  1362.          /* At least part of this HSP lies in the overlap strip. */
  1363.          hsp_var = hsp_list->hsp_array[hspcnt2];
  1364.          hsp_list->hsp_array[hspcnt2] = hsp;
  1365.          hsp_list->hsp_array[index] = hsp_var;
  1366.          ++hspcnt2;
  1367.       }
  1368.    }
  1369.    hspp1 = combined_hsp_list->hsp_array;
  1370.    hspp2 = hsp_list->hsp_array;
  1371.    /* Sort HSPs from in the overlap region by diagonal */
  1372.    qsort(hspp1, hspcnt1, sizeof(BlastHSP*), diag_compare_hsps);
  1373.    qsort(hspp2, hspcnt2, sizeof(BlastHSP*), diag_compare_hsps);
  1374.    for (index=0; index<hspcnt1; index++) {
  1375.       for (index1 = 0; index1<hspcnt2; index1++) {
  1376.          /* Skip already deleted HSPs */
  1377.          if (!hspp2[index1])
  1378.             continue;
  1379.          if (hspp1[index]->context == hspp2[index1]->context && 
  1380.              ABS(diag_compare_hsps(&hspp1[index], &hspp2[index1])) < 
  1381.              OVERLAP_DIAG_CLOSE) {
  1382.             if (merge_hsps) {
  1383.                if (Blast_HSPsMerge(hspp1[index], hspp2[index1], start)) {
  1384.                   /* Free the second HSP. */
  1385.                   hspp2[index1] = Blast_HSPFree(hspp2[index1]);
  1386.                }
  1387.             } else { /* No gap information available */
  1388.                if (Blast_HSPContained(hspp1[index], hspp2[index1])) {
  1389.                   sfree(hspp1[index]);
  1390.                   /* Point the first HSP to the new HSP; 
  1391.                      free the second HSP. */
  1392.                   hspp1[index] = hspp2[index1];
  1393.                   hspp2[index1] = NULL;
  1394.                   /* This HSP has been removed, so break out of the inner 
  1395.                      loop */
  1396.                   break;
  1397.                } else if (Blast_HSPContained(hspp2[index1], hspp1[index])) {
  1398.                   /* Just free the second HSP */
  1399.                   hspp2[index1] = Blast_HSPFree(hspp2[index1]);
  1400.                }
  1401.             }
  1402.          } else {
  1403.             /* This and remaining HSPs are too far from the one being 
  1404.                checked */
  1405.             break;
  1406.          }
  1407.       }
  1408.    }
  1409.    /* Purge the nulled out HSPs from the new HSP list */
  1410.       Blast_HSPListPurgeNullHSPs(hsp_list);
  1411.    /* The new number of HSPs is now the sum of the remaining counts in the 
  1412.       two lists, but if there is a restriction on the number of HSPs to keep,
  1413.       it might have to be reduced. */
  1414.    new_hspcnt = 
  1415.       MIN(hsp_list->hspcnt + combined_hsp_list->hspcnt, hsp_num_max);
  1416.    
  1417.    if (new_hspcnt >= combined_hsp_list->allocated-1 && 
  1418.        combined_hsp_list->do_not_reallocate == FALSE) {
  1419.       Int4 new_allocated = MIN(2*new_hspcnt, hsp_num_max);
  1420.       if (new_allocated > combined_hsp_list->allocated) {
  1421.          new_hsp_array = (BlastHSP**) 
  1422.             realloc(combined_hsp_list->hsp_array, 
  1423.                     new_allocated*sizeof(BlastHSP*));
  1424.          if (new_hsp_array == NULL) {
  1425.             combined_hsp_list->do_not_reallocate = TRUE; 
  1426.          } else {
  1427.             combined_hsp_list->hsp_array = new_hsp_array;
  1428.             combined_hsp_list->allocated = new_allocated;
  1429.          }
  1430.       } else {
  1431.          combined_hsp_list->do_not_reallocate = TRUE;
  1432.       }
  1433.       new_hspcnt = MIN(new_hspcnt, combined_hsp_list->allocated);
  1434.    }
  1435.    Blast_HSPListsCombineByScore(hsp_list, combined_hsp_list, new_hspcnt);
  1436.    return 0;
  1437. }
  1438. void Blast_HSPListAdjustOffsets(BlastHSPList* hsp_list, Int4 offset)
  1439. {
  1440.    Int4 index;
  1441.    BlastHSP* hsp;
  1442.    for (index=0; index<hsp_list->hspcnt; index++) {
  1443.       hsp = hsp_list->hsp_array[index];
  1444.       hsp->subject.offset += offset;
  1445.       hsp->subject.end += offset;
  1446.       hsp->subject.gapped_start += offset;
  1447.       if (hsp->gap_info)
  1448.          hsp->gap_info->start2 += offset;
  1449.    }
  1450. }
  1451. /** Callback for sorting hsp lists by their best evalue/score;
  1452.  * Evalues are compared only up to a relative error of 
  1453.  * FUZZY_EVALUE_COMPARE_FACTOR. 
  1454.  * It is assumed that the HSP arrays in each hit list are already sorted by 
  1455.  * e-value/score.
  1456. */
  1457. static int
  1458. evalue_compare_hsp_lists(const void* v1, const void* v2)
  1459. {
  1460.    BlastHSPList* h1,* h2;
  1461.    int retval = 0;
  1462.    
  1463.    h1 = *(BlastHSPList**) v1;
  1464.    h2 = *(BlastHSPList**) v2;
  1465.    
  1466.    /* If any of the HSP lists is empty, it is considered "worse" than the 
  1467.       other, unless the other is also empty. */
  1468.    if (h1->hspcnt == 0 && h2->hspcnt == 0)
  1469.       return 0;
  1470.    else if (h1->hspcnt == 0)
  1471.       return 1;
  1472.    else if (h2->hspcnt == 0)
  1473.       return -1;
  1474.    if ((retval = fuzzy_evalue_comp(h1->hsp_array[0]->evalue, 
  1475.                                    h2->hsp_array[0]->evalue)) != 0)
  1476.       return retval;
  1477.    if (h1->hsp_array[0]->score > h2->hsp_array[0]->score)
  1478.       return -1;
  1479.    if (h1->hsp_array[0]->score < h2->hsp_array[0]->score)
  1480.       return 1;
  1481.    
  1482.    /* In case of equal best E-values and scores, order will be determined
  1483.       by ordinal ids of the subject sequences */
  1484.    if (h1->oid > h2->oid)
  1485.       return -1;
  1486.    if (h1->oid < h2->oid)
  1487.       return 1;
  1488.    return 0;
  1489. }
  1490. /********************************************************************************
  1491.           Functions manipulating BlastHitList's
  1492. ********************************************************************************/
  1493. /*
  1494.    description in blast_hits.h
  1495.  */
  1496. BlastHitList* Blast_HitListNew(Int4 hitlist_size)
  1497. {
  1498.    BlastHitList* new_hitlist = (BlastHitList*) 
  1499.       calloc(1, sizeof(BlastHitList));
  1500.    new_hitlist->hsplist_max = hitlist_size;
  1501.    new_hitlist->low_score = INT4_MAX;
  1502.    return new_hitlist;
  1503. }
  1504. /*
  1505.    description in blast_hits.h
  1506. */
  1507. BlastHitList* Blast_HitListFree(BlastHitList* hitlist)
  1508. {
  1509.    if (!hitlist)
  1510.       return NULL;
  1511.    Blast_HitListHSPListsFree(hitlist);
  1512.    sfree(hitlist);
  1513.    return NULL;
  1514. }
  1515. /* description in blast_hits.h */
  1516. Int2 Blast_HitListHSPListsFree(BlastHitList* hitlist)
  1517. {
  1518.    Int4 index;
  1519.    
  1520.    if (!hitlist)
  1521. return 0;
  1522.    for (index = 0; index < hitlist->hsplist_count; ++index)
  1523.       hitlist->hsplist_array[index] =
  1524.          Blast_HSPListFree(hitlist->hsplist_array[index]);
  1525.    sfree(hitlist->hsplist_array);
  1526.    hitlist->hsplist_count = 0;
  1527.    return 0;
  1528. }
  1529. static void Blast_HitListPurge(BlastHitList* hit_list)
  1530. {
  1531.    Int4 index, hsplist_count;
  1532.    
  1533.    if (!hit_list)
  1534.       return;
  1535.    
  1536.    hsplist_count = hit_list->hsplist_count;
  1537.    for (index = 0; index < hsplist_count && 
  1538.            hit_list->hsplist_array[index]->hspcnt > 0; ++index);
  1539.    
  1540.    hit_list->hsplist_count = index;
  1541.    /* Free all empty HSP lists */
  1542.    for ( ; index < hsplist_count; ++index) {
  1543.       Blast_HSPListFree(hit_list->hsplist_array[index]);
  1544.    }
  1545. }
  1546. /** This is a copy of a static function from ncbimisc.c.
  1547.  * Turns array into a heap with respect to a given comparison function.
  1548.  */
  1549. static void
  1550. heapify (char* base0, char* base, char* lim, char* last, size_t width, int (*compar )(const void*, const void* ))
  1551. {
  1552.    size_t i;
  1553.    char   ch;
  1554.    char* left_son,* large_son;
  1555.    
  1556.    left_son = base0 + 2*(base-base0) + width;
  1557.    while (base <= lim) {
  1558.       if (left_son == last)
  1559.          large_son = left_son;
  1560.       else
  1561.          large_son = (*compar)(left_son, left_son+width) >= 0 ?
  1562.             left_son : left_son+width;
  1563.       if ((*compar)(base, large_son) < 0) {
  1564.          for (i=0; i<width; ++i) {
  1565.             ch = base[i];
  1566.             base[i] = large_son[i];
  1567.             large_son[i] = ch;
  1568.          }
  1569.          base = large_son;
  1570.          left_son = base0 + 2*(base-base0) + width;
  1571.       } else
  1572.          break;
  1573.    }
  1574. }
  1575. /** The first part of qsort: create heap only, without sorting it
  1576.  * @param b An array [in] [out]
  1577.  * @param nel Number of elements in b [in]
  1578.  * @param width The size of each element [in]
  1579.  * @param compar Callback to compare two heap elements [in]
  1580.  */
  1581. static void CreateHeap (void* b, size_t nel, size_t width, 
  1582.    int (*compar )(const void*, const void* ))   
  1583. {
  1584.    char*    base = (char*)b;
  1585.    size_t i;
  1586.    char*    base0 = (char*)base,* lim,* basef;
  1587.    
  1588.    if (nel < 2)
  1589.       return;
  1590.    
  1591.    lim = &base[((nel-2)/2)*width];
  1592.    basef = &base[(nel-1)*width];
  1593.    i = nel/2;
  1594.    for (base = &base0[(i - 1)*width]; i > 0; base = base - width) {
  1595.       heapify(base0, base, lim, basef, width, compar);
  1596.       i--;
  1597.    }
  1598. }
  1599. /** Given a BlastHitList* with a heapified HSP list array, remove
  1600.  *  the worst scoring HSP list and insert the new HSP list in the heap
  1601.  * @param hit_list Contains all HSP lists for a given query [in] [out]
  1602.  * @param hsp_list A new HSP list to be inserted into the hit list [in]
  1603.  */
  1604. static void 
  1605. Blast_HitListInsertHSPListInHeap(BlastHitList* hit_list, 
  1606.                                  BlastHSPList* hsp_list)
  1607. {
  1608.       Blast_HSPListFree(hit_list->hsplist_array[0]);
  1609.       hit_list->hsplist_array[0] = hsp_list;
  1610.       if (hit_list->hsplist_count >= 2) {
  1611.          heapify((char*)hit_list->hsplist_array, (char*)hit_list->hsplist_array, 
  1612.                  (char*)&hit_list->hsplist_array[(hit_list->hsplist_count-1)/2],
  1613.                  (char*)&hit_list->hsplist_array[hit_list->hsplist_count-1],
  1614.                  sizeof(BlastHSPList*), evalue_compare_hsp_lists);
  1615.       }
  1616.       hit_list->worst_evalue = 
  1617.          hit_list->hsplist_array[0]->hsp_array[0]->evalue;
  1618.       hit_list->low_score = hit_list->hsplist_array[0]->hsp_array[0]->score;
  1619. }
  1620. Int2 Blast_HitListUpdate(BlastHitList* hit_list, 
  1621.                                 BlastHSPList* hsp_list)
  1622. {
  1623.    if (hit_list->hsplist_count < hit_list->hsplist_max) {
  1624.       /* If the array of HSP lists for this query is not yet allocated, 
  1625.          do it here */
  1626.       if (!hit_list->hsplist_array)
  1627.          hit_list->hsplist_array = (BlastHSPList**)
  1628.             malloc(hit_list->hsplist_max*sizeof(BlastHSPList*));
  1629.       /* Just add to the end; sort later */
  1630.       hit_list->hsplist_array[hit_list->hsplist_count++] = hsp_list;
  1631.       hit_list->worst_evalue = 
  1632.          MAX(hsp_list->hsp_array[0]->evalue, hit_list->worst_evalue);
  1633.       hit_list->low_score = 
  1634.          MIN(hsp_list->hsp_array[0]->score, hit_list->low_score);
  1635.    } else {
  1636.       /* Compare e-values only with a certain precision */
  1637.       int evalue_order = fuzzy_evalue_comp(hsp_list->hsp_array[0]->evalue,
  1638.                                            hit_list->worst_evalue);
  1639.       if (evalue_order > 0 || 
  1640.           (evalue_order == 0 &&
  1641.            (hsp_list->hsp_array[0]->score < hit_list->low_score))) {
  1642.          /* This hit list is less significant than any of those already saved;
  1643.             discard it. Note that newer hits with score and e-value both equal
  1644.             to the current worst will be saved, at the expense of some older 
  1645.             hit.
  1646.          */
  1647.          Blast_HSPListFree(hsp_list);
  1648.       } else {
  1649.          if (!hit_list->heapified) {
  1650.             CreateHeap(hit_list->hsplist_array, hit_list->hsplist_count, 
  1651.                        sizeof(BlastHSPList*), evalue_compare_hsp_lists);
  1652.             hit_list->heapified = TRUE;
  1653.          }
  1654.          Blast_HitListInsertHSPListInHeap(hit_list, hsp_list);
  1655.       }
  1656.    }
  1657.    return 0;
  1658. }
  1659. /********************************************************************************
  1660.           Functions manipulating BlastHSPResults
  1661. ********************************************************************************/
  1662. Int2 Blast_HSPResultsInit(Int4 num_queries, BlastHSPResults** results_ptr)
  1663. {
  1664.    BlastHSPResults* results;
  1665.    Int2 status = 0;
  1666.    results = (BlastHSPResults*) malloc(sizeof(BlastHSPResults));
  1667.    results->num_queries = num_queries;
  1668.    results->hitlist_array = (BlastHitList**) 
  1669.       calloc(num_queries, sizeof(BlastHitList*));
  1670.    
  1671.    *results_ptr = results;
  1672.    return status;
  1673. }
  1674. BlastHSPResults* Blast_HSPResultsFree(BlastHSPResults* results)
  1675. {
  1676.    Int4 index;
  1677.    if (!results)
  1678.        return NULL;
  1679.    for (index = 0; index < results->num_queries; ++index)
  1680.       Blast_HitListFree(results->hitlist_array[index]);
  1681.    sfree(results->hitlist_array);
  1682.    sfree(results);
  1683.    return NULL;
  1684. }
  1685. Int2 Blast_HSPResultsSortByEvalue(BlastHSPResults* results)
  1686. {
  1687.    Int4 index;
  1688.    BlastHitList* hit_list;
  1689.    for (index = 0; index < results->num_queries; ++index) {
  1690.       hit_list = results->hitlist_array[index];
  1691.       if (hit_list && hit_list->hsplist_count > 1) {
  1692.          qsort(hit_list->hsplist_array, hit_list->hsplist_count, 
  1693.                   sizeof(BlastHSPList*), evalue_compare_hsp_lists);
  1694.       }
  1695.       Blast_HitListPurge(hit_list);
  1696.    }
  1697.    return 0;
  1698. }
  1699. Int2 Blast_HSPResultsSaveHitList(Uint1 program, BlastHSPResults* results, 
  1700.         BlastHSPList* hsp_list, BlastHitSavingParameters* hit_parameters)
  1701. {
  1702.    Int2 status = 0;
  1703.    BlastHSPList** hsp_list_array;
  1704.    BlastHSP* hsp;
  1705.    Int4 index;
  1706.    BlastHitSavingOptions* hit_options = hit_parameters->options;
  1707.    Uint1 context_factor;
  1708.    if (!hsp_list)
  1709.       return 0;
  1710.    if (program == blast_type_blastn) {
  1711.       context_factor = NUM_STRANDS;
  1712.    } else if (program == blast_type_blastx || 
  1713.               program == blast_type_tblastx) {
  1714.       context_factor = NUM_FRAMES;
  1715.    } else {
  1716.       context_factor = 1;
  1717.    }
  1718.    /* Sort the HSPs by e-value/score. E-value has a priority here, because
  1719.       lower scoring HSPs in linked sets might have lower e-values, and must
  1720.       be moved higher in the list. */
  1721.    if (hsp_list->hspcnt > 1) {
  1722.       qsort(hsp_list->hsp_array, hsp_list->hspcnt, sizeof(BlastHSP*), 
  1723.             evalue_compare_hsps);
  1724.    }
  1725.    /* Rearrange HSPs into multiple hit lists if more than one query */
  1726.    if (results->num_queries > 1) {
  1727.       BlastHSPList* tmp_hsp_list;
  1728.       hsp_list_array = calloc(results->num_queries, sizeof(BlastHSPList*));
  1729.       for (index = 0; index < hsp_list->hspcnt; index++) {
  1730.          hsp = hsp_list->hsp_array[index];
  1731.          tmp_hsp_list = hsp_list_array[hsp->context/context_factor];
  1732.          if (!tmp_hsp_list) {
  1733.             hsp_list_array[hsp->context/context_factor] = tmp_hsp_list = 
  1734.                Blast_HSPListNew(hit_options->hsp_num_max);
  1735.             tmp_hsp_list->oid = hsp_list->oid;
  1736.             tmp_hsp_list->traceback_done = hsp_list->traceback_done;
  1737.          }
  1738.          if (!tmp_hsp_list || tmp_hsp_list->do_not_reallocate) {
  1739.             tmp_hsp_list = NULL;
  1740.          } else if (tmp_hsp_list->hspcnt >= tmp_hsp_list->allocated) {
  1741.             BlastHSP** new_hsp_array;
  1742.             Int4 new_size = 
  1743.                MIN(2*tmp_hsp_list->allocated, tmp_hsp_list->hsp_max);
  1744.             if (new_size == tmp_hsp_list->hsp_max)
  1745.                tmp_hsp_list->do_not_reallocate = TRUE;
  1746.             
  1747.             new_hsp_array = realloc(tmp_hsp_list->hsp_array, 
  1748.                                     new_size*sizeof(BlastHSP*));
  1749.             if (!new_hsp_array) {
  1750.                tmp_hsp_list->do_not_reallocate = TRUE;
  1751.                tmp_hsp_list = NULL;
  1752.             } else {
  1753.                tmp_hsp_list->hsp_array = new_hsp_array;
  1754.                tmp_hsp_list->allocated = new_size;
  1755.             }
  1756.          }
  1757.          if (tmp_hsp_list) {
  1758.             tmp_hsp_list->hsp_array[tmp_hsp_list->hspcnt++] = hsp;
  1759.          } else {
  1760.             /* Cannot add more HSPs; free the memory */
  1761.             hsp_list->hsp_array[index] = Blast_HSPFree(hsp);
  1762.          }
  1763.       }
  1764.       /* Insert the hit list(s) into the appropriate places in the results 
  1765.          structure */
  1766.       for (index = 0; index < results->num_queries; index++) {
  1767.          if (hsp_list_array[index]) {
  1768.             if (!results->hitlist_array[index]) {
  1769.                results->hitlist_array[index] = 
  1770.                   Blast_HitListNew(hit_options->prelim_hitlist_size);
  1771.             }
  1772.             Blast_HitListUpdate(results->hitlist_array[index], 
  1773.                                 hsp_list_array[index]);
  1774.          }
  1775.       }
  1776.       sfree(hsp_list_array);
  1777.       /* All HSPs from the hsp_list structure are now moved to the results 
  1778.          structure, so set the HSP count back to 0 */
  1779.       hsp_list->hspcnt = 0;
  1780.       Blast_HSPListFree(hsp_list);
  1781.    } else if (hsp_list->hspcnt > 0) {
  1782.       /* Single query; save the HSP list directly into the results 
  1783.          structure */
  1784.       if (!results->hitlist_array[0]) {
  1785.          results->hitlist_array[0] = 
  1786.             Blast_HitListNew(hit_options->prelim_hitlist_size);
  1787.       }
  1788.       Blast_HitListUpdate(results->hitlist_array[0], 
  1789.                           hsp_list);
  1790.    }
  1791.    
  1792.    return status; 
  1793. }
  1794. void Blast_HSPResultsRPSUpdate(BlastHSPResults *final_result,
  1795.                       BlastHSPResults *init_result)
  1796. {
  1797.    Int4 i, j, k;
  1798.    BlastHitList **hitlist;
  1799.    BlastHSPList **hsplist;
  1800.    BlastHSP **hsp;
  1801.    /* Allocate the (one) hitlist of the final result,
  1802.       if it hasn't been allocated already */
  1803.    if (!final_result->hitlist_array[0])
  1804.       final_result->hitlist_array[0] = Blast_HitListNew(500);
  1805.    /* For each DB sequence... */
  1806.    hitlist = init_result->hitlist_array;
  1807.    for (i = 0; i < init_result->num_queries; i++) {
  1808.        if (hitlist[i] == NULL) 
  1809.            continue;
  1810.        /* DB sequence i has HSPLists; for each HSPList 
  1811.           (corresponding to a distinct DB sequence)... */
  1812.        hsplist = hitlist[i]->hsplist_array;
  1813.        for (j = 0; j < hitlist[i]->hsplist_count; j++) {
  1814.            /* Change the OID to make this HSPList correspond to
  1815.               a distinct DB sequence */
  1816.            
  1817.            hsplist[j]->oid = i;
  1818.            /* For each HSP in list j, there are no distinct 
  1819.               contexts/frames anymore */
  1820.            hsp = hsplist[j]->hsp_array;
  1821.            for (k = 0; k < hsplist[j]->hspcnt; k++)
  1822.                hsp[k]->context = 0;
  1823.            /* Add the modified HSPList to the new set of results */
  1824.            if (hsplist[j]->hspcnt)
  1825.                Blast_HitListUpdate(final_result->hitlist_array[0], 
  1826.                                    hsplist[j]);
  1827.            else
  1828.                hsplist[j] = Blast_HSPListFree(hsplist[j]);
  1829.        }
  1830.        /* Remove the original hit list (all of its contents
  1831.           have been moved) */
  1832.        hitlist[i]->hsplist_count = 0;
  1833.        init_result->hitlist_array[i] = Blast_HitListFree(hitlist[i]);
  1834.    }
  1835. }