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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: restriction.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 18:10:51  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.11
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: restriction.cpp,v 1000.1 2004/06/01 18:10:51 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 official 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.  * Authors:  Josh Cherry
  35.  *
  36.  * File Description:  Classes for representing and finding restriction sites
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. #include <objmgr/seq_vector.hpp>
  42. #include <algorithm>
  43. #include <algo/sequence/restriction.hpp>
  44. BEGIN_NCBI_SCOPE
  45. USING_SCOPE(objects);
  46. bool CRSpec::operator<(const CRSpec& rhs) const
  47. {
  48.     if (GetSeq() != rhs.GetSeq()) {
  49.         return GetSeq() < rhs.GetSeq();
  50.     }
  51.     // otherwise sequences identical
  52.     if (GetPlusCuts() != rhs.GetPlusCuts()) {
  53.         return GetPlusCuts() < rhs.GetPlusCuts();
  54.     }
  55.     if (GetMinusCuts() != rhs.GetMinusCuts()) {
  56.         return GetMinusCuts() < rhs.GetMinusCuts();
  57.     }
  58.     // otherwise arguments are equal, and < is false
  59.     return false;
  60. }
  61. void CREnzyme::Reset(void)
  62. {
  63.     m_Name.erase();
  64.     m_Specs.clear();
  65. }
  66. // helper functor for sorting enzymes by specificity
  67. struct SCompareSpecs
  68. {
  69.     bool operator()(const CREnzyme& lhs, const CREnzyme& rhs)
  70.     {
  71.         return lhs.GetSpecs() < rhs.GetSpecs();
  72.     }
  73. };
  74. void CREnzyme::CombineIsoschizomers(vector<CREnzyme>& enzymes)
  75. {
  76.     stable_sort(enzymes.begin(), enzymes.end(), SCompareSpecs());
  77.     vector<CREnzyme> result;
  78.     ITERATE (vector<CREnzyme>, enzyme, enzymes) {
  79.         if (enzyme != enzymes.begin() &&
  80.             enzyme->GetSpecs() == result.back().GetSpecs()) {
  81.             result.back().SetName() += "/";
  82.             result.back().SetName() += enzyme->GetName();
  83.         } else {
  84.             result.push_back(*enzyme);
  85.         }
  86.     }
  87.     swap(enzymes, result);
  88. }
  89. void CRSpec::Reset(void)
  90. {
  91.     m_Seq.erase();
  92.     m_PlusCuts.clear();
  93.     m_MinusCuts.clear();
  94. }
  95. ostream& operator<<(ostream& os, const CRSite& site)
  96. {
  97.     os << "Recog. site: " << site.GetStart() << '-'
  98.        << site.GetEnd() << endl;
  99.     os << "Plus strand cuts: ";
  100.     string s;
  101.     ITERATE (vector<int>, cut, site.GetPlusCuts()) {
  102.         if (!s.empty()) {
  103.             s += " ,";
  104.         }
  105.         s += NStr::IntToString(*cut);
  106.     }
  107.     os << s << endl;
  108.     os << "Minus strand cuts: ";
  109.     s.erase();
  110.     ITERATE (vector<int>, cut, site.GetMinusCuts()) {
  111.         if (!s.empty()) {
  112.             s += " ,";
  113.         }
  114.         s += NStr::IntToString(*cut);
  115.     }
  116.     os << s << endl;
  117.     
  118.     return os;    
  119. }
  120. ostream& operator<<(ostream& os, const CREnzResult& er)
  121. {
  122.     os << "Enzyme: " << er.GetEnzymeName() << endl;
  123.     os << er.GetDefiniteSites().size() << " definite sites:" << endl;
  124.     ITERATE (vector<CRSite>, site, er.GetDefiniteSites()) {
  125.         os << *site;
  126.     }
  127.     os << er.GetPossibleSites().size() << " possible sites:" << endl;
  128.     ITERATE (vector<CRSite>, site, er.GetPossibleSites()) {
  129.         os << *site;
  130.     }
  131.     return os;
  132. }
  133. struct SCompareLocation
  134. {
  135.     bool operator() (const CRSite& lhs, const CRSite& rhs) const
  136.     {
  137.         return lhs.GetStart() < rhs.GetStart();
  138.     }
  139. };
  140. // Class for internal use by restriction site finding.
  141. // Holds a pattern in ncbi8na, integers that specify
  142. // which enzyme (of a sequential collection) 
  143. // and which specifity of that
  144. // enzyme it represents, a field indicating
  145. // whether it represents the complement of the specificity,
  146. // and the length of the initial subpattern that was
  147. // put into the fsm.
  148. class CPatternRec
  149. {
  150. public:
  151.     enum EIsComplement {
  152.         eIsNotComplement,
  153.         eIsComplement
  154.     };
  155.     CPatternRec(string pattern, int enzyme_index, int spec_index,
  156.                 EIsComplement is_complement,
  157.                 unsigned int fsm_pat_size) : m_Pattern(pattern),
  158.                                              m_EnzymeIndex(enzyme_index),
  159.                                              m_SpecIndex(spec_index),
  160.                                              m_IsComplement(is_complement),
  161.                                              m_FsmPatSize(fsm_pat_size) {}
  162.     // member access
  163.     const string& GetPattern(void) const {return m_Pattern;}
  164.     int GetEnzymeIndex(void) const {return m_EnzymeIndex;}
  165.     int GetSpecIndex(void) const {return m_SpecIndex;}
  166.     EIsComplement GetIsComlement(void) const {return m_IsComplement;}
  167.     bool IsComplement(void) const {return m_IsComplement == eIsComplement;}
  168.     unsigned int GetFsmPatSize(void) const {return m_FsmPatSize;}
  169. private:
  170.     // pattern in ncbi8na
  171.     string m_Pattern;
  172.     // which enzyme and specificity we represent
  173.     int m_EnzymeIndex;
  174.     int m_SpecIndex;
  175.     // whether we represent the complement of the specificity
  176.     EIsComplement m_IsComplement;
  177.     unsigned int m_FsmPatSize;
  178. };
  179. void CFindRSites::x_ExpandRecursion(string& s, unsigned int pos,
  180.                                     CTextFsm<int>& fsm, int match_value)
  181. {
  182.     if (pos == s.size()) {
  183.         // this is the place
  184.         fsm.AddWord(s, match_value);
  185.         return;
  186.     }
  187.     char orig_ch = s[pos];
  188.     for (char x = 1;  x <= 8;  x <<= 1) {
  189.         if (orig_ch & x) {
  190.             s[pos] = x;
  191.             x_ExpandRecursion(s, pos + 1, fsm, match_value);
  192.         }
  193.     }
  194.     // restore original character
  195.     s[pos] = orig_ch;
  196. }
  197. void CFindRSites::x_AddPattern(const string& pat, CTextFsm<int>& fsm,
  198.                                int match_value)
  199. {
  200.     string s = pat;
  201.     x_ExpandRecursion(s, 0, fsm, match_value);
  202. }
  203. bool CFindRSites::x_IsAmbig(char nuc)
  204. {
  205.     static const bool ambig_table[16] = {
  206.         0, 0, 0, 1, 0, 1, 1, 1,
  207.         0, 1, 1, 1, 1, 1, 1, 1
  208.     };
  209.     return ambig_table[nuc];
  210. }
  211. /// Find all definite and possible sites in a sequence
  212. /// for a vector of enzymes, using a finite state machine.
  213. /// Templatized so that seq can be various containers
  214. /// (e.g., string, vector<char>, CSeqVector),
  215. /// but it must yield ncbi8na.
  216. template<class Seq>
  217. void x_FindRSite(const Seq& seq, const vector<CREnzyme>& enzymes,
  218.                  vector<CRef<CREnzResult> >& results)
  219. {
  220.     results.clear();
  221.     results.reserve(enzymes.size());
  222.     // vector of patterns for internal use
  223.     vector<CPatternRec> patterns;
  224.     patterns.reserve(enzymes.size());  // an underestimate
  225.     
  226.     // the finite state machine for the search
  227.     CTextFsm<int> fsm;
  228.     // iterate over enzymes
  229.     ITERATE (vector<CREnzyme>, enzyme, enzymes) {
  230.         results.push_back(CRef<CREnzResult> 
  231.                           (new CREnzResult(enzyme->GetName())));
  232.         string pat;
  233.         const vector<CRSpec>& specs = enzyme->GetSpecs();
  234.         // iterate over specificities for this enzyme
  235.         ITERATE (vector<CRSpec>, spec, specs) {
  236.             // one or two patterns for this specificity
  237.             // (one for pallindrome, two otherwise)
  238.             
  239.             // to avoid combinatorial explosion,
  240.             // if there are more than two Ns only use
  241.             // part of pattern before first N
  242.             CSeqMatch::IupacToNcbi8na(spec->GetSeq(), pat);
  243.             SIZE_TYPE fsm_pat_size = pat.find_first_of(0x0f);
  244.             {{
  245.                 SIZE_TYPE pos = pat.find_first_of(0x0f, fsm_pat_size + 1);
  246.                 if (pos == NPOS
  247.                     ||  pat.find_first_of(0x0f, pos + 1) == NPOS) {
  248.                     fsm_pat_size = pat.size();
  249.                 }
  250.             }}
  251.             patterns.push_back(CPatternRec(pat, enzyme - enzymes.begin(),
  252.                                            spec - specs.begin(), 
  253.                                            CPatternRec::eIsNotComplement,
  254.                                            fsm_pat_size));
  255.             // add pattern to fsm
  256.             // (add only fsm_pat_size of it)
  257.             CFindRSites::x_AddPattern(pat.substr(0, fsm_pat_size), fsm,
  258.                                       patterns.size() - 1);
  259.             // if the pattern is not pallindromic,
  260.             // do a search for its complement too
  261.             string comp = pat;
  262.             CSeqMatch::CompNcbi8na(comp);
  263.             if (comp != pat) {
  264.                 {{
  265.                     fsm_pat_size = comp.find_first_of(0x0f);
  266.                     SIZE_TYPE pos = comp.find_first_of(0x0f, fsm_pat_size + 1);
  267.                     if (pos == NPOS
  268.                         ||  comp.find_first_of(0x0f, pos + 1) == NPOS) {
  269.                         fsm_pat_size = comp.size();
  270.                     }
  271.                 }}
  272.                 patterns.push_back(CPatternRec(comp, enzyme 
  273.                                                - enzymes.begin(),
  274.                                                spec - specs.begin(), 
  275.                                                CPatternRec::eIsComplement,
  276.                                                fsm_pat_size));
  277.                 // add pattern to fsm
  278.                 // (add only fsm_pat_size of it)
  279.                 CFindRSites::x_AddPattern(comp.substr(0, fsm_pat_size), fsm,
  280.                                           patterns.size() - 1);
  281.             }
  282.         }
  283.     }
  284.     
  285.     // The fsm is set up.
  286.     // Now do the search.
  287.     fsm.Prime();
  288.     vector<int> ambig_nucs;  // for dealing with ambiguities later
  289.     int state = fsm.GetInitialState();
  290.     for (unsigned int i = 0;  i < seq.size();  i++) {
  291.         if (CFindRSites::x_IsAmbig(seq[i])) {
  292.             ambig_nucs.push_back(i);
  293.         }
  294.         state = fsm.GetNextState(state, seq[i]);
  295.         if (fsm.IsMatchFound(state)) {
  296.             const vector<int>& matches = fsm.GetMatches(state);
  297.             ITERATE (vector<int>, match, matches) {
  298.                 const CPatternRec& pattern = patterns[*match];
  299.                 TSeqPos begin_pos = i + 1 - pattern.GetFsmPatSize();
  300.                 TSeqPos end_pos = begin_pos 
  301.                     + pattern.GetPattern().size() - 1;
  302.                 
  303.                 // check for a full match to sequence
  304.                 if (pattern.GetFsmPatSize()
  305.                     != pattern.GetPattern().size()) {
  306.                     // Pattern put into fsm was less than the full pattern.
  307.                     // Must check that the sequence really matches.
  308.                     if (end_pos >= seq.size()) {
  309.                         // full pattern goes off the end of sequence;
  310.                         // not a match
  311.                         continue;
  312.                     }
  313.                     // could really test match for just 
  314.                     // right end of pattern here
  315.                     if (CSeqMatch::MatchNcbi8na(seq, pattern.GetPattern(),
  316.                                                 begin_pos) 
  317.                         == CSeqMatch::eYes) {
  318.                         // There must be a site here.  However, because
  319.                         // we'll later check all stretches containing
  320.                         // ambiguities, we must ignore them here to keep
  321.                         // from recording them twice.
  322.                         bool ambig = false;
  323.                         for (unsigned int n = begin_pos;  n <= end_pos;
  324.                              n++) {
  325.                             if (CFindRSites::x_IsAmbig(seq[n])) {
  326.                                 ambig = true;
  327.                                 break;
  328.                             }
  329.                         }
  330.                         if (ambig) {
  331.                             continue;  // ignore matches with ambig. seq.
  332.                         }
  333.                     } else {
  334.                         continue;  // not a real match
  335.                     }
  336.                 }
  337.                 CRSite site(begin_pos, end_pos);
  338.                 const CRSpec& spec = enzymes[pattern.GetEnzymeIndex()]
  339.                     .GetSpecs()[pattern.GetSpecIndex()];
  340.                 const vector<int>& plus_cuts = spec.GetPlusCuts();
  341.                 ITERATE (vector<int>, cut, plus_cuts) {
  342.                     if (pattern.IsComplement()) {
  343.                         site.SetPlusCuts()
  344.                             .push_back(begin_pos 
  345.                                        + pattern.GetPattern().size()
  346.                                        - *cut);
  347.                     } else {
  348.                         site.SetPlusCuts().push_back(begin_pos + *cut);
  349.                     }
  350.                 }
  351.                 const vector<int>& minus_cuts = spec.GetMinusCuts();
  352.                 ITERATE (vector<int>, cut, minus_cuts) {
  353.                     if (pattern.IsComplement()) {
  354.                         site.SetMinusCuts()
  355.                             .push_back(begin_pos
  356.                                        + pattern.GetPattern().size()
  357.                                        - *cut);
  358.                     } else {
  359.                         site.SetMinusCuts().push_back(begin_pos + *cut);
  360.                     }
  361.                 }
  362.                 results[pattern.GetEnzymeIndex()]->SetDefiniteSites()
  363.                     .push_back(site);
  364.             }
  365.         }
  366.     }  // end iteration over the sequence
  367.     // We've found all the matches involving unambiguous characters
  368.     // in sequence.  Now go back and examine any ambiguous places.
  369.     if (!ambig_nucs.empty()) {
  370.         ITERATE (vector<CPatternRec>, pattern, patterns) {
  371.             const string& pat = pattern->GetPattern();
  372.             // for reordering later
  373.             int ds_pos = results[pattern->GetEnzymeIndex()]
  374.                 ->GetDefiniteSites().size();
  375.             int ps_pos = results[pattern->GetEnzymeIndex()]
  376.                 ->GetPossibleSites().size();
  377.             // the next possible (starting) position to check
  378.             int next_pos = 0;
  379.             // iterate over ambiguous positions
  380.             ITERATE (vector<int>, pos, ambig_nucs) {
  381.                 int begin_check = *pos - pat.size() + 1;
  382.                 // don't try to check a negative position
  383.                 begin_check = max(begin_check, 0);
  384.                 // to avoid recording a site multiple times
  385.                 // when there are two nearby ambiguities
  386.                 begin_check = max(begin_check, next_pos);
  387.                 int end_check = min(*pos, (int) (seq.size() - pat.size()));
  388.                 int i;
  389.                 for (i = begin_check;  i <= end_check;  i++) {
  390.                     CSeqMatch::EMatch match
  391.                         = CSeqMatch::MatchNcbi8na(seq, pat, i);
  392.                     if (match == CSeqMatch::eNo) {
  393.                         continue;  // no match of any sort
  394.                     }
  395.                     // otherwise, a definite or possible site
  396.                     CRSite site(i, i + pat.size() -1);
  397.                     // figure out cleavage locations
  398.                     const vector<int>& plus_cuts 
  399.                         = enzymes[pattern->GetEnzymeIndex()]
  400.                         .GetSpecs()[pattern->GetSpecIndex()].GetPlusCuts();
  401.                     ITERATE (vector<int>, cut, plus_cuts) {
  402.                         if (pattern->IsComplement()) {
  403.                             site.SetPlusCuts()
  404.                                 .push_back(i + pattern->GetPattern().size()
  405.                                            - *cut);
  406.                         } else {
  407.                             site.SetPlusCuts().push_back(i + *cut);
  408.                         }
  409.                     }
  410.                     const vector<int>& minus_cuts 
  411.                         = enzymes[pattern->GetEnzymeIndex()]
  412.                         .GetSpecs()[pattern->GetSpecIndex()]
  413.                         .GetMinusCuts();
  414.                     ITERATE (vector<int>, cut, minus_cuts) {
  415.                         if (pattern->IsComplement()) {
  416.                             site.SetMinusCuts()
  417.                                 .push_back(i + pattern->GetPattern().size()
  418.                                            - *cut);
  419.                         } else {
  420.                             site.SetMinusCuts().push_back(i + *cut);
  421.                         }
  422.                     }
  423.                     if (match == CSeqMatch::eYes) {
  424.                         results[pattern->GetEnzymeIndex()]
  425.                             ->SetDefiniteSites().push_back(site);
  426.                     } else {
  427.                         results[pattern->GetEnzymeIndex()]
  428.                             ->SetPossibleSites().push_back(site);
  429.                     }
  430.                 }
  431.                 next_pos = i;
  432.             }  // end ITERATE over ambiguous positions
  433.             
  434.             // definite_sites and possible_sites may be out of order
  435.             vector<CRSite>& def_sites = results[pattern->GetEnzymeIndex()]
  436.                 ->SetDefiniteSites();
  437.             inplace_merge(def_sites.begin(),
  438.                           def_sites.begin() + ds_pos,
  439.                           def_sites.end(),
  440.                           SCompareLocation());
  441.             
  442.             vector<CRSite>& pos_sites = results[pattern->GetEnzymeIndex()]
  443.                 ->SetPossibleSites();
  444.             inplace_merge(pos_sites.begin(),
  445.                           pos_sites.begin() + ps_pos,
  446.                           pos_sites.end(),
  447.                           SCompareLocation());
  448.             
  449.         }  // end ITERATE over patterns
  450.     }  // end if (!ambig_nucs.empty())
  451. }
  452. // CFindRSites::Find for various sequence containers
  453. void CFindRSites::Find(const string& seq,
  454.                        const vector<CREnzyme>& enzymes,
  455.                        vector<CRef<CREnzResult> >& results)
  456. {
  457.     x_FindRSite(seq, enzymes, results);
  458. }
  459. void CFindRSites::Find(const vector<char>& seq,
  460.                        const vector<CREnzyme>& enzymes,
  461.                        vector<CRef<CREnzResult> >& results)
  462. {
  463.     x_FindRSite(seq, enzymes, results);
  464. }
  465. void CFindRSites::Find(const CSeqVector& seq,
  466.                        const vector<CREnzyme>& enzymes,
  467.                        vector<CRef<CREnzResult> >& results)
  468. {
  469.     string seq_ncbi8na;
  470.     CSeqVector vec(seq);
  471.     vec.SetNcbiCoding();
  472.     vec.GetSeqData(0, vec.size(), seq_ncbi8na);
  473.     x_FindRSite(seq_ncbi8na, enzymes, results);
  474. }
  475. END_NCBI_SCOPE
  476. /*
  477.  * ===========================================================================
  478.  * $Log: restriction.cpp,v $
  479.  * Revision 1000.1  2004/06/01 18:10:51  gouriano
  480.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.11
  481.  *
  482.  * Revision 1.11  2004/05/21 21:41:04  gorelenk
  483.  * Added PCH ncbi_pch.hpp
  484.  *
  485.  * Revision 1.10  2003/08/28 15:49:43  jcherry
  486.  * Fixed problem with x_FindRSite; pattern was being searched before
  487.  * it was read.
  488.  *
  489.  * Revision 1.9  2003/08/22 14:25:58  ucko
  490.  * Fix for MSVC, which seems to have problems with member templates.
  491.  *
  492.  * Revision 1.8  2003/08/22 02:17:18  ucko
  493.  * Fix WorkShop compilation.
  494.  *
  495.  * Revision 1.7  2003/08/21 20:05:59  dicuccio
  496.  * Added USING_SCOPE(objects) for MSVC
  497.  *
  498.  * Revision 1.6  2003/08/21 19:22:47  jcherry
  499.  * Moved restriction site finding to algo/sequence
  500.  *
  501.  * Revision 1.5  2003/08/21 18:38:31  jcherry
  502.  * Overloaded CFindRSites::Find to take several sequence containers.
  503.  * Added option to lump together enzymes with identical specificities.
  504.  *
  505.  * Revision 1.4  2003/08/21 12:03:07  dicuccio
  506.  * Make use of new typedef in plugin_utils.hpp for argument values.
  507.  *
  508.  * Revision 1.3  2003/08/20 22:57:44  jcherry
  509.  * Reimplemented restriction site finding using finite state machine
  510.  *
  511.  * Revision 1.2  2003/08/17 19:25:30  jcherry
  512.  * Changed member variable names to follow convention
  513.  *
  514.  * Revision 1.1  2003/08/12 18:52:58  jcherry
  515.  * Initial version
  516.  *
  517.  * ===========================================================================
  518.  */