jpayne@69
|
1 /* Copyright 2002 by Jeffrey Chang.
|
jpayne@69
|
2 * Copyright 2016, 2019 by Markus Piotrowski.
|
jpayne@69
|
3 * All rights reserved.
|
jpayne@69
|
4 *
|
jpayne@69
|
5 * This file is part of the Biopython distribution and governed by your
|
jpayne@69
|
6 * choice of the "Biopython License Agreement" or the "BSD 3-Clause License".
|
jpayne@69
|
7 * Please see the LICENSE file that should have been included as part of this
|
jpayne@69
|
8 * package.
|
jpayne@69
|
9 *
|
jpayne@69
|
10 * cpairwise2module.c
|
jpayne@69
|
11 * Created 30 Sep 2001
|
jpayne@69
|
12 *
|
jpayne@69
|
13 * Optimized C routines that complement pairwise2.py.
|
jpayne@69
|
14 */
|
jpayne@69
|
15
|
jpayne@69
|
16 #include "Python.h"
|
jpayne@69
|
17
|
jpayne@69
|
18
|
jpayne@69
|
19 #define _PRECISION 1000
|
jpayne@69
|
20 #define rint(x) (int)((x)*_PRECISION+0.5)
|
jpayne@69
|
21
|
jpayne@69
|
22 /* Functions in this module. */
|
jpayne@69
|
23
|
jpayne@69
|
24 static double calc_affine_penalty(int length, double open, double extend,
|
jpayne@69
|
25 int penalize_extend_when_opening)
|
jpayne@69
|
26 {
|
jpayne@69
|
27 double penalty;
|
jpayne@69
|
28
|
jpayne@69
|
29 if(length <= 0)
|
jpayne@69
|
30 return 0.0;
|
jpayne@69
|
31 penalty = open + extend * length;
|
jpayne@69
|
32 if(!penalize_extend_when_opening)
|
jpayne@69
|
33 penalty -= extend;
|
jpayne@69
|
34 return penalty;
|
jpayne@69
|
35 }
|
jpayne@69
|
36
|
jpayne@69
|
37 static double _get_match_score(PyObject *py_sequenceA, PyObject *py_sequenceB,
|
jpayne@69
|
38 PyObject *py_match_fn, int i, int j,
|
jpayne@69
|
39 char *sequenceA, char *sequenceB,
|
jpayne@69
|
40 int use_sequence_cstring,
|
jpayne@69
|
41 double match, double mismatch,
|
jpayne@69
|
42 int use_match_mismatch_scores)
|
jpayne@69
|
43 {
|
jpayne@69
|
44 PyObject *py_A=NULL, *py_B=NULL;
|
jpayne@69
|
45 PyObject *py_arglist=NULL, *py_result=NULL;
|
jpayne@69
|
46 double score = 0;
|
jpayne@69
|
47
|
jpayne@69
|
48 if(use_sequence_cstring && use_match_mismatch_scores) {
|
jpayne@69
|
49 score = (sequenceA[i] == sequenceB[j]) ? match : mismatch;
|
jpayne@69
|
50 return score;
|
jpayne@69
|
51 }
|
jpayne@69
|
52 /* Calculate the match score. */
|
jpayne@69
|
53 if(!(py_A = PySequence_GetItem(py_sequenceA, i)))
|
jpayne@69
|
54 goto _get_match_score_cleanup;
|
jpayne@69
|
55 if(!(py_B = PySequence_GetItem(py_sequenceB, j)))
|
jpayne@69
|
56 goto _get_match_score_cleanup;
|
jpayne@69
|
57 if(!(py_arglist = Py_BuildValue("(OO)", py_A, py_B)))
|
jpayne@69
|
58 goto _get_match_score_cleanup;
|
jpayne@69
|
59
|
jpayne@69
|
60 if(!(py_result = PyEval_CallObject(py_match_fn, py_arglist)))
|
jpayne@69
|
61 goto _get_match_score_cleanup;
|
jpayne@69
|
62 score = PyFloat_AsDouble(py_result);
|
jpayne@69
|
63
|
jpayne@69
|
64 _get_match_score_cleanup:
|
jpayne@69
|
65 if(py_A) {
|
jpayne@69
|
66 Py_DECREF(py_A);
|
jpayne@69
|
67 }
|
jpayne@69
|
68 if(py_B) {
|
jpayne@69
|
69 Py_DECREF(py_B);
|
jpayne@69
|
70 }
|
jpayne@69
|
71 if(py_arglist) {
|
jpayne@69
|
72 Py_DECREF(py_arglist);
|
jpayne@69
|
73 }
|
jpayne@69
|
74 if(py_result) {
|
jpayne@69
|
75 Py_DECREF(py_result);
|
jpayne@69
|
76 }
|
jpayne@69
|
77 return score;
|
jpayne@69
|
78 }
|
jpayne@69
|
79
|
jpayne@69
|
80 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
81 static PyObject* _create_bytes_object(PyObject* o)
|
jpayne@69
|
82 {
|
jpayne@69
|
83 PyObject* b;
|
jpayne@69
|
84 if (PyBytes_Check(o)) {
|
jpayne@69
|
85 return o;
|
jpayne@69
|
86 }
|
jpayne@69
|
87 if (!PyUnicode_Check(o)) {
|
jpayne@69
|
88 return NULL;
|
jpayne@69
|
89 }
|
jpayne@69
|
90 b = PyUnicode_AsASCIIString(o);
|
jpayne@69
|
91 if (!b) {
|
jpayne@69
|
92 PyErr_Clear();
|
jpayne@69
|
93 return NULL;
|
jpayne@69
|
94 }
|
jpayne@69
|
95 return b;
|
jpayne@69
|
96 }
|
jpayne@69
|
97 #endif
|
jpayne@69
|
98
|
jpayne@69
|
99 /* This function is a more-or-less straightforward port of the
|
jpayne@69
|
100 * equivalent function in pairwise2. Please see there for algorithm
|
jpayne@69
|
101 * documentation.
|
jpayne@69
|
102 */
|
jpayne@69
|
103 static PyObject *cpairwise2__make_score_matrix_fast(PyObject *self,
|
jpayne@69
|
104 PyObject *args)
|
jpayne@69
|
105 {
|
jpayne@69
|
106 int i;
|
jpayne@69
|
107 int row, col;
|
jpayne@69
|
108 PyObject *py_sequenceA, *py_sequenceB, *py_match_fn;
|
jpayne@69
|
109 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
110 PyObject *py_bytesA, *py_bytesB;
|
jpayne@69
|
111 #endif
|
jpayne@69
|
112 char *sequenceA=NULL, *sequenceB=NULL;
|
jpayne@69
|
113 int use_sequence_cstring;
|
jpayne@69
|
114 double open_A, extend_A, open_B, extend_B;
|
jpayne@69
|
115 int penalize_extend_when_opening, penalize_end_gaps_A, penalize_end_gaps_B;
|
jpayne@69
|
116 int align_globally, score_only;
|
jpayne@69
|
117
|
jpayne@69
|
118 PyObject *py_match=NULL, *py_mismatch=NULL;
|
jpayne@69
|
119 double first_A_gap, first_B_gap;
|
jpayne@69
|
120 double match, mismatch;
|
jpayne@69
|
121 double score;
|
jpayne@69
|
122 double best_score = 0;
|
jpayne@69
|
123 double local_max_score = 0;
|
jpayne@69
|
124 int use_match_mismatch_scores;
|
jpayne@69
|
125 int lenA, lenB;
|
jpayne@69
|
126 double *score_matrix = NULL;
|
jpayne@69
|
127 unsigned char *trace_matrix = NULL;
|
jpayne@69
|
128 PyObject *py_score_matrix=NULL, *py_trace_matrix=NULL;
|
jpayne@69
|
129
|
jpayne@69
|
130 double *col_cache_score = NULL;
|
jpayne@69
|
131 PyObject *py_retval = NULL;
|
jpayne@69
|
132
|
jpayne@69
|
133 if(!PyArg_ParseTuple(args, "OOOddddi(ii)ii", &py_sequenceA, &py_sequenceB,
|
jpayne@69
|
134 &py_match_fn, &open_A, &extend_A, &open_B, &extend_B,
|
jpayne@69
|
135 &penalize_extend_when_opening,
|
jpayne@69
|
136 &penalize_end_gaps_A, &penalize_end_gaps_B,
|
jpayne@69
|
137 &align_globally, &score_only))
|
jpayne@69
|
138 return NULL;
|
jpayne@69
|
139 if(!PySequence_Check(py_sequenceA) || !PySequence_Check(py_sequenceB)) {
|
jpayne@69
|
140 PyErr_SetString(PyExc_TypeError,
|
jpayne@69
|
141 "py_sequenceA and py_sequenceB should be sequences.");
|
jpayne@69
|
142 return NULL;
|
jpayne@69
|
143 }
|
jpayne@69
|
144
|
jpayne@69
|
145 /* Optimize for the common case. Check to see if py_sequenceA and
|
jpayne@69
|
146 py_sequenceB are strings. If they are, use the c string
|
jpayne@69
|
147 representation. */
|
jpayne@69
|
148 #if PY_MAJOR_VERSION < 3
|
jpayne@69
|
149 use_sequence_cstring = 0;
|
jpayne@69
|
150 if(PyString_Check(py_sequenceA) && PyString_Check(py_sequenceB)) {
|
jpayne@69
|
151 sequenceA = PyString_AS_STRING(py_sequenceA);
|
jpayne@69
|
152 sequenceB = PyString_AS_STRING(py_sequenceB);
|
jpayne@69
|
153 use_sequence_cstring = 1;
|
jpayne@69
|
154 }
|
jpayne@69
|
155 #else
|
jpayne@69
|
156 py_bytesA = _create_bytes_object(py_sequenceA);
|
jpayne@69
|
157 py_bytesB = _create_bytes_object(py_sequenceB);
|
jpayne@69
|
158 if (py_bytesA && py_bytesB) {
|
jpayne@69
|
159 sequenceA = PyBytes_AS_STRING(py_bytesA);
|
jpayne@69
|
160 sequenceB = PyBytes_AS_STRING(py_bytesB);
|
jpayne@69
|
161 use_sequence_cstring = 1;
|
jpayne@69
|
162 }
|
jpayne@69
|
163 else {
|
jpayne@69
|
164 Py_XDECREF(py_bytesA);
|
jpayne@69
|
165 Py_XDECREF(py_bytesB);
|
jpayne@69
|
166 use_sequence_cstring = 0;
|
jpayne@69
|
167 }
|
jpayne@69
|
168 #endif
|
jpayne@69
|
169
|
jpayne@69
|
170 if(!PyCallable_Check(py_match_fn)) {
|
jpayne@69
|
171 PyErr_SetString(PyExc_TypeError, "py_match_fn must be callable.");
|
jpayne@69
|
172 return NULL;
|
jpayne@69
|
173 }
|
jpayne@69
|
174 /* Optimize for the common case. Check to see if py_match_fn is
|
jpayne@69
|
175 an identity_match. If so, pull out the match and mismatch
|
jpayne@69
|
176 member variables and calculate the scores myself. */
|
jpayne@69
|
177 match = mismatch = 0;
|
jpayne@69
|
178 use_match_mismatch_scores = 0;
|
jpayne@69
|
179 if(!(py_match = PyObject_GetAttrString(py_match_fn, "match")))
|
jpayne@69
|
180 goto cleanup_after_py_match_fn;
|
jpayne@69
|
181 match = PyFloat_AsDouble(py_match);
|
jpayne@69
|
182 if(match==-1.0 && PyErr_Occurred())
|
jpayne@69
|
183 goto cleanup_after_py_match_fn;
|
jpayne@69
|
184 if(!(py_mismatch = PyObject_GetAttrString(py_match_fn, "mismatch")))
|
jpayne@69
|
185 goto cleanup_after_py_match_fn;
|
jpayne@69
|
186 mismatch = PyFloat_AsDouble(py_mismatch);
|
jpayne@69
|
187 if(mismatch==-1.0 && PyErr_Occurred())
|
jpayne@69
|
188 goto cleanup_after_py_match_fn;
|
jpayne@69
|
189 use_match_mismatch_scores = 1;
|
jpayne@69
|
190
|
jpayne@69
|
191 cleanup_after_py_match_fn:
|
jpayne@69
|
192 if(PyErr_Occurred())
|
jpayne@69
|
193 PyErr_Clear();
|
jpayne@69
|
194 if(py_match) {
|
jpayne@69
|
195 Py_DECREF(py_match);
|
jpayne@69
|
196 }
|
jpayne@69
|
197 if(py_mismatch) {
|
jpayne@69
|
198 Py_DECREF(py_mismatch);
|
jpayne@69
|
199 }
|
jpayne@69
|
200 /* Cache some commonly used gap penalties */
|
jpayne@69
|
201 first_A_gap = calc_affine_penalty(1, open_A, extend_A,
|
jpayne@69
|
202 penalize_extend_when_opening);
|
jpayne@69
|
203 first_B_gap = calc_affine_penalty(1, open_B, extend_B,
|
jpayne@69
|
204 penalize_extend_when_opening);
|
jpayne@69
|
205
|
jpayne@69
|
206 /* Allocate matrices for storing the results and initialize first row and col. */
|
jpayne@69
|
207 lenA = PySequence_Length(py_sequenceA);
|
jpayne@69
|
208 lenB = PySequence_Length(py_sequenceB);
|
jpayne@69
|
209 score_matrix = malloc((lenA+1)*(lenB+1)*sizeof(*score_matrix));
|
jpayne@69
|
210 if(!score_matrix) {
|
jpayne@69
|
211 PyErr_SetString(PyExc_MemoryError, "Out of memory");
|
jpayne@69
|
212 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
213 }
|
jpayne@69
|
214 for(i=0; i<(lenB+1); i++)
|
jpayne@69
|
215 score_matrix[i] = 0;
|
jpayne@69
|
216 for(i=0; i<(lenA+1)*(lenB+1); i += (lenB+1))
|
jpayne@69
|
217 score_matrix[i] = 0;
|
jpayne@69
|
218 /* If we only want the score, we don't need the trace matrix. */
|
jpayne@69
|
219 if (!score_only){
|
jpayne@69
|
220 trace_matrix = malloc((lenA+1)*(lenB+1)*sizeof(*trace_matrix));
|
jpayne@69
|
221 if(!trace_matrix) {
|
jpayne@69
|
222 PyErr_SetString(PyExc_MemoryError, "Out of memory");
|
jpayne@69
|
223 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
224 }
|
jpayne@69
|
225 for(i=0; i<(lenB+1); i++)
|
jpayne@69
|
226 trace_matrix[i] = 0;
|
jpayne@69
|
227 for(i=0; i<(lenA+1)*(lenB+1); i += (lenB+1))
|
jpayne@69
|
228 trace_matrix[i] = 0;
|
jpayne@69
|
229 }
|
jpayne@69
|
230 else
|
jpayne@69
|
231 trace_matrix = malloc(1);
|
jpayne@69
|
232
|
jpayne@69
|
233 /* Initialize the first row and col of the score matrix. */
|
jpayne@69
|
234 for(i=0; i<=lenA; i++) {
|
jpayne@69
|
235 if(penalize_end_gaps_B)
|
jpayne@69
|
236 score = calc_affine_penalty(i, open_B, extend_B,
|
jpayne@69
|
237 penalize_extend_when_opening);
|
jpayne@69
|
238 else
|
jpayne@69
|
239 score = 0;
|
jpayne@69
|
240 score_matrix[i*(lenB+1)] = score;
|
jpayne@69
|
241 }
|
jpayne@69
|
242 for(i=0; i<=lenB; i++) {
|
jpayne@69
|
243 if(penalize_end_gaps_A)
|
jpayne@69
|
244 score = calc_affine_penalty(i, open_A, extend_A,
|
jpayne@69
|
245 penalize_extend_when_opening);
|
jpayne@69
|
246 else
|
jpayne@69
|
247 score = 0;
|
jpayne@69
|
248 score_matrix[i] = score;
|
jpayne@69
|
249 }
|
jpayne@69
|
250
|
jpayne@69
|
251 /* Now initialize the col cache. */
|
jpayne@69
|
252 col_cache_score = malloc((lenB+1)*sizeof(*col_cache_score));
|
jpayne@69
|
253 memset((void *)col_cache_score, 0, (lenB+1)*sizeof(*col_cache_score));
|
jpayne@69
|
254 for(i=0; i<=lenB; i++) {
|
jpayne@69
|
255 col_cache_score[i] = calc_affine_penalty(i, (2*open_B), extend_B,
|
jpayne@69
|
256 penalize_extend_when_opening);
|
jpayne@69
|
257 }
|
jpayne@69
|
258
|
jpayne@69
|
259 /* Fill in the score matrix. The row cache is calculated on the fly.*/
|
jpayne@69
|
260 for(row=1; row<=lenA; row++) {
|
jpayne@69
|
261 double row_cache_score = calc_affine_penalty(row, (2*open_A), extend_A,
|
jpayne@69
|
262 penalize_extend_when_opening);
|
jpayne@69
|
263 for(col=1; col<=lenB; col++) {
|
jpayne@69
|
264 double match_score, nogap_score;
|
jpayne@69
|
265 double row_open, row_extend, col_open, col_extend;
|
jpayne@69
|
266 int best_score_rint, row_score_rint, col_score_rint;
|
jpayne@69
|
267 unsigned char row_trace_score, col_trace_score, trace_score;
|
jpayne@69
|
268
|
jpayne@69
|
269 /* Calculate the best score. */
|
jpayne@69
|
270 match_score = _get_match_score(py_sequenceA, py_sequenceB,
|
jpayne@69
|
271 py_match_fn, row-1, col-1,
|
jpayne@69
|
272 sequenceA, sequenceB,
|
jpayne@69
|
273 use_sequence_cstring,
|
jpayne@69
|
274 match, mismatch,
|
jpayne@69
|
275 use_match_mismatch_scores);
|
jpayne@69
|
276 if(match_score==-1.0 && PyErr_Occurred())
|
jpayne@69
|
277 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
278 nogap_score = score_matrix[(row-1)*(lenB+1)+col-1] + match_score;
|
jpayne@69
|
279
|
jpayne@69
|
280 if (!penalize_end_gaps_A && row==lenA) {
|
jpayne@69
|
281 row_open = score_matrix[(row)*(lenB+1)+col-1];
|
jpayne@69
|
282 row_extend = row_cache_score;
|
jpayne@69
|
283 }
|
jpayne@69
|
284 else {
|
jpayne@69
|
285 row_open = score_matrix[(row)*(lenB+1)+col-1] + first_A_gap;
|
jpayne@69
|
286 row_extend = row_cache_score + extend_A;
|
jpayne@69
|
287 }
|
jpayne@69
|
288 row_cache_score = (row_open > row_extend) ? row_open : row_extend;
|
jpayne@69
|
289
|
jpayne@69
|
290 if (!penalize_end_gaps_B && col==lenB){
|
jpayne@69
|
291 col_open = score_matrix[(row-1)*(lenB+1)+col];
|
jpayne@69
|
292 col_extend = col_cache_score[col];
|
jpayne@69
|
293 }
|
jpayne@69
|
294 else {
|
jpayne@69
|
295 col_open = score_matrix[(row-1)*(lenB+1)+col] + first_B_gap;
|
jpayne@69
|
296 col_extend = col_cache_score[col] + extend_B;
|
jpayne@69
|
297 }
|
jpayne@69
|
298 col_cache_score[col] = (col_open > col_extend) ? col_open : col_extend;
|
jpayne@69
|
299
|
jpayne@69
|
300 best_score = (row_cache_score > col_cache_score[col]) ? row_cache_score : col_cache_score[col];
|
jpayne@69
|
301 if(nogap_score > best_score)
|
jpayne@69
|
302 best_score = nogap_score;
|
jpayne@69
|
303
|
jpayne@69
|
304 if (best_score > local_max_score)
|
jpayne@69
|
305 local_max_score = best_score;
|
jpayne@69
|
306
|
jpayne@69
|
307 if(!align_globally && best_score < 0)
|
jpayne@69
|
308 score_matrix[row*(lenB+1)+col] = 0;
|
jpayne@69
|
309 else
|
jpayne@69
|
310 score_matrix[row*(lenB+1)+col] = best_score;
|
jpayne@69
|
311
|
jpayne@69
|
312 if (!score_only) {
|
jpayne@69
|
313 row_score_rint = rint(row_cache_score);
|
jpayne@69
|
314 col_score_rint = rint(col_cache_score[col]);
|
jpayne@69
|
315 row_trace_score = 0;
|
jpayne@69
|
316 col_trace_score = 0;
|
jpayne@69
|
317 if (rint(row_open) == row_score_rint)
|
jpayne@69
|
318 row_trace_score = row_trace_score|1;
|
jpayne@69
|
319 if (rint(row_extend) == row_score_rint)
|
jpayne@69
|
320 row_trace_score = row_trace_score|8;
|
jpayne@69
|
321 if (rint(col_open) == col_score_rint)
|
jpayne@69
|
322 col_trace_score = col_trace_score|4;
|
jpayne@69
|
323 if (rint(col_extend) == col_score_rint)
|
jpayne@69
|
324 col_trace_score = col_trace_score|16;
|
jpayne@69
|
325
|
jpayne@69
|
326 trace_score = 0;
|
jpayne@69
|
327 best_score_rint = rint(best_score);
|
jpayne@69
|
328 if (rint(nogap_score) == best_score_rint)
|
jpayne@69
|
329 trace_score = trace_score|2;
|
jpayne@69
|
330 if (row_score_rint == best_score_rint)
|
jpayne@69
|
331 trace_score += row_trace_score;
|
jpayne@69
|
332 if (col_score_rint == best_score_rint)
|
jpayne@69
|
333 trace_score += col_trace_score;
|
jpayne@69
|
334 trace_matrix[row*(lenB+1)+col] = trace_score;
|
jpayne@69
|
335 }
|
jpayne@69
|
336 }
|
jpayne@69
|
337 }
|
jpayne@69
|
338
|
jpayne@69
|
339 if (!align_globally)
|
jpayne@69
|
340 best_score = local_max_score;
|
jpayne@69
|
341
|
jpayne@69
|
342 /* Save the score and traceback matrices into real python objects. */
|
jpayne@69
|
343 if(!score_only) {
|
jpayne@69
|
344 if(!(py_score_matrix = PyList_New(lenA+1)))
|
jpayne@69
|
345 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
346 if(!(py_trace_matrix = PyList_New(lenA+1)))
|
jpayne@69
|
347 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
348
|
jpayne@69
|
349 for(row=0; row<=lenA; row++) {
|
jpayne@69
|
350 PyObject *py_score_row, *py_trace_row;
|
jpayne@69
|
351 if(!(py_score_row = PyList_New(lenB+1)))
|
jpayne@69
|
352 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
353 PyList_SET_ITEM(py_score_matrix, row, py_score_row);
|
jpayne@69
|
354 if(!(py_trace_row = PyList_New(lenB+1)))
|
jpayne@69
|
355 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
356 PyList_SET_ITEM(py_trace_matrix, row, py_trace_row);
|
jpayne@69
|
357
|
jpayne@69
|
358 for(col=0; col<=lenB; col++) {
|
jpayne@69
|
359 PyObject *py_score, *py_trace;
|
jpayne@69
|
360 int offset = row*(lenB+1) + col;
|
jpayne@69
|
361
|
jpayne@69
|
362 /* Set py_score_matrix[row][col] to the score. */
|
jpayne@69
|
363 if(!(py_score = PyFloat_FromDouble(score_matrix[offset])))
|
jpayne@69
|
364 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
365 PyList_SET_ITEM(py_score_row, col, py_score);
|
jpayne@69
|
366
|
jpayne@69
|
367 /* Set py_trace_matrix[row][col] to a list of indexes. On
|
jpayne@69
|
368 the edges of the matrix (row or column is 0), the
|
jpayne@69
|
369 matrix should be [None]. */
|
jpayne@69
|
370 if(!row || !col) {
|
jpayne@69
|
371 if(!(py_trace = Py_BuildValue("B", 1)))
|
jpayne@69
|
372 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
373 Py_INCREF(Py_None);
|
jpayne@69
|
374 PyList_SET_ITEM(py_trace_row, col, Py_None);
|
jpayne@69
|
375 }
|
jpayne@69
|
376 else {
|
jpayne@69
|
377 if(!(py_trace = Py_BuildValue("B", trace_matrix[offset])))
|
jpayne@69
|
378 goto _cleanup_make_score_matrix_fast;
|
jpayne@69
|
379 PyList_SET_ITEM(py_trace_row, col, py_trace);
|
jpayne@69
|
380
|
jpayne@69
|
381 }
|
jpayne@69
|
382 }
|
jpayne@69
|
383 }
|
jpayne@69
|
384 }
|
jpayne@69
|
385 else {
|
jpayne@69
|
386 py_score_matrix = PyList_New(1);
|
jpayne@69
|
387 py_trace_matrix = PyList_New(1);
|
jpayne@69
|
388 }
|
jpayne@69
|
389 py_retval = Py_BuildValue("(OOd)", py_score_matrix, py_trace_matrix, best_score);
|
jpayne@69
|
390
|
jpayne@69
|
391 _cleanup_make_score_matrix_fast:
|
jpayne@69
|
392 if(score_matrix)
|
jpayne@69
|
393 free(score_matrix);
|
jpayne@69
|
394 if(trace_matrix)
|
jpayne@69
|
395 free(trace_matrix);
|
jpayne@69
|
396 if(col_cache_score)
|
jpayne@69
|
397 free(col_cache_score);
|
jpayne@69
|
398 if(py_score_matrix){
|
jpayne@69
|
399 Py_DECREF(py_score_matrix);
|
jpayne@69
|
400 }
|
jpayne@69
|
401 if(py_trace_matrix){
|
jpayne@69
|
402 Py_DECREF(py_trace_matrix);
|
jpayne@69
|
403 }
|
jpayne@69
|
404
|
jpayne@69
|
405 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
406 if (py_bytesA != NULL && py_bytesA != py_sequenceA) Py_DECREF(py_bytesA);
|
jpayne@69
|
407 if (py_bytesB != NULL && py_bytesB != py_sequenceB) Py_DECREF(py_bytesB);
|
jpayne@69
|
408 #endif
|
jpayne@69
|
409
|
jpayne@69
|
410 return py_retval;
|
jpayne@69
|
411 }
|
jpayne@69
|
412
|
jpayne@69
|
413 static PyObject *cpairwise2_rint(PyObject *self, PyObject *args,
|
jpayne@69
|
414 PyObject *keywds)
|
jpayne@69
|
415 {
|
jpayne@69
|
416 double x;
|
jpayne@69
|
417 int precision = _PRECISION;
|
jpayne@69
|
418 int rint_x;
|
jpayne@69
|
419
|
jpayne@69
|
420 static char *kwlist[] = {"x", "precision", NULL};
|
jpayne@69
|
421
|
jpayne@69
|
422 if(!PyArg_ParseTupleAndKeywords(args, keywds, "d|l", kwlist,
|
jpayne@69
|
423 &x, &precision))
|
jpayne@69
|
424 return NULL;
|
jpayne@69
|
425 rint_x = (int)(x * precision + 0.5);
|
jpayne@69
|
426 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
427 return PyLong_FromLong((long)rint_x);
|
jpayne@69
|
428 #else
|
jpayne@69
|
429 return PyInt_FromLong((long)rint_x);
|
jpayne@69
|
430 #endif
|
jpayne@69
|
431 }
|
jpayne@69
|
432
|
jpayne@69
|
433 /* Module definition stuff */
|
jpayne@69
|
434
|
jpayne@69
|
435 static PyMethodDef cpairwise2Methods[] = {
|
jpayne@69
|
436 {"_make_score_matrix_fast",
|
jpayne@69
|
437 (PyCFunction)cpairwise2__make_score_matrix_fast, METH_VARARGS, ""},
|
jpayne@69
|
438 {"rint", (PyCFunction)cpairwise2_rint, METH_VARARGS|METH_KEYWORDS, ""},
|
jpayne@69
|
439 {NULL, NULL, 0, NULL}
|
jpayne@69
|
440 };
|
jpayne@69
|
441
|
jpayne@69
|
442 static char cpairwise2__doc__[] =
|
jpayne@69
|
443 "Optimized C routines that complement pairwise2.py. These are called from within pairwise2.py.\n\
|
jpayne@69
|
444 \n\
|
jpayne@69
|
445 ";
|
jpayne@69
|
446
|
jpayne@69
|
447 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
448
|
jpayne@69
|
449 static struct PyModuleDef moduledef = {
|
jpayne@69
|
450 PyModuleDef_HEAD_INIT,
|
jpayne@69
|
451 "cpairwise2",
|
jpayne@69
|
452 cpairwise2__doc__,
|
jpayne@69
|
453 -1,
|
jpayne@69
|
454 cpairwise2Methods,
|
jpayne@69
|
455 NULL,
|
jpayne@69
|
456 NULL,
|
jpayne@69
|
457 NULL,
|
jpayne@69
|
458 NULL
|
jpayne@69
|
459 };
|
jpayne@69
|
460
|
jpayne@69
|
461 PyObject *
|
jpayne@69
|
462 PyInit_cpairwise2(void)
|
jpayne@69
|
463
|
jpayne@69
|
464 #else
|
jpayne@69
|
465
|
jpayne@69
|
466 void
|
jpayne@69
|
467 /* for Windows: _declspec(dllexport) initcpairwise2(void) */
|
jpayne@69
|
468 initcpairwise2(void)
|
jpayne@69
|
469 #endif
|
jpayne@69
|
470
|
jpayne@69
|
471 {
|
jpayne@69
|
472 #if PY_MAJOR_VERSION >= 3
|
jpayne@69
|
473 PyObject* module = PyModule_Create(&moduledef);
|
jpayne@69
|
474 if (module==NULL) return NULL;
|
jpayne@69
|
475 return module;
|
jpayne@69
|
476 #else
|
jpayne@69
|
477 (void) Py_InitModule3("cpairwise2", cpairwise2Methods, cpairwise2__doc__);
|
jpayne@69
|
478 #endif
|
jpayne@69
|
479 }
|