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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: pattern.c,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:08:25  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: pattern.c,v 1000.2 2004/06/01 18:08:25 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 pattern.c
  38.  * Functions for finding pattern matches in sequence.
  39.  * @todo FIXME needs doxygen comments and lines shorter than 80 characters
  40.  */
  41. static char const rcsid[] = 
  42.     "$Id: pattern.c,v 1000.2 2004/06/01 18:08:25 gouriano Exp $";
  43. #include <algo/blast/core/blast_def.h>
  44. #include <algo/blast/core/pattern.h>
  45. /*Looks for 1 bits in the same position of s and mask
  46.   Let rightOne be the rightmost position where s and mask both have
  47.   a 1.
  48.   Let rightMaskOnly < rightOne be the rightmost position where mask has a 1, if any
  49.      or -1 otherwise
  50.   returns (rightOne - rightMaskOnly) */
  51.   
  52. static Int4 lenof(Int4 s, Int4 mask)
  53. {
  54.     Int4 checkingMatches = s & mask;  /*look for 1 bits in same position*/
  55.     Int4 rightOne; /*loop index looking for 1 in checkingMatches*/
  56.     Int4 rightMaskOnly; /*rightnost bit that is 1 in the mask only*/
  57.     rightMaskOnly = -1;
  58.     /*AAS Changed upper bound on loop here*/
  59.     for (rightOne = 0; rightOne < BITS_PACKED_PER_WORD; rightOne++) {
  60.        if ((checkingMatches >> rightOne) % 2  == 1) 
  61.           return rightOne - rightMaskOnly;
  62.        if ((mask >> rightOne) %2  == 1) 
  63.           rightMaskOnly = rightOne;
  64.     }
  65.     /*ErrPostEx(SEV_FATAL, 1, 0, "wrongn");*/
  66.     return(-1);
  67. }
  68. /* routine to find hits of pattern to sequence when sequence is proteins
  69.    hitArray is an array of matches to pass back
  70.    seq is the input sequence
  71.    len1 is the length of the input sequence
  72.    patternSearch carries variables that keep track of
  73.       search parameters
  74.    returns the number of matches*/
  75. static Int4 find_hitsS(Int4 *hitArray, const Uint1* seq, Int4 len1, 
  76. patternSearchItems *patternSearch)
  77. {
  78.     Int4 i; /*loop index on sequence*/
  79.     Int4 prefixMatchedBitPattern = 0; /*indicates where pattern aligns
  80.                  with seq; e.g., if value is 9 = 0101 then 
  81.                  last 3 chars of seq match first 3 positions in pattern
  82.                  and last 1 char of seq matches 1 position of pattern*/
  83.     Int4 numMatches = 0; /*number of matches found*/
  84.     Int4 mask;  /*mask of input pattern positions after which
  85.                   a match can be declared*/
  86.     Int4 maskShiftPlus1; /*mask shifted left 1 plus 1 */
  87.     mask = patternSearch->match_mask; 
  88.     maskShiftPlus1 = (mask << 1) + 1;
  89.     for (i = 0; i < len1; i++) {
  90.       /*shift the positions matched by 1 and try to match up against
  91.         the next character, also allow next character to match the
  92.         first position*/
  93.       prefixMatchedBitPattern =  
  94.          ((prefixMatchedBitPattern << 1) | maskShiftPlus1) & 
  95.          patternSearch->whichPositionPtr[seq[i]];
  96.       if (prefixMatchedBitPattern & mask) { 
  97.          /*first part of pair is index of place in seq where match
  98.            ends; second part is where match starts*/
  99.          hitArray[numMatches++] = i;
  100.          hitArray[numMatches++] = i - lenof(prefixMatchedBitPattern, mask)+1;
  101.          if (numMatches == MAX_HIT)
  102.          {
  103.             /*ErrPostEx(SEV_WARNING, 0, 0, 
  104.               "%ld matches saved, discarding others", numMatches);*/
  105.             break;
  106.          }
  107.       }
  108.     }
  109.     return numMatches;
  110. }
  111. /*find hits when sequence is DNA and pattern is short
  112.   returns twice the number of hits
  113.   pos indicates the starting position
  114.   len is length of sequence seq
  115.   hitArray stores the results*/
  116. static Int4 find_hitsS_DNA(Int4* hitArray, const Uint1* seq, Int4 pos, Int4 len,
  117.        patternSearchItems *patternSearch)
  118. {
  119.   /*Some variables and the algorithm are similar to what is
  120.     used in find_hits() above; see more detailed comments there*/
  121.   Uint4 prefixMatchedBitPattern; /*indicates where pattern aligns
  122.                                   with sequence*/
  123.   Uint4 mask2; /*mask to match agaist*/
  124.   Int4 maskShiftPlus1; /*mask2 shifted plus 1*/
  125.   Uint4 tmp; /*intermediate result of masked comparisons*/
  126.   Int4 i; /*index on seq*/
  127.   Int4 end; /*count of number of 4-mer iterations needed*/
  128.   Int4 remain; /*0,1,2,3 DNA letters left over*/
  129.   Int4 j; /*index on suffixRemnant*/
  130.   Int4 twiceNumHits = 0; /*twice the number of hits*/
  131.   mask2 = patternSearch->match_mask*BITS_PACKED_PER_WORD+15; 
  132.   maskShiftPlus1 = (patternSearch->match_mask << 1)+1;
  133.   if (pos != 0) {
  134.     pos = 4 - pos;
  135.     prefixMatchedBitPattern = ((patternSearch->match_mask * ((1 << (pos+1))-1)*2) +
  136.  (1 << (pos+1))-1)& patternSearch->DNAwhichSuffixPosPtr[seq[0]];
  137.     seq++;
  138.     end = (len-pos)/4; 
  139.     remain = (len-pos) % 4;
  140.   } 
  141.   else {
  142.     prefixMatchedBitPattern = maskShiftPlus1;
  143.     end = len/4; 
  144.     remain = len % 4;
  145.   }
  146.   for (i = 0; i < end; i++) {
  147.     if ( (tmp = (prefixMatchedBitPattern &
  148.                  patternSearch->DNAwhichPrefixPosPtr[seq[i]]))) {
  149.       for (j = 0; j < 4; j++) {
  150. if (tmp & patternSearch->match_mask) {
  151.   hitArray[twiceNumHits++] = i*4+j + pos;
  152.   hitArray[twiceNumHits++] = i*4+j + pos -lenof(tmp & patternSearch->match_mask, 
  153.   patternSearch->match_mask)+1;
  154. }
  155. tmp = (tmp << 1);
  156.       }
  157.     }
  158.     prefixMatchedBitPattern = (((prefixMatchedBitPattern << 4) | mask2) & patternSearch->DNAwhichSuffixPosPtr[seq[i]]);
  159.   }
  160.   /* In the last byte check bits only up to 'remain' */
  161.   if ( (tmp = (prefixMatchedBitPattern &
  162.                patternSearch->DNAwhichPrefixPosPtr[seq[i]]))) {
  163.      for (j = 0; j < remain; j++) {
  164.         if (tmp & patternSearch->match_mask) {
  165.            hitArray[twiceNumHits++] = i*4+j + pos;
  166.            hitArray[twiceNumHits++] = i*4+j + pos - lenof(tmp & patternSearch->match_mask, patternSearch->match_mask)+1;
  167.         }
  168.         tmp = (tmp << 1);
  169.      }
  170.   }
  171.   return twiceNumHits;
  172. }
  173. /*Top level routine when pattern has a short description
  174.   hitArray is to return the hits
  175.   seq is the input sequence
  176.   start is what position to start at in seq
  177.   len is the length of seq
  178.   is_dna is 1 if and only if seq is a DNA sequence
  179.   the return value from the appropriate lower level routine is passed
  180.   back*/
  181. static Int4  find_hitsS_head(Int4* hitArray, const Uint1* seq, Int4 start, Int4 len, 
  182.       Uint1 is_dna, patternSearchItems *patternSearch)
  183. {
  184.   if (is_dna) 
  185.     return find_hitsS_DNA(hitArray, &seq[start/4], start % 4, len, patternSearch);
  186.   return find_hitsS(hitArray, &seq[start], len, patternSearch);
  187. }
  188. /*Shift each word in the array left by 1 bit and add bit b,
  189.   if the new values is bigger that OVERFLOW1, then subtract OVERFLOW1 */
  190. static void lmove(Int4 *a, Uint1 b, patternSearchItems *patternSearch)
  191. {
  192.     Int4 x;
  193.     Int4 i; /*index on words*/
  194.     for (i = 0; i < patternSearch->numWords; i++) {
  195.       x = (a[i] << 1) + b;
  196.       if (x >= OVERFLOW1) {
  197. a[i] = x - OVERFLOW1; 
  198. b = 1;
  199.       }
  200.       else { 
  201. a[i] = x; 
  202. b = 0;
  203.       }
  204.     }
  205. }  
  206. /*Do a word-by-word bit-wise or of a and b and put the result back in a*/
  207. static void or(Int4 *a, Int4 *b, patternSearchItems *patternSearch)
  208. {
  209.     Int4 i; /*index over words*/
  210.     for (i = 0; i < patternSearch->numWords; i++) 
  211. a[i] = (a[i] | b[i]);
  212. }
  213. /*Do a word-by-word bit-wise or of a and b and put the result in
  214.   result; return 1 if there are any non-zero words*/
  215. static Int4 and(Int4 *result, Int4 *a, Int4 *b, patternSearchItems *patternSearch)
  216. {
  217.     Int4 i; /*index over words*/
  218.     Int4 returnValue = 0;
  219.     for (i = 0; i < patternSearch->numWords; i++) 
  220.       if ( (result[i] = (a[i] & b[i]) ) ) 
  221. returnValue = 1;
  222.     return returnValue;
  223. }
  224. /*Let F be the number of the first bit in s that is 1
  225.   Let G be the first bit in mask that is one such that G < F;
  226.   Else let G = -1;
  227.   Returns F - G*/
  228. static Int4 lenofL(Int4 *s, Int4 *mask, patternSearchItems *patternSearch)
  229. {
  230.     Int4 bitIndex; /*loop index over bits in a word*/
  231.     Int4 wordIndex;  /*loop index over words*/
  232.     Int4 firstOneInMask;
  233.     firstOneInMask = -1;
  234.     for (wordIndex = 0; wordIndex < patternSearch->numWords; wordIndex++) {
  235.       for (bitIndex = 0; bitIndex < BITS_PACKED_PER_WORD; bitIndex++) { 
  236. if ((s[wordIndex] >> bitIndex) % 2  == 1) 
  237.   return wordIndex*BITS_PACKED_PER_WORD+bitIndex-firstOneInMask;
  238. if ((mask[wordIndex] >> bitIndex) %2  == 1) 
  239.   firstOneInMask = wordIndex*BITS_PACKED_PER_WORD+bitIndex;
  240.       }
  241.     }
  242.     /*ErrPostEx(SEV_FATAL, 1, 0, "wrongn");*/
  243.     return(-1);
  244. }
  245. /* Finds places where pattern matches seq and returns them as
  246.    pairs of positions in consecutive entries of hitArray;
  247.    similar to find_hitsS
  248.    hitArray is array of hits to return
  249.    seq is the input sequence and len1 is its length
  250.    patternSearch carries all the pattern variables
  251.    return twice the number of hits*/
  252. static Int4 find_hitsL(Int4 *hitArray, const Uint1* seq, Int4 len1, 
  253.        patternSearchItems *patternSearch)
  254. {
  255.     Int4 wordIndex; /*index on words in mask*/
  256.     Int4 i; /*loop index on seq */
  257.     Int4  *prefixMatchedBitPattern; /*see similar variable in
  258.                                       find_hitsS*/
  259.     Int4 twiceNumHits = 0; /*counter for hitArray*/
  260.     Int4 *mask; /*local copy of match_maskL version of pattern
  261.                   indicates after which positions a match can be declared*/
  262.     Int4 *matchResult; /*Array of words to hold the result of the
  263.                          final test for a match*/
  264.     matchResult = (Int4 *) calloc(patternSearch->numWords, sizeof(Int4));
  265.     mask = (Int4 *) calloc(patternSearch->numWords, sizeof(Int4));
  266.     prefixMatchedBitPattern = (Int4 *) calloc(patternSearch->numWords, sizeof(Int4));
  267.     for (wordIndex = 0; wordIndex < patternSearch->numWords; wordIndex++) {
  268.       mask[wordIndex] = patternSearch->match_maskL[wordIndex];
  269.       prefixMatchedBitPattern[wordIndex] = 0;
  270.     }
  271.     /*This is a multiword version of the algorithm in find_hitsS*/
  272.     lmove(mask, 1, patternSearch);
  273.     for (i = 0; i < len1; i++) {
  274.       lmove(prefixMatchedBitPattern, 0, patternSearch);
  275.       or(prefixMatchedBitPattern, mask, patternSearch); 
  276.       and(prefixMatchedBitPattern, prefixMatchedBitPattern, patternSearch->bitPatternByLetter[seq[i]], patternSearch);
  277.       if (and(matchResult, prefixMatchedBitPattern, patternSearch->match_maskL, patternSearch)) { 
  278. hitArray[twiceNumHits++] = i; 
  279. hitArray[twiceNumHits++] = i-lenofL(matchResult, patternSearch->match_maskL, patternSearch)+1;
  280.       }
  281.     }
  282.     sfree(prefixMatchedBitPattern); 
  283.     sfree(matchResult); 
  284.     sfree(mask);
  285.     return twiceNumHits;
  286. }
  287. /*find matches when pattern is very long,
  288.   hitArray is used to pass back pairs of end position. start position for hits
  289.   seq is the sequence; len is its length
  290.   is_dna indicates if the sequence is DNA or protein*/
  291. static Int4 find_hitsLL(Int4 *hitArray, const Uint1* seq, Int4 len, Boolean is_dna,
  292.  patternSearchItems *patternSearch)
  293. {
  294.     Int4 twiceNumHits; /*twice the number of matches*/
  295.     Int4 twiceHitsOneCall; /*twice the number of hits in one call to 
  296.                                  find_hitsS */
  297.     Int4 wordIndex;  /*index over words in pattern*/
  298.     Int4 start; /*start position in sequence for calls to find_hitsS */
  299.     Int4 hitArray1[MAX_HIT]; /*used to get hits against different words*/
  300.     Int4 nextPosInHitArray; /*next available position in hitArray1 */
  301.     Int4 hitIndex1, hitIndex2;  /*indices over hitArray1*/
  302.     patternSearch->whichPositionPtr = 
  303.       patternSearch->SLL[patternSearch->whichMostSpecific]; 
  304.     patternSearch->match_mask = 
  305.       patternSearch->match_maskL[patternSearch->whichMostSpecific];
  306.     if (is_dna) {
  307.       patternSearch->DNAwhichPrefixPosPtr = patternSearch->DNAprefixSLL[patternSearch->whichMostSpecific];
  308.       patternSearch->DNAwhichSuffixPosPtr = patternSearch->DNAsuffixSLL[patternSearch->whichMostSpecific];
  309.     }
  310.     /*find matches to most specific word of pattern*/
  311.     twiceNumHits = find_hitsS_head(hitArray, seq, 0, len, is_dna, patternSearch);
  312.     if (twiceNumHits < 2) 
  313.       return 0;
  314.     /*extend matches word by word*/
  315.     for (wordIndex = patternSearch->whichMostSpecific+1; 
  316.  wordIndex < patternSearch->numWords; wordIndex++) {
  317. patternSearch->whichPositionPtr = 
  318.   patternSearch->SLL[wordIndex]; 
  319. patternSearch->match_mask = patternSearch->match_maskL[wordIndex];
  320. if (is_dna) {
  321.   patternSearch->DNAwhichPrefixPosPtr = patternSearch->DNAprefixSLL[wordIndex]; 
  322.   patternSearch->DNAwhichSuffixPosPtr = patternSearch->DNAsuffixSLL[wordIndex];
  323. }
  324. nextPosInHitArray = 0;
  325. for (hitIndex2 = 0; hitIndex2 < twiceNumHits; hitIndex2 += 2) {
  326.   twiceHitsOneCall = find_hitsS_head(&hitArray1[nextPosInHitArray], seq, 
  327.        hitArray[hitIndex2]+1, MIN(len-hitArray[hitIndex2]-1, 
  328.        patternSearch->spacing[wordIndex-1] + patternSearch->numPlacesInWord[wordIndex]), is_dna, patternSearch);
  329.   for (hitIndex1 = 0; hitIndex1 < twiceHitsOneCall; hitIndex1+= 2) {
  330.     hitArray1[nextPosInHitArray+hitIndex1] = 
  331.       hitArray[hitIndex2]+hitArray1[nextPosInHitArray+hitIndex1]+1;
  332.     hitArray1[nextPosInHitArray+hitIndex1+1] = hitArray[hitIndex2+1];
  333.   }
  334.   nextPosInHitArray += twiceHitsOneCall;
  335. }
  336. twiceNumHits = nextPosInHitArray;
  337. if (twiceNumHits < 2) 
  338.   return 0;
  339.         /*copy back matches that extend */
  340. for (hitIndex2 = 0; hitIndex2 < nextPosInHitArray; hitIndex2++) 
  341.   hitArray[hitIndex2] = hitArray1[hitIndex2];
  342.     }
  343.     /*extend each match back one word at a time*/
  344.     for (wordIndex = patternSearch->whichMostSpecific-1; wordIndex >=0; 
  345.  wordIndex--) {
  346.       patternSearch->whichPositionPtr = 
  347. patternSearch->SLL[wordIndex]; 
  348.       patternSearch->match_mask = patternSearch->match_maskL[wordIndex];
  349.       if (is_dna) {
  350. patternSearch->DNAwhichPrefixPosPtr = patternSearch->DNAprefixSLL[wordIndex]; 
  351. patternSearch->DNAwhichSuffixPosPtr = patternSearch->DNAsuffixSLL[wordIndex];
  352.       }
  353.       nextPosInHitArray = 0;
  354.       for (hitIndex2 = 0; hitIndex2 < twiceNumHits; hitIndex2 += 2) {
  355. start = hitArray[hitIndex2+1]-patternSearch->spacing[wordIndex]-patternSearch->numPlacesInWord[wordIndex];
  356. if (start < 0) 
  357.   start = 0;
  358. twiceHitsOneCall = find_hitsS_head(&hitArray1[nextPosInHitArray], seq, start, 
  359.     hitArray[hitIndex2+1]-start, is_dna, patternSearch);
  360. for (hitIndex1 = 0; hitIndex1 < twiceHitsOneCall; hitIndex1+= 2) {
  361.   hitArray1[nextPosInHitArray+hitIndex1] = hitArray[hitIndex2];
  362.   hitArray1[nextPosInHitArray+hitIndex1+1] = start + 
  363.     hitArray1[nextPosInHitArray+hitIndex1+1];
  364. }
  365. nextPosInHitArray += twiceHitsOneCall;
  366.       }
  367.       twiceNumHits = nextPosInHitArray;
  368.       if (twiceNumHits < 2) 
  369. return 0;
  370.       /*copy back matches that extend*/
  371.       for (hitIndex2 = 0; hitIndex2 < nextPosInHitArray; hitIndex2++) 
  372. hitArray[hitIndex2] = hitArray1[hitIndex2];
  373.     }
  374.     return twiceNumHits;
  375. }
  376. Int4 FindPatternHits(Int4 *hitArray, const Uint1* seq, Int4 len, 
  377.                Boolean is_dna, patternSearchItems * patternSearch)
  378. {
  379.     if (patternSearch->flagPatternLength == ONE_WORD_PATTERN) 
  380.       return find_hitsS_head(hitArray, seq, 0, len, is_dna, patternSearch);
  381.     if (patternSearch->flagPatternLength == MULTI_WORD_PATTERN) 
  382.       return find_hitsL(hitArray, seq, len, patternSearch);
  383.     return find_hitsLL(hitArray, seq, len, is_dna, patternSearch);
  384. }