Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}