void QuadTree_delete(QuadTree q){ int i, dim; if (!q) return; dim = q->dim; FREE(q->center); FREE(q->average); if (q->data) FREE(q->data); if (q->qts){ for (i = 0; i < 1<<dim; i++){ QuadTree_delete(q->qts[i]); } FREE(q->qts); } SingleLinkedList_delete(q->l, node_data_delete); FREE(q); }
static QuadTree QuadTree_add_internal(QuadTree q, real *coord, real weight, int id, int level){ int i, dim = q->dim, ii; node_data nd = NULL; int max_level = q->max_level; int idd; /* Make sure that coord is within bounding box */ for (i = 0; i < q->dim; i++) { if (coord[i] < q->center[i] - q->width - 1.e5*MACHINEACC*q->width || coord[i] > q->center[i] + q->width + 1.e5*MACHINEACC*q->width) { #ifdef DEBUG_PRINT fprintf(stderr,"coordinate %f is outside of the box:{%f, %f}, \n(q->center[i] - q->width) - coord[i] =%g, coord[i]-(q->center[i] + q->width) = %g\n",coord[i], (q->center[i] - q->width), (q->center[i] + q->width), (q->center[i] - q->width) - coord[i], coord[i]-(q->center[i] + q->width)); #endif //return NULL; } } if (q->n == 0){ /* if this node is empty right now */ q->n = 1; q->total_weight = weight; q->average = MALLOC(sizeof(real)*dim); for (i = 0; i < q->dim; i++) q->average[i] = coord[i]; nd = node_data_new(q->dim, weight, coord, id); assert(!(q->l)); q->l = SingleLinkedList_new(nd); } else if (level < max_level){ /* otherwise open up into 2^dim quadtrees unless the level is too high */ q->total_weight += weight; for (i = 0; i < q->dim; i++) q->average[i] = ((q->average[i])*q->n + coord[i])/(q->n + 1); if (!q->qts){ q->qts = MALLOC(sizeof(QuadTree)*(1<<dim)); for (i = 0; i < 1<<dim; i++) q->qts[i] = NULL; }/* done adding new quadtree, now add points to them */ /* insert the old node (if exist) and the current node into the appropriate child quadtree */ ii = QuadTree_get_quadrant(dim, q->center, coord); assert(ii < 1<<dim && ii >= 0); if (q->qts[ii] == NULL) q->qts[ii] = QuadTree_new_in_quadrant(q->dim, q->center, (q->width)/2, max_level, ii); q->qts[ii] = QuadTree_add_internal(q->qts[ii], coord, weight, id, level + 1); assert(q->qts[ii]); if (q->l){ idd = node_data_get_id(SingleLinkedList_get_data(q->l)); assert(q->n == 1); coord = node_data_get_coord(SingleLinkedList_get_data(q->l)); weight = node_data_get_weight(SingleLinkedList_get_data(q->l)); ii = QuadTree_get_quadrant(dim, q->center, coord); assert(ii < 1<<dim && ii >= 0); if (q->qts[ii] == NULL) q->qts[ii] = QuadTree_new_in_quadrant(q->dim, q->center, (q->width)/2, max_level, ii); q->qts[ii] = QuadTree_add_internal(q->qts[ii], coord, weight, idd, level + 1); assert(q->qts[ii]); /* delete the old node data on parent */ SingleLinkedList_delete(q->l, node_data_delete); q->l = NULL; } (q->n)++; } else { assert(!(q->qts)); /* level is too high, append data in the linked list */ (q->n)++; q->total_weight += weight; for (i = 0; i < q->dim; i++) q->average[i] = ((q->average[i])*q->n + coord[i])/(q->n + 1); nd = node_data_new(q->dim, weight, coord, id); assert(q->l); q->l = SingleLinkedList_prepend(q->l, nd); } return q; }
Multilevel_MQ_Clustering Multilevel_MQ_Clustering_establish(Multilevel_MQ_Clustering grid, int maxcluster) { int *matching = grid->matching; SparseMatrix A = grid->A; int n = grid->n, level = grid->level, nc = 0, nclusters = n; real mq = 0, mq_in = 0, mq_out = 0, mq_new, mq_in_new, mq_out_new, mq_max = 0, mq_in_max = 0, mq_out_max = 0; int *ia = A->ia, *ja = A->ja; real *a, amax = 0; real *deg_intra = grid->deg_intra, *wgt = grid->wgt; real *deg_intra_new, *wgt_new = NULL; int i, j, k, jj, jc, jmax; real *deg_inter, gain = 0, *dout = grid->dout, *dout_new, deg_in_i, deg_in_j, wgt_i, wgt_j, a_ij, dout_i, dout_j, dout_max = 0, wgt_jmax = 0; int *mask; real maxgain = 0; real total_gain = 0; SingleLinkedList *neighbors = NULL, lst; neighbors = MALLOC(sizeof(SingleLinkedList)*n); for (i = 0; i < n; i++) neighbors[i] = NULL; mq = grid->mq; mq_in = grid->mq_in; mq_out = grid->mq_out; deg_intra_new = MALLOC(sizeof(real)*n); wgt_new = MALLOC(sizeof(real)*n); deg_inter = MALLOC(sizeof(real)*n); mask = MALLOC(sizeof(int)*n); dout_new = MALLOC(sizeof(real)*n); for (i = 0; i < n; i++) mask[i] = -1; assert(n == A->n); for (i = 0; i < n; i++) matching[i] = UNMATCHED; /* gain in merging node A into cluster B is mq_in_new = mq_in - |E(A,A)|/(V(A))^2 - |E(B,B)|/(V(B))^2 + (|E(A,A)|+|E(B,B)|+|E(A,B)|)/(|V(A)|+|V(B)|)^2 . = mq_in - deg_intra(A)/|A|^2 - deg_intra(B)/|B|^2 + (deg_intra(A)+deg_intra(B)+a(A,B))/(|A|+|B|)^2 mq_out_new = mq_out - |E(A,B)|/(|V(A)|*V(B)|)-\sum_{C and A connected, C!=B} |E(A,C)|/(|V(A)|*|V(C)|)-\sum_{C and B connected,C!=B} |E(B,C)|/(|V(B)|*|V(C)|) . + \sum_{C connected to A or B, C!=A, C!=B} (|E(A,C)|+|E(B,C)|)/(|V(C)|*(|V(A)|+|V(B)|) . = mq_out + a(A,B)/(|A|*|B|)-\sum_{C and A connected} a(A,C)/(|A|*|C|)-\sum_{C and B connected} a(B,C)/(|B|*|C|) . + \sum_{C connected to A or B, C!=A, C!=B} (a(A,C)+a(B,C))/(|C|*(|A|+|B|)) Denote: dout(i) = \sum_{j -- i} a(i,j)/|j| then mq_out_new = mq_out - |E(A,B)|/(|V(A)|*V(B)|)-\sum_{C and A connected, C!=B} |E(A,C)|/(|V(A)|*|V(C)|)-\sum_{C and B connected,C!=B} |E(B,C)|/(|V(B)|*|V(C)|) . + \sum_{C connected to A or B, C!=A, C!=B} (|E(A,C)|+|E(B,C)|)/(|V(C)|*(|V(A)|+|V(B)|) . = mq_out + a(A,B)/(|A|*|B|)-dout(A)/|A| - dout(B)/|B| . + (dout(A)+dout(B))/(|A|+|B|) - (a(A,B)/|A|+a(A,B)/|B|)/(|A|+|B|) . = mq_out -dout(A)/|A| - dout(B)/|B| + (dout(A)+dout(B))/(|A|+|B|) after merging A and B into cluster AB, dout(AB) = dout(A) + dout(B); dout(C) := dout(C) - a(A,C)/|A| - a(B,C)/|B| + a(A,C)/(|A|+|B|) + a(B, C)/(|A|+|B|) mq_new = mq_in_new/(k-1) - mq_out_new/((k-1)*(k-2)) gain = mq_new - mq */ a = (real*) A->a; for (i = 0; i < n; i++) { if (matching[i] != UNMATCHED) continue; /* accumulate connections between i and clusters */ for (j = ia[i]; j < ia[i+1]; j++) { jj = ja[j]; if (jj == i) continue; if ((jc=matching[jj]) != UNMATCHED) { if (mask[jc] != i) { mask[jc] = i; deg_inter[jc] = a[j]; } else { deg_inter[jc] += a[j]; } } } deg_in_i = deg_intra[i]; wgt_i = wgt[i]; dout_i = dout[i]; maxgain = 0; jmax = -1; for (j = ia[i]; j < ia[i+1]; j++) { jj = ja[j]; if (jj == i) continue; jc = matching[jj]; if (jc == UNMATCHED) { a_ij = a[j]; wgt_j = wgt[jj]; deg_in_j = deg_intra[jj]; dout_j = dout[jj]; } else if (deg_inter[jc] < 0) { continue; } else { a_ij = deg_inter[jc]; wgt_j = wgt_new[jc]; deg_inter[jc] = -1; /* so that we do not redo the calulation when we hit another neighbor in cluster jc */ deg_in_j = deg_intra_new[jc]; dout_j = dout_new[jc]; } mq_in_new = mq_in - deg_in_i/pow(wgt_i, 2) - deg_in_j/pow(wgt_j,2) + (deg_in_i + deg_in_j + a_ij)/pow(wgt_i + wgt_j,2); mq_out_new = mq_out - dout_i/wgt_i - dout_j/wgt_j + (dout_i + dout_j)/(wgt_i + wgt_j); if (nclusters > 2) { mq_new = 2*(mq_in_new/(nclusters - 1) - mq_out_new/((nclusters - 1)*(nclusters - 2))); } else { mq_new = 2*mq_in_new/(nclusters - 1); } #ifdef DEBUG { int ncluster; double mq2, mq_in2, mq_out2, *dout2; int *matching2, nc2 = nc; matching2 = MALLOC(sizeof(int)*A->m); matching2 = MEMCPY(matching2, matching, sizeof(real)*A->m); if (jc != UNMATCHED) { matching2[i] = jc; } else { matching2[i] = nc2; matching2[jj] = nc2; nc2++; } for (k = 0; k < n; k++) if (matching2[k] == UNMATCHED) matching2[k] =nc2++; mq2 = get_mq(A, matching2, &ncluster, &mq_in2, &mq_out2, &dout2); fprintf(stderr," {dout_i, dout_j}={%f,%f}, {predicted, calculated}: mq = {%f, %f}, mq_in ={%f,%f}, mq_out = {%f,%f}\n",dout_i, dout_j, mq_new, mq2, mq_in_new, mq_in2, mq_out_new, mq_out2); mq_new = mq2; } #endif gain = mq_new - mq; if (Verbose) fprintf(stderr,"gain in merging node %d with node %d = %f-%f = %f\n", i, jj, mq, mq_new, gain); if (j == ia[i] || gain > maxgain) { maxgain = gain; jmax = jj; amax = a_ij; dout_max = dout_j; wgt_jmax = wgt_j; mq_max = mq_new; mq_in_max = mq_in_new; mq_out_max = mq_out_new; } } /* now merge i and jmax */ if (maxgain > 0 || (nc >= 1 && nc > maxcluster)) { total_gain += maxgain; jc = matching[jmax]; if (jc == UNMATCHED) { fprintf(stderr, "maxgain=%f, merge %d, %d\n",maxgain, i, jmax); neighbors[nc] = SingleLinkedList_new_int(jmax); neighbors[nc] = SingleLinkedList_prepend_int(neighbors[nc], i); dout_new[nc] = dout_i + dout_max; matching[i] = matching[jmax] = nc; wgt_new[nc] = wgt[i] + wgt[jmax]; deg_intra_new[nc] = deg_intra[i] + deg_intra[jmax] + amax; nc++; } else { fprintf(stderr,"maxgain=%f, merge with existing cluster %d, %d\n",maxgain, i, jc); neighbors[jc] = SingleLinkedList_prepend_int(neighbors[jc], i); dout_new[jc] = dout_i + dout_max; wgt_new[jc] += wgt[i]; matching[i] = jc; deg_intra_new[jc] += deg_intra[i] + amax; } mq = mq_max; mq_in = mq_in_max; mq_out = mq_out_max; nclusters--; } else { fprintf(stderr,"gain: %f -- no gain, skip merging node %d\n", maxgain, i); assert(maxgain <= 0); neighbors[nc] = SingleLinkedList_new_int(i); matching[i] = nc; deg_intra_new[nc] = deg_intra[i]; wgt_new[nc] = wgt[i]; nc++; } /* update scaled outdegree of neighbors of i and its merged node/cluster jmax */ jc = matching[i]; lst = neighbors[jc]; do { mask[*((int*) SingleLinkedList_get_data(lst))] = n+i; lst = SingleLinkedList_get_next(lst); } while (lst); lst = neighbors[jc]; do { k = *((int*) SingleLinkedList_get_data(lst)); for (j = ia[k]; j < ia[k+1]; j++) { jj = ja[j]; if (mask[jj] == n+i) continue;/* link to within cluster */ if ((jc = matching[jj]) == UNMATCHED) { if (k == i) { dout[jj] += -a[j]/wgt_i + a[j]/(wgt_i + wgt_jmax); } else { dout[jj] += -a[j]/wgt_jmax + a[j]/(wgt_i + wgt_jmax); } } else { if (k == i) { dout_new[jc] += -a[j]/wgt_i + a[j]/(wgt_i + wgt_jmax); } else { dout_new[jc] += -a[j]/wgt_jmax + a[j]/(wgt_i + wgt_jmax); } } } lst = SingleLinkedList_get_next(lst); } while (lst); } fprintf(stderr,"verbose=%d\n",Verbose); if (Verbose) fprintf(stderr,"mq = %f new mq = %f level = %d, n = %d, nc = %d, gain = %g, mq_in = %f, mq_out = %f\n", mq, mq + total_gain, level, n, nc, total_gain, mq_in, mq_out); #ifdef DEBUG { int ncluster; mq = get_mq(A, matching, &ncluster, &mq_in, &mq_out, &dout); fprintf(stderr," mq = %f\n",mq); } #endif if (nc >= 1 && (total_gain > 0 || nc < n)) { /* now set up restriction and prolongation operator */ SparseMatrix P, R, R0, B, cA; real one = 1.; Multilevel_MQ_Clustering cgrid; R0 = SparseMatrix_new(nc, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); for (i = 0; i < n; i++) { jj = matching[i]; SparseMatrix_coordinate_form_add_entries(R0, 1, &jj, &i, &one); } R = SparseMatrix_from_coordinate_format(R0); SparseMatrix_delete(R0); P = SparseMatrix_transpose(R); B = SparseMatrix_multiply(R, A); if (!B) goto RETURN; cA = SparseMatrix_multiply(B, P); if (!cA) goto RETURN; SparseMatrix_delete(B); grid->P = P; grid->R = R; level++; cgrid = Multilevel_MQ_Clustering_init(cA, level); deg_intra_new = REALLOC(deg_intra_new, nc*sizeof(real)); wgt_new = REALLOC(wgt_new, nc*sizeof(real)); cgrid->deg_intra = deg_intra_new; cgrid->mq = grid->mq + total_gain; cgrid->wgt = wgt_new; dout_new = REALLOC(dout_new, nc*sizeof(real)); cgrid->dout = dout_new; cgrid = Multilevel_MQ_Clustering_establish(cgrid, maxcluster); grid->next = cgrid; cgrid->prev = grid; } else { /* no more improvement, stop and final clustering found */ for (i = 0; i < n; i++) matching[i] = i; FREE(deg_intra_new); FREE(wgt_new); FREE(dout_new); } RETURN: for (i = 0; i < n; i++) SingleLinkedList_delete(neighbors[i], free); FREE(neighbors); FREE(deg_inter); FREE(mask); return grid; }