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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: blast_gapalign.c,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 18:07:19  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.101
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: blast_gapalign.c,v 1000.5 2004/06/01 18:07:19 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_gapalign.c
  38.  * Functions to perform gapped alignment
  39.  */
  40. static char const rcsid[] = 
  41.     "$Id: blast_gapalign.c,v 1000.5 2004/06/01 18:07:19 gouriano Exp $";
  42. #include <algo/blast/core/blast_options.h>
  43. #include <algo/blast/core/blast_def.h>
  44. #include <algo/blast/core/blast_gapalign.h>
  45. #include <algo/blast/core/blast_util.h> /* for NCBI2NA_UNPACK_BASE macros */
  46. #include <algo/blast/core/blast_setup.h>
  47. #include <algo/blast/core/greedy_align.h>
  48. static Int2 BLAST_DynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, 
  49.    BLAST_SequenceBlk* subject_blk, BlastGapAlignStruct* gap_align, 
  50.    const BlastScoringParameters* score_params, BlastInitHSP* init_hsp);
  51. static Int4 BLAST_AlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, 
  52.    Int4* pej, Int4* pei, BlastGapAlignStruct* gap_align,
  53.    const BlastScoringParameters* score_params, Boolean reverse_sequence);
  54. static Int2 BLAST_ProtGappedAlignment(Uint1 program, 
  55.    BLAST_SequenceBlk* query_in, BLAST_SequenceBlk* subject_in,
  56.    BlastGapAlignStruct* gap_align,
  57.    const BlastScoringParameters* score_params, BlastInitHSP* init_hsp);
  58. /** Auxiliary structure for dynamic programming gapped extension */
  59. typedef struct BlastGapDP {
  60.   Int4 best;
  61.   Int4 best_gap;
  62.   Int4 best_decline;
  63. } BlastGapDP;
  64. typedef struct GapData {
  65.   BlastGapDP* CD;
  66.   Int4** v;
  67.   Int4* sapp;                 /* Current script append ptr */
  68.   Int4  last;
  69.   Int4 h,  g;
  70. } GapData;
  71. /** Append "Delete k" op */
  72. #define DEL_(k) 
  73. data.last = (data.last < 0) ? (data.sapp[-1] -= (k)) : (*data.sapp++ = -(k));
  74. /** Append "Insert k" op */
  75. #define INS_(k) 
  76. data.last = (data.last > 0) ? (data.sapp[-1] += (k)) : (*data.sapp++ = (k));
  77. /** Append "Replace" op */
  78. #define REP_ 
  79. {data.last = *data.sapp++ = 0;}
  80. /* Divide by two to prevent underflows. */
  81. #define MININT INT4_MIN/2
  82. #define REPP_ 
  83. {*data.sapp++ = MININT; data.last = 0;}
  84. /** Are the two HSPs within a given number of diagonals from each other? */
  85. #define MB_HSP_CLOSE(q1, q2, s1, s2, c) 
  86. (ABS((q1-s1) - (q2-s2)) < c)
  87. /** Is one HSP contained in a diagonal strip around another? */
  88. #define MB_HSP_CONTAINED(qo1,qo2,qe2,so1,so2,se2,c) 
  89. (qo1>=qo2 && qo1<=qe2 && so1>=so2 && so1<=se2 && 
  90. MB_HSP_CLOSE(qo1,qo2,so1,so2,c))
  91. /** TRUE if c is between a and b; f between d and f. Determines if the
  92.  * coordinates are already in an HSP that has been evaluated. 
  93.  */
  94. #define CONTAINED_IN_HSP(a,b,c,d,e,f) (((a <= c && b >= c) && (d <= f && e >= f)) ? TRUE : FALSE)
  95. /** Callback for sorting HSPs by starting offset in query */ 
  96. static int
  97. query_offset_compare_hsps(const void* v1, const void* v2)
  98. {
  99. BlastHSP* h1,* h2;
  100. BlastHSP** hp1,** hp2;
  101. hp1 = (BlastHSP**) v1;
  102. hp2 = (BlastHSP**) v2;
  103. h1 = *hp1;
  104. h2 = *hp2;
  105. if (h1 == NULL || h2 == NULL)
  106. return 0;
  107.    /* If these are from different contexts, don't compare offsets */
  108.    if (h1->context < h2->context) 
  109.       return -1;
  110.    if (h1->context > h2->context)
  111.       return 1;
  112. if (h1->query.offset < h2->query.offset)
  113. return -1;
  114. if (h1->query.offset > h2->query.offset)
  115. return 1;
  116. return 0;
  117. }
  118. /** Callback for sorting HSPs by ending offset in query */
  119. static int
  120. query_end_compare_hsps(const void* v1, const void* v2)
  121. {
  122. BlastHSP* h1,* h2;
  123. BlastHSP** hp1,** hp2;
  124. hp1 = (BlastHSP**) v1;
  125. hp2 = (BlastHSP**) v2;
  126. h1 = *hp1;
  127. h2 = *hp2;
  128. if (h1 == NULL || h2 == NULL)
  129. return 0;
  130.    /* If these are from different contexts, don't compare offsets */
  131.    if (h1->context < h2->context) 
  132.       return -1;
  133.    if (h1->context > h2->context)
  134.       return 1;
  135. if (h1->query.end < h2->query.end)
  136. return -1;
  137. if (h1->query.end > h2->query.end)
  138. return 1;
  139. return 0;
  140. }
  141. /** Callback for sorting HSPs by score */
  142. static int
  143. score_compare_hsp(const void* v1, const void* v2)
  144. {
  145. BlastHSP* h1,* h2;
  146. BlastHSP** hp1,** hp2;
  147. hp1 = (BlastHSP**) v1;
  148. hp2 = (BlastHSP**) v2;
  149. h1 = *hp1;
  150. h2 = *hp2;
  151.         
  152.         /* NULL HSPs are moved to the end */
  153. if (h1 == NULL)
  154.            return 1;
  155.         if (h2 == NULL)
  156.            return -1;
  157. if (h1->score < h2->score) 
  158. return 1;
  159. if (h1->score > h2->score)
  160. return -1;
  161. return 0;
  162. }
  163. /** Check the gapped alignments for an overlap of two different alignments.
  164.  * A sufficient overlap is when two alignments have the same start values
  165.  * of have the same final values. 
  166.  * @param hsp_array Pointer to an array of BlastHSP structures [in]
  167.  * @param hsp_count The size of the hsp_array [in]
  168.  * @param frame What frame these HSPs are from? [in]
  169.  * @return The number of valid alignments remaining. 
  170. */
  171. static Int4
  172. CheckGappedAlignmentsForOverlap(BlastHSP* *hsp_array, Int4 hsp_count, Int2 frame)
  173. {
  174.    Int4 index1, index, increment;
  175.    if (*hsp_array == NULL || hsp_count == 0)
  176.       return 0;
  177.    
  178.    qsort(hsp_array, hsp_count, sizeof(BlastHSP*), query_offset_compare_hsps);
  179.    index=0;
  180.    increment=1;
  181.    while (index < hsp_count-increment) {
  182.       /* Check if both HSP's start on or end on the same digonal. */
  183.       if (hsp_array[index+increment] == NULL) {
  184.  increment++;
  185.  continue;
  186.       }
  187.       
  188.       if (frame != 0 && hsp_array[index+increment]->subject.frame != frame)
  189.  break;
  190.       
  191.       if (hsp_array[index] && hsp_array[index]->query.offset == hsp_array[index+increment]->query.offset &&
  192.   hsp_array[index]->subject.offset == hsp_array[index+increment]->subject.offset &&
  193.   SIGN(hsp_array[index]->query.frame) == SIGN(hsp_array[index+increment]->query.frame))
  194.       {
  195.  if (hsp_array[index]->score > hsp_array[index+increment]->score) {
  196.    sfree(hsp_array[index+increment]);
  197.     increment++;
  198.  } else {
  199.     sfree(hsp_array[index]);
  200.     index++;
  201.     increment = 1;
  202.  }
  203.       } else {
  204.  index++;
  205.  increment = 1;
  206.       }
  207.    }
  208.    
  209.    qsort(hsp_array, hsp_count, sizeof(BlastHSP*), query_end_compare_hsps);
  210.    index=0;
  211.    increment=1;
  212.    while (index < hsp_count-increment)
  213.    { /* Check if both HSP's start on or end on the same digonal. */
  214.       if (hsp_array[index+increment] == NULL)
  215.       {
  216.  increment++;
  217.  continue;
  218.       }
  219.       
  220.       if (frame != 0 && hsp_array[index+increment]->subject.frame != frame)
  221.  break;
  222.       
  223.       if (hsp_array[index] &&
  224.   hsp_array[index]->query.end == hsp_array[index+increment]->query.end &&
  225.   hsp_array[index]->subject.end == hsp_array[index+increment]->subject.end &&
  226.   SIGN(hsp_array[index]->query.frame) == SIGN(hsp_array[index+increment]->query.frame))
  227.       {
  228.  if (hsp_array[index]->score > hsp_array[index+increment]->score)
  229.  {
  230.           sfree(hsp_array[index+increment]);
  231.     increment++;
  232.  } else {
  233.     sfree(hsp_array[index]);
  234.     index++;
  235.     increment = 1;
  236.  }
  237.       } else {
  238.  index++;
  239.  increment = 1;
  240.       }
  241.    }
  242.    qsort(hsp_array,hsp_count,sizeof(BlastHSP*), score_compare_hsp);
  243.    
  244.    index1 = 0;
  245.    for (index=0; index<hsp_count; index++)
  246.    {
  247.       if (hsp_array[index] != NULL)
  248.  index1++;
  249.    }
  250.    return index1;
  251. }
  252. /** Retrieve the state structure corresponding to a given length
  253.  * @param head Pointer to the first element of the state structures 
  254.  *        array [in]
  255.  * @param length The length for which the state structure has to be 
  256.  *        found [in]
  257.  * @return The found or created state structure
  258.  */
  259. #define CHUNKSIZE 2097152
  260. static GapStateArrayStruct*
  261. GapGetState(GapStateArrayStruct** head, Int4 length)
  262. {
  263.    GapStateArrayStruct* retval,* var,* last;
  264.    Int4 chunksize = MAX(CHUNKSIZE, length + length/3);
  265.    length += length/3; /* Add on about 30% so the end will get reused. */
  266.    retval = NULL;
  267.    if (*head == NULL) {
  268.       retval = (GapStateArrayStruct*) 
  269.          malloc(sizeof(GapStateArrayStruct));
  270.       retval->state_array = (Uint1*) malloc(chunksize*sizeof(Uint1));
  271.       retval->length = chunksize;
  272.       retval->used = 0;
  273.       retval->next = NULL;
  274.       *head = retval;
  275.    } else {
  276.       var = *head;
  277.       last = *head;
  278.       while (var) {
  279.          if (length < (var->length - var->used)) {
  280.             retval = var;
  281.             break;
  282.          } else if (var->used == 0) { 
  283.             /* If it's empty and too small, replace. */
  284.             sfree(var->state_array);
  285.             var->state_array = (Uint1*) malloc(chunksize*sizeof(Uint1));
  286.             var->length = chunksize;
  287.             retval = var;
  288.             break;
  289.          }
  290.          last = var;
  291.          var = var->next;
  292.       }
  293.       
  294.       if (var == NULL)
  295.       {
  296.          retval = (GapStateArrayStruct*) malloc(sizeof(GapStateArrayStruct));
  297.          retval->state_array = (Uint1*) malloc(chunksize*sizeof(Uint1));
  298.          retval->length = chunksize;
  299.          retval->used = 0;
  300.          retval->next = NULL;
  301.          last->next = retval;
  302.       }
  303.    }
  304. #ifdef ERR_POST_EX_DEFINED
  305.    if (retval->state_array == NULL)
  306.       ErrPostEx(SEV_ERROR, 0, 0, "state array is NULL");
  307. #endif
  308.    return retval;
  309. }
  310. /** Remove a state from a state structure */
  311. static Boolean
  312. GapPurgeState(GapStateArrayStruct* state_struct)
  313. {
  314.    while (state_struct)
  315.    {
  316.       /*
  317. memset(state_struct->state_array, 0, state_struct->used);
  318.       */
  319.       state_struct->used = 0;
  320.       state_struct = state_struct->next;
  321.    }
  322.    
  323.    return TRUE;
  324. }
  325. /** Greatest common divisor */
  326. static Int4 gcd(Int4 a, Int4 b)
  327. {
  328.     Int4 c;
  329.     if (a < b) {
  330.         c = a;
  331.         a = b; b = c;
  332.     }
  333.     while ((c = a % b) != 0) {
  334.         a = b; b = c;
  335.     }
  336.     return b;
  337. }
  338. /** Divide 3 numbers by their greatest common divisor
  339.  * @return The GCD
  340.  */
  341. static Int4 gdb3(Int4* a, Int4* b, Int4* c)
  342. {
  343.     Int4 g;
  344.     if (*b == 0) g = gcd(*a, *c);
  345.     else g = gcd(*a, gcd(*b, *c));
  346.     if (g > 1) {
  347.         *a /= g;
  348.         *b /= g;
  349.         *c /= g;
  350.     }
  351.     return g;
  352. }
  353. /** Deallocate the memory for greedy gapped alignment */
  354. static SGreedyAlignMem* BLAST_GreedyAlignsfree(SGreedyAlignMem* gamp)
  355. {
  356.    if (gamp->flast_d) {
  357.       sfree(gamp->flast_d[0]);
  358.       sfree(gamp->flast_d);
  359.    } else {
  360.       if (gamp->flast_d_affine) {
  361.          sfree(gamp->flast_d_affine[0]);
  362.          sfree(gamp->flast_d_affine);
  363.       }
  364.       sfree(gamp->uplow_free);
  365.    }
  366.    sfree(gamp->max_row_free);
  367.    if (gamp->space)
  368.       MBSpaceFree(gamp->space);
  369.    sfree(gamp);
  370.    return NULL;
  371. }
  372. /** Allocate memory for the greedy gapped alignment algorithm
  373.  * @param score_params Parameters related to scoring [in]
  374.  * @param ext_params Options and parameters related to the extension [in]
  375.  * @param max_dbseq_length The length of the longest sequence in the 
  376.  *        database [in]
  377.  * @return The allocated SGreedyAlignMem structure
  378.  */
  379. static SGreedyAlignMem* 
  380. BLAST_GreedyAlignMemAlloc(const BlastScoringParameters* score_params,
  381.        const BlastExtensionParameters* ext_params,
  382.        Int4 max_dbseq_length)
  383. {
  384. #define ERROR_FRACTION 2    /* N.B.: This value should match the value of
  385.                                ERROR_FRACTION in the anonymous enum in
  386.                                greedy_align.c */
  387. #define ICEIL(x,y) ((((x)-1)/(y))+1)    /* FIXME: duplicated from greedy_align.c */
  388.    SGreedyAlignMem* gamp;
  389.    Int4 max_d, max_d_1, Xdrop, d_diff, max_cost, gd, i;
  390.    Int4 reward, penalty, gap_open, gap_extend;
  391.    Int4 Mis_cost, GE_cost;
  392.    Boolean do_traceback;
  393.    
  394.    if (score_params == NULL || ext_params == NULL) 
  395.       return NULL;
  396.    
  397.    do_traceback = 
  398.       (ext_params->options->ePrelimGapExt != eGreedyExt);
  399.    if (score_params->reward % 2 == 1) {
  400.       reward = 2*score_params->reward;
  401.       penalty = -2*score_params->penalty;
  402.       Xdrop = 2*ext_params->gap_x_dropoff;
  403.       gap_open = 2*score_params->gap_open;
  404.       gap_extend = 2*score_params->gap_extend;
  405.    } else {
  406.       reward = score_params->reward;
  407.       penalty = -score_params->penalty;
  408.       Xdrop = ext_params->gap_x_dropoff;
  409.       gap_open = score_params->gap_open;
  410.       gap_extend = score_params->gap_extend;
  411.    }
  412.    if (gap_open == 0 && gap_extend == 0)
  413.       gap_extend = reward / 2 + penalty;
  414.    max_d = (Int4) (max_dbseq_length / ERROR_FRACTION + 1);
  415.    gamp = (SGreedyAlignMem*) calloc(1, sizeof(SGreedyAlignMem));
  416.    if (score_params->gap_open==0 && score_params->gap_extend==0) {
  417.       d_diff = ICEIL(Xdrop+reward/2, penalty+reward);
  418.    
  419.       gamp->flast_d = (Int4**) malloc((max_d + 2) * sizeof(Int4*));
  420.       if (gamp->flast_d == NULL) {
  421.          sfree(gamp);
  422.          return NULL;
  423.       }
  424.       gamp->flast_d[0] = 
  425.          (Int4*) malloc((max_d + max_d + 6) * sizeof(Int4) * 2);
  426.       if (gamp->flast_d[0] == NULL) {
  427. #ifdef ERR_POST_EX_DEFINED
  428.  ErrPostEx(SEV_WARNING, 0, 0, 
  429.               "Failed to allocate %ld bytes for greedy alignment", 
  430.               (max_d + max_d + 6) * sizeof(Int4) * 2);
  431. #endif
  432.          BLAST_GreedyAlignsfree(gamp);
  433.          return NULL;
  434.       }
  435.       gamp->flast_d[1] = gamp->flast_d[0] + max_d + max_d + 6;
  436.       gamp->flast_d_affine = NULL;
  437.       gamp->uplow_free = NULL;
  438.    } else {
  439.       gamp->flast_d = NULL;
  440.       Mis_cost = reward + penalty;
  441.       GE_cost = gap_extend+reward/2;
  442.       max_d_1 = max_d;
  443.       max_d *= GE_cost;
  444.       max_cost = MAX(Mis_cost, gap_open+GE_cost);
  445.       gd = gdb3(&Mis_cost, &gap_open, &GE_cost);
  446.       d_diff = ICEIL(Xdrop+reward/2, gd);
  447.       gamp->uplow_free = (Int4*) calloc(2*(max_d+1+max_cost), sizeof(Int4));
  448.       gamp->flast_d_affine = (SThreeVal**) 
  449.  malloc((MAX(max_d, max_cost) + 2) * sizeof(SThreeVal*));
  450.       if (!gamp->uplow_free || !gamp->flast_d_affine) {
  451.          BLAST_GreedyAlignsfree(gamp);
  452.          return NULL;
  453.       }
  454.       gamp->flast_d_affine[0] = (SThreeVal*)
  455.  calloc((2*max_d_1 + 6) , sizeof(SThreeVal) * (max_cost+1));
  456.       for (i = 1; i <= max_cost; i++)
  457.  gamp->flast_d_affine[i] = 
  458.     gamp->flast_d_affine[i-1] + 2*max_d_1 + 6;
  459.       if (!gamp->flast_d_affine || !gamp->flast_d_affine[0])
  460.          BLAST_GreedyAlignsfree(gamp);
  461.    }
  462.    gamp->max_row_free = (Int4*) malloc(sizeof(Int4) * (max_d + 1 + d_diff));
  463.    if (do_traceback)
  464.       gamp->space = MBSpaceNew();
  465.    if (!gamp->max_row_free || (do_traceback && !gamp->space))
  466.       /* Failure in one of the memory allocations */
  467.       BLAST_GreedyAlignsfree(gamp);
  468.    return gamp;
  469. }
  470. /* Documented in blast_gapalign.h */
  471. BlastGapAlignStruct* 
  472. BLAST_GapAlignStructFree(BlastGapAlignStruct* gap_align)
  473. {
  474.    GapEditBlockDelete(gap_align->edit_block);
  475.    if (gap_align->greedy_align_mem)
  476.       BLAST_GreedyAlignsfree(gap_align->greedy_align_mem);
  477.    GapStateFree(gap_align->state_struct);
  478.    sfree(gap_align);
  479.    return NULL;
  480. }
  481. /* Documented in blast_gapalign.h */
  482. Int2
  483. BLAST_GapAlignStructNew(const BlastScoringParameters* score_params, 
  484.    const BlastExtensionParameters* ext_params, 
  485.    Uint4 max_subject_length, Int4 query_length, 
  486.    BlastScoreBlk* sbp, BlastGapAlignStruct** gap_align_ptr)
  487. {
  488.    Int2 status = 0;
  489.    BlastGapAlignStruct* gap_align;
  490.    /* If pointer to output structure is NULL, just don't do anything */ 
  491.    if (!gap_align_ptr)
  492.       return 0;
  493.    if (!gap_align_ptr || !sbp || !score_params || !ext_params)
  494.       return -1;
  495.    gap_align = (BlastGapAlignStruct*) calloc(1, sizeof(BlastGapAlignStruct));
  496.    *gap_align_ptr = gap_align;
  497.    gap_align->sbp = sbp;
  498.    gap_align->gap_x_dropoff = ext_params->gap_x_dropoff;
  499.    if (ext_params->options->ePrelimGapExt != eDynProgExt) {
  500.       max_subject_length = MIN(max_subject_length, MAX_DBSEQ_LEN);
  501.       gap_align->greedy_align_mem = 
  502.          BLAST_GreedyAlignMemAlloc(score_params, ext_params, 
  503.                                 max_subject_length);
  504.       if (!gap_align->greedy_align_mem)
  505.          gap_align = BLAST_GapAlignStructFree(gap_align);
  506.    }
  507.    if (!gap_align)
  508.       return -1;
  509.    gap_align->positionBased = (sbp->posMatrix != NULL);
  510.    return status;
  511. }
  512. /** Low level function to perform dynamic programming gapped extension 
  513.  * with traceback.
  514.  * @param A The query sequence [in]
  515.  * @param B The subject sequence [in]
  516.  * @param M Maximal extension length in query [in]
  517.  * @param N Maximal extension length in subject [in]
  518.  * @param S The traceback information from previous extension [in]
  519.  * @param a_offset Resulting starting offset in query [out]
  520.  * @param b_offset Resulting starting offset in subject [out]
  521.  * @param sapp The traceback information [out]
  522.  * @param gap_align Structure holding various information and allocated 
  523.  *        memory for the gapped alignment [in]
  524.  * @param score_params Parameters related to scoring [in]
  525.  * @param query_offset The starting offset in query [in]
  526.  * @param reversed Has the sequence been reversed? Used for psi-blast [in]
  527.  * @param reverse_sequence Do reverse the sequence [in]
  528.  * @return The best alignment score found.
  529. */
  530. #define SCRIPT_SUB      0x00
  531. #define SCRIPT_INS      0x01
  532. #define SCRIPT_DEL      0x02
  533. #define SCRIPT_DECLINE  0x03
  534. #define SCRIPT_OP_MASK  0x03
  535. #define SCRIPT_OPEN_GAP 0x04
  536. #define SCRIPT_INS_ROW  0x10
  537. #define SCRIPT_DEL_ROW  0x20
  538. #define SCRIPT_INS_COL  0x40
  539. #define SCRIPT_DEL_COL  0x80
  540. Int4
  541. ALIGN_EX(Uint1* A, Uint1* B, Int4 M, Int4 N, Int4* S, Int4* a_offset, 
  542. Int4* b_offset, Int4** sapp, BlastGapAlignStruct* gap_align, 
  543. const BlastScoringParameters* score_params, Int4 query_offset, 
  544.         Boolean reversed, Boolean reverse_sequence)
  545.     /* See SEMI_G_ALIGN_EX for more general comments on 
  546.        what this code is doing; comments in this function
  547.        only apply to the traceback computations */
  548.     BlastGapDP* score_array;
  549.     Int4 i; 
  550.     Int4 a_index;
  551.     Int4 b_index, b_size, first_b_index, last_b_index, b_increment;
  552.     Uint1* b_ptr;
  553.   
  554.     Int4 gap_open;
  555.     Int4 gap_extend;
  556.     Int4 gap_open_extend;
  557.     Int4 decline_penalty;
  558.     Int4 x_dropoff;
  559.     Int4 best_score;
  560.   
  561.     Int4* *matrix;
  562.     Int4* matrix_row;
  563.   
  564.     Int4 score;
  565.     Int4 score_gap_row;
  566.     Int4 score_gap_col;
  567.     Int4 score_decline;
  568.     Int4 next_score;
  569.     Int4 next_score_decline;
  570.   
  571.     GapData data;                       /* traceback variables */
  572.     GapStateArrayStruct* state_struct;
  573.     Uint1** edit_script;
  574.     Uint1* edit_script_row;
  575.     Int4 orig_b_index;
  576.     Uint1 script, next_script, script_row, script_col;
  577.     Int4 align_len;
  578.     matrix = gap_align->sbp->matrix;
  579.     *a_offset = 0;
  580.     *b_offset = 0;
  581.     gap_open = score_params->gap_open;
  582.     gap_extend = score_params->gap_extend;
  583.     gap_open_extend = gap_open + gap_extend;
  584.     decline_penalty = score_params->decline_align;
  585.     x_dropoff = gap_align->gap_x_dropoff;
  586.   
  587.     if (x_dropoff < gap_open_extend)
  588.         x_dropoff = gap_open_extend;
  589.   
  590.     if(N <= 0 || M <= 0) 
  591.         return 0;
  592.   
  593.     /* Initialize traceback information. edit_script[] is
  594.        a 2-D array which is filled in row by row as the 
  595.        dynamic programming takes place */
  596.     data.sapp = S;
  597.     data.last = 0;
  598.     *sapp = S;
  599.     GapPurgeState(gap_align->state_struct);
  600.     edit_script = (Uint1**) malloc(sizeof(Uint1*)*(M+1));
  601.     if (gap_extend > 0)
  602.         state_struct = GapGetState(&gap_align->state_struct, 
  603.                                    x_dropoff / gap_extend + 5);
  604.     else
  605.         state_struct = GapGetState(&gap_align->state_struct, N + 3);
  606.     edit_script[0] = state_struct->state_array;
  607.     edit_script_row = state_struct->state_array;
  608.     score_array = (BlastGapDP*)malloc((N + 2) * sizeof(BlastGapDP));
  609.     score = -gap_open_extend;
  610.     score_array[0].best = 0;
  611.     score_array[0].best_gap = -gap_open_extend;
  612.     score_array[0].best_decline = -gap_open_extend - decline_penalty;
  613.   
  614.     for (i = 1; i <= N; i++) {
  615.         if (score < -x_dropoff) 
  616.             break;
  617.         score_array[i].best = score;
  618.         score_array[i].best_gap = score - gap_open_extend; 
  619.         score_array[i].best_decline = score - gap_open_extend - decline_penalty;
  620.         score -= gap_extend;
  621.         edit_script_row[i] = SCRIPT_INS;
  622.     }
  623.     state_struct->used = i + 1;
  624.   
  625.     b_size = i;
  626.     best_score = 0;
  627.     first_b_index = 0;
  628.     if (reverse_sequence)
  629.         b_increment = -1;
  630.     else
  631.         b_increment = 1;
  632.   
  633.     for (a_index = 1; a_index <= M; a_index++) {
  634.         /* Set up the next row of the edit script; this involves
  635.            allocating memory for the row, then pointing to it */
  636.         if (gap_extend > 0)
  637.             state_struct = GapGetState(&gap_align->state_struct, 
  638.                           b_size - first_b_index + x_dropoff / gap_extend + 5);
  639.         else
  640.             state_struct = GapGetState(&gap_align->state_struct, 
  641.                           N + 3 - first_b_index);
  642.         edit_script[a_index] = state_struct->state_array + 
  643.                                 state_struct->used + 1;
  644.         edit_script_row = edit_script[a_index];
  645.         orig_b_index = first_b_index;
  646.         if (!(gap_align->positionBased)) {
  647.             if(reverse_sequence)
  648.                 matrix_row = matrix[ A[ M - a_index ] ];
  649.             else
  650.                 matrix_row = matrix[ A[ a_index ] ];
  651.         }
  652.         else {
  653.             if(reversed || reverse_sequence)
  654.                 matrix_row = gap_align->sbp->posMatrix[M - a_index];
  655.             else
  656.                 matrix_row = gap_align->sbp->posMatrix[a_index + query_offset];
  657.         }
  658.         if(reverse_sequence)
  659.             b_ptr = &B[N - first_b_index];
  660.         else
  661.             b_ptr = &B[first_b_index];
  662.         score = MININT;
  663.         score_gap_row = MININT;
  664.         score_decline = MININT;
  665.         last_b_index = first_b_index;
  666.         for (b_index = first_b_index; b_index < b_size; b_index++) {
  667.             b_ptr += b_increment;
  668.             score_gap_col = score_array[b_index].best_gap;
  669.             next_score = score_array[b_index].best + matrix_row[ *b_ptr ];
  670.             next_score_decline = score_array[b_index].best_decline;
  671.             /* script, script_row and script_col contain the
  672.                actions specified by the dynamic programming.
  673.                when the inner loop has finished, 'script' con-
  674.                tains all of the actions to perform, and is
  675.                written to edit_script[a_index][b_index]. Otherwise,
  676.                this inner loop is exactly the same as the one
  677.                in SEMI_G_ALIGN_EX() */
  678.             if (score_decline > score) {
  679.                 script = SCRIPT_DECLINE;
  680.                 score = score_decline;
  681.             }
  682.             else {
  683.                 script = SCRIPT_SUB;
  684.             }
  685.             if (score_gap_col < score_decline) {
  686.                 score_gap_col = score_decline;
  687.                 script_col = SCRIPT_DEL_COL;
  688.             }
  689.             else {
  690.                 script_col = SCRIPT_INS_COL;
  691.                 if (score < score_gap_col) {
  692.                     script = SCRIPT_DEL;
  693.                     score = score_gap_col;
  694.                 }
  695.             }
  696.             if (score_gap_row < score_decline) {
  697.                 score_gap_row = score_decline;
  698.                 script_row = SCRIPT_DEL_ROW;
  699.             }
  700.             else {
  701.                 script_row = SCRIPT_INS_ROW;
  702.                 if (score < score_gap_row) {
  703.                     script = SCRIPT_INS;
  704.                     score = score_gap_row;
  705.                 }
  706.             }
  707.             if (best_score - score > x_dropoff) {
  708.                 if (first_b_index == b_index)
  709.                     first_b_index++;
  710.                 else
  711.                     score_array[b_index].best = MININT;
  712.             }
  713.             else {
  714.                 last_b_index = b_index;
  715.                 if (score > best_score) {
  716.                     best_score = score;
  717.                     *a_offset = a_index;
  718.                     *b_offset = b_index;
  719.                 }
  720.                 score_gap_row -= gap_extend;
  721.                 score_gap_col -= gap_extend;
  722.                 if (score_gap_col < (score - gap_open_extend)) {
  723.                     score_array[b_index].best_gap = score - gap_open_extend;
  724.                 }
  725.                 else {
  726.                     score_array[b_index].best_gap = score_gap_col;
  727.                     script += script_col;
  728.                 }
  729.                 if (score_gap_row < (score - gap_open_extend)) 
  730.                     score_gap_row = score - gap_open_extend;
  731.                 else 
  732.                     script += script_row;
  733.                 if (score_decline < (score - gap_open)) {
  734.                     score_array[b_index].best_decline = score - gap_open - decline_penalty;
  735.                 }
  736.                 else {
  737.                     score_array[b_index].best_decline = score_decline - decline_penalty;
  738.                     script += SCRIPT_OPEN_GAP;
  739.                 }
  740.                 score_array[b_index].best = score;
  741.             }
  742.             score = next_score;
  743.             score_decline = next_score_decline;
  744.             edit_script_row[b_index] = script;
  745.         }
  746.   
  747.         if (first_b_index == b_size) {
  748.             a_index++;
  749.             break;
  750.         }
  751.         if (last_b_index < b_size - 1) {
  752.             b_size = last_b_index + 1;
  753.         }
  754.         else {
  755.             while (score_gap_row >= (best_score - x_dropoff) && b_size <= N) {
  756.                 score_array[b_size].best = score_gap_row;
  757.                 score_array[b_size].best_gap = score_gap_row - gap_open_extend;
  758.                 score_array[b_size].best_decline = score_gap_row - gap_open -
  759.                                                         decline_penalty;
  760.                 score_gap_row -= gap_extend;
  761.                 edit_script_row[b_size] = SCRIPT_INS;
  762.                 b_size++;
  763.             }
  764.         }
  765.         if (b_size <= N) {
  766.             score_array[b_size].best = MININT;
  767.             score_array[b_size].best_gap = MININT;
  768.             score_array[b_size].best_decline = MININT;
  769.             b_size++;
  770.         }
  771.         state_struct->used += MAX(b_index, b_size) - orig_b_index + 1;
  772.     }
  773.     
  774.     /* Pick the optimal path through the now complete
  775.        edit_script[][]. This is equivalent to flattening 
  776.        the 2-D array into a 1-D list of actions. */
  777.     a_index = *a_offset;
  778.     b_index = *b_offset;
  779.     script = 0;
  780.     edit_script_row = (Uint1 *)malloc(a_index + b_index);
  781.     for (i = 0; a_index > 0 || b_index > 0; i++) {
  782.         next_script = edit_script[a_index][b_index];
  783.         switch(script) {
  784.         case SCRIPT_INS:
  785.             script = next_script & SCRIPT_OP_MASK;
  786.             if (next_script & SCRIPT_INS_ROW)
  787.                 script = SCRIPT_INS;
  788.             else if (next_script & SCRIPT_DEL_ROW)
  789.                 script = SCRIPT_DECLINE;
  790.             break;
  791.         case SCRIPT_DEL:
  792.             script = next_script & SCRIPT_OP_MASK;
  793.             if (next_script & SCRIPT_INS_COL)
  794.                 script = SCRIPT_DEL;
  795.             else if (next_script & SCRIPT_DEL_COL)
  796.                 script = SCRIPT_DECLINE;
  797.             break;
  798.         case SCRIPT_DECLINE:
  799.             script = next_script & SCRIPT_OP_MASK;
  800.             if (next_script & SCRIPT_OPEN_GAP)
  801.                 script = SCRIPT_DECLINE;
  802.             break;
  803.         default:
  804.             script = next_script & SCRIPT_OP_MASK;
  805.             break;
  806.         }
  807.         if (script == SCRIPT_INS)
  808.             b_index--;
  809.         else if (script == SCRIPT_DEL)
  810.             a_index--;
  811.         else {
  812.             a_index--;
  813.             b_index--;
  814.         }
  815.         edit_script_row[i] = script;
  816.     }
  817.     /* Traceback proceeded backwards through edit_script, 
  818.        so the output traceback information is written 
  819.        in reverse order */
  820.     align_len = i;
  821.     for (i--; i >= 0; i--) {
  822.         if (edit_script_row[i] == SCRIPT_SUB) 
  823.             REP_
  824.         else if (edit_script_row[i] == SCRIPT_INS) 
  825.             INS_(1)
  826.         else if (edit_script_row[i] == SCRIPT_DECLINE) 
  827.             REPP_                     
  828.         else 
  829.             DEL_(1)      
  830.     }
  831.       
  832.     sfree(edit_script_row);
  833.     sfree(edit_script);
  834.     sfree(score_array);
  835.     align_len -= data.sapp - S;
  836.     if (align_len > 0)
  837.         memset(data.sapp, 0, align_len);
  838.     *sapp = data.sapp;
  839.     return best_score;
  840. }
  841. /** Low level function to perform gapped extension in one direction with 
  842.  * or without traceback.
  843.  * @param A The query sequence [in]
  844.  * @param B The subject sequence [in]
  845.  * @param M Maximal extension length in query [in]
  846.  * @param N Maximal extension length in subject [in]
  847.  * @param S The traceback information from previous extension [in]
  848.  * @param a_offset Resulting starting offset in query [out]
  849.  * @param b_offset Resulting starting offset in subject [out]
  850.  * @param score_only Only find the score, without saving traceback [in]
  851.  * @param sapp The traceback information [out]
  852.  * @param gap_align Structure holding various information and allocated 
  853.  *        memory for the gapped alignment [in]
  854.  * @param score_params Parameters related to scoring [in]
  855.  * @param query_offset The starting offset in query [in]
  856.  * @param reversed Has the sequence been reversed? Used for psi-blast [in]
  857.  * @param reverse_sequence Do reverse the sequence [in]
  858.  * @return The best alignment score found.
  859.  */
  860. static Int4 SEMI_G_ALIGN_EX(Uint1* A, Uint1* B, Int4 M, Int4 N,
  861.    Int4* S, Int4* a_offset, Int4* b_offset, Boolean score_only, Int4** sapp,
  862.    BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params, 
  863.    Int4 query_offset, Boolean reversed, Boolean reverse_sequence)
  864. {
  865.     BlastGapDP* score_array;            /* sequence pointers and indices */
  866.     Int4 i; 
  867.     Int4 a_index;
  868.     Int4 b_index, b_size, first_b_index, last_b_index, b_increment;
  869.     Uint1* b_ptr;
  870.   
  871.     Int4 gap_open;              /* alignment penalty variables */
  872.     Int4 gap_extend;
  873.     Int4 gap_open_extend;
  874.     Int4 decline_penalty;
  875.     Int4 x_dropoff;
  876.   
  877.     Int4* *matrix;              /* pointers to the score matrix */
  878.     Int4* matrix_row;
  879.   
  880.     Int4 score;                 /* score tracking variables */
  881.     Int4 score_gap_row;
  882.     Int4 score_gap_col;
  883.     Int4 score_decline;
  884.     Int4 next_score;
  885.     Int4 next_score_decline;
  886.     Int4 best_score;
  887.   
  888.     if (!score_only) {
  889.         return ALIGN_EX(A, B, M, N, S, a_offset, b_offset, sapp, gap_align, 
  890.                       score_params, query_offset, reversed, reverse_sequence);
  891.     }
  892.     
  893.     /* do initialization and sanity-checking */
  894.     matrix = gap_align->sbp->matrix;
  895.     *a_offset = 0;
  896.     *b_offset = 0;
  897.     gap_open = score_params->gap_open;
  898.     gap_extend = score_params->gap_extend;
  899.     gap_open_extend = gap_open + gap_extend;
  900.     decline_penalty = score_params->decline_align;
  901.     x_dropoff = gap_align->gap_x_dropoff;
  902.   
  903.     if (x_dropoff < gap_open_extend)
  904.         x_dropoff = gap_open_extend;
  905.   
  906.     if(N <= 0 || M <= 0) 
  907.         return 0;
  908.   
  909.     /* Allocate and fill in the auxiliary 
  910.        bookeeping structures (one struct
  911.        per letter of B) */
  912.     score_array = (BlastGapDP*)malloc((N + 2) * sizeof(BlastGapDP));
  913.     score = -gap_open_extend;
  914.     score_array[0].best = 0;
  915.     score_array[0].best_gap = -gap_open_extend;
  916.     score_array[0].best_decline = -gap_open_extend - decline_penalty;
  917.   
  918.     for (i = 1; i <= N; i++) {
  919.         if (score < -x_dropoff) 
  920.             break;
  921.         score_array[i].best = score;
  922.         score_array[i].best_gap = score - gap_open_extend; 
  923.         score_array[i].best_decline = score - gap_open_extend - decline_penalty;
  924.         score -= gap_extend;
  925.     }
  926.   
  927.     /* The inner loop below examines letters of B from 
  928.        index 'first_b_index' to 'b_size' */
  929.     b_size = i;
  930.     best_score = 0;
  931.     first_b_index = 0;
  932.     if (reverse_sequence)
  933.         b_increment = -1;
  934.     else
  935.         b_increment = 1;
  936.   
  937.     for (a_index = 1; a_index <= M; a_index++) {
  938.         /* pick out the row of the score matrix 
  939.            appropriate for A[a_index] */
  940.         if (!(gap_align->positionBased)) {
  941.             if(reverse_sequence)
  942.                 matrix_row = matrix[ A[ M - a_index ] ];
  943.             else
  944.                 matrix_row = matrix[ A[ a_index ] ];
  945.         }
  946.         else {
  947.             if(reversed || reverse_sequence)
  948.                 matrix_row = gap_align->sbp->posMatrix[M - a_index];
  949.             else 
  950.                 matrix_row = gap_align->sbp->posMatrix[a_index + query_offset];
  951.         }
  952.         if(reverse_sequence)
  953.             b_ptr = &B[N - first_b_index];
  954.         else
  955.             b_ptr = &B[first_b_index];
  956.         /* initialize running-score variables */
  957.         score = MININT;
  958.         score_gap_row = MININT;
  959.         score_decline = MININT;
  960.         last_b_index = first_b_index;
  961.         for (b_index = first_b_index; b_index < b_size; b_index++) {
  962.             b_ptr += b_increment;
  963.             score_gap_col = score_array[b_index].best_gap;
  964.             next_score = score_array[b_index].best + matrix_row[ *b_ptr ];
  965.             next_score_decline = score_array[b_index].best_decline;
  966.             /* decline the alignment if that improves the score */
  967.             score = MAX(score, score_decline);
  968.             
  969.             /* decline the best row score if that improves it;
  970.                if not, make it the new high score if it's
  971.                an improvement */
  972.             if (score_gap_col < score_decline)
  973.                 score_gap_col = score_decline;
  974.             else if (score < score_gap_col)
  975.                 score = score_gap_col;
  976.             /* decline the best column score if that improves it;
  977.                if not, make it the new high score if it's
  978.                an improvement */
  979.             if (score_gap_row < score_decline)
  980.                 score_gap_row = score_decline;
  981.             else if (score < score_gap_row)
  982.                 score = score_gap_row;
  983.             if (best_score - score > x_dropoff) {
  984.                 /* the current best score failed the X-dropoff
  985.                    criterion. Note that this does not stop the
  986.                    inner loop, only forces future iterations to
  987.                    skip this column of B. 
  988.                    Also, if the very first letter of B that was
  989.                    tested failed the X dropoff criterion, make
  990.                    sure future inner loops start one letter to 
  991.                    the right */
  992.                 if (b_index == first_b_index)
  993.                     first_b_index++;
  994.                 else
  995.                     score_array[b_index].best = MININT;
  996.             }
  997.             else {
  998.                 last_b_index = b_index;
  999.                 if (score > best_score) {
  1000.                     best_score = score;
  1001.                     *a_offset = a_index;
  1002.                     *b_offset = b_index;
  1003.                 }
  1004.                 /* If starting a gap at this position will improve
  1005.                    the best row, column, or declined alignment score, 
  1006.                    update them to reflect that. */
  1007.                 score_gap_row -= gap_extend;
  1008.                 score_gap_col -= gap_extend;
  1009.                 score_array[b_index].best_gap = MAX(score - gap_open_extend,
  1010.                                                     score_gap_col);
  1011.                 score_gap_row = MAX(score - gap_open_extend, score_gap_row);
  1012.                 score_array[b_index].best_decline = 
  1013.                         MAX(score_decline, score - gap_open) - decline_penalty;
  1014.                 score_array[b_index].best = score;
  1015.             }
  1016.             score = next_score;
  1017.             score_decline = next_score_decline;
  1018.         }
  1019.   
  1020.         /* Finish aligning if the best scores for all positions
  1021.            of B will fail the X-dropoff test, i.e. the inner loop 
  1022.            bounds have converged to each other */
  1023.         if (first_b_index == b_size)
  1024.             break;
  1025.         if (last_b_index < b_size - 1) {
  1026.             /* This row failed the X-dropoff test earlier than
  1027.                the last row did; just shorten the loop bounds
  1028.                before doing the next row */
  1029.             b_size = last_b_index + 1;
  1030.         }
  1031.         else {
  1032.             /* The inner loop finished without failing the X-dropoff
  1033.                test; initialize extra bookkeeping structures until
  1034.                the X dropoff test fails or we run out of letters in B. 
  1035.                The next inner loop will have larger bounds */
  1036.             while (score_gap_row >= (best_score - x_dropoff) && b_size <= N) {
  1037.                 score_array[b_size].best = score_gap_row;
  1038.                 score_array[b_size].best_gap = score_gap_row - gap_open_extend;
  1039.                 score_array[b_size].best_decline = score_gap_row - gap_open -
  1040.                                                         decline_penalty;
  1041.                 score_gap_row -= gap_extend;
  1042.                 b_size++;
  1043.             }
  1044.         }
  1045.         if (b_size <= N) {
  1046.             score_array[b_size].best = MININT;
  1047.             score_array[b_size].best_gap = MININT;
  1048.             score_array[b_size].best_decline = MININT;
  1049.             b_size++;
  1050.         }
  1051.     }
  1052.     
  1053.     sfree(score_array);
  1054.     return best_score;
  1055. }
  1056. /** Low level function to perform gapped extension with out-of-frame
  1057.  * gapping with traceback 
  1058.  * @param A The query sequence [in]
  1059.  * @param B The subject sequence [in]
  1060.  * @param M Maximal extension length in query [in]
  1061.  * @param N Maximal extension length in subject [in]
  1062.  * @param S The traceback information from previous extension [in]
  1063.  * @param a_offset Resulting starting offset in query [out]
  1064.  * @param b_offset Resulting starting offset in subject [out]
  1065.  * @param sapp The traceback information [out]
  1066.  * @param gap_align Structure holding various information and allocated 
  1067.  *        memory for the gapped alignment [in]
  1068.  * @param score_params Parameters related to scoring [in]
  1069.  * @param query_offset The starting offset in query [in]
  1070.  * @param reversed Has the sequence been reversed? Used for psi-blast [in]
  1071.  * @return The best alignment score found.
  1072.  */
  1073. #define SCRIPT_GAP_IN_A                 0
  1074. #define SCRIPT_AHEAD_ONE_FRAME          1
  1075. #define SCRIPT_AHEAD_TWO_FRAMES         2
  1076. #define SCRIPT_NEXT_IN_FRAME            3
  1077. #define SCRIPT_NEXT_PLUS_ONE_FRAME      4
  1078. #define SCRIPT_NEXT_PLUS_TWO_FRAMES     5
  1079. #define SCRIPT_GAP_IN_B                 6
  1080. #define SCRIPT_OOF_OP_MASK              0x07
  1081. #define SCRIPT_OOF_OPEN_GAP             0x10
  1082. #define SCRIPT_EXTEND_GAP_IN_A          0x20
  1083. #define SCRIPT_EXTEND_GAP_IN_B          0x40
  1084. static Int4 OOF_ALIGN(Uint1* A, Uint1* B, Int4 M, Int4 N,
  1085.    Int4* S, Int4* a_offset, Int4* b_offset, Int4** sapp, 
  1086.    BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params,
  1087.    Int4 query_offset, Boolean reversed)
  1088. {
  1089.     BlastGapDP* score_array;            /* sequence pointers and indices */
  1090.     Int4 i, increment; 
  1091.     Int4 a_index;
  1092.     Int4 b_index, b_size, first_b_index, last_b_index;
  1093.   
  1094.     Int4 gap_open;              /* alignment penalty variables */
  1095.     Int4 gap_extend;
  1096.     Int4 gap_open_extend;
  1097.     Int4 shift_penalty;
  1098.     Int4 x_dropoff;
  1099.   
  1100.     Int4* *matrix;              /* pointers to the score matrix */
  1101.     Int4* matrix_row;
  1102.   
  1103.     Int4 score;                 /* score tracking variables */
  1104.     Int4 score_row1; 
  1105.     Int4 score_row2; 
  1106.     Int4 score_row3;
  1107.     Int4 score_gap_col; 
  1108.     Int4 score_col1; 
  1109.     Int4 score_col2; 
  1110.     Int4 score_col3;
  1111.     Int4 score_other_frame1; 
  1112.     Int4 score_other_frame2; 
  1113.     Int4 best_score;
  1114.   
  1115.     GapData data;                       /* traceback variables */
  1116.     GapStateArrayStruct* state_struct;
  1117.     Uint1** edit_script;
  1118.     Uint1* edit_script_row;
  1119.     Int4 orig_b_index;
  1120.     Int1 script, next_script;
  1121.     Int4 align_len;
  1122.     /* do initialization and sanity-checking */
  1123.     matrix = gap_align->sbp->matrix;
  1124.     *a_offset = 0;
  1125.     *b_offset = -2;
  1126.     gap_open = score_params->gap_open;
  1127.     gap_extend = score_params->gap_extend;
  1128.     gap_open_extend = gap_open + gap_extend;
  1129.     shift_penalty = score_params->shift_pen;
  1130.     x_dropoff = gap_align->gap_x_dropoff;
  1131.   
  1132.     if (x_dropoff < gap_open_extend)
  1133.         x_dropoff = gap_open_extend;
  1134.   
  1135.     if(N <= 0 || M <= 0) 
  1136.         return 0;
  1137.   
  1138.     /* Initialize traceback information. edit_script[] is
  1139.        a 2-D array which is filled in row by row as the 
  1140.        dynamic programming takes place */
  1141.     data.sapp = S;
  1142.     data.last = 0;
  1143.     *sapp = S;
  1144.     GapPurgeState(gap_align->state_struct);
  1145.     edit_script = (Uint1**) malloc(sizeof(Uint1*)*(M+1));
  1146.     state_struct = GapGetState(&gap_align->state_struct, N + 5);
  1147.     edit_script[0] = state_struct->state_array;
  1148.     edit_script_row = state_struct->state_array;
  1149.     /* Allocate and fill in the auxiliary 
  1150.        bookeeping structures (one struct
  1151.        per letter of B) */
  1152.     score_array = (BlastGapDP*)calloc((N + 4), sizeof(BlastGapDP));
  1153.     score = -gap_open_extend;
  1154.     score_array[0].best = 0;
  1155.     score_array[0].best_gap = -gap_open_extend;
  1156.   
  1157.     for (i = 3; i <= N + 2; i += 3) {
  1158.         score_array[i].best = score;
  1159.         score_array[i].best_gap = score - gap_open_extend; 
  1160.         edit_script_row[i] = SCRIPT_GAP_IN_B;
  1161.         score_array[i-1].best = MININT;
  1162.         score_array[i-1].best_gap = MININT;
  1163.         edit_script_row[i-1] = SCRIPT_GAP_IN_B;
  1164.         score_array[i-2].best = MININT;
  1165.         score_array[i-2].best_gap = MININT;
  1166.         edit_script_row[i-2] = SCRIPT_GAP_IN_B;
  1167.         if (score < -x_dropoff) 
  1168.             break;
  1169.         score -= gap_extend;
  1170.     }
  1171.   
  1172.     /* The inner loop below examines letters of B from 
  1173.        index 'first_b_index' to 'b_size' */
  1174.     b_size = i - 2;
  1175.     state_struct->used = b_size + 1;
  1176.     score_array[b_size].best = MININT;
  1177.     score_array[b_size].best_gap = MININT;
  1178.     best_score = 0;
  1179.     first_b_index = 0;
  1180.     if (reversed) {
  1181.         increment = -1;
  1182.     }
  1183.     else {
  1184.         /* Allow for a backwards frame shift */
  1185.         B -= 2;
  1186.         increment = 1;
  1187.     }
  1188.   
  1189.     for (a_index = 1; a_index <= M; a_index++) {
  1190.         /* Set up the next row of the edit script; this involves
  1191.            allocating memory for the row, then pointing to it */
  1192.         state_struct = GapGetState(&gap_align->state_struct, 
  1193.                           N + 5 - first_b_index);
  1194.         edit_script[a_index] = state_struct->state_array + 
  1195.                                 state_struct->used + 1;
  1196.         edit_script_row = edit_script[a_index];
  1197.         orig_b_index = first_b_index;
  1198.         if (!(gap_align->positionBased)) {
  1199.             matrix_row = matrix[ A[ a_index * increment ] ];
  1200.         }
  1201.         else {
  1202.             if(reversed)
  1203.                 matrix_row = gap_align->sbp->posMatrix[M - a_index];
  1204.             else 
  1205.                 matrix_row = gap_align->sbp->posMatrix[a_index + query_offset];
  1206.         }
  1207.         score = MININT;
  1208.         score_row1 = MININT; 
  1209.         score_row2 = MININT; 
  1210.         score_row3 = MININT;
  1211.         score_gap_col = MININT; 
  1212.         score_col1 = MININT; 
  1213.         score_col2 = MININT; 
  1214.         score_col3 = MININT;
  1215.         score_other_frame1 = MININT; 
  1216.         score_other_frame2 = MININT; 
  1217.         last_b_index = first_b_index;
  1218.         b_index = first_b_index;
  1219.         /* The inner loop is identical to that of OOF_SEMI_G_ALIGN,
  1220.            except that traceback operations are sprinkled throughout. */
  1221.         while (b_index < b_size) {
  1222.             /* FRAME 0 */
  1223.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  1224.             score = MAX(score, score_col1);
  1225.             if (score == score_col1) {
  1226.                 script = SCRIPT_NEXT_IN_FRAME;
  1227.             }
  1228.             else if (score + shift_penalty == score_other_frame1) {
  1229.                 if (score_other_frame1 == score_col2)
  1230.                     script = SCRIPT_AHEAD_TWO_FRAMES;
  1231.                 else
  1232.                     script = SCRIPT_NEXT_PLUS_TWO_FRAMES;
  1233.             }
  1234.             else {
  1235.                 if (score_other_frame2 == score_col3)
  1236.                     script = SCRIPT_AHEAD_ONE_FRAME;
  1237.                 else
  1238.                     script = SCRIPT_NEXT_PLUS_ONE_FRAME;
  1239.             }
  1240.             score += matrix_row[ B[ b_index * increment ] ];
  1241.             score_other_frame1 = MAX(score_col1, score_array[b_index].best);
  1242.             score_col1 = score_array[b_index].best;
  1243.             score_gap_col = score_array[b_index].best_gap;
  1244.             if (score < MAX(score_gap_col, score_row1)) {
  1245.                 if (score_gap_col > score_row1) {
  1246.                     score = score_gap_col;
  1247.                     script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_A;
  1248.                 }
  1249.                 else {
  1250.                     score = score_row1;
  1251.                     script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1252.                 }
  1253.                 if (best_score - score > x_dropoff) {
  1254.                     if (first_b_index == b_index) 
  1255.                         first_b_index = b_index + 1;
  1256.                     else
  1257.                         score_array[b_index].best = MININT;
  1258.                 }
  1259.                 else {
  1260.                     last_b_index = b_index + 1;
  1261.                     score_array[b_index].best = score;
  1262.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  1263.                     score_row1 -= gap_extend;
  1264.                 }
  1265.             }
  1266.             else {
  1267.                 if (best_score - score > x_dropoff) {
  1268.                     if (first_b_index == b_index) 
  1269.                         first_b_index = b_index + 1;
  1270.                     else
  1271.                         score_array[b_index].best = MININT;
  1272.                 }
  1273.                 else {
  1274.                     last_b_index = b_index + 1;
  1275.                     score_array[b_index].best = score;
  1276.                     if (score > best_score) {
  1277.                         best_score = score;
  1278.                         *a_offset = a_index;
  1279.                         *b_offset = b_index;
  1280.                     }
  1281.                     score -= gap_open_extend;
  1282.                     score_row1 -= gap_extend;
  1283.                     if (score > score_row1)
  1284.                         score_row1 = score;
  1285.                     else
  1286.                         script |= SCRIPT_EXTEND_GAP_IN_B;
  1287.                     score_gap_col -= gap_extend;
  1288.                     if (score < score_gap_col) {
  1289.                         score_array[b_index].best_gap = score_gap_col;
  1290.                         script |= SCRIPT_EXTEND_GAP_IN_A;
  1291.                     }
  1292.                     else {
  1293.                         score_array[b_index].best_gap = score;
  1294.                     }
  1295.                 }
  1296.             }
  1297.             edit_script_row[b_index] = script;
  1298.             if (++b_index >= b_size) {
  1299.                 score = score_row1;
  1300.                 score_row1 = score_row2;
  1301.                 score_row2 = score_row3;
  1302.                 score_row3 = score;
  1303.                 break;
  1304.             }
  1305.             /* FRAME 1 */
  1306.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  1307.             score = MAX(score, score_col2);
  1308.             if (score == score_col2) {
  1309.                 script = SCRIPT_NEXT_IN_FRAME;
  1310.             }
  1311.             else if (score + shift_penalty == score_other_frame1) {
  1312.                 if (score_other_frame1 == score_col1)
  1313.                     script = SCRIPT_AHEAD_ONE_FRAME;
  1314.                 else
  1315.                     script = SCRIPT_NEXT_PLUS_ONE_FRAME;
  1316.             }
  1317.             else {
  1318.                 if (score_other_frame2 == score_col3)
  1319.                     script = SCRIPT_AHEAD_TWO_FRAMES;
  1320.                 else
  1321.                     script = SCRIPT_NEXT_PLUS_TWO_FRAMES;
  1322.             }
  1323.             score += matrix_row[ B[ b_index * increment ] ];
  1324.             score_other_frame2 = MAX(score_col2, score_array[b_index].best);
  1325.             score_col2 = score_array[b_index].best;
  1326.             score_gap_col = score_array[b_index].best_gap;
  1327.             if (score < MAX(score_gap_col, score_row2)) {
  1328.                 score = MAX(score_gap_col, score_row2);
  1329.                 if (best_score - score > x_dropoff) {
  1330.                     if (first_b_index == b_index) 
  1331.                         first_b_index = b_index + 1;
  1332.                     else
  1333.                         score_array[b_index].best = MININT;
  1334.                 }
  1335.                 else {
  1336.                     if (score == score_gap_col)
  1337.                         script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_A;
  1338.                     else 
  1339.                         script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1340.                     last_b_index = b_index + 1;
  1341.                     score_array[b_index].best = score;
  1342.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  1343.                     score_row2 -= gap_extend;
  1344.                 }
  1345.             }
  1346.             else {
  1347.                 if (best_score - score > x_dropoff) {
  1348.                     if (first_b_index == b_index) 
  1349.                         first_b_index = b_index + 1;
  1350.                     else
  1351.                         score_array[b_index].best = MININT;
  1352.                 }
  1353.                 else {
  1354.                     last_b_index = b_index + 1;
  1355.                     score_array[b_index].best = score;
  1356.                     if (score > best_score) {
  1357.                         best_score = score;
  1358.                         *a_offset = a_index;
  1359.                         *b_offset = b_index;
  1360.                     }
  1361.                     score -= gap_open_extend;
  1362.                     score_row2 -= gap_extend;
  1363.                     if (score > score_row2)
  1364.                         score_row2 = score;
  1365.                     else
  1366.                         script |= SCRIPT_EXTEND_GAP_IN_B;
  1367.                     score_gap_col -= gap_extend;
  1368.                     if (score < score_gap_col) {
  1369.                         score_array[b_index].best_gap = score_gap_col;
  1370.                         script |= SCRIPT_EXTEND_GAP_IN_A;
  1371.                     }
  1372.                     else {
  1373.                         score_array[b_index].best_gap = score;
  1374.                     }
  1375.                 }
  1376.             }
  1377.             edit_script_row[b_index] = script;
  1378.             ++b_index;
  1379.             if (b_index >= b_size) {
  1380.                 score = score_row2;
  1381.                 score_row2 = score_row1;
  1382.                 score_row1 = score_row3;
  1383.                 score_row3 = score;
  1384.                 break;
  1385.             }
  1386.             /* FRAME 2 */
  1387.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  1388.             score = MAX(score, score_col3);
  1389.             if (score == score_col3) {
  1390.                 script = SCRIPT_NEXT_IN_FRAME;
  1391.             }
  1392.             else if (score + shift_penalty == score_other_frame1) {
  1393.                 if (score_other_frame1 == score_col1)
  1394.                     script = SCRIPT_AHEAD_TWO_FRAMES;
  1395.                 else
  1396.                     script = SCRIPT_NEXT_PLUS_TWO_FRAMES;
  1397.             }
  1398.             else {
  1399.                 if (score_other_frame2 == score_col2)
  1400.                     script = SCRIPT_AHEAD_ONE_FRAME;
  1401.                 else
  1402.                     script = SCRIPT_NEXT_PLUS_ONE_FRAME;
  1403.             }
  1404.             score += matrix_row[ B[ b_index * increment ] ];
  1405.             score_other_frame1 = score_other_frame2;
  1406.             score_other_frame2 = MAX(score_col3, score_array[b_index].best);
  1407.             score_col3 = score_array[b_index].best;
  1408.             score_gap_col = score_array[b_index].best_gap;
  1409.             if (score < MAX(score_gap_col, score_row3)) {
  1410.                 score = MAX(score_gap_col, score_row3);
  1411.                 if (best_score - score > x_dropoff) {
  1412.                     if (first_b_index == b_index) 
  1413.                         first_b_index = b_index + 1;
  1414.                     else
  1415.                         score_array[b_index].best = MININT;
  1416.                 }
  1417.                 else {
  1418.                     if (score == score_gap_col)
  1419.                         script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_A;
  1420.                     else 
  1421.                         script = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1422.                     last_b_index = b_index + 1;
  1423.                     score_array[b_index].best = score;
  1424.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  1425.                     score_row3 -= gap_extend;
  1426.                 }
  1427.             }
  1428.             else {
  1429.                 if (best_score - score > x_dropoff) {
  1430.                     if (first_b_index == b_index) 
  1431.                         first_b_index = b_index + 1;
  1432.                     else
  1433.                         score_array[b_index].best = MININT;
  1434.                 }
  1435.                 else {
  1436.                     last_b_index = b_index + 1;
  1437.                     score_array[b_index].best = score;
  1438.                     if (score > best_score) {
  1439.                         best_score = score;
  1440.                         *a_offset = a_index;
  1441.                         *b_offset = b_index;
  1442.                     }
  1443.                     score -= gap_open_extend;
  1444.                     score_row3 -= gap_extend;
  1445.                     if (score > score_row3)
  1446.                         score_row3 = score;
  1447.                     else
  1448.                         script |= SCRIPT_EXTEND_GAP_IN_B;
  1449.                     score_gap_col -= gap_extend;
  1450.                     if (score < score_gap_col) {
  1451.                         score_array[b_index].best_gap = score_gap_col;
  1452.                         script |= SCRIPT_EXTEND_GAP_IN_A;
  1453.                     }
  1454.                     else {
  1455.                         score_array[b_index].best_gap = score;
  1456.                     }
  1457.                 }
  1458.             }
  1459.             edit_script_row[b_index] = script;
  1460.             b_index++;
  1461.         }
  1462.   
  1463.         /* Finish aligning if the best scores for all positions
  1464.            of B will fail the X-dropoff test, i.e. the inner loop 
  1465.            bounds have converged to each other */
  1466.         if (first_b_index == b_size)
  1467.             break;
  1468.         if (last_b_index < b_size) {
  1469.             /* This row failed the X-dropoff test earlier than
  1470.                the last row did; just shorten the loop bounds
  1471.                before doing the next row */
  1472.             b_size = last_b_index;
  1473.         }
  1474.         else {
  1475.             /* The inner loop finished without failing the X-dropoff
  1476.                test; initialize extra bookkeeping structures until
  1477.                the X dropoff test fails or we run out of letters in B. 
  1478.                The next inner loop will have larger bounds. 
  1479.              
  1480.                Keep initializing extra structures until the X dropoff
  1481.                test fails in all frames for this row */
  1482.             score = MAX(score_row1, MAX(score_row2, score_row3));
  1483.             last_b_index = b_size + (score - (best_score - x_dropoff)) /
  1484.                                                     gap_extend;
  1485.             last_b_index = MIN(last_b_index, N + 2);
  1486.             while (b_size < last_b_index) {
  1487.                 score_array[b_size].best = score_row1;
  1488.                 score_array[b_size].best_gap = score_row1 - gap_open_extend;
  1489.                 score_row1 -= gap_extend;
  1490.                 edit_script_row[b_size] = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1491.                 if (++b_size > last_b_index)
  1492.                     break;
  1493.                 score_array[b_size].best = score_row2;
  1494.                 score_array[b_size].best_gap = score_row2 - gap_open_extend;
  1495.                 score_row2 -= gap_extend;
  1496.                 edit_script_row[b_size] = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1497.                 if (++b_size > last_b_index)
  1498.                     break;
  1499.                 score_array[b_size].best = score_row3;
  1500.                 score_array[b_size].best_gap = score_row3 - gap_open_extend;
  1501.                 score_row3 -= gap_extend;
  1502.                 edit_script_row[b_size] = SCRIPT_OOF_OPEN_GAP | SCRIPT_GAP_IN_B;
  1503.                 if (++b_size > last_b_index)
  1504.                     break;
  1505.             }
  1506.         }
  1507.         /* chop off the best score in each frame */
  1508.         last_b_index = MIN(b_size + 4, N + 3);
  1509.         while (b_size < last_b_index) {
  1510.             score_array[b_size].best = MININT;
  1511.             score_array[b_size].best_gap = MININT;
  1512.             b_size++;
  1513.         }
  1514.         state_struct->used += MAX(b_index, b_size) - orig_b_index + 1;
  1515.     }
  1516.     a_index = *a_offset;
  1517.     b_index = *b_offset;
  1518.     script = 1;
  1519.     align_len = 0;
  1520.     edit_script_row = (Uint1 *)malloc(a_index + b_index);
  1521.     while (a_index > 0 || b_index > 0) {
  1522.         next_script = edit_script[a_index][b_index];
  1523.         switch (script) {
  1524.         case SCRIPT_GAP_IN_A:
  1525.             script = next_script & SCRIPT_OOF_OP_MASK;
  1526.             if (next_script & (SCRIPT_OOF_OPEN_GAP | SCRIPT_EXTEND_GAP_IN_A))
  1527.                 script = SCRIPT_GAP_IN_A;
  1528.             break;
  1529.         case SCRIPT_GAP_IN_B:
  1530.             script = next_script & SCRIPT_OOF_OP_MASK;
  1531.             if (next_script & (SCRIPT_OOF_OPEN_GAP | SCRIPT_EXTEND_GAP_IN_B))
  1532.                 script = SCRIPT_GAP_IN_B;
  1533.             break;
  1534.         default:
  1535.             script = next_script & SCRIPT_OOF_OP_MASK;
  1536.             break;
  1537.         }
  1538.         if (script == SCRIPT_GAP_IN_B) {
  1539.             b_index -= 3;
  1540.         }
  1541.         else {
  1542.             b_index -= script;
  1543.             a_index--;
  1544.         }
  1545.         edit_script_row[align_len++] = script;
  1546.     }
  1547.     /* Traceback proceeded backwards through edit_script, 
  1548.        so the output traceback information is written 
  1549.        in reverse order */
  1550.     for (align_len--; align_len >= 0; align_len--) 
  1551.         *data.sapp++ = edit_script_row[align_len];
  1552.       
  1553.     sfree(edit_script_row);
  1554.     sfree(edit_script);
  1555.     sfree(score_array);
  1556.     *sapp = data.sapp;
  1557.     if (!reversed)
  1558.         *b_offset -= 2;
  1559.     return best_score;
  1560. }
  1561. /** Low level function to perform gapped extension with out-of-frame
  1562.  * gapping with or without traceback.
  1563.  * @param A The query sequence [in]
  1564.  * @param B The subject sequence [in]
  1565.  * @param M Maximal extension length in query [in]
  1566.  * @param N Maximal extension length in subject [in]
  1567.  * @param S The traceback information from previous extension [in]
  1568.  * @param a_offset Resulting starting offset in query [out]
  1569.  * @param b_offset Resulting starting offset in subject [out]
  1570.  * @param score_only Only find the score, without saving traceback [in]
  1571.  * @param sapp the traceback information [out]
  1572.  * @param gap_align Structure holding various information and allocated 
  1573.  *        memory for the gapped alignment [in]
  1574.  * @param score_params Parameters related to scoring [in]
  1575.  * @param query_offset The starting offset in query [in]
  1576.  * @param reversed Has the sequence been reversed? Used for psi-blast [in]
  1577.  * @return The best alignment score found.
  1578.  */
  1579. static Int4 OOF_SEMI_G_ALIGN(Uint1* A, Uint1* B, Int4 M, Int4 N,
  1580.    Int4* S, Int4* a_offset, Int4* b_offset, Boolean score_only, Int4** sapp, 
  1581.    BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params,
  1582.    Int4 query_offset, Boolean reversed)
  1583. {
  1584.     BlastGapDP* score_array;            /* sequence pointers and indices */
  1585.     Int4 i, increment; 
  1586.     Int4 a_index;
  1587.     Int4 b_index, b_size, first_b_index, last_b_index;
  1588.   
  1589.     Int4 gap_open;              /* alignment penalty variables */
  1590.     Int4 gap_extend;
  1591.     Int4 gap_open_extend;
  1592.     Int4 shift_penalty;
  1593.     Int4 x_dropoff;
  1594.   
  1595.     Int4* *matrix;              /* pointers to the score matrix */
  1596.     Int4* matrix_row;
  1597.   
  1598.     Int4 score;                 /* score tracking variables */
  1599.     Int4 score_row1; 
  1600.     Int4 score_row2; 
  1601.     Int4 score_row3;
  1602.     Int4 score_gap_col; 
  1603.     Int4 score_col1; 
  1604.     Int4 score_col2; 
  1605.     Int4 score_col3;
  1606.     Int4 score_other_frame1; 
  1607.     Int4 score_other_frame2; 
  1608.     Int4 best_score;
  1609.   
  1610.     if (!score_only) {
  1611.         return OOF_ALIGN(A, B, M, N, S, a_offset, b_offset, sapp, gap_align, 
  1612.                       score_params, query_offset, reversed);
  1613.     }
  1614.     
  1615.     /* do initialization and sanity-checking */
  1616.     matrix = gap_align->sbp->matrix;
  1617.     *a_offset = 0;
  1618.     *b_offset = -2;
  1619.     gap_open = score_params->gap_open;
  1620.     gap_extend = score_params->gap_extend;
  1621.     gap_open_extend = gap_open + gap_extend;
  1622.     shift_penalty = score_params->shift_pen;
  1623.     x_dropoff = gap_align->gap_x_dropoff;
  1624.   
  1625.     if (x_dropoff < gap_open_extend)
  1626.         x_dropoff = gap_open_extend;
  1627.   
  1628.     if(N <= 0 || M <= 0) 
  1629.         return 0;
  1630.   
  1631.     /* Allocate and fill in the auxiliary 
  1632.        bookeeping structures (one struct
  1633.        per letter of B) */
  1634.     score_array = (BlastGapDP*)calloc((N + 5), sizeof(BlastGapDP));
  1635.     score = -gap_open_extend;
  1636.     score_array[0].best = 0;
  1637.     score_array[0].best_gap = -gap_open_extend;
  1638.   
  1639.     for (i = 3; i <= N + 2; i += 3) {
  1640.         score_array[i].best = score;
  1641.         score_array[i].best_gap = score - gap_open_extend; 
  1642.         score_array[i-1].best = MININT;
  1643.         score_array[i-1].best_gap = MININT;
  1644.         score_array[i-2].best = MININT;
  1645.         score_array[i-2].best_gap = MININT;
  1646.         if (score < -x_dropoff) 
  1647.             break;
  1648.         score -= gap_extend;
  1649.     }
  1650.   
  1651.     /* The inner loop below examines letters of B from 
  1652.        index 'first_b_index' to 'b_size' */
  1653.     b_size = i - 2;
  1654.     score_array[b_size].best = MININT;
  1655.     score_array[b_size].best_gap = MININT;
  1656.     best_score = 0;
  1657.     first_b_index = 0;
  1658.     if (reversed) {
  1659.         increment = -1;
  1660.     }
  1661.     else {
  1662.         /* Allow for a backwards frame shift */
  1663.         B -= 2;
  1664.         increment = 1;
  1665.     }
  1666.   
  1667.     for (a_index = 1; a_index <= M; a_index++) {
  1668.         /* XXX Why is this here? */
  1669.         score_array[2].best = MININT;
  1670.         score_array[2].best_gap = MININT;
  1671.         /* pick out the row of the score matrix 
  1672.            appropriate for A[a_index] */
  1673.         if (!(gap_align->positionBased)) {
  1674.             matrix_row = matrix[ A[ a_index * increment ] ];
  1675.         }
  1676.         else {
  1677.             if(reversed)
  1678.                 matrix_row = gap_align->sbp->posMatrix[M - a_index];
  1679.             else 
  1680.                 matrix_row = gap_align->sbp->posMatrix[a_index + query_offset];
  1681.         }
  1682.         /* initialize running-score variables */
  1683.         score = MININT;
  1684.         score_row1 = MININT; 
  1685.         score_row2 = MININT; 
  1686.         score_row3 = MININT;
  1687.         score_gap_col = MININT; 
  1688.         score_col1 = MININT; 
  1689.         score_col2 = MININT; 
  1690.         score_col3 = MININT;
  1691.         score_other_frame1 = MININT; 
  1692.         score_other_frame2 = MININT; 
  1693.         last_b_index = first_b_index;
  1694.         b_index = first_b_index;
  1695.         while (b_index < b_size) {
  1696.             /* FRAME 0 */
  1697.             /* Pick the best score among all frames */
  1698.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  1699.             score = MAX(score, score_col1) + 
  1700.                                 matrix_row[ B[ b_index * increment ] ];
  1701.             score_other_frame1 = MAX(score_col1, score_array[b_index].best);
  1702.             score_col1 = score_array[b_index].best;
  1703.             score_gap_col = score_array[b_index].best_gap;
  1704.             /* Use the row and column scores if they improve
  1705.                the score overall */
  1706.             if (score < MAX(score_gap_col, score_row1)) {
  1707.                 score = MAX(score_gap_col, score_row1);
  1708.                 if (best_score - score > x_dropoff) {
  1709.                    /* the current best score failed the X-dropoff
  1710.                       criterion. Note that this does not stop the
  1711.                       inner loop, only forces future iterations to
  1712.                       skip this column of B. 
  1713.    
  1714.                       Also, if the very first letter of B that was
  1715.                       tested failed the X dropoff criterion, make
  1716.                       sure future inner loops start one letter to 
  1717.                       the right */
  1718.                     if (first_b_index == b_index) 
  1719.                         first_b_index = b_index + 1;
  1720.                     else
  1721.                         score_array[b_index].best = MININT;
  1722.                 }
  1723.                 else {
  1724.                     /* update the row and column running scores */
  1725.                     last_b_index = b_index + 1;
  1726.                     score_array[b_index].best = score;
  1727.                     score_array[b_index].best_gap = score_gap_col - gap_extend;
  1728.                     score_row1 -= gap_extend;
  1729.                 }
  1730.             }
  1731.             else {
  1732.                 if (best_score - score > x_dropoff) {
  1733.                    /* the current best score failed the X-dropoff
  1734.                       criterion. */
  1735.                     if (first_b_index == b_index) 
  1736.                         first_b_index = b_index + 1;
  1737.                     else
  1738.                         score_array[b_index].best = MININT;
  1739.                 }
  1740.                 else {
  1741.                     /* The current best score exceeds the
  1742.                        row and column scores, and thus may
  1743.                        improve on the current optimal score */
  1744.                     last_b_index = b_index + 1;
  1745.                     score_array[b_index].best = score;
  1746.                     if (score > best_score) {
  1747.                         best_score = score;
  1748.                         *a_offset = a_index;
  1749.                         *b_offset = b_index;
  1750.                     }
  1751.                     /* compute the best scores that include gaps
  1752.                        or gap extensions */
  1753.                     score -= gap_open_extend;
  1754.                     score_row1 -= gap_extend;
  1755.                     score_row1 = MAX(score, score_row1);
  1756.                     score_array[b_index].best_gap = MAX(score, 
  1757.                                                   score_gap_col - gap_extend);
  1758.                 }
  1759.             }
  1760.             /* If this was the last letter of B checked, rotate
  1761.                the row scores so that code beyond the inner loop
  1762.                works correctly */
  1763.             if (++b_index >= b_size) {
  1764.                 score = score_row1;
  1765.                 score_row1 = score_row2;
  1766.                 score_row2 = score_row3;
  1767.                 score_row3 = score;
  1768.                 break;
  1769.             }
  1770.             /* FRAME 1 */
  1771.             /* This code, and that for Frame 2, are essentially the
  1772.                same as the preceeding code. The only real difference
  1773.                is the updating of the other_frame best scores */
  1774.             score = MAX(score_other_frame1, score_other_frame2) - shift_penalty;
  1775.             score = MAX(score, score_col2) + 
  1776.                                 matrix_row[ B[ b_index * increment ] ];
  1777.             score_other_frame2 = MAX(score_col2, score_array[b_index].best);
  1778.             score_col2 = score_array[b_index].best;
  1779.             score_gap_col = score_array[b_index].best_gap;
  1780.             if (score < MAX(score_gap_col, score_row2)) {
  1781.                 score = MAX(score_gap_col, score_row2);