/* quicksort_place: * For now, we keep the current implementation for stability, but * we should consider replacing this with an implementation similar to * quicksort_placef above. */ void quicksort_place(double *place, int *ordering, int first, int last) { if (first < last) { int middle; #ifdef __cplusplus split_by_place(place, ordering, first, last, middle); #else split_by_place(place, ordering, first, last, &middle); #endif quicksort_place(place, ordering, first, middle - 1); quicksort_place(place, ordering, middle + 1, last); } }
static void rescaleLayout(v_data * graph, int n, double *x_coords, double *y_coords, int interval, double distortion) { // Rectlinear distortion - auxiliary function int i; double *densities = NULL, *smoothed_densities = NULL; double *copy_coords = N_NEW(n, double); int *ordering = N_NEW(n, int); double factor; //compute_densities(graph, n, x_coords, y_coords, densities); for (i = 0; i < n; i++) { ordering[i] = i; } // just to make milder behavior: if (distortion >= 0) { factor = sqrt(distortion); } else { factor = -sqrt(-distortion); } quicksort_place(x_coords, ordering, 0, n - 1); densities = recompute_densities(graph, n, x_coords, densities); smoothed_densities = smooth_vec(densities, ordering, n, interval, smoothed_densities); cpvec(copy_coords, 0, n - 1, x_coords); for (i = 1; i < n; i++) { x_coords[ordering[i]] = x_coords[ordering[i - 1]] + (copy_coords[ordering[i]] - copy_coords[ordering[i - 1]]) / pow(smoothed_densities[ordering[i]], factor); } quicksort_place(y_coords, ordering, 0, n - 1); densities = recompute_densities(graph, n, y_coords, densities); smoothed_densities = smooth_vec(densities, ordering, n, interval, smoothed_densities); cpvec(copy_coords, 0, n - 1, y_coords); for (i = 1; i < n; i++) { y_coords[ordering[i]] = y_coords[ordering[i - 1]] + (copy_coords[ordering[i]] - copy_coords[ordering[i - 1]]) / pow(smoothed_densities[ordering[i]], factor); } free(densities); free(smoothed_densities); free(copy_coords); free(ordering); }
void quicksort_place(double *place, int *ordering, int first, int last) { if (first < last) { int middle = split_by_place(place, ordering, first, last); /* Checking for "already sorted" dramatically improves running time * and robustness (against uneven recursion) when not all values are * distinct (thefore we expect emerging chunks of equal values) * it never increased running time even when values were distinct */ if (!sorted_place(place,ordering,first,middle-1)) quicksort_place(place,ordering,first,middle-1); if (!sorted_place(place,ordering,middle+1,last)) quicksort_place(place,ordering,middle+1,last); } }
static void find_closest_pairs(double *place, int n, int num_pairs, PairStack * pairs_stack) { /* Fill the stack 'pairs_stack' with 'num_pairs' closest pairs int the 1-D layout 'place' */ int i; PairHeap heap; int *left = N_GNEW(n, int); int *right = N_GNEW(n, int); Pair pair = { 0, 0 }, new_pair; /* Order the nodes according to their place */ int *ordering = N_GNEW(n, int); int *inv_ordering = N_GNEW(n, int); for (i = 0; i < n; i++) { ordering[i] = i; } quicksort_place(place, ordering, 0, n - 1); for (i = 0; i < n; i++) { inv_ordering[ordering[i]] = i; } /* Intialize heap with all consecutive pairs */ initHeap(&heap, place, ordering, n); /* store the leftmost and rightmost neighbors of each node that were entered into heap */ for (i = 1; i < n; i++) { left[ordering[i]] = ordering[i - 1]; } for (i = 0; i < n - 1; i++) { right[ordering[i]] = ordering[i + 1]; } /* extract the 'num_pairs' closest pairs */ for (i = 0; i < num_pairs; i++) { int left_index; int right_index; int neighbor; if (!extractMax(&heap, &pair)) { break; /* not enough pairs */ } push(pairs_stack, pair); /* insert to heap "descendant" pairs */ left_index = inv_ordering[pair.left]; right_index = inv_ordering[pair.right]; if (left_index > 0) { neighbor = ordering[left_index - 1]; if (inv_ordering[right[neighbor]] < right_index) { /* we have a new pair */ new_pair.left = neighbor; new_pair.right = pair.right; new_pair.dist = place[pair.right] - place[neighbor]; insert(&heap, new_pair); right[neighbor] = pair.right; left[pair.right] = neighbor; } } if (right_index < n - 1) { neighbor = ordering[right_index + 1]; if (inv_ordering[left[neighbor]] > left_index) { /* we have a new pair */ new_pair.left = pair.left; new_pair.right = neighbor; new_pair.dist = place[neighbor] - place[pair.left]; insert(&heap, new_pair); left[neighbor] = pair.left; right[pair.left] = neighbor; } } } free(left); free(right); free(ordering); free(inv_ordering); freeHeap(&heap); }
static void rescale_layout_polarFocus(v_data * graph, int n, double *x_coords, double *y_coords, double x_focus, double y_focus, int interval, double distortion) { // Polar distortion - auxiliary function int i; double *densities = NULL, *smoothed_densities = NULL; double *distances = N_NEW(n, double); double *orig_distances = N_NEW(n, double); int *ordering; double ratio; for (i = 0; i < n; i++) { distances[i] = DIST(x_coords[i], y_coords[i], x_focus, y_focus); } cpvec(orig_distances, 0, n - 1, distances); ordering = N_NEW(n, int); for (i = 0; i < n; i++) { ordering[i] = i; } quicksort_place(distances, ordering, 0, n - 1); densities = compute_densities(graph, n, x_coords, y_coords); smoothed_densities = smooth_vec(densities, ordering, n, interval, smoothed_densities); // rescale distances if (distortion < 1.01 && distortion > 0.99) { for (i = 1; i < n; i++) { distances[ordering[i]] = distances[ordering[i - 1]] + (orig_distances[ordering[i]] - orig_distances[ordering [i - 1]]) / smoothed_densities[ordering[i]]; } } else { double factor; // just to make milder behavior: if (distortion >= 0) { factor = sqrt(distortion); } else { factor = -sqrt(-distortion); } for (i = 1; i < n; i++) { distances[ordering[i]] = distances[ordering[i - 1]] + (orig_distances[ordering[i]] - orig_distances[ordering [i - 1]]) / pow(smoothed_densities[ordering[i]], factor); } } // compute new coordinate: for (i = 0; i < n; i++) { if (orig_distances[i] == 0) { ratio = 0; } else { ratio = distances[i] / orig_distances[i]; } x_coords[i] = x_focus + (x_coords[i] - x_focus) * ratio; y_coords[i] = y_focus + (y_coords[i] - y_focus) * ratio; } free(densities); free(smoothed_densities); free(distances); free(orig_distances); free(ordering); }
static int maxmatch(v_data * graph, /* array of vtx data for graph */ ex_vtx_data * geom_graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int *mflag, /* flag indicating vtx selected or not */ int dist2_limit ) /* Compute a matching of the nodes set. The matching is not based only on the edge list of 'graph', which might be too small, but on the wider edge list of 'geom_graph' (which includes 'graph''s edges) We match nodes that are close both in the graph-theoretical sense and in the geometry sense (in the layout) */ { int *order; /* random ordering of vertices */ int *iptr, *jptr; /* loops through integer arrays */ int vtx; /* vertex to process next */ int neighbor; /* neighbor of a vertex */ int nmerged = 0; /* number of edges in matching */ int i, j; /* loop counters */ float max_norm_edge_weight; double inv_size; double *matchability = N_NEW(nvtxs, double); double min_edge_len; double closest_val = -1, val; int closest_neighbor; float *vtx_vec = N_NEW(nvtxs, float); float *weighted_vtx_vec = N_NEW(nvtxs, float); float sum_weights; // gather statistics, to enable normalizing the values double avg_edge_len = 0, avg_deg_2 = 0; int nedges = 0; for (i = 0; i < nvtxs; i++) { avg_deg_2 += graph[i].nedges; for (j = 1; j < graph[i].nedges; j++) { avg_edge_len += ddist(geom_graph, i, graph[i].edges[j]); nedges++; } } avg_edge_len /= nedges; avg_deg_2 /= nvtxs; avg_deg_2 *= avg_deg_2; // the normalized edge weight of edge <v,u> is defined as: // weight(<v,u>)/sqrt(size(v)*size(u)) // Now we compute the maximal normalized weight if (graph[0].ewgts != NULL) { max_norm_edge_weight = -1; for (i = 0; i < nvtxs; i++) { inv_size = sqrt(1.0 / geom_graph[i].size); for (j = 1; j < graph[i].nedges; j++) { if (graph[i].ewgts[j] * inv_size / sqrt((float) geom_graph[graph[i].edges[j]].size) > max_norm_edge_weight) { max_norm_edge_weight = (float) (graph[i].ewgts[j] * inv_size / sqrt((double) geom_graph[graph[i].edges[j]].size)); } } } } else { max_norm_edge_weight = 1; } /* Now determine the order of the vertices. */ iptr = order = N_NEW(nvtxs, int); jptr = mflag; for (i = 0; i < nvtxs; i++) { *(iptr++) = i; *(jptr++) = -1; } // Option 1: random permutation #if 0 int temp; for (i=0; i<nvtxs-1; i++) { // use long_rand() (not rand()), as n may be greater than RAND_MAX j=i+long_rand()%(nvtxs-i); temp=order[i]; order[i]=order[j]; order[j]=temp; } #endif // Option 2: sort the nodes begining with the ones highly approriate for matching #ifdef DEBUG srand(0); #endif for (i = 0; i < nvtxs; i++) { vtx = order[i]; matchability[vtx] = graph[vtx].nedges; // we less want to match high degree nodes matchability[vtx] += geom_graph[vtx].size; // we less want to match large sized nodes min_edge_len = 1e99; for (j = 1; j < graph[vtx].nedges; j++) { min_edge_len = MIN(min_edge_len, ddist(geom_graph, vtx, graph[vtx].edges[j]) / avg_edge_len); } matchability[vtx] += min_edge_len; // we less want to match distant nodes matchability[vtx] += ((double) rand()) / RAND_MAX; // add some randomness } quicksort_place(matchability, order, 0, nvtxs - 1); free(matchability); // Start determining the matched pairs for (i = 0; i < nvtxs; i++) { vtx_vec[i] = 0; } for (i = 0; i < nvtxs; i++) { weighted_vtx_vec[i] = 0; } // relative weights of the different criteria for (i = 0; i < nvtxs; i++) { vtx = order[i]; if (mflag[vtx] >= 0) { /* already matched. */ continue; } inv_size = sqrt(1.0 / geom_graph[vtx].size); sum_weights = fill_neighbors_vec(graph, vtx, weighted_vtx_vec); fill_neighbors_vec_unweighted(graph, vtx, vtx_vec); closest_neighbor = -1; /* We match node i with the "closest" neighbor, based on 4 criteria: (1) (Weighted) fraction of common neighbors (measured on orig. graph) (2) AvgDeg*AvgDeg/(deg(vtx)*deg(neighbor)) (degrees measured on orig. graph) (3) AvgEdgeLen/dist(vtx,neighbor) (4) Weight of normalized direct connection between nodes (measured on orig. graph) */ for (j = 1; j < geom_graph[vtx].nedges; j++) { neighbor = geom_graph[vtx].edges[j]; if (mflag[neighbor] >= 0) { /* already matched. */ continue; } // (1): val = A * unweighted_common_fraction(graph, vtx, neighbor, vtx_vec); if (val == 0 && (dist2_limit || !dist3(graph, vtx, neighbor))) { // graph theoretical distance is larger than 3 (or 2 if '!dist3(graph, vtx, neighbor)' is commented) // nodes cannot be matched continue; } // (2) val += B * avg_deg_2 / (graph[vtx].nedges * graph[neighbor].nedges); // (3) val += C * avg_edge_len / ddist(geom_graph, vtx, neighbor); // (4) val += (weighted_vtx_vec[neighbor] * inv_size / sqrt((float) geom_graph[neighbor].size)) / max_norm_edge_weight; if (val > closest_val || closest_neighbor == -1) { closest_neighbor = neighbor; closest_val = val; } } if (closest_neighbor != -1) { mflag[vtx] = closest_neighbor; mflag[closest_neighbor] = vtx; nmerged++; } empty_neighbors_vec(graph, vtx, vtx_vec); empty_neighbors_vec(graph, vtx, weighted_vtx_vec); } free(order); free(vtx_vec); free(weighted_vtx_vec); return (nmerged); }