Exemple #1
0
/* sparse_stress_subspace_majorization_kD:
 * Optimization of the stress function using sparse distance matrix, within a vector-space
 * Fastest and least accurate method
 *
 * NOTE: We use integral shortest path values here, assuming
 * this is only to get an initial layout. In general, if edge lengths
 * are involved, we may end up with 0 length edges. 
 */
static int sparse_stress_subspace_majorization_kD(vtx_data * graph,	/* Input graph in sparse representation */
						  int n,	/* Number of nodes */
						  int nedges_graph,	/* Number of edges */
						  double **coords,	/* coordinates of nodes (output layout)  */
						  int dim,	/* dimemsionality of layout */
						  int smart_ini,	/* smart initialization */
						  int exp,	/* scale exponent */
						  int reweight_graph,	/* difference model */
						  int n_iterations,	/* max #iterations */
						  int dist_bound,	/* neighborhood size in sparse distance matrix    */
						  int num_centers	/* #pivots in sparse distance matrix  */
    )
{
    int iterations;		/* output: number of iteration of the process */

    double conj_tol = tolerance_cg;	/* tolerance of Conjugate Gradient */

	/*************************************************
	** Computation of pivot-based, sparse, subspace-restricted **
	** k-D  stress minimization by majorization                **    
	*************************************************/

    int i, j, k, node;

	/*************************************************
	** First compute the subspace in which we optimize     **
	** The subspace is  the high-dimensional embedding     **
	*************************************************/

    int subspace_dim = MIN(stress_pca_dim, n);	/* overall dimensionality of subspace */
    double **subspace = N_GNEW(subspace_dim, double *);
    double *d_storage = N_GNEW(subspace_dim * n, double);
    int num_centers_local;
    DistType **full_coords;
    /* if i is a pivot than CenterIndex[i] is its index, otherwise CenterIndex[i]= -1 */
    int *CenterIndex;
    int *invCenterIndex;	/* list the pivot nodes  */
    Queue Q;
    float *old_weights;
    /* this matrix stores the distance between  each node and each "center" */
    DistType **Dij;
    /* this vector stores the distances of each node to the selected "centers" */
    DistType *dist;
    DistType max_dist;
    DistType *storage;
    int *visited_nodes;
    dist_data *distances;
    int available_space;
    int *storage1 = NULL;
    DistType *storage2 = NULL;
    int num_visited_nodes;
    int num_neighbors;
    int index;
    int nedges;
    DistType *dist_list;
    vtx_data *lap;
    int *edges;
    float *ewgts;
    double degree;
    double **directions;
    float **tmp_mat;
    float **matrix;
    double dist_ij;
    double *b;
    double *b_restricted;
    double L_ij;
    double old_stress, new_stress;
    boolean converged;

    for (i = 0; i < subspace_dim; i++) {
	subspace[i] = d_storage + i * n;
    }

    /* compute PHDE: */
    num_centers_local = MIN(n, MAX(2 * subspace_dim, 50));
    full_coords = NULL;
    /* High dimensional embedding */
    embed_graph(graph, n, num_centers_local, &full_coords, reweight_graph);
    /* Centering coordinates */
    center_coordinate(full_coords, n, num_centers_local);
    /* PCA */
    PCA_alloc(full_coords, num_centers_local, n, subspace, subspace_dim);

    free(full_coords[0]);
    free(full_coords);

	/*************************************************
	** Compute the sparse-shortest-distances matrix 'distances' **
	*************************************************/

    CenterIndex = N_GNEW(n, int);
    for (i = 0; i < n; i++) {
	CenterIndex[i] = -1;
    }
    invCenterIndex = NULL;

    mkQueue(&Q, n);
    old_weights = graph[0].ewgts;

    if (reweight_graph) {
	/* weight graph to separate high-degree nodes */
	/* in the future, perform slower Dijkstra-based computation */
	compute_new_weights(graph, n);
    }

    /* compute sparse distance matrix */
    /* first select 'num_centers' pivots from which we compute distance */
    /* to all other nodes */

    Dij = NULL;
    dist = N_GNEW(n, DistType);
    if (num_centers == 0) {	/* no pivots, skip pivots-to-nodes distance calculation */
	goto after_pivots_selection;
    }

    invCenterIndex = N_GNEW(num_centers, int);

    storage = N_GNEW(n * num_centers, DistType);
    Dij = N_GNEW(num_centers, DistType *);
    for (i = 0; i < num_centers; i++)
	Dij[i] = storage + i * n;

    /* select 'num_centers' pivots that are uniformaly spreaded over the graph */

    /* the first pivots is selected randomly */
    node = rand() % n;
    CenterIndex[node] = 0;
    invCenterIndex[0] = node;

    if (reweight_graph) {
	dijkstra(node, graph, n, Dij[0]);
    } else {
	bfs(node, graph, n, Dij[0], &Q);
    }

    /* find the most distant node from first pivot */
    max_dist = 0;
    for (i = 0; i < n; i++) {
	dist[i] = Dij[0][i];
	if (dist[i] > max_dist) {
	    node = i;
	    max_dist = dist[i];
	}
    }
    /* select other dim-1 nodes as pivots */
    for (i = 1; i < num_centers; i++) {
	CenterIndex[node] = i;
	invCenterIndex[i] = node;
	if (reweight_graph) {
	    dijkstra(node, graph, n, Dij[i]);
	} else {
	    bfs(node, graph, n, Dij[i], &Q);
	}
	max_dist = 0;
	for (j = 0; j < n; j++) {
	    dist[j] = MIN(dist[j], Dij[i][j]);
	    if (dist[j] > max_dist
		|| (dist[j] == max_dist && rand() % (j + 1) == 0)) {
		node = j;
		max_dist = dist[j];
	    }
	}
    }

  after_pivots_selection:

    /* Construct a sparse distance matrix 'distances' */

    /* initialize dist to -1, important for 'bfs_bounded(..)' */
    for (i = 0; i < n; i++) {
	dist[i] = -1;
    }

    visited_nodes = N_GNEW(n, int);
    distances = N_GNEW(n, dist_data);
    available_space = 0;
    nedges = 0;
    for (i = 0; i < n; i++) {
	if (CenterIndex[i] >= 0) {	/* a pivot node */
	    distances[i].edges = N_GNEW(n - 1, int);
	    distances[i].edist = N_GNEW(n - 1, DistType);
	    distances[i].nedges = n - 1;
	    nedges += n - 1;
	    distances[i].free_mem = TRUE;
	    index = CenterIndex[i];
	    for (j = 0; j < i; j++) {
		distances[i].edges[j] = j;
		distances[i].edist[j] = Dij[index][j];
	    }
	    for (j = i + 1; j < n; j++) {
		distances[i].edges[j - 1] = j;
		distances[i].edist[j - 1] = Dij[index][j];
	    }
	    continue;
	}

	/* a non pivot node */

	if (dist_bound > 0) {
	    if (reweight_graph) {
		num_visited_nodes =
		    dijkstra_bounded(i, graph, n, dist, dist_bound,
				     visited_nodes);
	    } else {
		num_visited_nodes =
		    bfs_bounded(i, graph, n, dist, &Q, dist_bound,
				visited_nodes);
	    }
	    /* filter the pivots out of the visited nodes list, and the self loop: */
	    for (j = 0; j < num_visited_nodes;) {
		if (CenterIndex[visited_nodes[j]] < 0
		    && visited_nodes[j] != i) {
		    /* not a pivot or self loop */
		    j++;
		} else {
		    dist[visited_nodes[j]] = -1;
		    visited_nodes[j] = visited_nodes[--num_visited_nodes];
		}
	    }
	} else {
	    num_visited_nodes = 0;
	}
	num_neighbors = num_visited_nodes + num_centers;
	if (num_neighbors > available_space) {
	    available_space = (dist_bound + 1) * n;
	    storage1 = N_GNEW(available_space, int);
	    storage2 = N_GNEW(available_space, DistType);
	    distances[i].free_mem = TRUE;
	} else {
Exemple #2
0
static void
local_beautify_kD(int *nodes, int num_nodes, vtx_data * graph, int n,
		  int dist_bound, int reweight_graph, double **coords,
		  int dim)
{
    /* Optimize locally the k-D position of each of the nodes in 'nodes' */
    /* sing majorization.  */
    /* Here, in each iteration only a single node is mobile */

    int i, j, k;
    int *visited_nodes;
    DistType *dist;
    double *weights;
    Queue Q;
    int num_visited_nodes;
    double dist_ij;
    int v, neighbor;
    double dist_1d;
    double total_wgts;
    double *newpos;
    double max_diff;

    if (dist_bound <= 0) {
	return;
    }

    visited_nodes = N_GNEW(n, int);
    dist = N_GNEW(n, DistType);
    weights = N_GNEW(n, double);
    newpos = N_GNEW(dim, double);
    mkQueue(&Q, n);

    /* initialize dist to -1, important for bfs_bounded */
    for (i = 0; i < n; i++) {
	dist[i] = -1;
    }

    for (i = 0; i < num_nodes; i++) {
	v = nodes[i];
	if (reweight_graph) {
	    num_visited_nodes =
		dijkstra_bounded(v, graph, n, dist, dist_bound,
				 visited_nodes);
	} else {
	    num_visited_nodes =
		bfs_bounded(v, graph, n, dist, &Q, dist_bound,
			    visited_nodes);
	}

	total_wgts = 0;
	for (j = 0; j < num_visited_nodes; j++) {
	    neighbor = visited_nodes[j];
	    if (neighbor != v) {
#ifdef Dij2
		total_wgts += weights[j] =
		    1.0 / ((double) dist[neighbor] *
			   (double) dist[neighbor]);
#else
		total_wgts += weights[j] = 1.0 / (double) dist[neighbor];
#endif
	    }
	}

	if (total_wgts == 0) {	/* no neighbors to current node */
	    continue;
	}

	do {
	    for (k = 0; k < dim; newpos[k++] = 0);

	    for (j = 0; j < num_visited_nodes; j++) {
		neighbor = visited_nodes[j];
		if (neighbor == v) {
		    continue;
		}
		for (k = 0; k < dim; k++) {
		    dist_1d = coords[k][v] - coords[k][neighbor];
		    dist_ij = distance_kD(coords, dim, v, neighbor);
		    newpos[k] +=
			weights[j] * (coords[k][neighbor] +
				      dist[neighbor] * dist_1d / dist_ij);
		}
	    }
	    max_diff = 0;
	    for (k = 0; k < dim; k++) {
		newpos[k] /= total_wgts;
		max_diff =
		    MAX(max_diff,
			fabs(newpos[k] - coords[k][v]) / fabs(newpos[k] +
							      1e-20));
		coords[k][v] = newpos[k];
	    }
	} while (max_diff > Epsilon);

	/* initialize 'dist' for next run of 'bfs_bounded' */
	for (j = 0; j < num_visited_nodes; j++) {
	    dist[visited_nodes[j]] = -1;
	}
    }

    free(visited_nodes);
    free(dist);
    free(weights);
    free(newpos);
    freeQueue(&Q);
}