mat mars(Agraph_t* g, struct marsopts opts) { int i, j, n = agnnodes(g), k = MIN(n, MAX(opts.k, 2)), iter = 0; mat dij, u, u_trans, q, r, q_t, tmp, tmp2, z; double* s = (double*) malloc(sizeof(double)*k); double* ones = (double*) malloc(sizeof(double)*n); double* d; int* anchors = (int*) malloc(sizeof(int)*k); int* clusters = NULL; double change = 1, old_stress = -1; dij = mat_new(k, n); u = mat_new(n,k); tmp = mat_new(n,k); darrset(ones,n,-1); select_anchors(g, dij, anchors, k); if(opts.color) { for(i = 0; i < k; i++) { Agnode_t* anchor = get_node(anchors[i]); agset(anchor, "color", "red"); } } if(opts.power != 1) { clusters = graph_cluster(g,dij,anchors); } singular_vectors(g, dij, opts.power, u, s); vec_scalar_mult(s, k, -1); u_trans = mat_trans(u); d = mat_mult_for_d(u, s, u_trans, ones); for(i = 0; i < u->c; i++) { double* col = mat_col(u,i); double* b = inv_mul_ax(d,col,u->r); for(j = 0; j < u->r; j++) { tmp->m[mindex(j,i,tmp)] = b[j]; } free(b); free(col); } tmp2 = mat_mult(u_trans,tmp); for(i = 0; i < k; i++) { tmp2->m[mindex(i,i,tmp2)] += (1.0/s[i]); } q = mat_new(tmp2->r, tmp2->c); r = mat_new(tmp2->c, tmp2->c); qr_factorize(tmp2,q,r); q_t = mat_trans(q); if(opts.given) { z = get_positions(g, opts.dim); } else { z = mat_rand(n, opts.dim); } translate_by_centroid(z); if(opts.viewer) { init_viewer(g, opts.max_iter); append_layout(z); } old_stress = stress(z, dij, anchors, opts.power); while(change > EPSILON && iter < opts.max_iter) { mat right_side; double new_stress; if(opts.power == 1) { right_side = barnes_hut(z); } else { right_side = barnes_hut_cluster(z, dij, clusters, opts.power); } for(i = 0; i < opts.dim; i++) { double sum = 0; double* x; double* b = mat_col(right_side,i); for(j = 0; j < right_side->r; j++) { sum += b[j]; } x = inv_mul_full(d, b, right_side->r, u, u_trans, q_t, r); for(j = 0; j < z->r; j++) { z->m[mindex(j,i,z)] = x[j] - sum/right_side->r; } free(x); free(b); } adjust_anchors(g, anchors, k, z); update_anchors(z, dij, anchors, opts.power); translate_by_centroid(z); if(opts.viewer) { append_layout(z); } new_stress = stress(z, dij, anchors, opts.power); change = fabs(new_stress-old_stress)/old_stress; old_stress = new_stress; mat_free(right_side); iter++; } mat_free(dij); mat_free(u); mat_free(u_trans); mat_free(q); mat_free(r); mat_free(q_t); mat_free(tmp); mat_free(tmp2); free(s); free(ones); free(d); free(anchors); free(clusters); return z; }
void run_dla(params p) { time_t start, now; FILE *fp; fp = fopen(p.output_filename, "w"); if (fp == NULL) { fprintf(stderr,"ERROR: could not open output file '%s'\n", p.output_filename); exit(EXIT_FAILURE); } if(KDT_DIM == 2) { fprintf(fp,"n x y\n"); } else if(KDT_DIM == 3) { fprintf(fp,"n x y z\n"); } else { fprintf(stderr, "DLA not defined for KDT_DIM=%d\n", KDT_DIM); exit(1); } setuprandom(p.seed); // setup initial world conditions point_list *buffer = kdt_new_point_list(p.n); tree_node *root = kdt_new_tree(); point *zero = (point *)malloc(sizeof(point)); vec_zero(zero); kdt_add_point(root, zero); double curr_max_radius = 0.0f; double starting_rad = starting_radius(p.min_inner_radius, curr_max_radius, p.inner_mult, p.step_size); double death_rad = death_radius(p.min_inner_radius, curr_max_radius, p.inner_mult, p.step_size, p.outer_mult); time(&start); time(&now); int i; for(i=0; i < p.n && (now - start) < p.max_secs; i++) { if(i % (p.n / 10) == 0 && p.log_progress == 1) { log_progress((double)i / (double)p.n * 100.0f, curr_max_radius, starting_rad, kdt_max_depth(root)); } point dir, end, col; point *pt = (point *)malloc(sizeof(point)); vec_rand_unit(pt); vec_scalar_mult(pt, pt, starting_rad); int walking = 1; while(walking) { vec_rand_unit(&dir); vec_scalar_mult(&dir, &dir, p.step_size); vec_add(&end, pt, &dir); if(kdt_collision_detect(root, pt, &end, &col, p.epsilon, buffer) && sticks(p.stickiness)) { vec_copy(pt, &col); kdt_add_point(root, pt); double pt_radius = vec_length(pt); if(pt_radius > curr_max_radius) { curr_max_radius = pt_radius; starting_rad = starting_radius(p.min_inner_radius, curr_max_radius, p.inner_mult, p.step_size); death_rad = death_radius(p.min_inner_radius, curr_max_radius, p.inner_mult, p.step_size, p.outer_mult); } walking = 0; } else { vec_copy(pt, &end); if(vec_length(pt) >= death_rad) { // if we have moved outside the max radius, start over vec_rand_unit(pt); vec_scalar_mult(pt, pt, starting_rad); } } } print_point(fp, i, pt); time(&now); } if (p.log_progress == 1) { log_progress((double)i / (double)p.n * 100.0f, curr_max_radius, starting_rad, kdt_max_depth(root)); } fclose(fp); }