@@ -37,6 +37,11 @@ fillSeed( const size_t i1min, const size_t i1max, const size_t i2min, const size
3737 size_t i1, i2, bpIn, u1, u2, j1, j2, u1p, u2p, k1,k2, u1best, u2best;
3838 E_type curE, bestE;
3939
40+ // determine whether or not lonely base pairs are allowed or if we have to
41+ // ensure a stacking to the right of the left boundary (i1,i2)
42+ const size_t noLpShift = seedConstraint.isLpAllowed () ? 0 : 1 ;
43+ E_type iStackE = E_type (0 );
44+
4045 size_t seedCountNotInf = 0 , seedCount = 0 ;
4146
4247 // fill for all start indices
@@ -75,6 +80,17 @@ fillSeed( const size_t i1min, const size_t i1max, const size_t i2min, const size
7580 // check if this index range is to be considered for seed search
7681 bool validSeedSite = isFeasibleSeedBasePair (j1,j2,true );
7782
83+ // if no LP : check for direct right-stacking of i
84+ if (noLpShift > 0 ) {
85+ // check if feasible extension
86+ if (isFeasibleSeedBasePair (i1+1 ,i2+1 )) {
87+ // get stacking energy
88+ iStackE = energy.getE_interLeft (i1,i1+1 ,i2,i2+1 );
89+ } else {
90+ validSeedSite = false ;
91+ }
92+ }
93+
7894 // init current seed energy
7995 curE = E_INF;
8096
@@ -83,31 +99,47 @@ fillSeed( const size_t i1min, const size_t i1max, const size_t i2min, const size
8399
84100 // base case: only left and right base pair present
85101 if (bpIn==0 ) {
86- // energy for stacking/bulge/interior depending on u1/u2
87- curE = energy.getE_interLeft (i1,j1,i2,j2);
102+ // if lonely bps are allowed or no bulge
103+ if (noLpShift == 0 || (u1==0 && u2==0 )) {
104+ // energy for stacking/bulge/interior depending on u1/u2
105+ curE = energy.getE_interLeft (i1,j1,i2,j2);
106+ }
88107
89108 } else {
90- // split seed recursively into all possible leading interior loops
91- // i1 .. i1+u1p+1 .. j1
92- // i2 .. i2+u2p+1 .. j2
93- for (u1p=1 +std::min (u1,energy.getMaxInternalLoopSize1 ()); u1p-- > 0 ;) {
94- for (u2p=1 +std::min (u2,energy.getMaxInternalLoopSize2 ()); u2p-- > 0 ;) {
95-
96- k1 = i1+u1p+1 ;
97- k2 = i2+u2p+1 ;
98- // check if split pair is complementary
99- // and recursed entry is < E_INF
100- if (! (isFeasibleSeedBasePair (k1,k2) && E_isNotINF ( getSeedE ( k1-offset1, k2-offset2, bpIn-1 , u1-u1p, u2-u2p ) ) ) ) {
101- continue ; // not complementary -> skip
102- }
103-
104- // update mfe for split at k1,k2
105- curE = std::min ( curE,
106- energy.getE_interLeft (i1,k1,i2,k2)
107- + getSeedE ( k1-offset1, k2-offset2, bpIn-1 , u1-u1p, u2-u2p )
108- );
109- } // u2p
110- } // u1p
109+
110+ // explicitly check direct stacking extension in noLP mode
111+ if (noLpShift > 0 && E_isNotINF ( getSeedE ( i1+1 -offset1, i2+1 -offset2, bpIn-1 , u1, u2 ) )) {
112+ curE = std::min ( curE, iStackE + getSeedE ( i1+1 -offset1, i2+1 -offset2, bpIn-1 , u1, u2 ) );
113+ }
114+
115+ // if enough interior base pairs left
116+ if (bpIn >= 1 +noLpShift) {
117+ // split seed recursively into all possible leading interior loops
118+ // i1 .. i1+u1p+1 .. j1
119+ // i2 .. i2+u2p+1 .. j2
120+ for (u1p=1 +std::min (u1,energy.getMaxInternalLoopSize1 ()); u1p-- > 0 ;) {
121+ for (u2p=1 +std::min (u2,energy.getMaxInternalLoopSize2 ()); u2p-- > 0 ;) {
122+
123+ // skip stacked extension for noLP since already covered above
124+ if (u1p+u2p < noLpShift) { continue ; }
125+
126+ k1 = i1+u1p+1 +noLpShift;
127+ k2 = i2+u2p+1 +noLpShift;
128+ // check if split pair is complementary
129+ // and recursed entry is < E_INF
130+ if (! (isFeasibleSeedBasePair (k1,k2) && E_isNotINF ( getSeedE ( k1-offset1, k2-offset2, bpIn-1 -noLpShift, u1-u1p, u2-u2p ) ) ) ) {
131+ continue ; // not complementary -> skip
132+ }
133+
134+ // update mfe for split at k1,k2
135+ curE = std::min ( curE,
136+ iStackE
137+ + energy.getE_interLeft (i1+noLpShift,k1,i2+noLpShift,k2)
138+ + getSeedE ( k1-offset1, k2-offset2, bpIn-1 -noLpShift, u1-u1p, u2-u2p )
139+ );
140+ } // u2p
141+ } // u1p
142+ }
111143 } // more than two base pairs
112144
113145 } // (j1,j2) complementary
@@ -215,10 +247,17 @@ traceBackSeed( Interaction & interaction
215247 // get energy of provided seed
216248 E_type curE = getSeedE (i1_,i2_,bpInbetween,u1_,u2_);
217249
250+ // determine whether or not lonely base pairs are allowed or if we have to
251+ // ensure a stacking to the right of the left boundary (i1,i2)
252+ const size_t noLpShift = seedConstraint.isLpAllowed () ? 0 : 1 ;
253+ E_type iStackE = E_type (0 );
254+
218255 // trace seed
219256 // trace each seed base pair (excluding right most)
220257 for ( size_t bpIn=1 +bpInbetween; bpIn-- > 0 ; ) {
221258
259+
260+
222261 // base case: only left and right base pair present
223262 if (bpIn==0 ) {
224263 // add left base pair if not left seed boundary
@@ -227,33 +266,58 @@ traceBackSeed( Interaction & interaction
227266 }
228267
229268 } else {
269+
270+ // if no LP : check for direct right-stacking of i
271+ if (noLpShift > 0 ) {
272+ // check if feasible extension
273+ assert (isFeasibleSeedBasePair (i1+1 ,i2+1 ));
274+ // get stacking energy
275+ iStackE = energy.getE_interLeft (i1+offset1,i1+1 +offset1,i2+offset2,i2+1 +offset2);
276+ // noLP : check stacking of i
277+ if ( E_equal ( curE, iStackE + getSeedE ( i1+1 , i2+1 , bpIn-1 , u1max, u2max )) ) {
278+ i1++;
279+ i2++;
280+ curE = getSeedE ( i1+1 , i2+1 , bpIn-1 , u1max, u2max );
281+ continue ;
282+ }
283+ // sanity check for noLP mode
284+ assert ( bpIn >= 1 +noLpShift );
285+ }
286+
230287 // split seed recursively into all possible leading interior loops
231288 // i1 .. i1+u1p+1 .. j1
232289 // i2 .. i2+u2p+1 .. j2
233290 bool traceNotFound = true ;
234291 for (u1=1 +u1max; traceNotFound && u1-- > 0 ;) {
235292 for (u2=1 +u2max; traceNotFound && u2-- > 0 ;) {
236293 // check if overall number of unpaired is not exceeded
237- if (u1+u2 > uMax) {
294+ // or skip stacked extension since covered above
295+ if (u1+u2 > uMax || u1+u2 < noLpShift) {
238296 continue ;
239297 }
240298
241- k1 = i1+u1+1 ;
242- k2 = i2+u2+1 ;
299+ k1 = i1+u1+1 +noLpShift ;
300+ k2 = i2+u2+1 +noLpShift ;
243301
244302 // check if valid trace
245303 if ( isFeasibleSeedBasePair (k1+offset1, k2+offset2) && E_isNotINF ( getSeedE ( k1, k2, bpIn-1 , u1max-u1, u2max-u2 ) ) ) {
246304
247305 // check if correct trace
248- if ( E_equal ( curE, energy.getE_interLeft (i1+offset1,k1+offset1,i2+offset2,k2+offset2)
249- + getSeedE ( k1, k2, bpIn-1 , u1max-u1, u2max-u2 )) )
306+ if ( E_equal ( curE, iStackE
307+ + energy.getE_interLeft (i1+noLpShift+offset1,k1+offset1,i2+noLpShift+offset2,k2+offset2)
308+ + getSeedE ( k1, k2, bpIn-1 -noLpShift, u1max-u1, u2max-u2 )) )
250309 {
251310 // store left base pair if not left seed boundary
252311 if (i1 != i1_) {
253312 interaction.basePairs .push_back ( energy.getBasePair (i1+offset1,i2+offset2) );
254313 }
314+ if (noLpShift > 0 ) {
315+ interaction.basePairs .push_back ( energy.getBasePair (i1+noLpShift+offset1,i2+noLpShift+offset2) );
316+ // reflect additional base pair
317+ bpIn--;
318+ }
255319 // store next energy value to trace
256- curE = getSeedE ( k1, k2, bpIn-1 , u1max-u1, u2max-u2 );
320+ curE = getSeedE ( k1, k2, bpIn-1 -noLpShift , u1max-u1, u2max-u2 );
257321 // reset for next trace step
258322 i1 = k1;
259323 i2 = k2;
0 commit comments