1 package align2;
2 import java.util.Arrays;
3 
4 import dna.AminoAcid;
5 import shared.KillSwitch;
6 import shared.Shared;
7 import shared.Tools;
8 import stream.SiteScore;
9 
10 /**
11  * Modification of MultiStateAligner9ts to replace fixed affine steps with an array */
12 public final class MultiStateAligner11tsJNI extends MSA{
13 
14 	static {
Shared.loadJNI()15 		Shared.loadJNI();
16 	}
17 
fillUnlimitedJNI(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int[] result, long[] iterationsUnlimited, int[] packed, int[] POINTSoff_SUB_ARRAY, int[] POINTSoff_INS_ARRAY, int maxRows, int maxColumns)18 	private native void fillUnlimitedJNI(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int[] result, long[] iterationsUnlimited, int[] packed, int[] POINTSoff_SUB_ARRAY, int[] POINTSoff_INS_ARRAY, int maxRows, int maxColumns);
19 
fillLimitedXJNI(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore, int[] result, long[] iterationsLimited, int[] packed, int[] POINTSoff_SUB_ARRAY, int[] POINTSoff_INS_ARRAY, int maxRows, int maxColumns, int bandwidth, float bandwidthRatio, int[] vertLimit, int[] horizLimit, byte[] baseToNumber, int[] POINTSoff_INS_ARRAY_C)20 	private native void fillLimitedXJNI(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore, int[] result, long[] iterationsLimited, int[] packed, int[] POINTSoff_SUB_ARRAY, int[] POINTSoff_INS_ARRAY, int maxRows, int maxColumns, int bandwidth, float bandwidthRatio, int[] vertLimit, int[] horizLimit, byte[] baseToNumber, int[] POINTSoff_INS_ARRAY_C);
21 
main(String[] args)22 	public static void main(String[] args){
23 		byte[] read=args[0].getBytes();
24 		byte[] ref=args[1].getBytes();
25 		byte[] original=ref;
26 
27 		MultiStateAligner11tsJNI msa=new MultiStateAligner11tsJNI(read.length, ref.length);
28 		System.out.println("Initial: ");
29 		//printMatrix(msa.packed, read.length, ref.length, TIMEMASK, SCOREOFFSET);
30 
31 		int[] max=msa.fillLimited(read, ref, 0, ref.length-1, 0, null);
32 
33 		System.out.println("Max: "+Arrays.toString(max));
34 
35 		System.out.println("Final: ");
36 		//printMatrix(msa.packed, read.length, ref.length, TIMEMASK, SCOREOFFSET);
37 
38 		byte[] out=msa.traceback(read, ref,  0, ref.length-1, max[0], max[1], max[2], false);
39 
40 		int[] score=null;
41 		score=msa.score(read, ref,  0, ref.length-1, max[0], max[1], max[2], false);
42 
43 		System.out.println(new String(ref));
44 		System.out.println(new String(read));
45 		System.out.println(new String(out));
46 		System.out.println("Score: "+Arrays.toString(score));
47 	}
48 
MultiStateAligner11tsJNI(int maxRows_, int maxColumns_)49 	public MultiStateAligner11tsJNI(int maxRows_, int maxColumns_){
50 		super(maxRows_, maxColumns_);
51 
52 		packed=KillSwitch.allocInt1D(3*(maxRows+1)*(maxColumns+1));
53 		grefbuffer=KillSwitch.allocByte1D(maxColumns+2);
54 		vertLimit=KillSwitch.allocInt1D(maxRows+1);
55 		horizLimit=KillSwitch.allocInt1D(maxColumns+1);
56 
57 		Arrays.fill(vertLimit, BADoff);
58 		Arrays.fill(horizLimit, BADoff);
59 
60 		for(int matrix=0; matrix<3; matrix++){
61 			for(int i=1; i<=maxRows; i++){
62 				for(int j=0; j<maxColumns+1; j++){
63 					packed[(matrix)*(maxRows+1)*(maxColumns+1)+(i)*(maxColumns+1)+(j)]|=BADoff;
64 				}
65 			}
66 			for(int i=0; i<=maxRows; i++){
67 				int prevScore=(i<2 ? 0 : packed[(matrix)*(maxRows+1)*(maxColumns+1)+(i-1)*(maxColumns+1)+(0)]);
68 				int score=prevScore+POINTSoff_INS_ARRAY[i];
69 				packed[(matrix)*(maxRows+1)*(maxColumns+1)+(i)*(maxColumns+1)+(0)]=score;
70 			}
71 		}
72 	}
73 
74 	@Override
fillLimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore, int[] gaps)75 	public final int[] fillLimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore, int[] gaps){
76 		if(gaps==null){return fillLimitedX(read, ref, refStartLoc, refEndLoc, minScore);}
77 		else{
78 			byte[] gref=makeGref(ref, gaps, refStartLoc, refEndLoc);
79 
80 			if(verbose && greflimit>0 && greflimit<500){
81 				System.err.println(new String(gref, 0, greflimit));
82 			}
83 
84 			assert(gref!=null) : "Excessively long read:\n"+new String(read);
85 			return fillLimitedX(read, gref, 0, greflimit, minScore);
86 		}
87 	}
88 
89 	/** return new int[] {rows, maxC, maxS, max};
90 	 * Will not fill areas that cannot match minScore */
fillLimitedX(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore)91 	private final int[] fillLimitedX(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int minScore){
92 		if(verbose){System.err.println("fillLimitedX");}
93 		rows=read.length;
94 		columns=refEndLoc-refStartLoc+1;
95 
96 		final int halfband=(bandwidth<1 && bandwidthRatio<=0) ? 0 :
97 			Tools.max(Tools.min(bandwidth<1 ? 9999999 : bandwidth, bandwidthRatio<=0 ? 9999999 : 8+(int)(rows*bandwidthRatio)), (columns-rows+8))/2;
98 
99 		if(minScore<1 || (columns+rows<90) || ((halfband<1 || halfband*3>columns) && (columns>read.length+Tools.min(170, read.length+20)))){
100 			return fillUnlimited(read, ref, refStartLoc, refEndLoc);
101 		}
102 
103 		minScore-=120; //Increases quality trivially
104 
105 		//Create arrays for passing values to and from native library
106 		int[] result = KillSwitch.allocInt1D(5);
107 		long[] iterationsLimitedArray = new long[1];
108 
109 		//Put values into array for passing to native library
110 		iterationsLimitedArray[0] = iterationsLimited;
111 
112 		fillLimitedXJNI(read,ref,refStartLoc,refEndLoc,minScore,result,iterationsLimitedArray,packed,POINTSoff_SUB_ARRAY,POINTSoff_INS_ARRAY,maxRows,maxColumns,bandwidth,bandwidthRatio,vertLimit,horizLimit,AminoAcid.baseToNumber,POINTSoff_INS_ARRAY_C);
113 
114 		//Retrieve variables from native library that were updated there
115 		iterationsLimited = iterationsLimitedArray[0];
116 
117 		if(result[4]==1){
118 			return null;
119 		}
120 
121 		//return new int[] {rows, maxCol, maxState, maxScore};
122 		return new int[] {result[0], result[1], result[2], result[3]};
123 	}
124 
125 	@Override
fillUnlimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int[] gaps)126 	public final int[] fillUnlimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int[] gaps){
127 		if(gaps==null){return fillUnlimited(read, ref, refStartLoc, refEndLoc);}
128 		else{
129 			byte[] gref=makeGref(ref, gaps, refStartLoc, refEndLoc);
130 			assert(gref!=null) : "Excessively long read:\n"+new String(read);
131 			return fillUnlimited(read, gref, 0, greflimit);
132 		}
133 	}
134 
135 	/** return new int[] {rows, maxC, maxS, max};
136 	 * Does not require a min score (ie, same as old method) */
fillUnlimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc)137 	private final int[] fillUnlimited(byte[] read, byte[] ref, int refStartLoc, int refEndLoc){
138 
139 		//Create arrays for passing values to and from native library
140 		int[] result = KillSwitch.allocInt1D(4);
141 		long[] iterationsUnlimitedArray = new long[1];
142 		iterationsUnlimitedArray[0] = iterationsUnlimited;
143 
144 		fillUnlimitedJNI(read,ref,refStartLoc,refEndLoc,result,iterationsUnlimitedArray,packed,POINTSoff_SUB_ARRAY,POINTSoff_INS_ARRAY,maxRows,maxColumns);
145 
146 		//Retrieve variables from native library that were updated there
147 		long myiterationsUnlimited = iterationsUnlimitedArray[0];
148 
149 		//return new int[] {rows, maxCol, maxState, maxScore};
150 		return new int[] {result[0], result[1], result[2], result[3]};
151 	}
152 
153 	@Override
154 	@Deprecated
155 	/** return new int[] {rows, maxC, maxS, max}; */
fillQ(byte[] read, byte[] ref, byte[] baseScores, int refStartLoc, int refEndLoc)156 	public final int[] fillQ(byte[] read, byte[] ref, byte[] baseScores, int refStartLoc, int refEndLoc){
157 		assert(false) : "Needs to be redone to work with score cutoffs.  Not difficult.";
158 		rows=read.length;
159 		columns=refEndLoc-refStartLoc+1;
160 
161 		assert(rows<=maxRows) : "Check that values are in-bounds before calling this function: "+rows+", "+maxRows;
162 		assert(columns<=maxColumns) : "Check that values are in-bounds before calling this function: "+columns+", "+maxColumns;
163 
164 		assert(refStartLoc>=0) : "Check that values are in-bounds before calling this function: "+refStartLoc;
165 		assert(refEndLoc<ref.length) : "Check that values are in-bounds before calling this function: "+refEndLoc+", "+ref.length;
166 
167 		for(int row=1; row<=rows; row++){
168 			for(int col=1; col<=columns; col++){
169 				final boolean match=(read[row-1]==ref[refStartLoc+col-1]);
170 				final boolean prevMatch=(row<2 || col<2 ? false : read[row-2]==ref[refStartLoc+col-2]);
171 				{//Calculate match and sub scores
172 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
173 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
174 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
175 					final int streak=(packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&TIMEMASK);
176 					{//Calculate match/sub score
177 						if(match){
178 							int scoreMS=scoreFromDiag+(prevMatch ? POINTSoff_MATCH2 : POINTSoff_MATCH);
179 							int scoreD=scoreFromDel+POINTSoff_MATCH;
180 							int scoreI=scoreFromIns+POINTSoff_MATCH;
181 
182 							int score;
183 							int time;
184 							if(scoreMS>=scoreD && scoreMS>=scoreI){
185 								score=scoreMS;
186 								time=(prevMatch ? streak+1 : 1);
187 							}else if(scoreD>=scoreI){
188 								score=scoreD;
189 								time=1;
190 							}else{
191 								score=scoreI;
192 								time=1;
193 							}
194 							score+=(((int)baseScores[row-1])<<SCOREOFFSET); //modifier
195 
196 							if(time>MAX_TIME){time=MAX_TIME-MASK5;}
197 							assert(score>=MINoff_SCORE) : "Score overflow - use MSA2 instead";
198 							assert(score<=MAXoff_SCORE) : "Score overflow - use MSA2 instead";
199 							packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]=(score|time);
200 							assert((score&SCOREMASK)==score);
201 							assert((time&TIMEMASK)==time);
202 
203 						}else{
204 							int scoreMS=scoreFromDiag+(prevMatch ? (streak<=1 ? POINTSoff_SUBR : POINTSoff_SUB) :
205 								POINTSoff_SUB_ARRAY[streak+1]);
206 							int scoreD=scoreFromDel+POINTSoff_SUB; //+2 to move it as close as possible to the deletion / insertion
207 							int scoreI=scoreFromIns+POINTSoff_SUB;
208 
209 							int score;
210 							int time;
211 							byte prevState;
212 							if(scoreMS>=scoreD && scoreMS>=scoreI){
213 								score=scoreMS;
214 								time=(prevMatch ? 1 : streak+1);
215 								prevState=MODE_MS;
216 							}else if(scoreD>=scoreI){
217 								score=scoreD;
218 								time=1;
219 								prevState=MODE_DEL;
220 							}else{
221 								score=scoreI;
222 								time=1;
223 								prevState=MODE_INS;
224 							}
225 
226 							if(time>MAX_TIME){time=MAX_TIME-MASK5;}
227 							assert(score>=MINoff_SCORE) : "Score overflow - use MSA2 instead";
228 							assert(score<=MAXoff_SCORE) : "Score overflow - use MSA2 instead";
229 							packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]=(score|time);
230 							assert((score&SCOREMASK)==score);
231 							assert((time&TIMEMASK)==time);
232 						}
233 					}
234 				}
235 
236 				{//Calculate DEL score
237 					final int streak=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&TIMEMASK;
238 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
239 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
240 
241 					int scoreMS=scoreFromDiag+POINTSoff_DEL;
242 					int scoreD=scoreFromDel+(streak==0 ? POINTSoff_DEL :
243 						streak<LIMIT_FOR_COST_3 ? POINTSoff_DEL2 :
244 							streak<LIMIT_FOR_COST_4 ? POINTSoff_DEL3 :
245 								streak<LIMIT_FOR_COST_5 ? POINTSoff_DEL4 :
246 									((streak&MASK5)==0 ? POINTSoff_DEL5 : 0));
247 
248 					int score;
249 					int time;
250 					byte prevState;
251 					if(scoreMS>=scoreD){
252 						score=scoreMS;
253 						time=1;
254 						prevState=MODE_MS;
255 					}else{
256 						score=scoreD;
257 						time=streak+1;
258 						prevState=MODE_DEL;
259 					}
260 
261 					if(time>MAX_TIME){time=MAX_TIME-MASK5;}
262 					assert(score>=MINoff_SCORE) : "Score overflow - use MSA2 instead";
263 					assert(score<=MAXoff_SCORE) : "Score overflow - use MSA2 instead";
264 					packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]=(score|time);
265 					assert((score&SCOREMASK)==score);
266 					assert((time&TIMEMASK)==time);
267 				}
268 
269 				{//Calculate INS score
270 					final int streak=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&TIMEMASK;
271 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
272 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
273 
274 					int scoreMS=scoreFromDiag+POINTSoff_INS;
275 					int scoreI=scoreFromIns+POINTSoff_INS_ARRAY[streak+1];
276 
277 					int score;
278 					int time;
279 					byte prevState;
280 					if(scoreMS>=scoreI){
281 						score=scoreMS;
282 						time=1;
283 						prevState=MODE_MS;
284 					}else{
285 						score=scoreI;
286 						time=streak+1;
287 						prevState=MODE_INS;
288 					}
289 
290 					if(time>MAX_TIME){time=MAX_TIME-MASK5;}
291 					assert(score>=MINoff_SCORE) : "Score overflow - use MSA2 instead";
292 					assert(score<=MAXoff_SCORE) : "Score overflow - use MSA2 instead";
293 					packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]=(score|time);
294 					assert((score&SCOREMASK)==score);
295 					assert((time&TIMEMASK)==time);
296 				}
297 			}
298 		}
299 
300 		int maxCol=-1;
301 		int maxState=-1;
302 		int maxScore=Integer.MIN_VALUE;
303 
304 		for(int state=0; state<3; state++){
305 			for(int col=1; col<=columns; col++){
306 				int x=packed[(state)*(maxRows+1)*(maxColumns+1)+(rows)*(maxColumns+1)+(col)]&SCOREMASK;
307 				if(x>maxScore){
308 					maxScore=x;
309 					maxCol=col;
310 					maxState=state;
311 				}
312 			}
313 		}
314 		maxScore>>=SCOREOFFSET;
315 
316 		return new int[] {rows, maxCol, maxState, maxScore};
317 	}
318 
319 	@Override
320 	/** @return {score, bestRefStart, bestRefStop} */
321 	/** Generates the match string */
322 	public final byte[] traceback(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int row, int col, int state, boolean gapped){
323 		if(gapped){
324 			final byte[] gref=grefbuffer;
325 			int gstart=translateToGappedCoordinate(refStartLoc, gref);
326 			int gstop=translateToGappedCoordinate(refEndLoc, gref);
327 			byte[] out=traceback2(read, gref, gstart, gstop, row, col, state);
328 			return out;
329 		}else{
330 			return traceback2(read, ref, refStartLoc, refEndLoc, row, col, state);
331 		}
332 	}
333 
334 	@Override
335 	/** Generates the match string */
336 	public final byte[] traceback2(byte[] read, byte[] ref, int refStartLoc, int refEndLoc, int row, int col, int state){
337 		assert(refStartLoc<=refEndLoc) : refStartLoc+", "+refEndLoc;
338 		assert(row==rows);
339 
340 		byte[] out=new byte[row+col-1]; //TODO if an out of bound crash occurs, try removing the "-1".
341 		int outPos=0;
342 
343 		int gaps=0;
344 
345 		if(state==MODE_INS){
346 		}
347 
348 		while(row>0 && col>0){
349 			final int time=packed[(state)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]&TIMEMASK;
350 			final byte prev;
351 
352 			if(state==MODE_MS){
353 				if(time>1){prev=(byte)state;}
354 				else{
355 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
356 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
357 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
358 					if(scoreFromDiag>=scoreFromDel && scoreFromDiag>=scoreFromIns){prev=MODE_MS;}
359 					else if(scoreFromDel>=scoreFromIns){prev=MODE_DEL;}
360 					else{prev=MODE_INS;}
361 				}
362 
363 				byte c=read[row-1];
364 				byte r=ref[refStartLoc+col-1];
365 				if(c==r){
366 					out[outPos]='m';
367 				}else{
368 					if(!AminoAcid.isFullyDefined(c)){
369 						out[outPos]='N';
370 					}else if(!AminoAcid.isFullyDefined(r)){
371 						out[outPos]='N';
372 					}else{
373 						out[outPos]='S';
374 					}
375 				}
376 
377 				row--;
378 				col--;
379 			}else if(state==MODE_DEL){
380 				if(time>1){prev=(byte)state;}
381 				else{
382 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
383 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
384 					if(scoreFromDiag>=scoreFromDel){prev=MODE_MS;}
385 					else{prev=MODE_DEL;}
386 				}
387 
388 				byte r=ref[refStartLoc+col-1];
389 				if(r==GAPC){
390 					out[outPos]='-';
391 					gaps++;
392 				}else{
393 					out[outPos]='D';
394 				}
395 				col--;
396 			}else{
397 				if(time>1){prev=(byte)state;}
398 				else{
399 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
400 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
401 					if(scoreFromDiag>=scoreFromIns){prev=MODE_MS;}
402 					else{prev=MODE_INS;}
403 				}
404 
405 				assert(state==MODE_INS) : state;
406 				if(col==0){
407 					out[outPos]='X';
408 				}else if(col>=columns){
409 					out[outPos]='Y';
410 				}else{
411 					out[outPos]='I';
412 				}
413 				row--;
414 			}
415 
416 			state=prev;
417 			outPos++;
418 		}
419 
420 		assert(row==0 || col==0);
421 		if(col!=row){
422 			while(row>0){
423 				out[outPos]='X';
424 				outPos++;
425 				row--;
426 				col--;
427 			}
428 			if(col>0){
429 				//do nothing
430 			}
431 		}
432 
433 		byte[] out2=new byte[outPos];
434 		for(int i=0; i<outPos; i++){
435 			out2[i]=out[outPos-i-1];
436 		}
437 		out=null;
438 
439 		if(gaps==0){return out2;}
440 
441 		byte[] out3=new byte[out2.length+gaps*(GAPLEN-1)];
442 		for(int i=0, j=0; i<out2.length; i++){
443 			byte c=out2[i];
444 			if(c!=GAPC){
445 				out3[j]=c;
446 				j++;
447 			}else{
448 				int lim=j+GAPLEN;
449 				for(; j<lim; j++){
450 					out3[j]='D';
451 				}
452 			}
453 		}
454 		return out3;
455 	}
456 
457 	@Override
458 	/** @return {score, bestRefStart, bestRefStop} */
459 	public final int[] score(final byte[] read, final byte[] ref, final int refStartLoc, final int refEndLoc,
460 			final int maxRow, final int maxCol, final int maxState, boolean gapped){
461 		if(gapped){
462 			if(verbose){
463 				System.err.println("score():");
464 				System.err.println("origin="+grefRefOrigin+", "+refStartLoc+", "+refEndLoc+", "+maxRow+", "+maxCol);
465 			}
466 			final byte[] gref=grefbuffer;
467 			int gstart=translateToGappedCoordinate(refStartLoc, gref);
468 			int gstop=translateToGappedCoordinate(refEndLoc, gref);
469 
470 			assert(translateFromGappedCoordinate(gstart, gref)==refStartLoc); //TODO: Remove slow assertions
471 			assert(translateFromGappedCoordinate(gstop, gref)==refEndLoc);
472 
473 			assert(gstart==0) : gstart; //TODO: skip translation if this is always zero
474 
475 			if(verbose){System.err.println("gstart, gstop: "+gstart+", "+gstop);}
476 			int[] out=score2(read, gref, gstart, gstop, maxRow, maxCol, maxState);
477 			if(verbose){System.err.println("got score "+Arrays.toString(out));}
478 
479 			assert(out[1]==translateToGappedCoordinate(translateFromGappedCoordinate(out[1], gref), gref)) :
480 				"Verifying: "+out[1]+" -> "+translateFromGappedCoordinate(out[1], gref)+" -> "+
481 				translateToGappedCoordinate(translateFromGappedCoordinate(out[1], gref), gref);
482 			assert(out[2]==translateToGappedCoordinate(translateFromGappedCoordinate(out[2], gref), gref));
483 
484 			out[1]=translateFromGappedCoordinate(out[1], gref);
485 			out[2]=translateFromGappedCoordinate(out[2], gref);
486 			if(verbose){System.err.println("returning score "+Arrays.toString(out));}
487 			return out;
488 		}else{
489 			return score2(read, ref, refStartLoc, refEndLoc, maxRow, maxCol, maxState);
490 		}
491 	}
492 
493 	@Override
494 	/** @return {score, bestRefStart, bestRefStop, maxRow, maxCol, maxState}, <br>
495 	 * or {score, bestRefStart, bestRefStop, maxRow, maxCol, maxState, padLeft, padRight} <br>
496 	 * if more padding is needed */
497 	public final int[] score2(final byte[] read, final byte[] ref, final int refStartLoc, final int refEndLoc,
498 			final int maxRow, final int maxCol, final int maxState){
499 		int row=maxRow;
500 		int col=maxCol;
501 		int state=maxState;
502 
503 		assert(maxState>=0 && maxState<3) :
504 			maxState+", "+maxRow+", "+maxCol+"\n"+new String(read)+"\n"+toString(ref, refStartLoc, refEndLoc);
505 		//assert(maxRow>=0 && maxRow<packed[0].length) :
506 		//	maxState+", "+maxRow+", "+maxCol+"\n"+new String(read)+"\n"+toString(ref, refStartLoc, refEndLoc);
507 		//assert(maxCol>=0 && maxCol<packed[0][0].length) :
508 		//	maxState+", "+maxRow+", "+maxCol+"\n"+new String(read)+"\n"+toString(ref, refStartLoc, refEndLoc);
509 
510 		int score=packed[(maxState)*(maxRows+1)*(maxColumns+1)+(maxRow)*(maxColumns+1)+(maxCol)]&SCOREMASK; //Or zero, if it is to be recalculated
511 
512 		if(row<rows){
513 			int difR=rows-row;
514 			int difC=columns-col;
515 
516 			while(difR>difC){
517 				score+=POINTSoff_NOREF;
518 				difR--;
519 			}
520 
521 			row+=difR;
522 			col+=difR;
523 		}
524 
525 		assert(refStartLoc<=refEndLoc);
526 		assert(row==rows);
527 
528 		final int bestRefStop=refStartLoc+col-1;
529 
530 		if(verbose){System.err.println("Scoring.");}
531 
532 		int stateTime=0;
533 
534 		while(row>0 && col>0){
535 			if(verbose){System.err.println("state="+state+", row="+row+", col="+col);}
536 
537 			final int time=packed[(state)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col)]&TIMEMASK;
538 			final byte prev;
539 
540 			if(state==MODE_MS){
541 				if(time>1){prev=(byte)state;}
542 				else{
543 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
544 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
545 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col-1)]&SCOREMASK;
546 					if(scoreFromDiag>=scoreFromDel && scoreFromDiag>=scoreFromIns){prev=MODE_MS;}
547 					else if(scoreFromDel>=scoreFromIns){prev=MODE_DEL;}
548 					else{prev=MODE_INS;}
549 				}
550 				row--;
551 				col--;
552 			}else if(state==MODE_DEL){
553 				if(time>1){prev=(byte)state;}
554 				else{
555 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
556 					final int scoreFromDel=packed[(MODE_DEL)*(maxRows+1)*(maxColumns+1)+(row)*(maxColumns+1)+(col-1)]&SCOREMASK;
557 					if(scoreFromDiag>=scoreFromDel){prev=MODE_MS;}
558 					else{prev=MODE_DEL;}
559 				}
560 				col--;
561 			}else{
562 				assert(state==MODE_INS);
563 				if(time>1){prev=(byte)state;}
564 				else{
565 					final int scoreFromDiag=packed[(MODE_MS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
566 					final int scoreFromIns=packed[(MODE_INS)*(maxRows+1)*(maxColumns+1)+(row-1)*(maxColumns+1)+(col)]&SCOREMASK;
567 					if(scoreFromDiag>=scoreFromIns){prev=MODE_MS;}
568 					else{prev=MODE_INS;}
569 				}
570 				row--;
571 			}
572 
573 			if(col<0){
574 				if(verbose){
575 					System.err.println("Warning, column went below 0 at row="+row);
576 				}
577 				break; //prevents an out of bounds access
578 			}
579 
580 			if(state==prev){stateTime++;}else{stateTime=0;}
581 			state=prev;
582 
583 			if(verbose){System.err.println("state2="+state+", time="+time+", stateTime="+stateTime+", row2="+row+", col2="+col+"\n");}
584 		}
585 		if(row>col){
586 			col-=row;
587 		}
588 
589 		final int bestRefStart=refStartLoc+col;
590 
591 		score>>=SCOREOFFSET;
592 
593 		if(verbose){
594 			System.err.println("bestRefStart="+bestRefStart+", refStartLoc="+refStartLoc);
595 			System.err.println("bestRefStop="+bestRefStop+", refEndLoc="+refEndLoc);
596 		}
597 
598 		int padLeft=0;
599 		int padRight=0;
600 		if(bestRefStart<refStartLoc){
601 			padLeft=Tools.max(0, refStartLoc-bestRefStart);
602 		}else if(bestRefStart==refStartLoc && state==MODE_INS){
603 			padLeft=stateTime;
604 		}
605 		if(bestRefStop>refEndLoc){
606 			padRight=Tools.max(0, bestRefStop-refEndLoc);
607 		}else if(bestRefStop==refEndLoc && maxState==MODE_INS){
608 			padRight=packed[(maxState)*(maxRows+1)*(maxColumns+1)+(maxRow)*(maxColumns+1)+(maxCol)]&TIMEMASK;
609 		}
610 
611 		int[] rvec;
612 		if(padLeft>0 || padRight>0){ //Suggest extra padding in cases of overflow
613 			rvec=new int[] {score, bestRefStart, bestRefStop, maxRow, maxCol, maxState, padLeft, padRight};
614 		}else{
615 			rvec=new int[] {score, bestRefStart, bestRefStop, maxRow, maxCol, maxState};
616 		}
617 		return rvec;
618 	}
619 
620 	/**
621 	 * Fills grefbuffer
622 	 * @param ref
623 	 * @param a
624 	 * @param b
625 	 * @param gaps
626 	 * @return gref
627 	 */
628 	private final byte[] makeGref(byte[] ref, int[] gaps, int refStartLoc, int refEndLoc){
629 		assert(gaps!=null && gaps.length>0);
630 
631 		assert(refStartLoc<=gaps[0]) : refStartLoc+", "+refEndLoc+", "+Arrays.toString(gaps);
632 		assert(refEndLoc>=gaps[gaps.length-1]);
633 
634 		final int g0_old=gaps[0];
635 		final int gN_old=gaps[gaps.length-1];
636 		gaps[0]=Tools.min(gaps[0], refStartLoc);
637 		gaps[gaps.length-1]=Tools.max(gN_old, refEndLoc);
638 		grefRefOrigin=gaps[0];
639 
640 		if(verbose){System.err.println("\ngaps2: "+Arrays.toString(gaps));}
641 
642 		byte[] gref=grefbuffer;
643 
644 		int gpos=0;
645 		for(int i=0; i<gaps.length; i+=2){
646 			int x=gaps[i];
647 			int y=gaps[i+1];
648 
649 			for(int r=x; r<=y; r++, gpos++){
650 				//TODO: if out of bounds, use an 'N'
651 				assert(gpos<gref.length) :
652 					"\ngpos="+gpos+", gref.length="+gref.length+/*", read.length="+read.length+*/", gaps2="+Arrays.toString(gaps)+
653 					"\ni="+i+", r="+r+", x="+x+", y="+y+
654 					"\nGapTools.calcGrefLen("+gaps[0]+", "+gaps[gaps.length-1]+", gaps)="+GapTools.calcGrefLen(gaps[0], gaps[gaps.length-1], gaps)+
655 					"\nGapTools.calcGrefLen("+gaps[0]+", "+gaps[gaps.length-1]+", gaps)="+GapTools.calcGrefLen(gaps[0], gaps[gaps.length-1], gaps)+
656 					"\n"+refStartLoc+", "+refEndLoc+", "+greflimit+", "+GREFLIMIT2_CUSHION+"\n"+new String(gref)+"\n"/*+new String(read)+"\n"*/;
657 				gref[gpos]=ref[r];
658 			}
659 
660 			if(i+2<gaps.length){
661 				int z=gaps[i+2];
662 				assert(z>y);
663 				int gap=z-y-1;
664 				assert(gap>=MINGAP) : gap+"\t"+MINGAP;
665 				if(gap<MINGAP){
666 					assert(false) : "TODO - just fill in normally";
667 				}else{
668 					int rem=gap%GAPLEN;
669 					int lim=y+GAPBUFFER+rem;
670 
671 					int div=(gap-GAPBUFFER2)/GAPLEN;
672 					if(verbose){
673 						System.err.println("div = "+div);
674 					}
675 					assert(div>0);
676 
677 					for(int r=y+1; r<=lim; r++, gpos++){
678 						gref[gpos]=ref[r];
679 					}
680 					for(int g=0; g<div; g++, gpos++){
681 						gref[gpos]=GAPC;
682 					}
683 					for(int r=z-GAPBUFFER; r<z; r++, gpos++){
684 						gref[gpos]=ref[r];
685 					}
686 				}
687 			}
688 		}
689 
690 		greflimit=gpos;
691 
692 		assert(gref[gpos-1]==ref[refEndLoc]);
693 		{
694 			final int lim=Tools.min(gref.length, greflimit+GREFLIMIT2_CUSHION);
695 			if(lim>gref.length){
696 				System.err.println("gref buffer overflow: "+lim+" > "+gref.length);
697 				return null;
698 			}
699 			for(int i=greflimit, r=refEndLoc+1; i<lim; i++, r++){
700 				gref[i]=(r<ref.length ? ref[r] : (byte)'N');
701 				greflimit2=i;
702 			}
703 		}
704 
705 		if(verbose){
706 			System.err.println("gref:\n"+new String(gref));
707 		}
708 
709 		gaps[0]=g0_old;
710 		gaps[gaps.length-1]=gN_old;
711 
712 		if(verbose){
713 			System.err.println("\ngaps3: "+Arrays.toString(gaps));
714 		}
715 
716 		return gref;
717 	}
718 
719 	private final int translateFromGappedCoordinate(int point, byte[] gref){
720 		if(verbose){System.err.println("translateFromGappedCoordinate("+point+"), gro="+grefRefOrigin+", grl="+greflimit);}
721 		if(point<=0){return grefRefOrigin+point;}
722 		for(int i=0, j=grefRefOrigin; i<greflimit2; i++){
723 			byte c=gref[i];
724 			assert(point>=i) : "\n"+grefRefOrigin+"\n"+point+"\n"+new String(gref)+"\n";
725 
726 			if(i==point){
727 				if(verbose){System.err.println(" -> "+j);}
728 				return j;
729 			}
730 
731 			j+=(c==GAPC ? GAPLEN : 1);
732 		}
733 
734 		System.err.println(grefRefOrigin);
735 		System.err.println(point);
736 		System.err.println(new String(gref));
737 
738 		throw new RuntimeException("Out of bounds.");
739 	}
740 
741 	private final int translateToGappedCoordinate(int point, byte[] gref){
742 		if(verbose){System.err.println("translateToGappedCoordinate("+point+"), gro="+grefRefOrigin+", grl="+greflimit);}
743 		if(point<=grefRefOrigin){return point-grefRefOrigin;}
744 		for(int i=0, j=grefRefOrigin; i<greflimit2; i++){
745 			assert(point>=j) : "\n"+grefRefOrigin+"\n"+point+"\n"+new String(gref)+"\n";
746 			byte c=gref[i];
747 
748 			if(j==point){
749 				if(verbose){System.err.println(" -> "+i);}
750 				return i;
751 			}
752 
753 			j+=(c==GAPC ? GAPLEN : 1);
754 		}
755 
756 		System.err.println(grefRefOrigin);
757 		System.err.println(point);
758 		System.err.println(new String(gref));
759 
760 		throw new RuntimeException("Out of bounds.");
761 	}
762 
763 	/** Calculates score based on an array from Index */
764 	private final int calcAffineScore(int[] locArray){
765 		int score=0;
766 		int lastLoc=-2; //Last true location
767 		int lastValue=-1;
768 		int timeInMode=0;
769 
770 		for(int i=0; i<locArray.length; i++){
771 			int loc=locArray[i];
772 
773 			if(loc>0){//match
774 				if(loc==lastValue){//contiguous match
775 					score+=POINTS_MATCH2;
776 				}else if(loc==lastLoc || lastLoc<0){//match after a sub, or first match
777 					score+=POINTS_MATCH;
778 				}else if(loc<lastLoc){//deletion
779 					assert(lastLoc>=0);
780 					score+=POINTS_MATCH;
781 					score+=POINTS_DEL;
782 					int dif=lastLoc-loc+1;
783 					if(dif>MINGAP){
784 						int rem=dif%GAPLEN;
785 						int div=(dif-GAPBUFFER2)/GAPLEN;
786 						score+=(div*POINTS_GAP);
787 						assert(rem+GAPBUFFER2<dif);
788 						dif=rem+GAPBUFFER2;
789 						assert(dif>LIMIT_FOR_COST_4); //and probably LIMIT_FOR_COST_5
790 					}
791 					if(dif>LIMIT_FOR_COST_5){
792 						score+=((dif-LIMIT_FOR_COST_5+MASK5)/TIMESLIP)*POINTS_DEL5;
793 						dif=LIMIT_FOR_COST_5;
794 					}
795 					if(dif>LIMIT_FOR_COST_4){
796 						score+=(dif-LIMIT_FOR_COST_4)*POINTS_DEL4;
797 						dif=LIMIT_FOR_COST_4;
798 					}
799 					if(dif>LIMIT_FOR_COST_3){
800 						score+=(dif-LIMIT_FOR_COST_3)*POINTS_DEL3;
801 						dif=LIMIT_FOR_COST_3;
802 					}
803 					if(dif>1){
804 						score+=(dif-1)*POINTS_DEL2;
805 					}
806 					timeInMode=1;
807 				}else if(loc>lastLoc){//insertion
808 					assert(lastLoc>=0);
809 					score+=(POINTS_MATCH+POINTS_INS_ARRAY_C[lastLoc-loc]);
810 					timeInMode=1;
811 				}else{
812 					assert(false);
813 				}
814 				lastLoc=loc;
815 			}else{//substitution
816 				if(lastValue<0 && timeInMode>0){//contiguous
817 					timeInMode++;
818 					score+=(POINTS_SUB_ARRAY[timeInMode]);
819 				}else{
820 					score+=POINTS_SUB;
821 					timeInMode=1;
822 				}
823 			}
824 			lastValue=loc;
825 		}
826 		assert(score<=maxQuality(locArray.length));
827 		return score;
828 	}
829 
830 	@Override
831 	public final int calcAffineScore(final int[] locArray, final byte[] baseScores, final byte bases[]){
832 		int score=0;
833 		int lastLoc=-3; //Last true location
834 		int lastValue=-1;
835 		int timeInMode=0;
836 
837 		for(int i=0; i<locArray.length; i++){
838 			final int loc=locArray[i];
839 
840 			if(loc>0){//match
841 				if(loc==lastValue){//contiguous match
842 					score+=(POINTS_MATCH2+baseScores[i]);
843 				}else if(loc==lastLoc || lastLoc<0){//match after a sub, or first match
844 					score+=(POINTS_MATCH+baseScores[i]);
845 				}else if(loc<lastLoc){//deletion
846 					assert(lastLoc>=0);
847 					score+=(POINTS_MATCH+baseScores[i]);
848 					score+=POINTS_DEL;
849 					int dif=lastLoc-loc+1;
850 					if(dif>MINGAP){
851 						int rem=dif%GAPLEN;
852 						int div=(dif-GAPBUFFER2)/GAPLEN;
853 						score+=(div*POINTS_GAP);
854 						assert(rem+GAPBUFFER2<dif);
855 						dif=rem+GAPBUFFER2;
856 						assert(dif>LIMIT_FOR_COST_4); //and probably LIMIT_FOR_COST_5
857 					}
858 					if(dif>LIMIT_FOR_COST_5){
859 						score+=((dif-LIMIT_FOR_COST_5+MASK5)/TIMESLIP)*POINTS_DEL5;
860 						dif=LIMIT_FOR_COST_5;
861 					}
862 					if(dif>LIMIT_FOR_COST_4){
863 						score+=(dif-LIMIT_FOR_COST_4)*POINTS_DEL4;
864 						dif=LIMIT_FOR_COST_4;
865 					}
866 					if(dif>LIMIT_FOR_COST_3){
867 						score+=(dif-LIMIT_FOR_COST_3)*POINTS_DEL3;
868 						dif=LIMIT_FOR_COST_3;
869 					}
870 					if(dif>1){
871 						score+=(dif-1)*POINTS_DEL2;
872 					}
873 					timeInMode=1;
874 				}else if(loc>lastLoc){//insertion
875 					assert(lastLoc>=0);
876 					score+=(POINTS_MATCH+baseScores[i]+POINTS_INS_ARRAY_C[Tools.min(loc-lastLoc, 5)]);
877 					timeInMode=1;
878 				}else{
879 					assert(false);
880 				}
881 				lastLoc=loc;
882 			}else if(loc==-1){//substitution
883 				if(lastValue<0 && timeInMode>0){//contiguous
884 					timeInMode++;
885 					score+=(POINTS_SUB_ARRAY[timeInMode]);
886 				}else{
887 					score+=POINTS_SUB;
888 					timeInMode=1;
889 				}
890 			}else{
891 				assert(loc==-2) : "\ni="+i+", loc="+loc+", score="+score+", lastLoc="+lastLoc+", lastValue="+lastValue
892 					+", time="+timeInMode+", length="+locArray.length+"\nbases=\n"+new String(bases)
893 					+"\nlocs[]=\n"+Arrays.toString(locArray)+"\n"+new String(bases)+"\n"
894 					+"If this happens please ensure that the reference has a startpad of Ns longer than readlength.";//N (no-call or no-ref)
895 				timeInMode=0;
896 				score+=POINTS_NOCALL;
897 			}
898 			lastValue=loc;
899 		}
900 		assert(score<=maxQuality(locArray.length));
901 		return score;
902 	}
903 
904 	@Override
905 	public final int calcAffineScore(int[] locArray, byte[] baseScores, byte[] bases, int minContig){
906 		assert(minContig>1) : minContig;
907 
908 		int contig=0;
909 		int maxContig=0;
910 
911 		int score=0;
912 		int lastLoc=-3; //Last true location
913 		int lastValue=-1;
914 		int timeInMode=0;
915 
916 		for(int i=0; i<locArray.length; i++){
917 			int loc=locArray[i];
918 
919 			if(loc>0){//match
920 				if(loc==lastValue){//contiguous match
921 					contig++;
922 					score+=(POINTS_MATCH2+baseScores[i]);
923 				}else if(loc==lastLoc || lastLoc<0){//match after a sub, or first match
924 					maxContig=Tools.max(maxContig, contig);
925 					contig=1;
926 					score+=(POINTS_MATCH+baseScores[i]);
927 				}else if(loc<lastLoc){//deletion
928 					maxContig=Tools.max(maxContig, contig);
929 					contig=0;
930 					assert(lastLoc>=0);
931 					score+=(POINTS_MATCH+baseScores[i]);
932 					score+=POINTS_DEL;
933 					int dif=lastLoc-loc+1;
934 					if(dif>MINGAP){
935 						int rem=dif%GAPLEN;
936 						int div=(dif-GAPBUFFER2)/GAPLEN;
937 						score+=(div*POINTS_GAP);
938 						assert(rem+GAPBUFFER2<dif);
939 						dif=rem+GAPBUFFER2;
940 						assert(dif>LIMIT_FOR_COST_4); //and probably LIMIT_FOR_COST_5
941 					}
942 					if(dif>LIMIT_FOR_COST_5){
943 						score+=((dif-LIMIT_FOR_COST_5+MASK5)/TIMESLIP)*POINTS_DEL5;
944 						dif=LIMIT_FOR_COST_5;
945 					}
946 					if(dif>LIMIT_FOR_COST_4){
947 						score+=(dif-LIMIT_FOR_COST_4)*POINTS_DEL4;
948 						dif=LIMIT_FOR_COST_4;
949 					}
950 					if(dif>LIMIT_FOR_COST_3){
951 						score+=(dif-LIMIT_FOR_COST_3)*POINTS_DEL3;
952 						dif=LIMIT_FOR_COST_3;
953 					}
954 					if(dif>1){
955 						score+=(dif-1)*POINTS_DEL2;
956 					}
957 					timeInMode=1;
958 				}else if(loc>lastLoc){//insertion
959 					maxContig=Tools.max(maxContig, contig);
960 					contig=0;
961 					assert(lastLoc>=0);
962 					score+=(POINTS_MATCH+baseScores[i]+POINTS_INS_ARRAY_C[Tools.min(loc-lastLoc, 5)]);
963 					timeInMode=1;
964 				}else{
965 					assert(false);
966 				}
967 				lastLoc=loc;
968 			}else if(loc==-1){//substitution
969 				if(lastValue<0 && timeInMode>0){//contiguous
970 					timeInMode++;
971 					score+=(POINTS_SUB_ARRAY[timeInMode]);
972 				}else{
973 					score+=POINTS_SUB;
974 					timeInMode=1;
975 				}
976 			}else{
977 				assert(loc==-2) : loc+"\n"+Arrays.toString(locArray)+"\n"+Arrays.toString(baseScores)+"\n"+new String(bases)+"\n"
978 						+"If this happens please ensure that the reference has a startpad of Ns longer than readlength.";//N (no-call or no-ref)
979 				timeInMode=0;
980 				score+=POINTS_NOCALL;
981 			}
982 			lastValue=loc;
983 		}
984 		assert(score<=maxQuality(locArray.length));
985 		if(Tools.max(contig, maxContig)<minContig){score=Tools.min(score, -50*locArray.length);}
986 		return score;
987 	}
988 
989 	@Override
990 	public final int scoreNoIndels(byte[] read, byte[] ref, final int refStart){
991 		return scoreNoIndels(read, ref, refStart, null);
992 	}
993 	@Override
994 	public final int scoreNoIndels(byte[] read, byte[] ref, final int refStart, final SiteScore ss){
995 		int score=0;
996 		int mode=-1;
997 		int timeInMode=0;
998 
999 		//This block handles cases where the read runs outside the reference
1000 		//Of course, padding the reference with 'N' would be better, but...
1001 		int readStart=0;
1002 		int readStop=read.length;
1003 		final int refStop=refStart+read.length;
1004 		boolean semiperfect=true;
1005 		int norefs=0;
1006 
1007 		if(refStart<0){
1008 			readStart=0-refStart;
1009 			score+=POINTS_NOREF*readStart;
1010 			norefs+=readStart;
1011 		}
1012 		if(refStop>ref.length){
1013 			int dif=(refStop-ref.length);
1014 			readStop-=dif;
1015 			score+=POINTS_NOREF*dif;
1016 			norefs+=dif;
1017 		}
1018 
1019 		for(int i=readStart; i<readStop; i++){
1020 			byte c=read[i];
1021 			byte r=ref[refStart+i];
1022 
1023 			if(c==r && c!='N'){
1024 				if(mode==MODE_MS){
1025 					timeInMode++;
1026 					score+=POINTS_MATCH2;
1027 				}else{
1028 					timeInMode=0;
1029 					score+=POINTS_MATCH;
1030 				}
1031 				mode=MODE_MS;
1032 			}else if(c<0 || c=='N'){
1033 				score+=POINTS_NOCALL;
1034 				semiperfect=false;
1035 			}else if(r<0 || r=='N'){
1036 				score+=POINTS_NOREF;
1037 				norefs++;
1038 			}else{
1039 				if(mode==MODE_SUB){timeInMode++;}
1040 				else{timeInMode=0;}
1041 
1042 				score+=(POINTS_SUB_ARRAY[timeInMode+1]);
1043 				mode=MODE_SUB;
1044 				semiperfect=false;
1045 			}
1046 		}
1047 
1048 		return score;
1049 	}
1050 
1051 	@Override
1052 	public final byte[] genMatchNoIndels(byte[] read, byte[] ref, final int refStart){
1053 		if(read==null || ref==null){return null;}
1054 
1055 		final byte[] match=new byte[read.length];
1056 
1057 		for(int i=0, j=refStart; i<read.length; i++, j++){
1058 			byte c=read[i];
1059 			byte r=(j<0 || j>=ref.length) ? (byte)'N' : ref[j];
1060 
1061 			if(c=='N' || r=='N'){match[i]='N';}
1062 			else if(c==r){match[i]='m';}
1063 			else{match[i]='S';}
1064 
1065 		}
1066 
1067 		return match;
1068 	}
1069 
1070 	@Override
1071 	public final int scoreNoIndels(byte[] read, byte[] ref, byte[] baseScores, final int refStart){
1072 		return scoreNoIndels(read, ref, baseScores, refStart, null);
1073 	}
1074 	@Override
1075 	public final int scoreNoIndels(byte[] read, byte[] ref, byte[] baseScores, final int refStart, SiteScore ss){
1076 		int score=0;
1077 		int mode=-1;
1078 		int timeInMode=0;
1079 		int norefs=0;
1080 
1081 		//This block handles cases where the read runs outside the reference
1082 		//Of course, padding the reference with 'N' would be better, but...
1083 		int readStart=0;
1084 		int readStop=read.length;
1085 		final int refStop=refStart+read.length;
1086 		boolean semiperfect=true;
1087 
1088 		if(refStart<0){
1089 			readStart=0-refStart;
1090 			score+=POINTS_NOREF*readStart;
1091 			norefs+=readStart;
1092 		}
1093 		if(refStop>ref.length){
1094 			int dif=(refStop-ref.length);
1095 			readStop-=dif;
1096 			score+=POINTS_NOREF*dif;
1097 			norefs+=dif;
1098 		}
1099 
1100 		for(int i=readStart; i<readStop; i++){
1101 			byte c=read[i];
1102 			byte r=ref[refStart+i];
1103 
1104 			if(c==r && c!='N'){
1105 				if(mode==MODE_MS){
1106 					timeInMode++;
1107 					score+=POINTS_MATCH2;
1108 				}else{
1109 					timeInMode=0;
1110 					score+=POINTS_MATCH;
1111 				}
1112 				score+=baseScores[i];
1113 				mode=MODE_MS;
1114 			}else if(c<0 || c=='N'){
1115 				score+=POINTS_NOCALL;
1116 				semiperfect=false;
1117 			}else if(r<0 || r=='N'){
1118 				score+=POINTS_NOREF;
1119 				norefs++;
1120 			}else{
1121 				if(mode==MODE_SUB){timeInMode++;}
1122 				else{timeInMode=0;}
1123 
1124 				score+=(POINTS_SUB_ARRAY[timeInMode+1]);
1125 				mode=MODE_SUB;
1126 				semiperfect=false;
1127 			}
1128 		}
1129 
1130 		return score;
1131 	}
1132 
1133 	@Override
1134 	public final int scoreNoIndelsAndMakeMatchString(byte[] read, byte[] ref, byte[] baseScores, final int refStart, byte[][] matchReturn){
1135 		int score=0;
1136 		int mode=-1;
1137 		int timeInMode=0;
1138 
1139 		assert(refStart<=ref.length) : refStart+", "+ref.length;
1140 
1141 		//This block handles cases where the read runs outside the reference
1142 		//Of course, padding the reference with 'N' would be better, but...
1143 		int readStart=0;
1144 		int readStop=read.length;
1145 		final int refStop=refStart+read.length;
1146 		if(refStart<0 || refStop>ref.length){return -99999;}
1147 		if(refStart<0){
1148 			readStart=0-refStart;
1149 			score+=POINTS_NOREF*readStart;
1150 		}
1151 		if(refStop>ref.length){
1152 			int dif=(refStop-ref.length);
1153 			System.err.println(new String(read)+"\ndif="+dif+", ref.length="+ref.length+", refStop="+refStop);
1154 			readStop-=dif;
1155 			score+=POINTS_NOREF*dif;
1156 		}
1157 		assert(refStart+readStop<=ref.length) : "readStart="+readStart+", readStop="+readStop+
1158 		", refStart="+refStart+", refStop="+refStop+", ref.length="+ref.length+", read.length="+read.length;
1159 
1160 		assert(matchReturn!=null);
1161 		assert(matchReturn.length==1);
1162 		if(matchReturn[0]==null || matchReturn[0].length!=read.length){
1163 			assert(matchReturn[0]==null || matchReturn[0].length<read.length) : matchReturn[0].length+"!="+read.length;
1164 			matchReturn[0]=new byte[read.length];
1165 		}
1166 		final byte[] match=matchReturn[0];
1167 
1168 		for(int i=readStart; i<readStop; i++){
1169 			byte c=read[i];
1170 			byte r=ref[refStart+i];
1171 
1172 			assert(r!='.' && c!='.');
1173 
1174 			if(c==r && c!='N'){
1175 				if(mode==MODE_MS){
1176 					timeInMode++;
1177 					score+=POINTS_MATCH2;
1178 				}else{
1179 					timeInMode=0;
1180 					score+=POINTS_MATCH;
1181 				}
1182 				score+=baseScores[i];
1183 				match[i]='m';
1184 				mode=MODE_MS;
1185 			}else if(c<0 || c=='N'){
1186 				score+=POINTS_NOCALL;
1187 				match[i]='N';
1188 			}else if(r<0 || r=='N'){
1189 				score+=POINTS_NOREF;
1190 				match[i]='N';
1191 			}else{
1192 				match[i]='S';
1193 				if(mode==MODE_SUB){timeInMode++;}
1194 				else{timeInMode=0;}
1195 
1196 				score+=(POINTS_SUB_ARRAY[timeInMode+1]);
1197 				mode=MODE_SUB;
1198 			}
1199 		}
1200 
1201 		return score;
1202 	}
1203 
1204 	@Override
1205 	public final int scoreNoIndelsAndMakeMatchString(byte[] read, byte[] ref, final int refStart, byte[][] matchReturn){
1206 		int score=0;
1207 		int mode=-1;
1208 		int timeInMode=0;
1209 
1210 		assert(refStart<=ref.length) : refStart+", "+ref.length;
1211 
1212 		//This block handles cases where the read runs outside the reference
1213 		//Of course, padding the reference with 'N' would be better, but...
1214 		int readStart=0;
1215 		int readStop=read.length;
1216 		final int refStop=refStart+read.length;
1217 		if(refStart<0 || refStop>ref.length){return -99999;}
1218 		if(refStart<0){
1219 			readStart=0-refStart;
1220 			score+=POINTS_NOREF*readStart;
1221 		}
1222 		if(refStop>ref.length){
1223 			int dif=(refStop-ref.length);
1224 			System.err.println(new String(read)+"\ndif="+dif+", ref.length="+ref.length+", refStop="+refStop);
1225 			readStop-=dif;
1226 			score+=POINTS_NOREF*dif;
1227 		}
1228 		assert(refStart+readStop<=ref.length) : "readStart="+readStart+", readStop="+readStop+
1229 		", refStart="+refStart+", refStop="+refStop+", ref.length="+ref.length+", read.length="+read.length;
1230 
1231 		assert(matchReturn!=null);
1232 		assert(matchReturn.length==1);
1233 		if(matchReturn[0]==null || matchReturn[0].length!=read.length){
1234 			assert(matchReturn[0]==null || matchReturn[0].length<read.length) : matchReturn[0].length+"!="+read.length;
1235 			matchReturn[0]=new byte[read.length];
1236 		}
1237 		final byte[] match=matchReturn[0];
1238 
1239 		for(int i=readStart; i<readStop; i++){
1240 			byte c=read[i];
1241 			byte r=ref[refStart+i];
1242 
1243 			assert(r!='.' && c!='.');
1244 
1245 			if(c==r && c!='N'){
1246 				if(mode==MODE_MS){
1247 					timeInMode++;
1248 					score+=POINTS_MATCH2;
1249 				}else{
1250 					timeInMode=0;
1251 					score+=POINTS_MATCH;
1252 				}
1253 				match[i]='m';
1254 				mode=MODE_MS;
1255 			}else if(c<0 || c=='N'){
1256 				score+=POINTS_NOCALL;
1257 				match[i]='N';
1258 			}else if(r<0 || r=='N'){
1259 				score+=POINTS_NOREF;
1260 				match[i]='N';
1261 			}else{
1262 				match[i]='S';
1263 				if(mode==MODE_SUB){timeInMode++;}
1264 				else{timeInMode=0;}
1265 
1266 				if(AFFINE_ARRAYS){
1267 					score+=(POINTS_SUB_ARRAY[timeInMode+1]);
1268 				}else{
1269 					if(timeInMode==0){score+=POINTS_SUB;}
1270 					else if(timeInMode<LIMIT_FOR_COST_3){score+=POINTS_SUB2;}
1271 					else{score+=POINTS_SUB3;}
1272 				}
1273 				mode=MODE_SUB;
1274 			}
1275 		}
1276 
1277 		return score;
1278 	}
1279 
1280 	@Override
1281 	public final int maxQuality(int numBases){
1282 		return POINTS_MATCH+(numBases-1)*(POINTS_MATCH2);
1283 	}
1284 
1285 	@Override
1286 	public final int maxQuality(byte[] baseScores){
1287 		return POINTS_MATCH+(baseScores.length-1)*(POINTS_MATCH2)+Tools.sumInt(baseScores);
1288 	}
1289 
1290 	@Override
1291 	public final int maxImperfectScore(int numBases){
1292 		int maxQ=maxQuality(numBases);
1293 		int maxI=maxQ+Tools.min(POINTS_DEL, POINTS_INS-POINTS_MATCH2);
1294 		assert(maxI<(maxQ-(POINTS_MATCH2+POINTS_MATCH2)+(POINTS_MATCH+POINTS_SUB)));
1295 		return maxI;
1296 	}
1297 
1298 	@Override
1299 	public final int maxImperfectScore(byte[] baseScores){
1300 		int maxQ=maxQuality(baseScores);
1301 		int maxI=maxQ+Tools.min(POINTS_DEL, POINTS_INS-POINTS_MATCH2);
1302 		assert(maxI<(maxQ-(POINTS_MATCH2+POINTS_MATCH2)+(POINTS_MATCH+POINTS_SUB)));
1303 		return maxI;
1304 	}
1305 
1306 	@Override
1307 	public int calcDelScore(int len, boolean approximateGaps){
1308 		if(len<=0){return 0;}
1309 		int score=POINTS_DEL;
1310 
1311 		if(approximateGaps && len>MINGAP){
1312 			int rem=len%GAPLEN;
1313 			int div=(len-GAPBUFFER2)/GAPLEN;
1314 			score+=(div*POINTS_GAP);
1315 			assert(rem+GAPBUFFER2<len);
1316 			len=rem+GAPBUFFER2;
1317 			assert(len>LIMIT_FOR_COST_4); //and probably LIMIT_FOR_COST_5
1318 		}
1319 
1320 		if(len>LIMIT_FOR_COST_5){
1321 			score+=((len-LIMIT_FOR_COST_5+MASK5)/TIMESLIP)*POINTS_DEL5;
1322 			len=LIMIT_FOR_COST_5;
1323 		}
1324 		if(len>LIMIT_FOR_COST_4){
1325 			score+=(len-LIMIT_FOR_COST_4)*POINTS_DEL4;
1326 			len=LIMIT_FOR_COST_4;
1327 		}
1328 		if(len>LIMIT_FOR_COST_3){
1329 			score+=(len-LIMIT_FOR_COST_3)*POINTS_DEL3;
1330 			len=LIMIT_FOR_COST_3;
1331 		}
1332 		if(len>1){
1333 			score+=(len-1)*POINTS_DEL2;
1334 		}
1335 		return score;
1336 	}
1337 
1338 	private static int calcDelScoreOffset(int len){
1339 		if(len<=0){return 0;}
1340 		int score=POINTSoff_DEL;
1341 
1342 		if(len>LIMIT_FOR_COST_5){
1343 			score+=((len-LIMIT_FOR_COST_5+MASK5)/TIMESLIP)*POINTSoff_DEL5;
1344 			len=LIMIT_FOR_COST_5;
1345 		}
1346 		if(len>LIMIT_FOR_COST_4){
1347 			score+=(len-LIMIT_FOR_COST_4)*POINTSoff_DEL4;
1348 			len=LIMIT_FOR_COST_4;
1349 		}
1350 		if(len>LIMIT_FOR_COST_3){
1351 			score+=(len-LIMIT_FOR_COST_3)*POINTSoff_DEL3;
1352 			len=LIMIT_FOR_COST_3;
1353 		}
1354 		if(len>1){
1355 			score+=(len-1)*POINTSoff_DEL2;
1356 		}
1357 		return score;
1358 	}
1359 
1360 	@Override
1361 	public int calcInsScore(int len){
1362 		if(len<=0){return 0;}
1363 		if(AFFINE_ARRAYS){
1364 			return POINTS_INS_ARRAY_C[len];
1365 		}else{
1366 			int score=POINTS_INS;
1367 
1368 			if(len>LIMIT_FOR_COST_4){
1369 				score+=(len-LIMIT_FOR_COST_4)*POINTS_INS4;
1370 				len=LIMIT_FOR_COST_4;
1371 			}
1372 			if(len>LIMIT_FOR_COST_3){
1373 				score+=(len-LIMIT_FOR_COST_3)*POINTS_INS3;
1374 				len=LIMIT_FOR_COST_3;
1375 			}
1376 			if(len>1){
1377 				score+=(len-1)*POINTS_INS2;
1378 			}
1379 			return score;
1380 		}
1381 	}
1382 
1383 	private static int calcInsScoreOffset(int len){
1384 		if(len<=0){return 0;}
1385 		if(AFFINE_ARRAYS){
1386 			return POINTSoff_INS_ARRAY_C[len];
1387 		}else{
1388 			int score=POINTSoff_INS;
1389 			if(len>LIMIT_FOR_COST_4){
1390 				score+=(len-LIMIT_FOR_COST_4)*POINTSoff_INS4;
1391 				len=LIMIT_FOR_COST_4;
1392 			}
1393 			if(len>LIMIT_FOR_COST_3){
1394 				score+=(len-LIMIT_FOR_COST_3)*POINTSoff_INS3;
1395 				len=LIMIT_FOR_COST_3;
1396 			}
1397 			if(len>1){
1398 				score+=(len-1)*POINTSoff_INS2;
1399 			}
1400 			return score;
1401 		}
1402 	}
1403 
1404 	private final int[]packed;
1405 	private final byte[] grefbuffer;
1406 	private int greflimit=-1;
1407 	private int greflimit2=-1;
1408 	private int grefRefOrigin=-1;
1409 
1410 	@Override
1411 	/**DO NOT MODIFY*/
1412 	public final byte[] getGrefbuffer(){
1413 		return grefbuffer;
1414 	}
1415 
1416 	public final int[] vertLimit;
1417 	public final int[] horizLimit;
1418 
1419 	@Override
1420 	public CharSequence showVertLimit(){
1421 		StringBuilder sb=new StringBuilder();
1422 		for(int i=0; i<=rows; i++){sb.append(vertLimit[i]>>SCOREOFFSET).append(",");}
1423 		return sb;
1424 	}
1425 
1426 	@Override
1427 	public CharSequence showHorizLimit(){
1428 		StringBuilder sb=new StringBuilder();
1429 		for(int i=0; i<=columns; i++){sb.append(horizLimit[i]>>SCOREOFFSET).append(",");}
1430 		return sb;
1431 	}
1432 
1433 	public static float minIdToMinRatio(double minid){
1434 		if(minid>1){minid=minid/100;}
1435 		assert(minid>0 && minid<=1) : "Min identity should be between 0 and 1.  Values above 1 will be assumed to be percent and divided by 100.";
1436 		double matchdif=POINTS_MATCH-POINTS_MATCH2;
1437 		double match=POINTS_MATCH2;
1438 		double sub=-POINTS_MATCH2+0.5*(matchdif+POINTS_SUB)+0.5*POINTS_SUB2;
1439 		double del=0.1*(matchdif+POINTS_DEL)+0.2*POINTS_DEL2+0.4*POINTS_DEL3+0.3*POINTS_DEL4;
1440 		double ins=-POINTS_MATCH2+0.4*(matchdif+POINTS_INS)+0.3*(POINTS_INS2)+0.3*(POINTS_INS3);
1441 		double badAvg=.7*sub+.2*del+.1*ins;
1442 		double badFraction=1-minid;
1443 		double minratio=(match+badFraction*badAvg)/match;
1444 		assert(minratio<=1);
1445 		minratio=Tools.max(0.1, minratio);
1446 		return (float)minratio;
1447 	}
1448 
1449 	public static final int TIMEBITS=11;
1450 	public static final int SCOREBITS=32-TIMEBITS;
1451 	public static final int MAX_TIME=((1<<TIMEBITS)-1);
1452 	public static final int MAX_SCORE=((1<<(SCOREBITS-1))-1)-2000;
1453 	public static final int MIN_SCORE=0-MAX_SCORE; //Keeps it 1 point above "BAD".
1454 
1455 	public static final int SCOREOFFSET=TIMEBITS;
1456 
1457 	public static final int TIMEMASK=~((-1)<<TIMEBITS);
1458 	public static final int SCOREMASK=(~((-1)<<SCOREBITS))<<SCOREOFFSET;
1459 
1460 	public static final int POINTS_NOREF=0;
1461 	public static final int POINTS_NOCALL=0;
1462 	public static final int POINTS_MATCH=70;
1463 	public static final int POINTS_MATCH2=100; //Note:  Changing to 90 substantially reduces false positives
1464 	public static final int POINTS_COMPATIBLE=50;
1465 	public static final int POINTS_SUB=-127;
1466 	public static final int POINTS_SUBR=-147; //increased penalty if prior match streak was at most 1
1467 	public static final int POINTS_SUB2=-51;
1468 	public static final int POINTS_SUB3=-25;
1469 	public static final int POINTS_MATCHSUB=-10;
1470 	public static final int POINTS_INS=-395;
1471 	public static final int POINTS_INS2=-39;
1472 	public static final int POINTS_INS3=-23;
1473 	public static final int POINTS_INS4=-8;
1474 	public static final int POINTS_DEL=-472;
1475 	public static final int POINTS_DEL2=-33;
1476 	public static final int POINTS_DEL3=-9;
1477 	public static final int POINTS_DEL4=-1;
1478 	public static final int POINTS_DEL5=-1;
1479 	public static final int POINTS_DEL_REF_N=-10;
1480 	public static final int POINTS_GAP=0-GAPCOST;
1481 
1482 	public static final int TIMESLIP=4;
1483 	public static final int MASK5=TIMESLIP-1;
1484 	static{assert(Integer.bitCount(TIMESLIP)==1);}
1485 
1486 	private static final int BARRIER_I1=2;
1487 	private static final int BARRIER_D1=3;
1488 
1489 	public static final int LIMIT_FOR_COST_3=5;
1490 	public static final int LIMIT_FOR_COST_4=20;
1491 	public static final int LIMIT_FOR_COST_5=80;
1492 
1493 	public static final int BAD=MIN_SCORE-1;
1494 
1495 	public static final int POINTSoff_NOREF=(POINTS_NOREF<<SCOREOFFSET);
1496 	public static final int POINTSoff_NOCALL=(POINTS_NOCALL<<SCOREOFFSET);
1497 	public static final int POINTSoff_MATCH=(POINTS_MATCH<<SCOREOFFSET);
1498 	public static final int POINTSoff_MATCH2=(POINTS_MATCH2<<SCOREOFFSET);
1499 	public static final int POINTSoff_COMPATIBLE=(POINTS_COMPATIBLE<<SCOREOFFSET);
1500 	public static final int POINTSoff_SUB=(POINTS_SUB<<SCOREOFFSET);
1501 	public static final int POINTSoff_SUBR=(POINTS_SUBR<<SCOREOFFSET);
1502 	public static final int POINTSoff_SUB2=(POINTS_SUB2<<SCOREOFFSET);
1503 	public static final int POINTSoff_SUB3=(POINTS_SUB3<<SCOREOFFSET);
1504 	public static final int POINTSoff_MATCHSUB=(POINTS_MATCHSUB<<SCOREOFFSET);
1505 	public static final int POINTSoff_INS=(POINTS_INS<<SCOREOFFSET);
1506 	public static final int POINTSoff_INS2=(POINTS_INS2<<SCOREOFFSET);
1507 	public static final int POINTSoff_INS3=(POINTS_INS3<<SCOREOFFSET);
1508 	public static final int POINTSoff_INS4=(POINTS_INS4<<SCOREOFFSET);
1509 	public static final int POINTSoff_DEL=(POINTS_DEL<<SCOREOFFSET);
1510 	public static final int POINTSoff_DEL2=(POINTS_DEL2<<SCOREOFFSET);
1511 	public static final int POINTSoff_DEL3=(POINTS_DEL3<<SCOREOFFSET);
1512 	public static final int POINTSoff_DEL4=(POINTS_DEL4<<SCOREOFFSET);
1513 	public static final int POINTSoff_DEL5=(POINTS_DEL5<<SCOREOFFSET);
1514 	public static final int POINTSoff_GAP=(POINTS_GAP<<SCOREOFFSET);
1515 	public static final int POINTSoff_DEL_REF_N=(POINTS_DEL_REF_N<<SCOREOFFSET);
1516 	public static final int BADoff=(BAD<<SCOREOFFSET);
1517 	public static final int MAXoff_SCORE=MAX_SCORE<<SCOREOFFSET;
1518 	public static final int MINoff_SCORE=MIN_SCORE<<SCOREOFFSET;
1519 
1520 	public static final boolean AFFINE_ARRAYS=true;
1521 	public static final int[] POINTS_INS_ARRAY;
1522 	public static final int[] POINTSoff_INS_ARRAY;
1523 	public static final int[] POINTS_INS_ARRAY_C;
1524 	public static final int[] POINTSoff_INS_ARRAY_C;
1525 
1526 	public static final int[] POINTS_SUB_ARRAY;
1527 	public static final int[] POINTSoff_SUB_ARRAY;
1528 	public static final int[] POINTS_SUB_ARRAY_C;
1529 	public static final int[] POINTSoff_SUB_ARRAY_C;
1530 
1531 	static{
1532 		POINTS_INS_ARRAY=new int[604];
1533 		POINTSoff_INS_ARRAY=new int[604];
1534 		POINTS_INS_ARRAY_C=new int[604];
1535 		POINTSoff_INS_ARRAY_C=new int[604];
1536 
1537 		for(int i=1; i<POINTS_INS_ARRAY.length; i++){
1538 			int pts, ptsoff;
1539 			if(i>LIMIT_FOR_COST_4){
1540 				pts=POINTS_INS4;
1541 				ptsoff=POINTSoff_INS4;
1542 			}else if(i>LIMIT_FOR_COST_3){
1543 				pts=POINTS_INS3;
1544 				ptsoff=POINTSoff_INS3;
1545 			}else if(i>1){
1546 				pts=POINTS_INS2;
1547 				ptsoff=POINTSoff_INS2;
1548 			}else{
1549 				pts=POINTS_INS;
1550 				ptsoff=POINTSoff_INS;
1551 			}
1552 			POINTS_INS_ARRAY[i]=pts;
1553 			POINTSoff_INS_ARRAY[i]=ptsoff;
1554 			POINTS_INS_ARRAY_C[i]=Tools.max(MIN_SCORE, pts+POINTS_INS_ARRAY_C[i-1]);
1555 			POINTSoff_INS_ARRAY_C[i]=Tools.max(MINoff_SCORE, ptsoff+POINTSoff_INS_ARRAY_C[i-1]);
1556 		}
1557 
1558 		POINTS_SUB_ARRAY=new int[604];
1559 		POINTSoff_SUB_ARRAY=new int[604];
1560 		POINTS_SUB_ARRAY_C=new int[604];
1561 		POINTSoff_SUB_ARRAY_C=new int[604];
1562 
1563 		for(int i=1; i<POINTS_SUB_ARRAY.length; i++){
1564 			int pts, ptsoff;
1565 			if(i>LIMIT_FOR_COST_3){
1566 				pts=POINTS_SUB3;
1567 				ptsoff=POINTSoff_SUB3;
1568 			}else if(i>1){
1569 				pts=POINTS_SUB2;
1570 				ptsoff=POINTSoff_SUB2;
1571 			}else{
1572 				pts=POINTS_SUB;
1573 				ptsoff=POINTSoff_SUB;
1574 			}
1575 			POINTS_SUB_ARRAY[i]=pts;
1576 			POINTSoff_SUB_ARRAY[i]=ptsoff;
1577 			POINTS_SUB_ARRAY_C[i]=Tools.max(MIN_SCORE, pts+POINTS_SUB_ARRAY_C[i-1]);
1578 			POINTSoff_SUB_ARRAY_C[i]=Tools.max(MINoff_SCORE, ptsoff+POINTSoff_SUB_ARRAY_C[i-1]);
1579 		}
1580 	}
1581 
1582 	@Override
1583 	public final int POINTS_NOREF(){return POINTS_NOREF;}
1584 	@Override
1585 	public final int POINTS_NOCALL(){return POINTS_NOCALL;}
1586 	@Override
1587 	public final int POINTS_MATCH(){return POINTS_MATCH;}
1588 	@Override
1589 	public final int POINTS_MATCH2(){return POINTS_MATCH2;}
1590 	@Override
1591 	public final int POINTS_COMPATIBLE(){return POINTS_COMPATIBLE;}
1592 	@Override
1593 	public final int POINTS_SUB(){return POINTS_SUB;}
1594 	@Override
1595 	public final int POINTS_SUBR(){return POINTS_SUBR;}
1596 	@Override
1597 	public final int POINTS_SUB2(){return POINTS_SUB2;}
1598 	@Override
1599 	public final int POINTS_SUB3(){return POINTS_SUB3;}
1600 	@Override
1601 	public final int POINTS_MATCHSUB(){return POINTS_MATCHSUB;}
1602 	@Override
1603 	public final int POINTS_INS(){return POINTS_INS;}
1604 	@Override
1605 	public final int POINTS_INS2(){return POINTS_INS2;}
1606 	@Override
1607 	public final int POINTS_INS3(){return POINTS_INS3;}
1608 	@Override
1609 	public final int POINTS_INS4(){return POINTS_INS4;}
1610 	@Override
1611 	public final int POINTS_DEL(){return POINTS_DEL;}
1612 	@Override
1613 	public final int POINTS_DEL2(){return POINTS_DEL2;}
1614 	@Override
1615 	public final int POINTS_DEL3(){return POINTS_DEL3;}
1616 	@Override
1617 	public final int POINTS_DEL4(){return POINTS_DEL4;}
1618 	@Override
1619 	public final int POINTS_DEL5(){return POINTS_DEL5;}
1620 	@Override
1621 	public final int POINTS_DEL_REF_N(){return POINTS_DEL_REF_N;}
1622 	@Override
1623 	public final int POINTS_GAP(){return POINTS_GAP;}
1624 
1625 	@Override
1626 	public final int TIMESLIP(){return TIMESLIP;}
1627 	@Override
1628 	public final int MASK5(){return MASK5;}
1629 	@Override
1630 	public final int SCOREOFFSET(){return SCOREOFFSET();}
1631 
1632 	@Override
1633 	final int BARRIER_I1(){return BARRIER_I1;}
1634 	@Override
1635 	final int BARRIER_D1(){return BARRIER_D1;}
1636 
1637 	@Override
1638 	public final int LIMIT_FOR_COST_3(){return LIMIT_FOR_COST_3;}
1639 	@Override
1640 	public final int LIMIT_FOR_COST_4(){return LIMIT_FOR_COST_4;}
1641 	@Override
1642 	public final int LIMIT_FOR_COST_5(){return LIMIT_FOR_COST_5;}
1643 
1644 	@Override
1645 	public final int BAD(){return BAD;}
1646 
1647 	private int rows;
1648 	private int columns;
1649 
1650 }
1651