struct sr_distances * sr_distances_dup(struct sr_distances *distances) { struct sr_distances *dup_distances; dup_distances = sr_distances_new(distances->m, distances->n); memcpy(dup_distances->distances, distances->distances, sizeof(*distances->distances) * (get_distance_position(distances, distances->m - 1, distances->n - 1) + 1)); return dup_distances; }
/* constructor */ PyObject * sr_py_distances_new(PyTypeObject *object, PyObject *args, PyObject *kwds) { struct sr_py_distances *o = (struct sr_py_distances*) PyObject_New(struct sr_py_distances, &sr_py_distances_type); if (!o) return PyErr_NoMemory(); PyObject *thread_list; int m, n; int dist_type = SR_DISTANCE_LEVENSHTEIN; static const char *kwlist[] = { "threads", "m", "dist_type", NULL }; if (PyArg_ParseTupleAndKeywords(args, kwds, "O!i|i", (char **)kwlist, &PyList_Type, &thread_list, &m, &dist_type)) { n = PyList_Size(thread_list); struct sr_thread *threads[n]; if (!validate_distance_params(m, n, dist_type)) return NULL; if (!prepare_thread_array(thread_list, threads, n)) return NULL; o->distances = sr_threads_compare(threads, m, n, dist_type); } else if (PyArg_ParseTuple(args, "ii", &m, &n)) { PyErr_Clear(); if (m < 1 || n < 2) { PyErr_SetString(PyExc_ValueError, "Distance matrix must have at least 1 row and 2 columns"); return NULL; } o->distances = sr_distances_new(m, n); } else return NULL; return (PyObject *)o; }
struct sr_distances * sr_threads_compare(struct sr_thread **threads, int m, int n, enum sr_distance_type dist_type) { struct sr_distances *distances; int i, j; float dist; distances = sr_distances_new(m, n); if (n <= 0) return distances; /* Check that all threads are of the same type */ enum sr_report_type type, prev_type = threads[0]->type; for (i = 0; i < n; i++) { type = threads[i]->type; assert(prev_type == type); prev_type = type; } for (i = 0; i < m; i++) { for (j = i + 1; j < n; j++) { /* XXX: GDB crashes have a special normalization step for * clustering. If there's something similar for other types, we can * generalize it -- meanwhile there's a separate case for GDB here */ if (type == SR_REPORT_GDB) { struct sr_gdb_thread *thread1 = (struct sr_gdb_thread*)threads[i], *thread2 = (struct sr_gdb_thread*)threads[j]; int ok = 0, all = 0; sr_gdb_thread_quality_counts(thread1, &ok, &all); sr_gdb_thread_quality_counts(thread2, &ok, &all); if (ok != all) { /* There are some unknown function names, try to pair them, but * the threads need to be copied first. */ thread1 = sr_gdb_thread_dup(thread1, false); thread2 = sr_gdb_thread_dup(thread2, false); sr_normalize_gdb_paired_unknown_function_names(thread1, thread2); } dist = sr_distance(dist_type, (struct sr_thread*)thread1, (struct sr_thread*)thread2); if (ok != all) { sr_gdb_thread_free(thread1); sr_gdb_thread_free(thread2); } } else dist = sr_distance(dist_type, threads[i], threads[j]); distances->distances[get_distance_position(distances, i, j)] = dist; } } return distances; }