| 938 | } |
| 939 | |
| 940 | static int NeedlemanWunsch_init(NeedlemanWunsch *self, PyObject *args, PyObject *kwargs) { |
| 941 | PyObject *substitution_matrix_obj = NULL; |
| 942 | sz_error_cost_t open = -1, extend = -1; |
| 943 | PyObject *capabilities_tuple = NULL; |
| 944 | sz_capability_t capabilities = default_hardware_capabilities; |
| 945 | |
| 946 | // Parse arguments: substitution_matrix, open, extend, capabilities |
| 947 | static char *kwlist[] = {"substitution_matrix", "open", "extend", "capabilities", NULL}; |
| 948 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iiO", kwlist, &substitution_matrix_obj, &open, &extend, |
| 949 | &capabilities_tuple)) |
| 950 | return -1; |
| 951 | |
| 952 | // Validate substitution matrix (should be a 256x256 numpy array) |
| 953 | if (!numpy_available || !PyArray_Check(substitution_matrix_obj)) { |
| 954 | PyErr_SetString(PyExc_TypeError, "substitution_matrix must be a NumPy array"); |
| 955 | return -1; |
| 956 | } |
| 957 | |
| 958 | PyArrayObject *subs_array = (PyArrayObject *)substitution_matrix_obj; |
| 959 | if (PyArray_NDIM(subs_array) != 2 || PyArray_DIM(subs_array, 0) != 256 || PyArray_DIM(subs_array, 1) != 256) { |
| 960 | PyErr_SetString(PyExc_ValueError, "substitution_matrix must be a 256x256 array"); |
| 961 | return -1; |
| 962 | } |
| 963 | |
| 964 | if (PyArray_TYPE(subs_array) != NPY_INT8) { |
| 965 | PyErr_SetString(PyExc_TypeError, "substitution_matrix must have int8 dtype"); |
| 966 | return -1; |
| 967 | } |
| 968 | |
| 969 | // Check that array is C-contiguous for safe memory access |
| 970 | if (!PyArray_IS_C_CONTIGUOUS(subs_array)) { |
| 971 | PyErr_SetString(PyExc_ValueError, |
| 972 | "substitution_matrix must be a C-contiguous array. Use np.ascontiguousarray() to convert."); |
| 973 | return -1; |
| 974 | } |
| 975 | |
| 976 | // Parse capabilities if provided |
| 977 | if (capabilities_tuple) { |
| 978 | if (parse_and_intersect_capabilities(capabilities_tuple, &capabilities) != 0) { return -1; } |
| 979 | } |
| 980 | |
| 981 | // Initialize the engine |
| 982 | sz_error_cost_t *subs_data = (sz_error_cost_t *)PyArray_DATA(subs_array); |
| 983 | |
| 984 | // Create a simple checksum of the substitution matrix for the description |
| 985 | sz_u32_t subs_checksum = 0; |
| 986 | for (int i = 0; i < 256; i += 16) // Sample every 16th element |
| 987 | subs_checksum += (sz_u32_t)subs_data[i * 256 + i]; // Diagonal elements |
| 988 | |
| 989 | char const *error_detail = NULL; |
| 990 | sz_status_t status = |
| 991 | szs_needleman_wunsch_scores_init(subs_data, open, extend, NULL, capabilities, &self->handle, &error_detail); |
| 992 | if (status != sz_success_k) { |
| 993 | set_stringzilla_error(status, error_detail, "NeedlemanWunsch initialization"); |
| 994 | return -1; |
| 995 | } |
| 996 | |
| 997 | snprintf(self->description, sizeof(self->description), "%X,%d,%d", subs_checksum & 0xFFFF, open, extend); |
nothing calls this directly
no test coverage detected
searching dependent graphs…