Spaces:
No application file
No application file
/* Copyright 2018-2019 by Michiel de Hoon. All rights reserved. | |
* This file is part of the Biopython distribution and governed by your | |
* choice of the "Biopython License Agreement" or the "BSD 3-Clause License". | |
* Please see the LICENSE file that should have been included as part of this | |
* package. | |
*/ | |
typedef enum {NeedlemanWunschSmithWaterman, | |
Gotoh, | |
WatermanSmithBeyer, | |
Unknown} Algorithm; | |
typedef enum {Global, Local} Mode; | |
typedef struct { | |
unsigned char trace : 5; | |
unsigned char path : 3; | |
} Trace; | |
typedef struct { | |
unsigned char Ix : 4; | |
unsigned char Iy : 4; | |
} TraceGapsGotoh; | |
typedef struct { | |
int* MIx; | |
int* IyIx; | |
int* MIy; | |
int* IxIy; | |
} TraceGapsWatermanSmithBeyer; | |
typedef struct { | |
PyObject_HEAD | |
Trace** M; | |
union { TraceGapsGotoh** gotoh; | |
TraceGapsWatermanSmithBeyer** waterman_smith_beyer; } gaps; | |
int nA; | |
int nB; | |
int iA; | |
int iB; | |
Mode mode; | |
Algorithm algorithm; | |
Py_ssize_t length; | |
unsigned char strand; | |
} PathGenerator; | |
static PyObject* | |
PathGenerator_create_path(PathGenerator* self, int i, int j) { | |
PyObject* tuple; | |
PyObject* target_row; | |
PyObject* query_row; | |
PyObject* value; | |
int path; | |
int k, l; | |
int n = 1; | |
int direction = 0; | |
Trace** M = self->M; | |
const unsigned char strand = self->strand; | |
k = i; | |
l = j; | |
while (1) { | |
path = M[k][l].path; | |
if (!path) break; | |
if (path != direction) { | |
n++; | |
direction = path; | |
} | |
switch (path) { | |
case HORIZONTAL: l++; break; | |
case VERTICAL: k++; break; | |
case DIAGONAL: k++; l++; break; | |
} | |
} | |
direction = 0; | |
tuple = PyTuple_New(2); | |
if (!tuple) return NULL; | |
target_row = PyTuple_New(n); | |
query_row = PyTuple_New(n); | |
PyTuple_SET_ITEM(tuple, 0, target_row); | |
PyTuple_SET_ITEM(tuple, 1, query_row); | |
if (target_row && query_row) { | |
k = 0; | |
switch (strand) { | |
case '+': | |
while (1) { | |
path = M[i][j].path; | |
if (path != direction) { | |
value = PyLong_FromLong(i); | |
if (!value) break; | |
PyTuple_SET_ITEM(target_row, k, value); | |
value = PyLong_FromLong(j); | |
if (!value) break; | |
PyTuple_SET_ITEM(query_row, k, value); | |
k++; | |
direction = path; | |
} | |
switch (path) { | |
case HORIZONTAL: j++; break; | |
case VERTICAL: i++; break; | |
case DIAGONAL: i++; j++; break; | |
default: return tuple; | |
} | |
} | |
break; | |
case '-': { | |
const int nB = self->nB; | |
while (1) { | |
path = M[i][j].path; | |
if (path != direction) { | |
value = PyLong_FromLong(i); | |
if (!value) break; | |
PyTuple_SET_ITEM(target_row, k, value); | |
value = PyLong_FromLong(nB-j); | |
if (!value) break; | |
PyTuple_SET_ITEM(query_row, k, value); | |
k++; | |
direction = path; | |
} | |
switch (path) { | |
case HORIZONTAL: j++; break; | |
case VERTICAL: i++; break; | |
case DIAGONAL: i++; j++; break; | |
default: return tuple; | |
} | |
} | |
break; | |
} | |
} | |
} | |
Py_DECREF(tuple); /* all references were stolen */ | |
return PyErr_NoMemory(); | |
} | |
static Py_ssize_t | |
PathGenerator_needlemanwunsch_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
Py_ssize_t term; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t temp; | |
Py_ssize_t* counts; | |
counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!counts) goto exit; | |
counts[0] = 1; | |
for (j = 1; j <= nB; j++) { | |
trace = M[0][j].trace; | |
count = 0; | |
if (trace & HORIZONTAL) SAFE_ADD(counts[j-1], count); | |
counts[j] = count; | |
} | |
for (i = 1; i <= nA; i++) { | |
trace = M[i][0].trace; | |
count = 0; | |
if (trace & VERTICAL) SAFE_ADD(counts[0], count); | |
temp = counts[0]; | |
counts[0] = count; | |
for (j = 1; j <= nB; j++) { | |
trace = M[i][j].trace; | |
count = 0; | |
if (trace & HORIZONTAL) SAFE_ADD(counts[j-1], count); | |
if (trace & VERTICAL) SAFE_ADD(counts[j], count); | |
if (trace & DIAGONAL) SAFE_ADD(temp, count); | |
temp = counts[j]; | |
counts[j] = count; | |
} | |
} | |
PyMem_Free(counts); | |
exit: | |
return count; | |
} | |
static Py_ssize_t | |
PathGenerator_smithwaterman_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
Py_ssize_t term; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t total = 0; | |
Py_ssize_t temp; | |
Py_ssize_t* counts; | |
counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!counts) goto exit; | |
counts[0] = 1; | |
for (j = 1; j <= nB; j++) counts[j] = 1; | |
for (i = 1; i <= nA; i++) { | |
temp = counts[0]; | |
counts[0] = 1; | |
for (j = 1; j <= nB; j++) { | |
trace = M[i][j].trace; | |
count = 0; | |
if (trace & DIAGONAL) SAFE_ADD(temp, count); | |
if (M[i][j].trace & ENDPOINT) SAFE_ADD(count, total); | |
if (trace & HORIZONTAL) SAFE_ADD(counts[j-1], count); | |
if (trace & VERTICAL) SAFE_ADD(counts[j], count); | |
temp = counts[j]; | |
if (count == 0 && (trace & STARTPOINT)) count = 1; | |
counts[j] = count; | |
} | |
} | |
count = total; | |
PyMem_Free(counts); | |
exit: | |
return count; | |
} | |
static Py_ssize_t | |
PathGenerator_gotoh_global_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsGotoh** gaps = self->gaps.gotoh; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t term; | |
Py_ssize_t M_temp; | |
Py_ssize_t Ix_temp; | |
Py_ssize_t Iy_temp; | |
Py_ssize_t* M_counts = NULL; | |
Py_ssize_t* Ix_counts = NULL; | |
Py_ssize_t* Iy_counts = NULL; | |
M_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!M_counts) goto exit; | |
Ix_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Ix_counts) goto exit; | |
Iy_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Iy_counts) goto exit; | |
M_counts[0] = 1; | |
Ix_counts[0] = 0; | |
Iy_counts[0] = 0; | |
for (j = 1; j <= nB; j++) { | |
M_counts[j] = 0; | |
Ix_counts[j] = 0; | |
Iy_counts[j] = 1; | |
} | |
for (i = 1; i <= nA; i++) { | |
M_temp = M_counts[0]; | |
M_counts[0] = 0; | |
Ix_temp = Ix_counts[0]; | |
Ix_counts[0] = 1; | |
Iy_temp = Iy_counts[0]; | |
Iy_counts[0] = 0; | |
for (j = 1; j <= nB; j++) { | |
count = 0; | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) SAFE_ADD(M_temp, count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_temp, count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_temp, count); | |
M_temp = M_counts[j]; | |
M_counts[j] = count; | |
count = 0; | |
trace = gaps[i][j].Ix; | |
if (trace & M_MATRIX) SAFE_ADD(M_temp, count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_counts[j], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_counts[j], count); | |
Ix_temp = Ix_counts[j]; | |
Ix_counts[j] = count; | |
count = 0; | |
trace = gaps[i][j].Iy; | |
if (trace & M_MATRIX) SAFE_ADD(M_counts[j-1], count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_counts[j-1], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_counts[j-1], count); | |
Iy_temp = Iy_counts[j]; | |
Iy_counts[j] = count; | |
} | |
} | |
count = 0; | |
if (M[nA][nB].trace) SAFE_ADD(M_counts[nB], count); | |
if (gaps[nA][nB].Ix) SAFE_ADD(Ix_counts[nB], count); | |
if (gaps[nA][nB].Iy) SAFE_ADD(Iy_counts[nB], count); | |
exit: | |
if (M_counts) PyMem_Free(M_counts); | |
if (Ix_counts) PyMem_Free(Ix_counts); | |
if (Iy_counts) PyMem_Free(Iy_counts); | |
return count; | |
} | |
static Py_ssize_t | |
PathGenerator_gotoh_local_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsGotoh** gaps = self->gaps.gotoh; | |
Py_ssize_t term; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t total = 0; | |
Py_ssize_t M_temp; | |
Py_ssize_t Ix_temp; | |
Py_ssize_t Iy_temp; | |
Py_ssize_t* M_counts = NULL; | |
Py_ssize_t* Ix_counts = NULL; | |
Py_ssize_t* Iy_counts = NULL; | |
M_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!M_counts) goto exit; | |
Ix_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Ix_counts) goto exit; | |
Iy_counts = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Iy_counts) goto exit; | |
M_counts[0] = 1; | |
Ix_counts[0] = 0; | |
Iy_counts[0] = 0; | |
for (j = 1; j <= nB; j++) { | |
M_counts[j] = 1; | |
Ix_counts[j] = 0; | |
Iy_counts[j] = 0; | |
} | |
for (i = 1; i <= nA; i++) { | |
M_temp = M_counts[0]; | |
M_counts[0] = 1; | |
Ix_temp = Ix_counts[0]; | |
Ix_counts[0] = 0; | |
Iy_temp = Iy_counts[0]; | |
Iy_counts[0] = 0; | |
for (j = 1; j <= nB; j++) { | |
count = 0; | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) SAFE_ADD(M_temp, count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_temp, count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_temp, count); | |
if (count == 0 && (trace & STARTPOINT)) count = 1; | |
M_temp = M_counts[j]; | |
M_counts[j] = count; | |
if (M[i][j].trace & ENDPOINT) SAFE_ADD(count, total); | |
count = 0; | |
trace = gaps[i][j].Ix; | |
if (trace & M_MATRIX) SAFE_ADD(M_temp, count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_counts[j], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_counts[j], count); | |
Ix_temp = Ix_counts[j]; | |
Ix_counts[j] = count; | |
count = 0; | |
trace = gaps[i][j].Iy; | |
if (trace & M_MATRIX) SAFE_ADD(M_counts[j-1], count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_counts[j-1], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_counts[j-1], count); | |
Iy_temp = Iy_counts[j]; | |
Iy_counts[j] = count; | |
} | |
} | |
count = total; | |
exit: | |
if (M_counts) PyMem_Free(M_counts); | |
if (Ix_counts) PyMem_Free(Ix_counts); | |
if (Iy_counts) PyMem_Free(Iy_counts); | |
return count; | |
} | |
static Py_ssize_t | |
PathGenerator_waterman_smith_beyer_global_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
int* p; | |
int gap; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsWatermanSmithBeyer** gaps = self->gaps.waterman_smith_beyer; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t term; | |
Py_ssize_t** M_count = NULL; | |
Py_ssize_t** Ix_count = NULL; | |
Py_ssize_t** Iy_count = NULL; | |
M_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!M_count) goto exit; | |
Ix_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!Ix_count) goto exit; | |
Iy_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!Iy_count) goto exit; | |
for (i = 0; i <= nA; i++) { | |
M_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!M_count[i]) goto exit; | |
Ix_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Ix_count[i]) goto exit; | |
Iy_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Iy_count[i]) goto exit; | |
} | |
for (i = 0; i <= nA; i++) { | |
for (j = 0; j <= nB; j++) { | |
count = 0; | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) SAFE_ADD(M_count[i-1][j-1], count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_count[i-1][j-1], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_count[i-1][j-1], count); | |
if (count == 0) count = 1; /* happens at M[0][0] only */ | |
M_count[i][j] = count; | |
count = 0; | |
p = gaps[i][j].MIx; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(M_count[i-gap][j], count); | |
p++; | |
} | |
} | |
p = gaps[i][j].IyIx; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(Iy_count[i-gap][j], count); | |
p++; | |
} | |
} | |
Ix_count[i][j] = count; | |
count = 0; | |
p = gaps[i][j].MIy; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(M_count[i][j-gap], count); | |
p++; | |
} | |
} | |
p = gaps[i][j].IxIy; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(Ix_count[i][j-gap], count); | |
p++; | |
} | |
} | |
Iy_count[i][j] = count; | |
} | |
} | |
count = 0; | |
if (M[nA][nB].trace) | |
SAFE_ADD(M_count[nA][nB], count); | |
if (gaps[nA][nB].MIx[0] || gaps[nA][nB].IyIx[0]) | |
SAFE_ADD(Ix_count[nA][nB], count); | |
if (gaps[nA][nB].MIy[0] || gaps[nA][nB].IxIy[0]) | |
SAFE_ADD(Iy_count[nA][nB], count); | |
exit: | |
if (M_count) { | |
if (Ix_count) { | |
if (Iy_count) { | |
for (i = 0; i <= nA; i++) { | |
if (!M_count[i]) break; | |
PyMem_Free(M_count[i]); | |
if (!Ix_count[i]) break; | |
PyMem_Free(Ix_count[i]); | |
if (!Iy_count[i]) break; | |
PyMem_Free(Iy_count[i]); | |
} | |
PyMem_Free(Iy_count); | |
} | |
PyMem_Free(Ix_count); | |
} | |
PyMem_Free(M_count); | |
} | |
return count; | |
} | |
static Py_ssize_t | |
PathGenerator_waterman_smith_beyer_local_length(PathGenerator* self) | |
{ | |
int i; | |
int j; | |
int trace; | |
int* p; | |
int gap; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsWatermanSmithBeyer** gaps = self->gaps.waterman_smith_beyer; | |
Py_ssize_t term; | |
Py_ssize_t count = MEMORY_ERROR; | |
Py_ssize_t total = 0; | |
Py_ssize_t** M_count = NULL; | |
Py_ssize_t** Ix_count = NULL; | |
Py_ssize_t** Iy_count = NULL; | |
M_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!M_count) goto exit; | |
Ix_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!Ix_count) goto exit; | |
Iy_count = PyMem_Malloc((nA+1)*sizeof(Py_ssize_t*)); | |
if (!Iy_count) goto exit; | |
for (i = 0; i <= nA; i++) { | |
M_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!M_count[i]) goto exit; | |
Ix_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Ix_count[i]) goto exit; | |
Iy_count[i] = PyMem_Malloc((nB+1)*sizeof(Py_ssize_t)); | |
if (!Iy_count[i]) goto exit; | |
} | |
for (i = 0; i <= nA; i++) { | |
for (j = 0; j <= nB; j++) { | |
count = 0; | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) SAFE_ADD(M_count[i-1][j-1], count); | |
if (trace & Ix_MATRIX) SAFE_ADD(Ix_count[i-1][j-1], count); | |
if (trace & Iy_MATRIX) SAFE_ADD(Iy_count[i-1][j-1], count); | |
if (count == 0 && (trace & STARTPOINT)) count = 1; | |
M_count[i][j] = count; | |
if (M[i][j].trace & ENDPOINT) SAFE_ADD(count, total); | |
count = 0; | |
p = gaps[i][j].MIx; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(M_count[i-gap][j], count); | |
p++; | |
} | |
} | |
p = gaps[i][j].IyIx; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(Iy_count[i-gap][j], count); | |
p++; | |
} | |
} | |
Ix_count[i][j] = count; | |
count = 0; | |
p = gaps[i][j].MIy; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(M_count[i][j-gap], count); | |
p++; | |
} | |
} | |
p = gaps[i][j].IxIy; | |
if (p) { | |
while (1) { | |
gap = *p; | |
if (!gap) break; | |
SAFE_ADD(Ix_count[i][j-gap], count); | |
p++; | |
} | |
} | |
Iy_count[i][j] = count; | |
} | |
} | |
count = total; | |
exit: | |
if (M_count) { | |
if (Ix_count) { | |
if (Iy_count) { | |
for (i = 0; i <= nA; i++) { | |
if (!M_count[i]) break; | |
PyMem_Free(M_count[i]); | |
if (!Ix_count[i]) break; | |
PyMem_Free(Ix_count[i]); | |
if (!Iy_count[i]) break; | |
PyMem_Free(Iy_count[i]); | |
} | |
PyMem_Free(Iy_count); | |
} | |
PyMem_Free(Ix_count); | |
} | |
PyMem_Free(M_count); | |
} | |
return count; | |
} | |
static Py_ssize_t PathGenerator_length(PathGenerator* self) { | |
Py_ssize_t length = self->length; | |
if (length == 0) { | |
switch (self->algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
switch (self->mode) { | |
case Global: | |
length = PathGenerator_needlemanwunsch_length(self); | |
break; | |
case Local: | |
length = PathGenerator_smithwaterman_length(self); | |
break; | |
default: | |
/* should not happen, but some compilers complain that | |
* that length can be used uninitialized. | |
*/ | |
PyErr_SetString(PyExc_RuntimeError, "Unknown mode"); | |
return -1; | |
} | |
break; | |
case Gotoh: | |
switch (self->mode) { | |
case Global: | |
length = PathGenerator_gotoh_global_length(self); | |
break; | |
case Local: | |
length = PathGenerator_gotoh_local_length(self); | |
break; | |
default: | |
/* should not happen, but some compilers complain that | |
* that length can be used uninitialized. | |
*/ | |
PyErr_SetString(PyExc_RuntimeError, "Unknown mode"); | |
return -1; | |
} | |
break; | |
case WatermanSmithBeyer: | |
switch (self->mode) { | |
case Global: | |
length = PathGenerator_waterman_smith_beyer_global_length(self); | |
break; | |
case Local: | |
length = PathGenerator_waterman_smith_beyer_local_length(self); | |
break; | |
default: | |
/* should not happen, but some compilers complain that | |
* that length can be used uninitialized. | |
*/ | |
PyErr_SetString(PyExc_RuntimeError, "Unknown mode"); | |
return -1; | |
} | |
break; | |
case Unknown: | |
default: | |
PyErr_SetString(PyExc_RuntimeError, "Unknown algorithm"); | |
return -1; | |
} | |
self->length = length; | |
} | |
switch (length) { | |
case OVERFLOW_ERROR: | |
PyErr_Format(PyExc_OverflowError, | |
"number of optimal alignments is larger than %zd", | |
PY_SSIZE_T_MAX); | |
break; | |
case MEMORY_ERROR: | |
PyErr_SetNone(PyExc_MemoryError); | |
break; | |
default: | |
break; | |
} | |
return length; | |
} | |
static void | |
PathGenerator_dealloc(PathGenerator* self) | |
{ | |
int i; | |
const int nA = self->nA; | |
const Algorithm algorithm = self->algorithm; | |
Trace** M = self->M; | |
if (M) { | |
for (i = 0; i <= nA; i++) { | |
if (!M[i]) break; | |
PyMem_Free(M[i]); | |
} | |
PyMem_Free(M); | |
} | |
switch (algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
break; | |
case Gotoh: { | |
TraceGapsGotoh** gaps = self->gaps.gotoh; | |
if (gaps) { | |
for (i = 0; i <= nA; i++) { | |
if (!gaps[i]) break; | |
PyMem_Free(gaps[i]); | |
} | |
PyMem_Free(gaps); | |
} | |
break; | |
} | |
case WatermanSmithBeyer: { | |
TraceGapsWatermanSmithBeyer** gaps = self->gaps.waterman_smith_beyer; | |
if (gaps) { | |
int j; | |
const int nB = self->nB; | |
int* trace; | |
for (i = 0; i <= nA; i++) { | |
if (!gaps[i]) break; | |
for (j = 0; j <= nB; j++) { | |
trace = gaps[i][j].MIx; | |
if (trace) PyMem_Free(trace); | |
trace = gaps[i][j].IyIx; | |
if (trace) PyMem_Free(trace); | |
trace = gaps[i][j].MIy; | |
if (trace) PyMem_Free(trace); | |
trace = gaps[i][j].IxIy; | |
if (trace) PyMem_Free(trace); | |
} | |
PyMem_Free(gaps[i]); | |
} | |
PyMem_Free(gaps); | |
} | |
break; | |
} | |
case Unknown: | |
default: | |
PyErr_WriteUnraisable((PyObject*)self); | |
break; | |
} | |
Py_TYPE(self)->tp_free((PyObject*)self); | |
} | |
static PyObject* PathGenerator_next_needlemanwunsch(PathGenerator* self) | |
{ | |
int i = 0; | |
int j = 0; | |
int path; | |
int trace = 0; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
path = M[i][j].path; | |
if (path == DONE) return NULL; | |
if (path == 0) { | |
/* Generate the first path. */ | |
i = nA; | |
j = nB; | |
} | |
else { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
while (1) { | |
if (path == HORIZONTAL) { | |
trace = M[i][++j].trace; | |
if (trace & VERTICAL) { | |
M[--i][j].path = VERTICAL; | |
break; | |
} | |
if (trace & DIAGONAL) { | |
M[--i][--j].path = DIAGONAL; | |
break; | |
} | |
} | |
else if (path == VERTICAL) { | |
trace = M[++i][j].trace; | |
if (trace & DIAGONAL) { | |
M[--i][--j].path = DIAGONAL; | |
break; | |
} | |
} | |
else /* DIAGONAL */ { | |
i++; | |
j++; | |
} | |
path = M[i][j].path; | |
if (!path) { | |
/* we reached the end of the alignment without finding | |
* an alternative path */ | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
} | |
} | |
/* Follow the traceback until we reach the origin. */ | |
while (1) { | |
trace = M[i][j].trace; | |
if (trace & HORIZONTAL) M[i][--j].path = HORIZONTAL; | |
else if (trace & VERTICAL) M[--i][j].path = VERTICAL; | |
else if (trace & DIAGONAL) M[--i][--j].path = DIAGONAL; | |
else break; | |
} | |
return PathGenerator_create_path(self, 0, 0); | |
} | |
static PyObject* PathGenerator_next_smithwaterman(PathGenerator* self) | |
{ | |
int trace = 0; | |
int i = self->iA; | |
int j = self->iB; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
int path = M[0][0].path; | |
if (path == DONE || path == NONE) return NULL; | |
path = M[i][j].path; | |
if (path) { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
while (1) { | |
if (path == HORIZONTAL) { | |
trace = M[i][++j].trace; | |
if (trace & VERTICAL) { | |
M[--i][j].path = VERTICAL; | |
break; | |
} | |
else if (trace & DIAGONAL) { | |
M[--i][--j].path = DIAGONAL; | |
break; | |
} | |
} | |
else if (path == VERTICAL) { | |
trace = M[++i][j].trace; | |
if (trace & DIAGONAL) { | |
M[--i][--j].path = DIAGONAL; | |
break; | |
} | |
} | |
else /* DIAGONAL */ { | |
i++; | |
j++; | |
} | |
path = M[i][j].path; | |
if (!path) break; | |
} | |
} | |
if (path) { | |
trace = M[i][j].trace; | |
} else { | |
/* Find a suitable end point for a path. | |
* Only allow end points ending at the M matrix. */ | |
while (1) { | |
if (j < nB) j++; | |
else if (i < nA) { | |
i++; | |
j = 0; | |
} | |
else { | |
/* we reached the end of the sequences without finding | |
* an alternative path */ | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
trace = M[i][j].trace; | |
if (trace & ENDPOINT) { | |
trace &= DIAGONAL; /* exclude paths ending in a gap */ | |
break; | |
} | |
} | |
M[i][j].path = 0; | |
} | |
/* Follow the traceback until we reach the origin. */ | |
while (1) { | |
if (trace & HORIZONTAL) M[i][--j].path = HORIZONTAL; | |
else if (trace & VERTICAL) M[--i][j].path = VERTICAL; | |
else if (trace & DIAGONAL) M[--i][--j].path = DIAGONAL; | |
else if (trace & STARTPOINT) { | |
self->iA = i; | |
self->iB = j; | |
return PathGenerator_create_path(self, i, j); | |
} | |
else { | |
PyErr_SetString(PyExc_RuntimeError, | |
"Unexpected trace in PathGenerator_next_smithwaterman"); | |
return NULL; | |
} | |
trace = M[i][j].trace; | |
} | |
} | |
static PyObject* PathGenerator_next_gotoh_global(PathGenerator* self) | |
{ | |
int i = 0; | |
int j = 0; | |
int m; | |
int path; | |
int trace = 0; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsGotoh** gaps = self->gaps.gotoh; | |
m = M_MATRIX; | |
path = M[i][j].path; | |
if (path == DONE) return NULL; | |
if (path == 0) { | |
i = nA; | |
j = nB; | |
} | |
else { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
while (1) { | |
path = M[i][j].path; | |
if (path == 0) { | |
switch (m) { | |
case M_MATRIX: m = Ix_MATRIX; break; | |
case Ix_MATRIX: m = Iy_MATRIX; break; | |
case Iy_MATRIX: m = 0; break; | |
} | |
break; | |
} | |
switch (path) { | |
case HORIZONTAL: trace = gaps[i][++j].Iy; break; | |
case VERTICAL: trace = gaps[++i][j].Ix; break; | |
case DIAGONAL: trace = M[++i][++j].trace; break; | |
} | |
switch (m) { | |
case M_MATRIX: | |
if (trace & Ix_MATRIX) { | |
m = Ix_MATRIX; | |
break; | |
} | |
case Ix_MATRIX: | |
if (trace & Iy_MATRIX) { | |
m = Iy_MATRIX; | |
break; | |
} | |
case Iy_MATRIX: | |
default: | |
switch (path) { | |
case HORIZONTAL: m = Iy_MATRIX; break; | |
case VERTICAL: m = Ix_MATRIX; break; | |
case DIAGONAL: m = M_MATRIX; break; | |
} | |
continue; | |
} | |
switch (path) { | |
case HORIZONTAL: j--; break; | |
case VERTICAL: i--; break; | |
case DIAGONAL: i--; j--; break; | |
} | |
M[i][j].path = path; | |
break; | |
} | |
} | |
if (path == 0) { | |
/* Generate a new path. */ | |
switch (m) { | |
case M_MATRIX: | |
if (M[nA][nB].trace) { | |
/* m = M_MATRIX; */ | |
break; | |
} | |
case Ix_MATRIX: | |
if (gaps[nA][nB].Ix) { | |
m = Ix_MATRIX; | |
break; | |
} | |
case Iy_MATRIX: | |
if (gaps[nA][nB].Iy) { | |
m = Iy_MATRIX; | |
break; | |
} | |
default: | |
/* exhausted this generator */ | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
} | |
switch (m) { | |
case M_MATRIX: | |
trace = M[i][j].trace; | |
path = DIAGONAL; | |
i--; j--; | |
break; | |
case Ix_MATRIX: | |
trace = gaps[i][j].Ix; | |
path = VERTICAL; | |
i--; | |
break; | |
case Iy_MATRIX: | |
trace = gaps[i][j].Iy; | |
path = HORIZONTAL; | |
j--; | |
break; | |
} | |
while (1) { | |
if (trace & M_MATRIX) { | |
trace = M[i][j].trace; | |
M[i][j].path = path; | |
path = DIAGONAL; | |
i--; j--; | |
} | |
else if (trace & Ix_MATRIX) { | |
M[i][j].path = path; | |
trace = gaps[i][j].Ix; | |
path = VERTICAL; | |
i--; | |
} | |
else if (trace & Iy_MATRIX) { | |
M[i][j].path = path; | |
trace = gaps[i][j].Iy; | |
path = HORIZONTAL; | |
j--; | |
} | |
else break; | |
} | |
return PathGenerator_create_path(self, 0, 0); | |
} | |
static PyObject* PathGenerator_next_gotoh_local(PathGenerator* self) | |
{ | |
int trace = 0; | |
int i; | |
int j; | |
int m = M_MATRIX; | |
int iA = self->iA; | |
int iB = self->iB; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsGotoh** gaps = self->gaps.gotoh; | |
int path = M[0][0].path; | |
if (path == DONE) return NULL; | |
path = M[iA][iB].path; | |
if (path) { | |
i = iA; | |
j = iB; | |
while (1) { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
path = M[i][j].path; | |
if (path == 0) { | |
m = M_MATRIX; | |
iA = i; | |
iB = j; | |
break; | |
} | |
switch (path) { | |
case HORIZONTAL: trace = gaps[i][++j].Iy; break; | |
case VERTICAL: trace = gaps[++i][j].Ix; break; | |
case DIAGONAL: trace = M[++i][++j].trace; break; | |
} | |
switch (m) { | |
case M_MATRIX: | |
if (trace & Ix_MATRIX) { | |
m = Ix_MATRIX; | |
break; | |
} | |
case Ix_MATRIX: | |
if (trace & Iy_MATRIX) { | |
m = Iy_MATRIX; | |
break; | |
} | |
case Iy_MATRIX: | |
default: | |
switch (path) { | |
case HORIZONTAL: m = Iy_MATRIX; break; | |
case VERTICAL: m = Ix_MATRIX; break; | |
case DIAGONAL: m = M_MATRIX; break; | |
} | |
continue; | |
} | |
switch (path) { | |
case HORIZONTAL: j--; break; | |
case VERTICAL: i--; break; | |
case DIAGONAL: i--; j--; break; | |
} | |
M[i][j].path = path; | |
break; | |
} | |
} | |
if (path == 0) { | |
/* Find the end point for a new path. */ | |
while (1) { | |
if (iB < nB) iB++; | |
else if (iA < nA) { | |
iA++; | |
iB = 0; | |
} | |
else { | |
/* we reached the end of the alignment without finding | |
* an alternative path */ | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
if (M[iA][iB].trace & ENDPOINT) { | |
M[iA][iB].path = 0; | |
break; | |
} | |
} | |
m = M_MATRIX; | |
i = iA; | |
j = iB; | |
} | |
while (1) { | |
switch (m) { | |
case M_MATRIX: trace = M[i][j].trace; break; | |
case Ix_MATRIX: trace = gaps[i][j].Ix; break; | |
case Iy_MATRIX: trace = gaps[i][j].Iy; break; | |
} | |
if (trace == STARTPOINT) { | |
self->iA = i; | |
self->iB = j; | |
return PathGenerator_create_path(self, i, j); | |
} | |
switch (m) { | |
case M_MATRIX: | |
path = DIAGONAL; | |
i--; | |
j--; | |
break; | |
case Ix_MATRIX: | |
path = VERTICAL; | |
i--; | |
break; | |
case Iy_MATRIX: | |
path = HORIZONTAL; | |
j--; | |
break; | |
} | |
if (trace & M_MATRIX) m = M_MATRIX; | |
else if (trace & Ix_MATRIX) m = Ix_MATRIX; | |
else if (trace & Iy_MATRIX) m = Iy_MATRIX; | |
else { | |
PyErr_SetString(PyExc_RuntimeError, | |
"Unexpected trace in PathGenerator_next_gotoh_local"); | |
return NULL; | |
} | |
M[i][j].path = path; | |
} | |
return NULL; | |
} | |
static PyObject* | |
PathGenerator_next_waterman_smith_beyer_global(PathGenerator* self) | |
{ | |
int i = 0, j = 0; | |
int iA, iB; | |
int trace; | |
int* gapM; | |
int* gapXY; | |
int m = M_MATRIX; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsWatermanSmithBeyer** gaps = self->gaps.waterman_smith_beyer; | |
int gap; | |
int path = M[0][0].path; | |
if (path == DONE) return NULL; | |
if (path) { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
while (1) { | |
if (!path) { | |
m <<= 1; | |
break; | |
} | |
switch (path) { | |
case HORIZONTAL: | |
iA = i; | |
iB = j; | |
while (M[i][iB].path == HORIZONTAL) iB++; | |
break; | |
case VERTICAL: | |
iA = i; | |
while (M[iA][j].path == VERTICAL) iA++; | |
iB = j; | |
break; | |
case DIAGONAL: | |
iA = i + 1; | |
iB = j + 1; | |
break; | |
default: | |
PyErr_SetString(PyExc_RuntimeError, | |
"Unexpected path in PathGenerator_next_waterman_smith_beyer_global"); | |
return NULL; | |
} | |
if (i == iA) { /* HORIZONTAL */ | |
gapM = gaps[iA][iB].MIy; | |
gapXY = gaps[iA][iB].IxIy; | |
if (m == M_MATRIX) { | |
gap = iB - j; | |
while (*gapM != gap) gapM++; | |
gapM++; | |
gap = *gapM; | |
if (gap) { | |
j = iB - gap; | |
while (j < iB) M[i][--iB].path = HORIZONTAL; | |
break; | |
} | |
} else if (m == Ix_MATRIX) { | |
gap = iB - j; | |
while (*gapXY != gap) gapXY++; | |
gapXY++; | |
} | |
gap = *gapXY; | |
if (gap) { | |
m = Ix_MATRIX; | |
j = iB - gap; | |
while (j < iB) M[i][--iB].path = HORIZONTAL; | |
break; | |
} | |
/* no alternative found; continue pruning */ | |
m = Iy_MATRIX; | |
j = iB; | |
} | |
else if (j == iB) { /* VERTICAL */ | |
gapM = gaps[iA][iB].MIx; | |
gapXY = gaps[iA][iB].IyIx; | |
if (m == M_MATRIX) { | |
gap = iA - i; | |
while (*gapM != gap) gapM++; | |
gapM++; | |
gap = *gapM; | |
if (gap) { | |
i = iA - gap; | |
while (i < iA) M[--iA][j].path = VERTICAL; | |
break; | |
} | |
} else if (m == Iy_MATRIX) { | |
gap = iA - i; | |
while (*gapXY != gap) gapXY++; | |
gapXY++; | |
} | |
gap = *gapXY; | |
if (gap) { | |
m = Iy_MATRIX; | |
i = iA - gap; | |
while (i < iA) M[--iA][j].path = VERTICAL; | |
break; | |
} | |
/* no alternative found; continue pruning */ | |
m = Ix_MATRIX; | |
i = iA; | |
} | |
else { /* DIAGONAL */ | |
i = iA - 1; | |
j = iB - 1; | |
trace = M[iA][iB].trace; | |
switch (m) { | |
case M_MATRIX: | |
if (trace & Ix_MATRIX) { | |
m = Ix_MATRIX; | |
M[i][j].path = DIAGONAL; | |
break; | |
} | |
case Ix_MATRIX: | |
if (trace & Iy_MATRIX) { | |
m = Iy_MATRIX; | |
M[i][j].path = DIAGONAL; | |
break; | |
} | |
case Iy_MATRIX: | |
default: | |
/* no alternative found; continue pruning */ | |
m = M_MATRIX; | |
i = iA; | |
j = iB; | |
path = M[i][j].path; | |
continue; | |
} | |
/* alternative found; build path until starting point */ | |
break; | |
} | |
path = M[i][j].path; | |
} | |
} | |
if (!path) { | |
/* Find a suitable end point for a path. */ | |
switch (m) { | |
case M_MATRIX: | |
if (M[nA][nB].trace) { | |
/* m = M_MATRIX; */ | |
break; | |
} | |
case Ix_MATRIX: | |
if (gaps[nA][nB].MIx[0] || gaps[nA][nB].IyIx[0]) { | |
m = Ix_MATRIX; | |
break; | |
} | |
case Iy_MATRIX: | |
if (gaps[nA][nB].MIy[0] || gaps[nA][nB].IxIy[0]) { | |
m = Iy_MATRIX; | |
break; | |
} | |
default: | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
i = nA; | |
j = nB; | |
} | |
/* Follow the traceback until we reach the origin. */ | |
while (1) { | |
switch (m) { | |
case M_MATRIX: | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) m = M_MATRIX; | |
else if (trace & Ix_MATRIX) m = Ix_MATRIX; | |
else if (trace & Iy_MATRIX) m = Iy_MATRIX; | |
else return PathGenerator_create_path(self, i, j); | |
i--; | |
j--; | |
M[i][j].path = DIAGONAL; | |
break; | |
case Ix_MATRIX: | |
gap = gaps[i][j].MIx[0]; | |
if (gap) m = M_MATRIX; | |
else { | |
gap = gaps[i][j].IyIx[0]; | |
m = Iy_MATRIX; | |
} | |
iA = i - gap; | |
while (iA < i) M[--i][j].path = VERTICAL; | |
M[i][j].path = VERTICAL; | |
break; | |
case Iy_MATRIX: | |
gap = gaps[i][j].MIy[0]; | |
if (gap) m = M_MATRIX; | |
else { | |
gap = gaps[i][j].IxIy[0]; | |
m = Ix_MATRIX; | |
} | |
iB = j - gap; | |
while (iB < j) M[i][--j].path = HORIZONTAL; | |
M[i][j].path = HORIZONTAL; | |
break; | |
} | |
} | |
} | |
static PyObject* | |
PathGenerator_next_waterman_smith_beyer_local(PathGenerator* self) | |
{ | |
int i, j, m; | |
int trace = 0; | |
int* gapM; | |
int* gapXY; | |
int iA = self->iA; | |
int iB = self->iB; | |
const int nA = self->nA; | |
const int nB = self->nB; | |
Trace** M = self->M; | |
TraceGapsWatermanSmithBeyer** gaps = self->gaps.waterman_smith_beyer; | |
int gap; | |
int path = M[0][0].path; | |
if (path == DONE) return NULL; | |
m = 0; | |
path = M[iA][iB].path; | |
if (path) { | |
/* We already have a path. Prune the path to see if there are | |
* any alternative paths. */ | |
m = M_MATRIX; | |
i = iA; | |
j = iB; | |
while (1) { | |
path = M[i][j].path; | |
switch (path) { | |
case HORIZONTAL: | |
iA = i; | |
iB = j; | |
while (M[i][iB].path == HORIZONTAL) iB++; | |
break; | |
case VERTICAL: | |
iA = i; | |
iB = j; | |
while (M[iA][j].path == VERTICAL) iA++; | |
break; | |
case DIAGONAL: | |
iA = i + 1; | |
iB = j + 1; | |
break; | |
default: | |
iA = -1; | |
break; | |
} | |
if (iA < 0) { | |
m = 0; | |
iA = i; | |
iB = j; | |
break; | |
} | |
if (i == iA) { /* HORIZONTAL */ | |
gapM = gaps[iA][iB].MIy; | |
gapXY = gaps[iA][iB].IxIy; | |
if (m == M_MATRIX) { | |
gap = iB - j; | |
while (*gapM != gap) gapM++; | |
gapM++; | |
gap = *gapM; | |
if (gap) { | |
j = iB - gap; | |
while (j < iB) M[i][--iB].path = HORIZONTAL; | |
break; | |
} | |
} else if (m == Ix_MATRIX) { | |
gap = iB - j; | |
while (*gapXY != gap) gapXY++; | |
gapXY++; | |
} | |
gap = *gapXY; | |
if (gap) { | |
m = Ix_MATRIX; | |
j = iB - gap; | |
M[i][j].path = HORIZONTAL; | |
while (iB > j) M[i][--iB].path = HORIZONTAL; | |
break; | |
} | |
/* no alternative found; continue pruning */ | |
m = Iy_MATRIX; | |
j = iB; | |
} | |
else if (j == iB) { /* VERTICAL */ | |
gapM = gaps[iA][iB].MIx; | |
gapXY = gaps[iA][iB].IyIx; | |
if (m == M_MATRIX) { | |
gap = iA - i; | |
while (*gapM != gap) gapM++; | |
gapM++; | |
gap = *gapM; | |
if (gap) { | |
i = iA - gap; | |
while (i < iA) M[--iA][j].path = VERTICAL; | |
break; | |
} | |
} else if (m == Iy_MATRIX) { | |
gap = iA - i; | |
while (*gapXY != gap) gapXY++; | |
gapXY++; | |
} | |
gap = *gapXY; | |
if (gap) { | |
m = Iy_MATRIX; | |
i = iA - gap; | |
M[i][j].path = VERTICAL; | |
while (iA > i) M[--iA][j].path = VERTICAL; | |
break; | |
} | |
/* no alternative found; continue pruning */ | |
m = Ix_MATRIX; | |
i = iA; | |
} | |
else { /* DIAGONAL */ | |
i = iA - 1; | |
j = iB - 1; | |
trace = M[iA][iB].trace; | |
switch (m) { | |
case M_MATRIX: | |
if (trace & Ix_MATRIX) { | |
m = Ix_MATRIX; | |
M[i][j].path = DIAGONAL; | |
break; | |
} | |
case Ix_MATRIX: | |
if (trace & Iy_MATRIX) { | |
m = Iy_MATRIX; | |
M[i][j].path = DIAGONAL; | |
break; | |
} | |
case Iy_MATRIX: | |
default: | |
/* no alternative found; continue pruning */ | |
m = M_MATRIX; | |
i = iA; | |
j = iB; | |
continue; | |
} | |
/* alternative found; build path until starting point */ | |
break; | |
} | |
} | |
} | |
if (m == 0) { | |
/* We are at [nA][nB]. Find a suitable end point for a path. */ | |
while (1) { | |
if (iB < nB) iB++; | |
else if (iA < nA) { | |
iA++; | |
iB = 0; | |
} | |
else { | |
/* exhausted this generator */ | |
M[0][0].path = DONE; | |
return NULL; | |
} | |
if (M[iA][iB].trace & ENDPOINT) break; | |
} | |
M[iA][iB].path = 0; | |
m = M_MATRIX; | |
i = iA; | |
j = iB; | |
} | |
/* Follow the traceback until we reach the origin. */ | |
while (1) { | |
switch (m) { | |
case Ix_MATRIX: | |
gapM = gaps[i][j].MIx; | |
gapXY = gaps[i][j].IyIx; | |
iB = j; | |
gap = *gapM; | |
if (gap) m = M_MATRIX; | |
else { | |
gap = *gapXY; | |
m = Iy_MATRIX; | |
} | |
iA = i - gap; | |
while (i > iA) M[--i][iB].path = VERTICAL; | |
break; | |
case Iy_MATRIX: | |
gapM = gaps[i][j].MIy; | |
gapXY = gaps[i][j].IxIy; | |
iA = i; | |
gap = *gapM; | |
if (gap) m = M_MATRIX; | |
else { | |
gap = *gapXY; | |
m = Ix_MATRIX; | |
} | |
iB = j - gap; | |
while (j > iB) M[iA][--j].path = HORIZONTAL; | |
break; | |
case M_MATRIX: | |
iA = i-1; | |
iB = j-1; | |
trace = M[i][j].trace; | |
if (trace & M_MATRIX) m = M_MATRIX; | |
else if (trace & Ix_MATRIX) m = Ix_MATRIX; | |
else if (trace & Iy_MATRIX) m = Iy_MATRIX; | |
else if (trace == STARTPOINT) { | |
self->iA = i; | |
self->iB = j; | |
return PathGenerator_create_path(self, i, j); | |
} | |
else { | |
PyErr_SetString(PyExc_RuntimeError, | |
"Unexpected trace in PathGenerator_next_waterman_smith_beyer_local"); | |
return NULL; | |
} | |
M[iA][iB].path = DIAGONAL; | |
break; | |
} | |
i = iA; | |
j = iB; | |
} | |
} | |
static PyObject * | |
PathGenerator_next(PathGenerator* self) | |
{ | |
const Mode mode = self->mode; | |
const Algorithm algorithm = self->algorithm; | |
switch (algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
switch (mode) { | |
case Global: | |
return PathGenerator_next_needlemanwunsch(self); | |
case Local: | |
return PathGenerator_next_smithwaterman(self); | |
} | |
case Gotoh: | |
switch (mode) { | |
case Global: | |
return PathGenerator_next_gotoh_global(self); | |
case Local: | |
return PathGenerator_next_gotoh_local(self); | |
} | |
case WatermanSmithBeyer: | |
switch (mode) { | |
case Global: | |
return PathGenerator_next_waterman_smith_beyer_global(self); | |
case Local: | |
return PathGenerator_next_waterman_smith_beyer_local(self); | |
} | |
case Unknown: | |
default: | |
PyErr_SetString(PyExc_RuntimeError, "Unknown algorithm"); | |
return NULL; | |
} | |
} | |
static const char PathGenerator_reset__doc__[] = "reset the iterator"; | |
static PyObject* | |
PathGenerator_reset(PathGenerator* self) | |
{ | |
switch (self->mode) { | |
case Local: | |
self->iA = 0; | |
self->iB = 0; | |
case Global: { | |
Trace** M = self->M; | |
switch (self->algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
case Gotoh: { | |
if (M[0][0].path != NONE) M[0][0].path = 0; | |
break; | |
} | |
case WatermanSmithBeyer: { | |
M[0][0].path = 0; | |
break; | |
} | |
case Unknown: | |
default: | |
break; | |
} | |
} | |
} | |
Py_INCREF(Py_None); | |
return Py_None; | |
} | |
static PyMethodDef PathGenerator_methods[] = { | |
{"reset", | |
(PyCFunction)PathGenerator_reset, | |
METH_NOARGS, | |
PathGenerator_reset__doc__ | |
}, | |
{NULL} /* Sentinel */ | |
}; | |
static PySequenceMethods PathGenerator_as_sequence = { | |
(lenfunc)PathGenerator_length, /* sq_length */ | |
NULL, /* sq_concat */ | |
NULL, /* sq_repeat */ | |
NULL, /* sq_item */ | |
NULL, /* sq_ass_item */ | |
NULL, /* sq_contains */ | |
NULL, /* sq_inplace_concat */ | |
NULL, /* sq_inplace_repeat */ | |
}; | |
static PyTypeObject PathGenerator_Type = { | |
PyVarObject_HEAD_INIT(NULL, 0) | |
"Path generator", /* tp_name */ | |
sizeof(PathGenerator), /* tp_basicsize */ | |
0, /* tp_itemsize */ | |
(destructor)PathGenerator_dealloc, /* tp_dealloc */ | |
0, /* tp_print */ | |
0, /* tp_getattr */ | |
0, /* tp_setattr */ | |
0, /* tp_reserved */ | |
0, /* tp_repr */ | |
0, /* tp_as_number */ | |
&PathGenerator_as_sequence, /* tp_as_sequence */ | |
0, /* tp_as_mapping */ | |
0, /* tp_hash */ | |
0, /* tp_call */ | |
0, /* tp_str */ | |
0, /* tp_getattro */ | |
0, /* tp_setattro */ | |
0, /* tp_as_buffer */ | |
Py_TPFLAGS_DEFAULT, /* tp_flags */ | |
0, /* tp_doc */ | |
0, /* tp_traverse */ | |
0, /* tp_clear */ | |
0, /* tp_richcompare */ | |
0, /* tp_weaklistoffset */ | |
PyObject_SelfIter, /* tp_iter */ | |
(iternextfunc)PathGenerator_next, /* tp_iternext */ | |
PathGenerator_methods, /* tp_methods */ | |
}; | |
typedef struct { | |
PyObject_HEAD | |
Mode mode; | |
Algorithm algorithm; | |
double match; | |
double mismatch; | |
double epsilon; | |
double target_internal_open_gap_score; | |
double target_internal_extend_gap_score; | |
double target_left_open_gap_score; | |
double target_left_extend_gap_score; | |
double target_right_open_gap_score; | |
double target_right_extend_gap_score; | |
double query_internal_open_gap_score; | |
double query_internal_extend_gap_score; | |
double query_left_open_gap_score; | |
double query_left_extend_gap_score; | |
double query_right_open_gap_score; | |
double query_right_extend_gap_score; | |
PyObject* target_gap_function; | |
PyObject* query_gap_function; | |
Py_buffer substitution_matrix; | |
PyObject* alphabet; | |
int* mapping; | |
int wildcard; | |
} Aligner; | |
static Py_ssize_t | |
set_alphabet(Aligner* self, PyObject* alphabet) | |
{ | |
Py_ssize_t size; | |
if (alphabet == Py_None) { | |
if (self->alphabet) { | |
Py_DECREF(self->alphabet); | |
self->alphabet = NULL; | |
} | |
if (self->mapping) { | |
PyMem_Free(self->mapping); | |
self->mapping = NULL; | |
} | |
return 0; | |
} | |
else if (PyUnicode_Check(alphabet)) { | |
int* mapping; | |
int i; | |
int n; | |
int kind; | |
void* characters; | |
if (PyUnicode_READY(alphabet) == -1) return -1; | |
size = PyUnicode_GET_LENGTH(alphabet); | |
if (size == 0) { | |
PyErr_SetString(PyExc_ValueError, "alphabet has zero length"); | |
return -1; | |
} | |
kind = PyUnicode_KIND(alphabet); | |
switch (kind) { | |
case PyUnicode_1BYTE_KIND: { | |
n = 1 << 8 * sizeof(Py_UCS1); | |
break; | |
} | |
case PyUnicode_2BYTE_KIND: { | |
n = 1 << 8 * sizeof(Py_UCS2); | |
break; | |
} | |
case PyUnicode_4BYTE_KIND: { | |
n = 0x110000; /* Maximum code point in Unicode 6.0 | |
* is 0x10ffff = 1114111 */ | |
break; | |
} | |
default: | |
PyErr_SetString(PyExc_ValueError, "could not interpret alphabet"); | |
return -1; | |
} | |
characters = PyUnicode_DATA(alphabet); | |
mapping = PyMem_Malloc(n*sizeof(int)); | |
if (!mapping) return -1; | |
for (i = 0; i < n; i++) mapping[i] = MISSING_LETTER; | |
for (i = 0; i < size; i++) { | |
Py_UCS4 character = PyUnicode_READ(kind, characters, i); | |
if (mapping[character] != MISSING_LETTER) { | |
PyObject* c = PyUnicode_FromKindAndData(kind, &character, 1); | |
PyErr_Format(PyExc_ValueError, | |
"alphabet contains '%S' more than once", c); | |
Py_XDECREF(c); | |
PyMem_Free(mapping); | |
return -1; | |
} | |
mapping[character] = i; | |
} | |
Py_INCREF(alphabet); | |
if (self->mapping) PyMem_Free(self->mapping); | |
self->mapping = mapping; | |
} | |
else { | |
/* alphabet is not a string; cannot use mapping */ | |
PyObject* sequence = PySequence_Fast(alphabet, | |
"alphabet should support the sequence protocol (e.g.,\n" | |
"strings, lists, and tuples can be valid alphabets)."); | |
if (!sequence) return -1; | |
size = PySequence_Fast_GET_SIZE(sequence); | |
Py_DECREF(sequence); | |
if (self->mapping) { | |
PyMem_Free(self->mapping); | |
self->mapping = NULL; | |
} | |
Py_INCREF(alphabet); | |
} | |
Py_XDECREF(self->alphabet); | |
self->alphabet = alphabet; | |
return size; | |
} | |
static int | |
Aligner_init(Aligner *self, PyObject *args, PyObject *kwds) | |
{ | |
self->mode = Global; | |
self->match = 1.0; | |
self->mismatch = 0.0; | |
self->epsilon = 1.e-6; | |
self->target_internal_open_gap_score = 0; | |
self->target_internal_extend_gap_score = 0; | |
self->query_internal_open_gap_score = 0; | |
self->query_internal_extend_gap_score = 0; | |
self->target_left_open_gap_score = 0; | |
self->target_left_extend_gap_score = 0; | |
self->target_right_open_gap_score = 0; | |
self->target_right_extend_gap_score = 0; | |
self->query_left_open_gap_score = 0; | |
self->query_left_extend_gap_score = 0; | |
self->query_right_open_gap_score = 0; | |
self->query_right_extend_gap_score = 0; | |
self->target_gap_function = NULL; | |
self->query_gap_function = NULL; | |
self->substitution_matrix.obj = NULL; | |
self->substitution_matrix.buf = NULL; | |
self->algorithm = Unknown; | |
self->alphabet = NULL; | |
self->mapping = NULL; | |
self->wildcard = -1; | |
return 0; | |
} | |
static void | |
Aligner_dealloc(Aligner* self) | |
{ Py_XDECREF(self->target_gap_function); | |
Py_XDECREF(self->query_gap_function); | |
if (self->substitution_matrix.obj) PyBuffer_Release(&self->substitution_matrix); | |
Py_XDECREF(self->alphabet); | |
Py_XDECREF(self->mapping); | |
Py_TYPE(self)->tp_free((PyObject*)self); | |
} | |
static PyObject* | |
Aligner_repr(Aligner* self) | |
{ | |
const char text[] = "Pairwise aligner, implementing the Needleman-Wunsch, Smith-Waterman, Gotoh, and Waterman-Smith-Beyer global and local alignment algorithms"; | |
return PyUnicode_FromString(text); | |
} | |
static PyObject* | |
Aligner_str(Aligner* self) | |
{ | |
char text[1024]; | |
char* p = text; | |
PyObject* substitution_matrix = self->substitution_matrix.obj; | |
void* args[3]; | |
int n = 0; | |
PyObject* wildcard = NULL; | |
PyObject* s; | |
p += sprintf(p, "Pairwise sequence aligner with parameters\n"); | |
if (substitution_matrix) { | |
p += sprintf(p, " substitution_matrix: <%s object at %p>\n", | |
Py_TYPE(substitution_matrix)->tp_name, | |
substitution_matrix); | |
} else { | |
if (self->wildcard == -1) { | |
p += sprintf(p, " wildcard: None\n"); | |
} | |
else { | |
wildcard = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, | |
&self->wildcard, 1); | |
if (!wildcard) return NULL; | |
p += sprintf(p, " wildcard: '%%U'\n"); | |
args[n++] = wildcard; | |
} | |
p += sprintf(p, " match_score: %f\n", self->match); | |
p += sprintf(p, " mismatch_score: %f\n", self->mismatch); | |
} | |
if (self->target_gap_function) { | |
p += sprintf(p, " target_gap_function: %%R\n"); | |
args[n++] = self->target_gap_function; | |
} | |
else { | |
p += sprintf(p, " target_internal_open_gap_score: %f\n", | |
self->target_internal_open_gap_score); | |
p += sprintf(p, " target_internal_extend_gap_score: %f\n", | |
self->target_internal_extend_gap_score); | |
p += sprintf(p, " target_left_open_gap_score: %f\n", | |
self->target_left_open_gap_score); | |
p += sprintf(p, " target_left_extend_gap_score: %f\n", | |
self->target_left_extend_gap_score); | |
p += sprintf(p, " target_right_open_gap_score: %f\n", | |
self->target_right_open_gap_score); | |
p += sprintf(p, " target_right_extend_gap_score: %f\n", | |
self->target_right_extend_gap_score); | |
} | |
if (self->query_gap_function) { | |
p += sprintf(p, " query_gap_function: %%R\n"); | |
args[n++] = self->query_gap_function; | |
} | |
else { | |
p += sprintf(p, " query_internal_open_gap_score: %f\n", | |
self->query_internal_open_gap_score); | |
p += sprintf(p, " query_internal_extend_gap_score: %f\n", | |
self->query_internal_extend_gap_score); | |
p += sprintf(p, " query_left_open_gap_score: %f\n", | |
self->query_left_open_gap_score); | |
p += sprintf(p, " query_left_extend_gap_score: %f\n", | |
self->query_left_extend_gap_score); | |
p += sprintf(p, " query_right_open_gap_score: %f\n", | |
self->query_right_open_gap_score); | |
p += sprintf(p, " query_right_extend_gap_score: %f\n", | |
self->query_right_extend_gap_score); | |
} | |
switch (self->mode) { | |
case Global: sprintf(p, " mode: global\n"); break; | |
case Local: sprintf(p, " mode: local\n"); break; | |
} | |
s = PyUnicode_FromFormat(text, args[0], args[1], args[2]); | |
Py_XDECREF(wildcard); | |
return s; | |
} | |
static char Aligner_mode__doc__[] = "alignment mode ('global' or 'local')"; | |
static PyObject* | |
Aligner_get_mode(Aligner* self, void* closure) | |
{ const char* message = NULL; | |
switch (self->mode) { | |
case Global: message = "global"; break; | |
case Local: message = "local"; break; | |
} | |
return PyUnicode_FromString(message); | |
} | |
static int | |
Aligner_set_mode(Aligner* self, PyObject* value, void* closure) | |
{ | |
if (PyUnicode_Check(value)) { | |
if (PyUnicode_CompareWithASCIIString(value, "global") == 0) { | |
self->mode = Global; | |
return 0; | |
} | |
if (PyUnicode_CompareWithASCIIString(value, "local") == 0) { | |
self->mode = Local; | |
return 0; | |
} | |
} | |
PyErr_SetString(PyExc_ValueError, | |
"invalid mode (expected 'global' or 'local'"); | |
return -1; | |
} | |
static char Aligner_match_score__doc__[] = "match score"; | |
static PyObject* | |
Aligner_get_match_score(Aligner* self, void* closure) | |
{ if (self->substitution_matrix.obj) { | |
Py_INCREF(Py_None); | |
return Py_None; | |
} | |
return PyFloat_FromDouble(self->match); | |
} | |
static int | |
Aligner_set_match_score(Aligner* self, PyObject* value, void* closure) | |
{ | |
const double match = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) { | |
PyErr_SetString(PyExc_ValueError, "invalid match score"); | |
return -1; | |
} | |
if (self->substitution_matrix.obj) { | |
if (set_alphabet(self, Py_None) < 0) return -1; | |
PyBuffer_Release(&self->substitution_matrix); | |
} | |
self->match = match; | |
return 0; | |
} | |
static char Aligner_mismatch_score__doc__[] = "mismatch score"; | |
static PyObject* | |
Aligner_get_mismatch_score(Aligner* self, void* closure) | |
{ if (self->substitution_matrix.obj) { | |
Py_INCREF(Py_None); | |
return Py_None; | |
} | |
return PyFloat_FromDouble(self->mismatch); | |
} | |
static int | |
Aligner_set_mismatch_score(Aligner* self, PyObject* value, void* closure) | |
{ | |
const double mismatch = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) { | |
PyErr_SetString(PyExc_ValueError, "invalid mismatch score"); | |
return -1; | |
} | |
if (self->substitution_matrix.obj) { | |
if (set_alphabet(self, Py_None) < 0) return -1; | |
PyBuffer_Release(&self->substitution_matrix); | |
} | |
self->mismatch = mismatch; | |
return 0; | |
} | |
static char Aligner_substitution_matrix__doc__[] = "substitution_matrix"; | |
static PyObject* | |
Aligner_get_substitution_matrix(Aligner* self, void* closure) | |
{ PyObject* object = self->substitution_matrix.obj; | |
if (!object) object = Py_None; | |
Py_INCREF(object); | |
return object; | |
} | |
static int | |
Aligner_set_substitution_matrix(Aligner* self, PyObject* values, void* closure) | |
{ | |
PyObject* alphabet; | |
Py_ssize_t size = -1; | |
Py_buffer view; | |
const int flag = PyBUF_FORMAT | PyBUF_ND; | |
if (values == Py_None) { | |
if (self->substitution_matrix.obj) | |
PyBuffer_Release(&self->substitution_matrix); | |
return 0; | |
} | |
if (PyObject_GetBuffer(values, &view, flag) != 0) { | |
PyErr_SetString(PyExc_ValueError, "expected a matrix"); | |
return -1; | |
} | |
if (view.ndim != 2) { | |
PyErr_Format(PyExc_ValueError, | |
"substitution matrix has incorrect rank (%d expected 2)", | |
view.ndim); | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
if (view.len == 0) { | |
PyErr_SetString(PyExc_ValueError, "substitution matrix has zero size"); | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
if (strcmp(view.format, "d") != 0) { | |
PyErr_SetString(PyExc_ValueError, | |
"substitution matrix should contain float values"); | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
if (view.itemsize != sizeof(double)) { | |
PyErr_Format(PyExc_RuntimeError, | |
"substitution matrix has unexpected item byte size " | |
"(%zd, expected %zd)", view.itemsize, sizeof(double)); | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
if (view.shape[0] != view.shape[1]) { | |
PyErr_Format(PyExc_ValueError, | |
"substitution matrix should be square " | |
"(found a %zd x %zd matrix)", | |
view.shape[0], view.shape[1]); | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
alphabet = PyObject_GetAttrString(values, "alphabet"); | |
if (alphabet) { | |
size = set_alphabet(self, alphabet); | |
Py_DECREF(alphabet); | |
} else { | |
/* Set a substitution matrix without setting an alphabet; useful | |
* when aligning integers. */ | |
PyErr_Clear(); | |
size = set_alphabet(self, Py_None); | |
} | |
if (size < 0) { | |
PyBuffer_Release(&view); | |
return -1; | |
} | |
if (self->substitution_matrix.obj) PyBuffer_Release(&self->substitution_matrix); | |
self->substitution_matrix = view; | |
return 0; | |
} | |
static char Aligner_alphabet__doc__[] = "alphabet"; | |
static PyObject* | |
Aligner_get_alphabet(Aligner* self, void* closure) | |
{ PyObject* object = self->alphabet; | |
if (!object) object = Py_None; | |
Py_INCREF(object); | |
return object; | |
} | |
static int | |
Aligner_set_alphabet(Aligner* self, PyObject* alphabet, void* closure) | |
{ | |
if (self->substitution_matrix.obj) { | |
PyErr_SetString(PyExc_AttributeError, | |
"can't set alphabet if a substitution matrix is used"); | |
return -1; | |
} | |
if (set_alphabet(self, alphabet) < 0) return -1; | |
return 0; | |
} | |
static char Aligner_gap_score__doc__[] = "gap score"; | |
static PyObject* | |
Aligner_get_gap_score(Aligner* self, void* closure) | |
{ | |
if (self->target_gap_function || self->query_gap_function) { | |
if (self->target_gap_function != self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
Py_INCREF(self->target_gap_function); | |
return self->target_gap_function; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_internal_extend_gap_score | |
|| score != self->target_left_open_gap_score | |
|| score != self->target_left_extend_gap_score | |
|| score != self->target_right_open_gap_score | |
|| score != self->target_right_extend_gap_score | |
|| score != self->query_internal_open_gap_score | |
|| score != self->query_internal_extend_gap_score | |
|| score != self->query_left_open_gap_score | |
|| score != self->query_left_extend_gap_score | |
|| score != self->query_right_open_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ if (PyCallable_Check(value)) { | |
Py_XDECREF(self->target_gap_function); | |
Py_XDECREF(self->query_gap_function); | |
Py_INCREF(value); | |
Py_INCREF(value); | |
self->target_gap_function = value; | |
self->query_gap_function = value; | |
} | |
else { | |
const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_open_gap_score = score; | |
self->target_internal_extend_gap_score = score; | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
self->query_internal_open_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_open_gap_score__doc__[] = "internal and end open gap score"; | |
static PyObject* | |
Aligner_get_open_gap_score(Aligner* self, void* closure) | |
{ | |
if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_left_open_gap_score | |
|| score != self->target_right_open_gap_score | |
|| score != self->query_internal_open_gap_score | |
|| score != self->query_left_open_gap_score | |
|| score != self->query_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_open_gap_score = score; | |
self->target_left_open_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->query_internal_open_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_extend_gap_score__doc__[] = "extend gap score"; | |
static PyObject* | |
Aligner_get_extend_gap_score(Aligner* self, void* closure) | |
{ | |
if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_extend_gap_score; | |
if (score != self->target_left_extend_gap_score | |
|| score != self->target_right_extend_gap_score | |
|| score != self->query_internal_extend_gap_score | |
|| score != self->query_left_extend_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_extend_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_internal_gap_score__doc__[] = "internal gap score"; | |
static PyObject* | |
Aligner_get_internal_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_internal_extend_gap_score | |
|| score != self->query_internal_open_gap_score | |
|| score != self->query_internal_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_internal_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_open_gap_score = score; | |
self->target_internal_extend_gap_score = score; | |
self->query_internal_open_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_internal_open_gap_score__doc__[] = "internal open gap score"; | |
static PyObject* | |
Aligner_get_internal_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->query_internal_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_internal_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_open_gap_score = score; | |
self->query_internal_open_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_internal_extend_gap_score__doc__[] = "internal extend gap score"; | |
static PyObject* | |
Aligner_get_internal_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_extend_gap_score; | |
if (score != self->query_internal_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_internal_extend_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_internal_extend_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_end_gap_score__doc__[] = "end gap score"; | |
static PyObject* | |
Aligner_get_end_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_left_extend_gap_score | |
|| score != self->target_right_open_gap_score | |
|| score != self->target_right_extend_gap_score | |
|| score != self->query_left_open_gap_score | |
|| score != self->query_left_extend_gap_score | |
|| score != self->query_right_open_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_end_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_end_open_gap_score__doc__[] = "end open gap score"; | |
static PyObject* | |
Aligner_get_end_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_right_open_gap_score | |
|| score != self->query_left_open_gap_score | |
|| score != self->query_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_end_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_open_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_end_extend_gap_score__doc__[] = "end extend gap score"; | |
static PyObject* | |
Aligner_get_end_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_extend_gap_score; | |
if (score != self->target_right_extend_gap_score | |
|| score != self->query_left_extend_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_end_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_extend_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_left_gap_score__doc__[] = "left gap score"; | |
static PyObject* | |
Aligner_get_left_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_left_extend_gap_score | |
|| score != self->query_left_open_gap_score | |
|| score != self->query_left_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_left_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_right_gap_score__doc__[] = "right gap score"; | |
static PyObject* | |
Aligner_get_right_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_right_open_gap_score; | |
if (score != self->target_right_extend_gap_score | |
|| score != self->query_right_open_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_right_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_left_open_gap_score__doc__[] = "left open gap score"; | |
static PyObject* | |
Aligner_get_left_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->query_left_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_left_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_open_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_left_extend_gap_score__doc__[] = "left extend gap score"; | |
static PyObject* | |
Aligner_get_left_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_extend_gap_score; | |
if (score != self->query_left_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_left_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_left_extend_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_right_open_gap_score__doc__[] = "right open gap score"; | |
static PyObject* | |
Aligner_get_right_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_right_open_gap_score; | |
if (score != self->query_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_right_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_right_open_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_right_extend_gap_score__doc__[] = "right extend gap score"; | |
static PyObject* | |
Aligner_get_right_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function || self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_right_extend_gap_score; | |
if (score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_right_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->target_right_extend_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_open_gap_score__doc__[] = "target open gap score"; | |
static PyObject* | |
Aligner_get_target_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_left_open_gap_score | |
|| score != self->target_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_internal_open_gap_score = score; | |
self->target_left_open_gap_score = score; | |
self->target_right_open_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_extend_gap_score__doc__[] = "target extend gap score"; | |
static PyObject* | |
Aligner_get_target_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_extend_gap_score; | |
if (score != self->target_left_extend_gap_score | |
|| score != self->target_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_internal_extend_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_gap_score__doc__[] = "target gap score"; | |
static PyObject* | |
Aligner_get_target_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
Py_INCREF(self->target_gap_function); | |
return self->target_gap_function; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_internal_extend_gap_score | |
|| score != self->target_left_open_gap_score | |
|| score != self->target_left_extend_gap_score | |
|| score != self->target_right_open_gap_score | |
|| score != self->target_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ | |
if (PyCallable_Check(value)) { | |
Py_XDECREF(self->target_gap_function); | |
Py_INCREF(value); | |
self->target_gap_function = value; | |
} | |
else { | |
const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) { | |
PyErr_SetString(PyExc_ValueError, | |
"gap score should be numerical or callable"); | |
return -1; | |
} | |
self->target_internal_open_gap_score = score; | |
self->target_internal_extend_gap_score = score; | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_open_gap_score__doc__[] = "query gap open score"; | |
static PyObject* | |
Aligner_get_query_open_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_internal_open_gap_score; | |
if (score != self->query_left_open_gap_score | |
|| score != self->query_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_internal_open_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_right_open_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_extend_gap_score__doc__[] = "query gap extend score"; | |
static PyObject* | |
Aligner_get_query_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_internal_extend_gap_score; | |
if (score != self->query_left_extend_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_internal_extend_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_gap_score__doc__[] = "query gap score"; | |
static PyObject* | |
Aligner_get_query_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
Py_INCREF(self->query_gap_function); | |
return self->query_gap_function; | |
} | |
else { | |
const double score = self->query_internal_open_gap_score; | |
if (score != self->query_left_open_gap_score | |
|| score != self->query_right_open_gap_score | |
|| score != self->query_internal_extend_gap_score | |
|| score != self->query_left_extend_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ if (PyCallable_Check(value)) { | |
Py_XDECREF(self->query_gap_function); | |
Py_INCREF(value); | |
self->query_gap_function = value; | |
} | |
else { | |
const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) { | |
PyErr_SetString(PyExc_ValueError, | |
"gap score should be numerical or callable"); | |
return -1; | |
} | |
self->query_internal_open_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_internal_open_gap_score__doc__[] = "target internal open gap score"; | |
static PyObject* | |
Aligner_get_target_internal_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_internal_open_gap_score); | |
} | |
static int | |
Aligner_set_target_internal_open_gap_score(Aligner* self, | |
PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_internal_open_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_internal_extend_gap_score__doc__[] = "target internal extend gap score"; | |
static PyObject* | |
Aligner_get_target_internal_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_internal_extend_gap_score); | |
} | |
static int | |
Aligner_set_target_internal_extend_gap_score(Aligner* self, | |
PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_internal_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_internal_gap_score__doc__[] = "target internal gap score"; | |
static PyObject* | |
Aligner_get_target_internal_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_internal_open_gap_score; | |
if (score != self->target_internal_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_internal_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_internal_open_gap_score = score; | |
self->target_internal_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_end_gap_score__doc__[] = "target end gap score"; | |
static PyObject* | |
Aligner_get_target_end_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_left_extend_gap_score | |
|| score != self->target_right_open_gap_score | |
|| score != self->target_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_end_gap_score(Aligner* self, PyObject* value, void* closure) { | |
const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_end_open_gap_score__doc__[] = "target end open gap score"; | |
static PyObject* | |
Aligner_get_target_end_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_end_open_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_open_gap_score = score; | |
self->target_right_open_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_end_extend_gap_score__doc__[] = "target end extend gap score"; | |
static PyObject* | |
Aligner_get_target_end_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_extend_gap_score; | |
if (score != self->target_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_end_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_extend_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_left_open_gap_score__doc__[] = "target left open score"; | |
static PyObject* | |
Aligner_get_target_left_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_left_open_gap_score); | |
} | |
static int | |
Aligner_set_target_left_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_open_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_left_extend_gap_score__doc__[] = "target left extend score"; | |
static PyObject* | |
Aligner_get_target_left_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_left_extend_gap_score); | |
} | |
static int | |
Aligner_set_target_left_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_left_gap_score__doc__[] = "target left score"; | |
static PyObject* | |
Aligner_get_target_left_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_left_open_gap_score; | |
if (score != self->target_left_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_left_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_left_open_gap_score = score; | |
self->target_left_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_right_gap_score_open__doc__[] = "target right open score"; | |
static PyObject* | |
Aligner_get_target_right_open_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_right_open_gap_score); | |
} | |
static int | |
Aligner_set_target_right_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_right_open_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_right_extend_gap_score__doc__[] = "target right extend score"; | |
static PyObject* | |
Aligner_get_target_right_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->target_right_extend_gap_score); | |
} | |
static int | |
Aligner_set_target_right_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_target_right_gap_score__doc__[] = "target right score"; | |
static PyObject* | |
Aligner_get_target_right_gap_score(Aligner* self, void* closure) | |
{ if (self->target_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->target_right_open_gap_score; | |
if (score != self->target_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_target_right_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->target_right_open_gap_score = score; | |
self->target_right_extend_gap_score = score; | |
if (self->target_gap_function) { | |
Py_DECREF(self->target_gap_function); | |
self->target_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_end_gap_score__doc__[] = "query end score"; | |
static PyObject* | |
Aligner_get_query_end_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_left_open_gap_score; | |
if (score != self->query_left_extend_gap_score | |
|| score != self->query_right_open_gap_score | |
|| score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_end_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_end_open_gap_score__doc__[] = "query end open score"; | |
static PyObject* | |
Aligner_get_query_end_open_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_left_open_gap_score; | |
if (score != self->query_right_open_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_end_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_open_gap_score = score; | |
self->query_right_open_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_end_extend_gap_score__doc__[] = "query end extend score"; | |
static PyObject* | |
Aligner_get_query_end_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_left_extend_gap_score; | |
if (score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_end_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_extend_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_internal_open_gap_score__doc__[] = "query internal open gap score"; | |
static PyObject* | |
Aligner_get_query_internal_open_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_internal_open_gap_score); | |
} | |
static int | |
Aligner_set_query_internal_open_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_internal_open_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_internal_extend_gap_score__doc__[] = "query internal extend gap score"; | |
static PyObject* | |
Aligner_get_query_internal_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_internal_extend_gap_score); | |
} | |
static int | |
Aligner_set_query_internal_extend_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_internal_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_internal_gap_score__doc__[] = "query internal gap score"; | |
static PyObject* | |
Aligner_get_query_internal_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_internal_open_gap_score; | |
if (score != self->query_internal_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_internal_gap_score(Aligner* self, PyObject* value, | |
void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_internal_open_gap_score = score; | |
self->query_internal_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_left_open_gap_score__doc__[] = "query left open score"; | |
static PyObject* | |
Aligner_get_query_left_open_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_left_open_gap_score); | |
} | |
static int | |
Aligner_set_query_left_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_open_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_left_extend_gap_score__doc__[] = "query left extend score"; | |
static PyObject* | |
Aligner_get_query_left_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_left_extend_gap_score); | |
} | |
static int | |
Aligner_set_query_left_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_left_gap_score__doc__[] = "query left score"; | |
static PyObject* | |
Aligner_get_query_left_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_left_open_gap_score; | |
if (score != self->query_left_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_left_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_left_open_gap_score = score; | |
self->query_left_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_right_open_gap_score__doc__[] = "query right open score"; | |
static PyObject* | |
Aligner_get_query_right_open_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_right_open_gap_score); | |
} | |
static int | |
Aligner_set_query_right_open_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_right_open_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_right_extend_gap_score__doc__[] = "query right extend score"; | |
static PyObject* | |
Aligner_get_query_right_extend_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(self->query_right_extend_gap_score); | |
} | |
static int | |
Aligner_set_query_right_extend_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_query_right_gap_score__doc__[] = "query right score"; | |
static PyObject* | |
Aligner_get_query_right_gap_score(Aligner* self, void* closure) | |
{ if (self->query_gap_function) { | |
PyErr_SetString(PyExc_ValueError, "using a gap score function"); | |
return NULL; | |
} | |
else { | |
const double score = self->query_right_open_gap_score; | |
if (score != self->query_right_extend_gap_score) { | |
PyErr_SetString(PyExc_ValueError, "gap scores are different"); | |
return NULL; | |
} | |
return PyFloat_FromDouble(score); | |
} | |
} | |
static int | |
Aligner_set_query_right_gap_score(Aligner* self, PyObject* value, void* closure) | |
{ const double score = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->query_right_open_gap_score = score; | |
self->query_right_extend_gap_score = score; | |
if (self->query_gap_function) { | |
Py_DECREF(self->query_gap_function); | |
self->query_gap_function = NULL; | |
} | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static char Aligner_epsilon__doc__[] = "roundoff epsilon"; | |
static PyObject* | |
Aligner_get_epsilon(Aligner* self, void* closure) | |
{ return PyFloat_FromDouble(self->epsilon); | |
} | |
static int | |
Aligner_set_epsilon(Aligner* self, PyObject* value, void* closure) | |
{ const double epsilon = PyFloat_AsDouble(value); | |
if (PyErr_Occurred()) return -1; | |
self->epsilon = epsilon; | |
self->algorithm = Unknown; | |
return 0; | |
} | |
static PyObject* | |
Aligner_get_wildcard(Aligner* self, void* closure) | |
{ | |
if (self->wildcard == -1) { | |
Py_INCREF(Py_None); | |
return Py_None; | |
} | |
else { | |
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, &self->wildcard, 1); | |
} | |
} | |
static int | |
Aligner_set_wildcard(Aligner* self, PyObject* value, void* closure) | |
{ | |
if (value == Py_None) { | |
self->wildcard = -1; | |
return 0; | |
} | |
if (!PyUnicode_Check(value)) { | |
PyErr_SetString(PyExc_TypeError, | |
"wildcard should be a single character, or None"); | |
return -1; | |
} | |
if (PyUnicode_READY(value) == -1) return -1; | |
if (PyUnicode_GET_LENGTH(value) != 1) { | |
PyErr_SetString(PyExc_ValueError, | |
"wildcard should be a single character, or None"); | |
return -1; | |
} | |
self->wildcard = PyUnicode_READ_CHAR(value, 0); | |
return 0; | |
} | |
static char Aligner_wildcard__doc__[] = "wildcard character"; | |
static Algorithm _get_algorithm(Aligner* self) | |
{ | |
Algorithm algorithm = self->algorithm; | |
if (algorithm == Unknown) { | |
const double target_gap_open = self->target_internal_open_gap_score; | |
const double query_gap_open = self->query_internal_open_gap_score; | |
const double target_gap_extend = self->target_internal_extend_gap_score; | |
const double query_gap_extend = self->query_internal_extend_gap_score; | |
const double target_left_open = self->target_left_open_gap_score; | |
const double target_left_extend = self->target_left_extend_gap_score; | |
const double query_left_open = self->query_left_open_gap_score; | |
const double target_right_open = self->target_right_open_gap_score; | |
const double query_right_open = self->query_right_open_gap_score; | |
const double target_right_extend = self->target_right_extend_gap_score; | |
const double query_left_extend = self->query_left_extend_gap_score; | |
const double query_right_extend = self->query_right_extend_gap_score; | |
if (self->target_gap_function || self->query_gap_function) | |
algorithm = WatermanSmithBeyer; | |
else if (target_gap_open == target_gap_extend | |
&& query_gap_open == query_gap_extend | |
&& target_left_open == target_left_extend | |
&& target_right_open == target_right_extend | |
&& query_left_open == query_left_extend | |
&& query_right_open == query_right_extend) | |
algorithm = NeedlemanWunschSmithWaterman; | |
else | |
algorithm = Gotoh; | |
self->algorithm = algorithm; | |
} | |
return algorithm; | |
} | |
static char Aligner_algorithm__doc__[] = "alignment algorithm"; | |
static PyObject* | |
Aligner_get_algorithm(Aligner* self, void* closure) | |
{ | |
const char* s = NULL; | |
const Mode mode = self->mode; | |
const Algorithm algorithm = _get_algorithm(self); | |
switch (algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
switch (mode) { | |
case Global: | |
s = "Needleman-Wunsch"; | |
break; | |
case Local: | |
s = "Smith-Waterman"; | |
break; | |
} | |
break; | |
case Gotoh: | |
switch (mode) { | |
case Global: | |
s = "Gotoh global alignment algorithm"; | |
break; | |
case Local: | |
s = "Gotoh local alignment algorithm"; | |
break; | |
} | |
break; | |
case WatermanSmithBeyer: | |
switch (mode) { | |
case Global: | |
s = "Waterman-Smith-Beyer global alignment algorithm"; | |
break; | |
case Local: | |
s = "Waterman-Smith-Beyer local alignment algorithm"; | |
break; | |
} | |
break; | |
case Unknown: | |
default: | |
break; | |
} | |
return PyUnicode_FromString(s); | |
} | |
static PyGetSetDef Aligner_getset[] = { | |
{"mode", | |
(getter)Aligner_get_mode, | |
(setter)Aligner_set_mode, | |
Aligner_mode__doc__, NULL}, | |
{"match_score", | |
(getter)Aligner_get_match_score, | |
(setter)Aligner_set_match_score, | |
Aligner_match_score__doc__, NULL}, | |
{"mismatch_score", | |
(getter)Aligner_get_mismatch_score, | |
(setter)Aligner_set_mismatch_score, | |
Aligner_mismatch_score__doc__, NULL}, | |
{"match", /* synonym for match_score */ | |
(getter)Aligner_get_match_score, | |
(setter)Aligner_set_match_score, | |
Aligner_match_score__doc__, NULL}, | |
{"mismatch", /* synonym for mismatch_score */ | |
(getter)Aligner_get_mismatch_score, | |
(setter)Aligner_set_mismatch_score, | |
Aligner_mismatch_score__doc__, NULL}, | |
{"substitution_matrix", | |
(getter)Aligner_get_substitution_matrix, | |
(setter)Aligner_set_substitution_matrix, | |
Aligner_substitution_matrix__doc__, NULL}, | |
{"alphabet", | |
(getter)Aligner_get_alphabet, | |
(setter)Aligner_set_alphabet, | |
Aligner_alphabet__doc__, NULL}, | |
{"gap_score", | |
(getter)Aligner_get_gap_score, | |
(setter)Aligner_set_gap_score, | |
Aligner_gap_score__doc__, NULL}, | |
{"open_gap_score", | |
(getter)Aligner_get_open_gap_score, | |
(setter)Aligner_set_open_gap_score, | |
Aligner_open_gap_score__doc__, NULL}, | |
{"extend_gap_score", | |
(getter)Aligner_get_extend_gap_score, | |
(setter)Aligner_set_extend_gap_score, | |
Aligner_extend_gap_score__doc__, NULL}, | |
{"internal_gap_score", | |
(getter)Aligner_get_internal_gap_score, | |
(setter)Aligner_set_internal_gap_score, | |
Aligner_internal_gap_score__doc__, NULL}, | |
{"internal_open_gap_score", | |
(getter)Aligner_get_internal_open_gap_score, | |
(setter)Aligner_set_internal_open_gap_score, | |
Aligner_internal_open_gap_score__doc__, NULL}, | |
{"internal_extend_gap_score", | |
(getter)Aligner_get_internal_extend_gap_score, | |
(setter)Aligner_set_internal_extend_gap_score, | |
Aligner_internal_extend_gap_score__doc__, NULL}, | |
{"end_gap_score", | |
(getter)Aligner_get_end_gap_score, | |
(setter)Aligner_set_end_gap_score, | |
Aligner_end_gap_score__doc__, NULL}, | |
{"end_open_gap_score", | |
(getter)Aligner_get_end_open_gap_score, | |
(setter)Aligner_set_end_open_gap_score, | |
Aligner_end_open_gap_score__doc__, NULL}, | |
{"end_extend_gap_score", | |
(getter)Aligner_get_end_extend_gap_score, | |
(setter)Aligner_set_end_extend_gap_score, | |
Aligner_end_extend_gap_score__doc__, NULL}, | |
{"left_gap_score", | |
(getter)Aligner_get_left_gap_score, | |
(setter)Aligner_set_left_gap_score, | |
Aligner_left_gap_score__doc__, NULL}, | |
{"left_open_gap_score", | |
(getter)Aligner_get_left_open_gap_score, | |
(setter)Aligner_set_left_open_gap_score, | |
Aligner_left_open_gap_score__doc__, NULL}, | |
{"left_extend_gap_score", | |
(getter)Aligner_get_left_extend_gap_score, | |
(setter)Aligner_set_left_extend_gap_score, | |
Aligner_left_extend_gap_score__doc__, NULL}, | |
{"right_gap_score", | |
(getter)Aligner_get_right_gap_score, | |
(setter)Aligner_set_right_gap_score, | |
Aligner_right_gap_score__doc__, NULL}, | |
{"right_open_gap_score", | |
(getter)Aligner_get_right_open_gap_score, | |
(setter)Aligner_set_right_open_gap_score, | |
Aligner_right_open_gap_score__doc__, NULL}, | |
{"right_extend_gap_score", | |
(getter)Aligner_get_right_extend_gap_score, | |
(setter)Aligner_set_right_extend_gap_score, | |
Aligner_right_extend_gap_score__doc__, NULL}, | |
{"target_open_gap_score", | |
(getter)Aligner_get_target_open_gap_score, | |
(setter)Aligner_set_target_open_gap_score, | |
Aligner_target_open_gap_score__doc__, NULL}, | |
{"target_extend_gap_score", | |
(getter)Aligner_get_target_extend_gap_score, | |
(setter)Aligner_set_target_extend_gap_score, | |
Aligner_target_extend_gap_score__doc__, NULL}, | |
{"target_gap_score", | |
(getter)Aligner_get_target_gap_score, | |
(setter)Aligner_set_target_gap_score, | |
Aligner_target_gap_score__doc__, NULL}, | |
{"query_open_gap_score", | |
(getter)Aligner_get_query_open_gap_score, | |
(setter)Aligner_set_query_open_gap_score, | |
Aligner_query_open_gap_score__doc__, NULL}, | |
{"query_extend_gap_score", | |
(getter)Aligner_get_query_extend_gap_score, | |
(setter)Aligner_set_query_extend_gap_score, | |
Aligner_query_extend_gap_score__doc__, NULL}, | |
{"query_gap_score", | |
(getter)Aligner_get_query_gap_score, | |
(setter)Aligner_set_query_gap_score, | |
Aligner_query_gap_score__doc__, NULL}, | |
{"target_end_gap_score", | |
(getter)Aligner_get_target_end_gap_score, | |
(setter)Aligner_set_target_end_gap_score, | |
Aligner_target_end_gap_score__doc__, NULL}, | |
{"target_end_open_gap_score", | |
(getter)Aligner_get_target_end_open_gap_score, | |
(setter)Aligner_set_target_end_open_gap_score, | |
Aligner_target_end_open_gap_score__doc__, NULL}, | |
{"target_end_extend_gap_score", | |
(getter)Aligner_get_target_end_extend_gap_score, | |
(setter)Aligner_set_target_end_extend_gap_score, | |
Aligner_target_end_extend_gap_score__doc__, NULL}, | |
{"target_internal_open_gap_score", | |
(getter)Aligner_get_target_internal_open_gap_score, | |
(setter)Aligner_set_target_internal_open_gap_score, | |
Aligner_target_internal_open_gap_score__doc__, NULL}, | |
{"target_internal_extend_gap_score", | |
(getter)Aligner_get_target_internal_extend_gap_score, | |
(setter)Aligner_set_target_internal_extend_gap_score, | |
Aligner_target_internal_extend_gap_score__doc__, NULL}, | |
{"target_internal_gap_score", | |
(getter)Aligner_get_target_internal_gap_score, | |
(setter)Aligner_set_target_internal_gap_score, | |
Aligner_target_internal_gap_score__doc__, NULL}, | |
{"target_left_open_gap_score", | |
(getter)Aligner_get_target_left_open_gap_score, | |
(setter)Aligner_set_target_left_open_gap_score, | |
Aligner_target_left_open_gap_score__doc__, NULL}, | |
{"target_left_extend_gap_score", | |
(getter)Aligner_get_target_left_extend_gap_score, | |
(setter)Aligner_set_target_left_extend_gap_score, | |
Aligner_target_left_extend_gap_score__doc__, NULL}, | |
{"target_left_gap_score", | |
(getter)Aligner_get_target_left_gap_score, | |
(setter)Aligner_set_target_left_gap_score, | |
Aligner_target_left_gap_score__doc__, NULL}, | |
{"target_right_open_gap_score", | |
(getter)Aligner_get_target_right_open_gap_score, | |
(setter)Aligner_set_target_right_open_gap_score, | |
Aligner_target_right_gap_score_open__doc__, NULL}, | |
{"target_right_extend_gap_score", | |
(getter)Aligner_get_target_right_extend_gap_score, | |
(setter)Aligner_set_target_right_extend_gap_score, | |
Aligner_target_right_extend_gap_score__doc__, NULL}, | |
{"target_right_gap_score", | |
(getter)Aligner_get_target_right_gap_score, | |
(setter)Aligner_set_target_right_gap_score, | |
Aligner_target_right_gap_score__doc__, NULL}, | |
{"query_end_gap_score", | |
(getter)Aligner_get_query_end_gap_score, | |
(setter)Aligner_set_query_end_gap_score, | |
Aligner_query_end_gap_score__doc__, NULL}, | |
{"query_end_open_gap_score", | |
(getter)Aligner_get_query_end_open_gap_score, | |
(setter)Aligner_set_query_end_open_gap_score, | |
Aligner_query_end_open_gap_score__doc__, NULL}, | |
{"query_end_extend_gap_score", | |
(getter)Aligner_get_query_end_extend_gap_score, | |
(setter)Aligner_set_query_end_extend_gap_score, | |
Aligner_query_end_extend_gap_score__doc__, NULL}, | |
{"query_internal_open_gap_score", | |
(getter)Aligner_get_query_internal_open_gap_score, | |
(setter)Aligner_set_query_internal_open_gap_score, | |
Aligner_query_internal_open_gap_score__doc__, NULL}, | |
{"query_internal_extend_gap_score", | |
(getter)Aligner_get_query_internal_extend_gap_score, | |
(setter)Aligner_set_query_internal_extend_gap_score, | |
Aligner_query_internal_extend_gap_score__doc__, NULL}, | |
{"query_internal_gap_score", | |
(getter)Aligner_get_query_internal_gap_score, | |
(setter)Aligner_set_query_internal_gap_score, | |
Aligner_query_internal_gap_score__doc__, NULL}, | |
{"query_left_open_gap_score", | |
(getter)Aligner_get_query_left_open_gap_score, | |
(setter)Aligner_set_query_left_open_gap_score, | |
Aligner_query_left_open_gap_score__doc__, NULL}, | |
{"query_left_extend_gap_score", | |
(getter)Aligner_get_query_left_extend_gap_score, | |
(setter)Aligner_set_query_left_extend_gap_score, | |
Aligner_query_left_extend_gap_score__doc__, NULL}, | |
{"query_left_gap_score", | |
(getter)Aligner_get_query_left_gap_score, | |
(setter)Aligner_set_query_left_gap_score, | |
Aligner_query_left_gap_score__doc__, NULL}, | |
{"query_right_open_gap_score", | |
(getter)Aligner_get_query_right_open_gap_score, | |
(setter)Aligner_set_query_right_open_gap_score, | |
Aligner_query_right_open_gap_score__doc__, NULL}, | |
{"query_right_extend_gap_score", | |
(getter)Aligner_get_query_right_extend_gap_score, | |
(setter)Aligner_set_query_right_extend_gap_score, | |
Aligner_query_right_extend_gap_score__doc__, NULL}, | |
{"query_right_gap_score", | |
(getter)Aligner_get_query_right_gap_score, | |
(setter)Aligner_set_query_right_gap_score, | |
Aligner_query_right_gap_score__doc__, NULL}, | |
{"epsilon", | |
(getter)Aligner_get_epsilon, | |
(setter)Aligner_set_epsilon, | |
Aligner_epsilon__doc__, NULL}, | |
{"wildcard", | |
(getter)Aligner_get_wildcard, | |
(setter)Aligner_set_wildcard, | |
Aligner_wildcard__doc__, NULL}, | |
{"algorithm", | |
(getter)Aligner_get_algorithm, | |
(setter)NULL, | |
Aligner_algorithm__doc__, NULL}, | |
{NULL} /* Sentinel */ | |
}; | |
/* ----------------- alignment algorithms ----------------- */ | |
/* -------------- allocation & deallocation ------------- */ | |
static PathGenerator* | |
PathGenerator_create_NWSW(int nA, int nB, Mode mode, unsigned char strand) | |
{ | |
int i; | |
unsigned char trace = 0; | |
Trace** M; | |
PathGenerator* paths; | |
paths = (PathGenerator*)PyType_GenericAlloc(&PathGenerator_Type, 0); | |
if (!paths) return NULL; | |
paths->iA = 0; | |
paths->iB = 0; | |
paths->nA = nA; | |
paths->nB = nB; | |
paths->M = NULL; | |
paths->gaps.gotoh = NULL; | |
paths->gaps.waterman_smith_beyer = NULL; | |
paths->algorithm = NeedlemanWunschSmithWaterman; | |
paths->mode = mode; | |
paths->length = 0; | |
paths->strand = strand; | |
M = PyMem_Malloc((nA+1)*sizeof(Trace*)); | |
paths->M = M; | |
if (!M) goto exit; | |
switch (mode) { | |
case Global: trace = VERTICAL; break; | |
case Local: trace = STARTPOINT; break; | |
} | |
for (i = 0; i <= nA; i++) { | |
M[i] = PyMem_Malloc((nB+1)*sizeof(Trace)); | |
if (!M[i]) goto exit; | |
M[i][0].trace = trace; | |
} | |
if (mode == Global) { | |
M[0][0].trace = 0; | |
trace = HORIZONTAL; | |
} | |
for (i = 1; i <= nB; i++) M[0][i].trace = trace; | |
M[0][0].path = 0; | |
return paths; | |
exit: | |
Py_DECREF(paths); | |
PyErr_SetNone(PyExc_MemoryError); | |
return NULL; | |
} | |
static PathGenerator* | |
PathGenerator_create_Gotoh(int nA, int nB, Mode mode, unsigned char strand) | |
{ | |
int i; | |
unsigned char trace; | |
Trace** M; | |
TraceGapsGotoh** gaps; | |
PathGenerator* paths; | |
switch (mode) { | |
case Global: trace = 0; break; | |
case Local: trace = STARTPOINT; break; | |
default: | |
/* Should not happen, but the compiler has no way of knowing that, | |
* as the enum Mode does not restrict the value of mode, which can | |
* be any integer. Include default: here to prevent compiler | |
* warnings. | |
*/ | |
PyErr_Format(PyExc_RuntimeError, | |
"mode has unexpected value %d", mode); | |
return NULL; | |
} | |
paths = (PathGenerator*)PyType_GenericAlloc(&PathGenerator_Type, 0); | |
if (!paths) return NULL; | |
paths->iA = 0; | |
paths->iB = 0; | |
paths->nA = nA; | |
paths->nB = nB; | |
paths->M = NULL; | |
paths->gaps.gotoh = NULL; | |
paths->algorithm = Gotoh; | |
paths->mode = mode; | |
paths->length = 0; | |
paths->strand = strand; | |
M = PyMem_Malloc((nA+1)*sizeof(Trace*)); | |
if (!M) goto exit; | |
paths->M = M; | |
for (i = 0; i <= nA; i++) { | |
M[i] = PyMem_Malloc((nB+1)*sizeof(Trace)); | |
if (!M[i]) goto exit; | |
M[i][0].trace = trace; | |
} | |
gaps = PyMem_Malloc((nA+1)*sizeof(TraceGapsGotoh*)); | |
if (!gaps) goto exit; | |
paths->gaps.gotoh = gaps; | |
for (i = 0; i <= nA; i++) { | |
gaps[i] = PyMem_Malloc((nB+1)*sizeof(TraceGapsGotoh)); | |
if (!gaps[i]) goto exit; | |
} | |
gaps[0][0].Ix = 0; | |
gaps[0][0].Iy = 0; | |
if (mode == Global) { | |
for (i = 1; i <= nA; i++) { | |
gaps[i][0].Ix = Ix_MATRIX; | |
gaps[i][0].Iy = 0; | |
} | |
gaps[1][0].Ix = M_MATRIX; | |
for (i = 1; i <= nB; i++) { | |
M[0][i].trace = 0; | |
gaps[0][i].Ix = 0; | |
gaps[0][i].Iy = Iy_MATRIX; | |
} | |
gaps[0][1].Iy = M_MATRIX; | |
} | |
else if (mode == Local) { | |
for (i = 1; i < nA; i++) { | |
gaps[i][0].Ix = 0; | |
gaps[i][0].Iy = 0; | |
} | |
for (i = 1; i <= nB; i++) { | |
M[0][i].trace = trace; | |
gaps[0][i].Ix = 0; | |
gaps[0][i].Iy = 0; | |
} | |
} | |
M[0][0].path = 0; | |
return paths; | |
exit: | |
Py_DECREF(paths); | |
PyErr_SetNone(PyExc_MemoryError); | |
return NULL; | |
} | |
static PathGenerator* | |
PathGenerator_create_WSB(int nA, int nB, Mode mode, unsigned char strand) | |
{ | |
int i, j; | |
int* trace; | |
Trace** M = NULL; | |
TraceGapsWatermanSmithBeyer** gaps = NULL; | |
PathGenerator* paths; | |
paths = (PathGenerator*)PyType_GenericAlloc(&PathGenerator_Type, 0); | |
if (!paths) return NULL; | |
paths->iA = 0; | |
paths->iB = 0; | |
paths->nA = nA; | |
paths->nB = nB; | |
paths->M = NULL; | |
paths->gaps.waterman_smith_beyer = NULL; | |
paths->algorithm = WatermanSmithBeyer; | |
paths->mode = mode; | |
paths->length = 0; | |
paths->strand = strand; | |
M = PyMem_Malloc((nA+1)*sizeof(Trace*)); | |
if (!M) goto exit; | |
paths->M = M; | |
for (i = 0; i <= nA; i++) { | |
M[i] = PyMem_Malloc((nB+1)*sizeof(Trace)); | |
if (!M[i]) goto exit; | |
} | |
gaps = PyMem_Malloc((nA+1)*sizeof(TraceGapsWatermanSmithBeyer*)); | |
if (!gaps) goto exit; | |
paths->gaps.waterman_smith_beyer = gaps; | |
for (i = 0; i <= nA; i++) gaps[i] = NULL; | |
for (i = 0; i <= nA; i++) { | |
gaps[i] = PyMem_Malloc((nB+1)*sizeof(TraceGapsWatermanSmithBeyer)); | |
if (!gaps[i]) goto exit; | |
for (j = 0; j <= nB; j++) { | |
gaps[i][j].MIx = NULL; | |
gaps[i][j].IyIx = NULL; | |
gaps[i][j].MIy = NULL; | |
gaps[i][j].IxIy = NULL; | |
} | |
M[i][0].path = 0; | |
switch (mode) { | |
case Global: | |
M[i][0].trace = 0; | |
trace = PyMem_Malloc(2*sizeof(int)); | |
if (!trace) goto exit; | |
gaps[i][0].MIx = trace; | |
trace[0] = i; | |
trace[1] = 0; | |
trace = PyMem_Malloc(sizeof(int)); | |
if (!trace) goto exit; | |
gaps[i][0].IyIx = trace; | |
trace[0] = 0; | |
break; | |
case Local: | |
M[i][0].trace = STARTPOINT; | |
break; | |
} | |
} | |
for (i = 1; i <= nB; i++) { | |
switch (mode) { | |
case Global: | |
M[0][i].trace = 0; | |
trace = PyMem_Malloc(2*sizeof(int)); | |
if (!trace) goto exit; | |
gaps[0][i].MIy = trace; | |
trace[0] = i; | |
trace[1] = 0; | |
trace = PyMem_Malloc(sizeof(int)); | |
if (!trace) goto exit; | |
gaps[0][i].IxIy = trace; | |
trace[0] = 0; | |
break; | |
case Local: | |
M[0][i].trace = STARTPOINT; | |
break; | |
} | |
} | |
M[0][0].path = 0; | |
return paths; | |
exit: | |
Py_DECREF(paths); | |
PyErr_SetNone(PyExc_MemoryError); | |
return NULL; | |
} | |
/* ----------------- alignment algorithms ----------------- */ | |
static PyObject* | |
Aligner_needlemanwunsch_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
NEEDLEMANWUNSCH_SCORE(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_needlemanwunsch_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
NEEDLEMANWUNSCH_SCORE(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_smithwaterman_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
SMITHWATERMAN_SCORE(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_smithwaterman_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
SMITHWATERMAN_SCORE(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_needlemanwunsch_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
NEEDLEMANWUNSCH_ALIGN(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_needlemanwunsch_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
NEEDLEMANWUNSCH_ALIGN(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_smithwaterman_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
SMITHWATERMAN_ALIGN(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_smithwaterman_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
SMITHWATERMAN_ALIGN(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_global_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
GOTOH_GLOBAL_SCORE(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_global_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
GOTOH_GLOBAL_SCORE(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_local_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
GOTOH_LOCAL_SCORE(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_local_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
GOTOH_LOCAL_SCORE(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_global_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
GOTOH_GLOBAL_ALIGN(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_global_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
GOTOH_GLOBAL_ALIGN(MATRIX_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_local_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
GOTOH_LOCAL_ALIGN(COMPARE_SCORE); | |
} | |
static PyObject* | |
Aligner_gotoh_local_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
GOTOH_LOCAL_ALIGN(MATRIX_SCORE); | |
} | |
static int | |
_call_query_gap_function(Aligner* aligner, int i, int j, double* score) | |
{ | |
double value; | |
PyObject* result; | |
PyObject* function = aligner->query_gap_function; | |
if (!function) | |
value = aligner->query_internal_open_gap_score | |
+ (j-1) * aligner->query_internal_extend_gap_score; | |
else { | |
result = PyObject_CallFunction(function, "ii", i, j); | |
if (result == NULL) return 0; | |
value = PyFloat_AsDouble(result); | |
Py_DECREF(result); | |
if (value == -1.0 && PyErr_Occurred()) return 0; | |
} | |
*score = value; | |
return 1; | |
} | |
static int | |
_call_target_gap_function(Aligner* aligner, int i, int j, double* score) | |
{ | |
double value; | |
PyObject* result; | |
PyObject* function = aligner->target_gap_function; | |
if (!function) | |
value = aligner->target_internal_open_gap_score | |
+ (j-1) * aligner->target_internal_extend_gap_score; | |
else { | |
result = PyObject_CallFunction(function, "ii", i, j); | |
if (result == NULL) return 0; | |
value = PyFloat_AsDouble(result); | |
Py_DECREF(result); | |
if (value == -1.0 && PyErr_Occurred()) return 0; | |
} | |
*score = value; | |
return 1; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_global_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
WATERMANSMITHBEYER_ENTER_SCORE; | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_GLOBAL_SCORE(COMPARE_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_GLOBAL_SCORE(COMPARE_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_SCORE; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_global_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
WATERMANSMITHBEYER_ENTER_SCORE; | |
switch (strand) { | |
case '+': | |
WATERMANSMITHBEYER_GLOBAL_SCORE(MATRIX_SCORE, j); | |
break; | |
case '-': | |
WATERMANSMITHBEYER_GLOBAL_SCORE(MATRIX_SCORE, nB-j); | |
break; | |
} | |
WATERMANSMITHBEYER_EXIT_SCORE; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_local_score_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
double maximum = 0.0; | |
WATERMANSMITHBEYER_ENTER_SCORE; | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_LOCAL_SCORE(COMPARE_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_LOCAL_SCORE(COMPARE_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_SCORE; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_local_score_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
double maximum = 0.0; | |
WATERMANSMITHBEYER_ENTER_SCORE; | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_LOCAL_SCORE(MATRIX_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_LOCAL_SCORE(MATRIX_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_SCORE; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_global_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
WATERMANSMITHBEYER_ENTER_ALIGN(Global); | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_GLOBAL_ALIGN(COMPARE_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_GLOBAL_ALIGN(COMPARE_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_ALIGN; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_global_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
WATERMANSMITHBEYER_ENTER_ALIGN(Global); | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_GLOBAL_ALIGN(MATRIX_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_GLOBAL_ALIGN(MATRIX_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_ALIGN; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_local_align_compare(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const double match = self->match; | |
const double mismatch = self->mismatch; | |
const int wildcard = self->wildcard; | |
int im = nA; | |
int jm = nB; | |
double maximum = 0; | |
WATERMANSMITHBEYER_ENTER_ALIGN(Local); | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_LOCAL_ALIGN(COMPARE_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_LOCAL_ALIGN(COMPARE_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_ALIGN; | |
} | |
static PyObject* | |
Aligner_watermansmithbeyer_local_align_matrix(Aligner* self, | |
const int* sA, int nA, | |
const int* sB, int nB, | |
unsigned char strand) | |
{ | |
const Py_ssize_t n = self->substitution_matrix.shape[0]; | |
const double* scores = self->substitution_matrix.buf; | |
int im = nA; | |
int jm = nB; | |
double maximum = 0; | |
WATERMANSMITHBEYER_ENTER_ALIGN(Local); | |
switch (strand) { | |
case '+': { | |
WATERMANSMITHBEYER_LOCAL_ALIGN(MATRIX_SCORE, j); | |
break; | |
} | |
case '-': { | |
WATERMANSMITHBEYER_LOCAL_ALIGN(MATRIX_SCORE, nB-j); | |
break; | |
} | |
} | |
WATERMANSMITHBEYER_EXIT_ALIGN; | |
} | |
static int* | |
convert_1bytes_to_ints(const int mapping[], Py_ssize_t n, const unsigned char s[]) | |
{ | |
unsigned char c; | |
Py_ssize_t i; | |
int index; | |
int* indices; | |
if (n == 0) { | |
PyErr_SetString(PyExc_ValueError, "sequence has zero length"); | |
return NULL; | |
} | |
indices = PyMem_Malloc(n*sizeof(int)); | |
if (!indices) { | |
PyErr_NoMemory(); | |
return NULL; | |
} | |
if (!mapping) for (i = 0; i < n; i++) indices[i] = s[i]; | |
else { | |
for (i = 0; i < n; i++) { | |
c = s[i]; | |
index = mapping[(int)c]; | |
if (index == MISSING_LETTER) { | |
PyErr_SetString(PyExc_ValueError, | |
"sequence contains letters not in the alphabet"); | |
PyMem_Free(indices); | |
return NULL; | |
} | |
indices[i] = index; | |
} | |
} | |
return indices; | |
} | |
static int* | |
convert_2bytes_to_ints(const int mapping[], Py_ssize_t n, const Py_UCS2 s[]) | |
{ | |
Py_UCS2 c; | |
Py_ssize_t i; | |
int index; | |
int* indices; | |
if (n == 0) { | |
PyErr_SetString(PyExc_ValueError, "sequence has zero length"); | |
return NULL; | |
} | |
indices = PyMem_Malloc(n*sizeof(int)); | |
if (!indices) { | |
PyErr_NoMemory(); | |
return NULL; | |
} | |
if (!mapping) for (i = 0; i < n; i++) indices[i] = s[i]; | |
else { | |
for (i = 0; i < n; i++) { | |
c = s[i]; | |
index = mapping[(int)c]; | |
if (index == MISSING_LETTER) { | |
PyErr_SetString(PyExc_ValueError, | |
"sequence contains letters not in the alphabet"); | |
PyMem_Free(indices); | |
return NULL; | |
} | |
indices[i] = index; | |
} | |
} | |
return indices; | |
} | |
static int* | |
convert_4bytes_to_ints(const int mapping[], Py_ssize_t n, const Py_UCS4 s[]) | |
{ | |
unsigned char c; | |
Py_ssize_t i; | |
int index; | |
int* indices; | |
if (n == 0) { | |
PyErr_SetString(PyExc_ValueError, "sequence has zero length"); | |
return NULL; | |
} | |
indices = PyMem_Malloc(n*sizeof(int)); | |
if (!indices) { | |
PyErr_NoMemory(); | |
return NULL; | |
} | |
if (!mapping) for (i = 0; i < n; i++) indices[i] = s[i]; | |
else { | |
for (i = 0; i < n; i++) { | |
c = s[i]; | |
index = mapping[(int)c]; | |
if (index == MISSING_LETTER) { | |
PyErr_SetString(PyExc_ValueError, | |
"sequence contains letters not in the alphabet"); | |
PyMem_Free(indices); | |
return NULL; | |
} | |
indices[i] = index; | |
} | |
} | |
return indices; | |
} | |
static int | |
convert_objects_to_ints(Py_buffer* view, PyObject* alphabet, PyObject* sequence) | |
{ | |
Py_ssize_t i, j; | |
Py_ssize_t n; | |
Py_ssize_t m; | |
int* indices = NULL; | |
PyObject *obj1, *obj2; | |
int equal; | |
view->buf = NULL; | |
sequence = PySequence_Fast(sequence, | |
"argument should support the sequence protocol"); | |
if (!sequence) return 0; | |
if (!alphabet) { | |
PyErr_SetString(PyExc_ValueError, | |
"alphabet is None; cannot interpret sequence"); | |
goto exit; | |
} | |
alphabet = PySequence_Fast(alphabet, NULL); /* should never fail */ | |
n = PySequence_Size(sequence); | |
m = PySequence_Size(alphabet); | |
if (m != (int)m) { | |
PyErr_SetString(PyExc_ValueError, "alphabet is too long"); | |
goto exit; | |
} | |
indices = PyMem_Malloc(n*sizeof(int)); | |
if (!indices) { | |
PyErr_NoMemory(); | |
goto exit; | |
} | |
for (i = 0; i < n; i++) { | |
obj1 = PySequence_Fast_GET_ITEM(sequence, i); | |
for (j = 0; j < m; j++) { | |
obj2 = PySequence_Fast_GET_ITEM(alphabet, j); | |
equal = PyObject_RichCompareBool(obj1, obj2, Py_EQ); | |
if (equal == 1) /* obj1 == obj2 */ { | |
indices[i] = (int)j; | |
break; | |
} | |
else if (equal == -1) /* error */ { | |
PyMem_Del(indices); | |
goto exit; | |
} | |
/* else (equal == 0) continue; */ /* not equal */ | |
} | |
if (j == m) { | |
PyErr_SetString(PyExc_ValueError, "failed to find object in alphabet"); | |
goto exit; | |
} | |
} | |
view->buf = indices; | |
view->itemsize = 1; | |
view->len = n; | |
exit: | |
Py_DECREF(sequence); | |
Py_XDECREF(alphabet); | |
if (view->buf) return 1; | |
return 0; | |
} | |
static int | |
sequence_converter(PyObject* argument, void* pointer) | |
{ | |
Py_buffer* view = pointer; | |
Py_ssize_t i; | |
Py_ssize_t n; | |
int index; | |
int* indices; | |
const int flag = PyBUF_FORMAT | PyBUF_C_CONTIGUOUS; | |
Aligner* aligner; | |
int* mapping; | |
if (argument == NULL) { | |
if (view->obj) PyBuffer_Release(view); | |
else { | |
indices = view->buf; | |
PyMem_Free(indices); | |
} | |
return 1; | |
} | |
aligner = (Aligner*)view->obj; | |
view->obj = NULL; | |
if (PyObject_GetBuffer(argument, view, flag) == 0) { | |
if (view->ndim != 1) { | |
PyErr_Format(PyExc_ValueError, | |
"sequence has incorrect rank (%d expected 1)", view->ndim); | |
return 0; | |
} | |
n = view->len / view->itemsize; | |
if (n == 0) { | |
PyErr_SetString(PyExc_ValueError, "sequence has zero length"); | |
return 0; | |
} | |
if (strcmp(view->format, "c") == 0 || strcmp(view->format, "B") == 0) { | |
if (view->itemsize != sizeof(char)) { | |
PyErr_Format(PyExc_ValueError, | |
"sequence has unexpected item byte size " | |
"(%ld, expected %ld)", view->itemsize, sizeof(char)); | |
return 0; | |
} | |
indices = convert_1bytes_to_ints(aligner->mapping, n, view->buf); | |
if (!indices) return 0; | |
PyBuffer_Release(view); | |
view->itemsize = 1; | |
view->len = n; | |
view->buf = indices; | |
return Py_CLEANUP_SUPPORTED; | |
} | |
if (strcmp(view->format, "i") == 0 || strcmp(view->format, "l") == 0) { | |
if (view->itemsize != sizeof(int)) { | |
PyErr_Format(PyExc_ValueError, | |
"sequence has unexpected item byte size " | |
"(%ld, expected %ld)", view->itemsize, sizeof(int)); | |
return 0; | |
} | |
indices = view->buf; | |
if (aligner->substitution_matrix.obj) { | |
const Py_ssize_t m = aligner->substitution_matrix.shape[0]; | |
for (i = 0; i < n; i++) { | |
index = indices[i]; | |
if (index < 0) { | |
PyErr_Format(PyExc_ValueError, | |
"sequence item %zd is negative (%d)", | |
i, index); | |
return 0; | |
} | |
if (index >= m) { | |
PyErr_Format(PyExc_ValueError, | |
"sequence item %zd is out of bound" | |
" (%d, should be < %zd)", i, index, m); | |
return 0; | |
} | |
} | |
} | |
return Py_CLEANUP_SUPPORTED; | |
} | |
PyErr_Format(PyExc_ValueError, | |
"sequence has incorrect data type '%s'", view->format); | |
return 0; | |
} | |
PyErr_Clear(); /* To clear the exception raised by PyObject_GetBuffer */ | |
mapping = aligner->mapping; | |
if (PyUnicode_Check(argument)) { | |
if (PyUnicode_READY(argument) == -1) return 0; | |
n = PyUnicode_GET_LENGTH(argument); | |
switch (PyUnicode_KIND(argument)) { | |
case PyUnicode_1BYTE_KIND: { | |
Py_UCS1* s = PyUnicode_1BYTE_DATA(argument); | |
indices = convert_1bytes_to_ints(mapping, n, (unsigned char*)s); | |
break; | |
} | |
case PyUnicode_2BYTE_KIND: { | |
Py_UCS2* s = PyUnicode_2BYTE_DATA(argument); | |
indices = convert_2bytes_to_ints(mapping, n, s); | |
break; | |
} | |
case PyUnicode_4BYTE_KIND: { | |
Py_UCS4* s = PyUnicode_4BYTE_DATA(argument); | |
indices = convert_4bytes_to_ints(mapping, n, s); | |
break; | |
} | |
default: | |
PyErr_SetString(PyExc_ValueError, "could not interpret unicode data"); | |
return 0; | |
} | |
if (!indices) return 0; | |
view->buf = indices; | |
view->itemsize = 1; | |
view->len = n; | |
return Py_CLEANUP_SUPPORTED; | |
} | |
if (!mapping) { | |
if (!convert_objects_to_ints(view, aligner->alphabet, argument)) return 0; | |
return Py_CLEANUP_SUPPORTED; | |
} | |
PyErr_SetString(PyExc_ValueError, "sequence has unexpected format"); | |
return 0; | |
} | |
static int | |
strand_converter(PyObject* argument, void* pointer) | |
{ | |
if (!PyUnicode_Check(argument)) goto error; | |
if (PyUnicode_READY(argument) == -1) return 0; | |
if (PyUnicode_GET_LENGTH(argument) == 1) { | |
const Py_UCS4 ch = PyUnicode_READ_CHAR(argument, 0); | |
if (ch < 128) { | |
const char c = ch; | |
if (ch == '+' || ch == '-') { | |
*((char*)pointer) = c; | |
return 1; | |
} | |
} | |
} | |
error: | |
PyErr_SetString(PyExc_ValueError, "strand must be '+' or '-'"); | |
return 0; | |
} | |
static const char Aligner_score__doc__[] = "calculates the alignment score"; | |
static PyObject* | |
Aligner_score(Aligner* self, PyObject* args, PyObject* keywords) | |
{ | |
const int* sA; | |
const int* sB; | |
int nA; | |
int nB; | |
Py_buffer bA = {0}; | |
Py_buffer bB = {0}; | |
const Mode mode = self->mode; | |
const Algorithm algorithm = _get_algorithm(self); | |
char strand = '+'; | |
PyObject* result = NULL; | |
PyObject* substitution_matrix = self->substitution_matrix.obj; | |
static char *kwlist[] = {"sequenceA", "sequenceB", "strand", NULL}; | |
bA.obj = (PyObject*)self; | |
bB.obj = (PyObject*)self; | |
if(!PyArg_ParseTupleAndKeywords(args, keywords, "O&O&O&", kwlist, | |
sequence_converter, &bA, | |
sequence_converter, &bB, | |
strand_converter, &strand)) | |
return NULL; | |
nA = (int) (bA.len / bA.itemsize); | |
nB = (int) (bB.len / bB.itemsize); | |
if (nA != bA.len / bA.itemsize || nB != bB.len / bB.itemsize) { | |
sequence_converter(NULL, &bA); | |
sequence_converter(NULL, &bB); | |
PyErr_SetString(PyExc_ValueError, "sequences too long"); | |
return 0; | |
} | |
sA = bA.buf; | |
sB = bB.buf; | |
switch (algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_needlemanwunsch_score_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_needlemanwunsch_score_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_smithwaterman_score_matrix(self, sA, nA, sB, nB); | |
else | |
result = Aligner_smithwaterman_score_compare(self, sA, nA, sB, nB); | |
break; | |
} | |
break; | |
case Gotoh: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_gotoh_global_score_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_gotoh_global_score_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_gotoh_local_score_matrix(self, sA, nA, sB, nB); | |
else | |
result = Aligner_gotoh_local_score_compare(self, sA, nA, sB, nB); | |
break; | |
} | |
break; | |
case WatermanSmithBeyer: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_watermansmithbeyer_global_score_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_watermansmithbeyer_global_score_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_watermansmithbeyer_local_score_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_watermansmithbeyer_local_score_compare(self, sA, nA, sB, nB, strand); | |
break; | |
} | |
break; | |
case Unknown: | |
default: | |
PyErr_SetString(PyExc_RuntimeError, "unknown algorithm"); | |
break; | |
} | |
sequence_converter(NULL, &bA); | |
sequence_converter(NULL, &bB); | |
return result; | |
} | |
static const char Aligner_align__doc__[] = "align two sequences"; | |
static PyObject* | |
Aligner_align(Aligner* self, PyObject* args, PyObject* keywords) | |
{ | |
const int* sA; | |
const int* sB; | |
int nA; | |
int nB; | |
Py_buffer bA = {0}; | |
Py_buffer bB = {0}; | |
const Mode mode = self->mode; | |
const Algorithm algorithm = _get_algorithm(self); | |
char strand = '+'; | |
PyObject* result = NULL; | |
PyObject* substitution_matrix = self->substitution_matrix.obj; | |
static char *kwlist[] = {"sequenceA", "sequenceB", "strand", NULL}; | |
bA.obj = (PyObject*)self; | |
bB.obj = (PyObject*)self; | |
if(!PyArg_ParseTupleAndKeywords(args, keywords, "O&O&O&", kwlist, | |
sequence_converter, &bA, | |
sequence_converter, &bB, | |
strand_converter, &strand)) | |
return NULL; | |
nA = (int) (bA.len / bA.itemsize); | |
nB = (int) (bB.len / bB.itemsize); | |
if (nA != bA.len / bA.itemsize || nB != bB.len / bB.itemsize) { | |
sequence_converter(NULL, &bA); | |
sequence_converter(NULL, &bB); | |
PyErr_SetString(PyExc_ValueError, "sequences too long"); | |
return 0; | |
} | |
sA = bA.buf; | |
sB = bB.buf; | |
switch (algorithm) { | |
case NeedlemanWunschSmithWaterman: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_needlemanwunsch_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_needlemanwunsch_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_smithwaterman_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_smithwaterman_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
} | |
break; | |
case Gotoh: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_gotoh_global_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_gotoh_global_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_gotoh_local_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_gotoh_local_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
} | |
break; | |
case WatermanSmithBeyer: | |
switch (mode) { | |
case Global: | |
if (substitution_matrix) | |
result = Aligner_watermansmithbeyer_global_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_watermansmithbeyer_global_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
case Local: | |
if (substitution_matrix) | |
result = Aligner_watermansmithbeyer_local_align_matrix(self, sA, nA, sB, nB, strand); | |
else | |
result = Aligner_watermansmithbeyer_local_align_compare(self, sA, nA, sB, nB, strand); | |
break; | |
} | |
break; | |
case Unknown: | |
default: | |
PyErr_SetString(PyExc_RuntimeError, "unknown algorithm"); | |
break; | |
} | |
sequence_converter(NULL, &bA); | |
sequence_converter(NULL, &bB); | |
return result; | |
} | |
static char Aligner_doc[] = | |
"Aligner.\n"; | |
static PyMethodDef Aligner_methods[] = { | |
{"score", | |
(PyCFunction)Aligner_score, | |
METH_VARARGS | METH_KEYWORDS, | |
Aligner_score__doc__ | |
}, | |
{"align", | |
(PyCFunction)Aligner_align, | |
METH_VARARGS | METH_KEYWORDS, | |
Aligner_align__doc__ | |
}, | |
{NULL} /* Sentinel */ | |
}; | |
static PyTypeObject AlignerType = { | |
PyVarObject_HEAD_INIT(NULL, 0) | |
"_algorithms.PairwiseAligner", /* tp_name */ | |
sizeof(Aligner), /* tp_basicsize */ | |
0, /* tp_itemsize */ | |
(destructor)Aligner_dealloc, /* tp_dealloc */ | |
0, /* tp_print */ | |
0, /* tp_getattr */ | |
0, /* tp_setattr */ | |
0, /* tp_compare */ | |
(reprfunc)Aligner_repr, /* tp_repr */ | |
0, /* tp_as_number */ | |
0, /* tp_as_sequence */ | |
0, /* tp_as_mapping */ | |
0, /* tp_hash */ | |
0, /* tp_call */ | |
(reprfunc)Aligner_str, /* tp_str */ | |
0, /* tp_getattro */ | |
0, /* tp_setattro */ | |
0, /* tp_as_buffer */ | |
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ | |
Aligner_doc, /* tp_doc */ | |
0, /* tp_traverse */ | |
0, /* tp_clear */ | |
0, /* tp_richcompare */ | |
0, /* tp_weaklistoffset */ | |
0, /* tp_iter */ | |
0, /* tp_iternext */ | |
Aligner_methods, /* tp_methods */ | |
0, /* tp_members */ | |
Aligner_getset, /* tp_getset */ | |
0, /* tp_base */ | |
0, /* tp_dict */ | |
0, /* tp_descr_get */ | |
0, /* tp_descr_set */ | |
0, /* tp_dictoffset */ | |
(initproc)Aligner_init, /* tp_init */ | |
}; | |
/* Module definition */ | |
static char _aligners__doc__[] = | |
"C extension module implementing pairwise alignment algorithms"; | |
static struct PyModuleDef moduledef = { | |
PyModuleDef_HEAD_INIT, | |
"_aligners", | |
_aligners__doc__, | |
-1, | |
NULL, | |
NULL, | |
NULL, | |
NULL, | |
NULL | |
}; | |
PyObject * | |
PyInit__aligners(void) | |
{ | |
PyObject* module; | |
AlignerType.tp_new = PyType_GenericNew; | |
if (PyType_Ready(&AlignerType) < 0 || PyType_Ready(&PathGenerator_Type) < 0) | |
return NULL; | |
module = PyModule_Create(&moduledef); | |
if (!module) return NULL; | |
Py_INCREF(&AlignerType); | |
/* Reference to AlignerType will be stolen by PyModule_AddObject | |
* only if it is successful. */ | |
if (PyModule_AddObject(module, | |
"PairwiseAligner", (PyObject*) &AlignerType) < 0) { | |
Py_DECREF(&AlignerType); | |
Py_DECREF(module); | |
return NULL; | |
} | |
return module; | |
} | |