From: erg Date: Wed, 29 Apr 2009 00:48:48 +0000 (+0000) Subject: Add support for mds model, in which user-supplied edge distances are X-Git-Tag: LAST_LIBGRAPH~32^2~2134 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=671fd8be85ebff68b52872d7b9e1bc6c5c707f64;p=graphviz Add support for mds model, in which user-supplied edge distances are used rather than weighted shortest paths. --- diff --git a/lib/neatogen/neatoinit.c b/lib/neatogen/neatoinit.c index 3b03c00d2..5d3d99efb 100644 --- a/lib/neatogen/neatoinit.c +++ b/lib/neatogen/neatoinit.c @@ -731,7 +731,7 @@ static int neatoModel(graph_t * g) char *p = agget(g, "model"); char c; - if (!p || (!(c = *p))) + if (!p || (!(c = *p))) /* if p is NULL or "" */ return MODEL_SHORTPATH; if ((c == 'c') && streq(p, "circuit")) return MODEL_CIRCUIT; @@ -741,6 +741,20 @@ static int neatoModel(graph_t * g) else if (streq(p, "shortpath")) return MODEL_SHORTPATH; } + if ((c == 'm') && streq(p, "mds")) { +#ifndef WITH_CGRAPH + if (agindex(g->root->proto->e, "len") >= 0) +#else /* WITH_CGRAPH */ + if (agattr(g, AGEDGE, "len", 0)) +#endif /* WITH_CGRAPH */ + return MODEL_MDS; + else { + agerr(AGWARN, + "edges in graph %s have no len attribute. Hence, the mds model\n", agnameof(g)); + agerr(AGPREV, "is inappropriate. Reverting to the shortest path model.\n"); + return MODEL_SHORTPATH; + } + } agerr(AGWARN, "Unknown value %s for attribute \"model\" in graph %s - ignored\n", p, agnameof(g)); @@ -1157,8 +1171,8 @@ void dumpData(graph_t * g, vtx_data * gp, int nv, int ne) /* majorization: * Solve stress using majorization. * Old neato attributes to incorporate: - * weight? - * model will be MODE_MAJOR, MODE_HIER or MODE_IPSEP + * weight + * mode will be MODE_MAJOR, MODE_HIER or MODE_IPSEP */ static void majorization(graph_t *mg, graph_t * g, int nv, int mode, int model, int dim, int steps) @@ -1309,6 +1323,27 @@ static void subset_model(Agraph_t * G, int nG) freeGraphData(gp); } +/* mds_model: + * Assume the matrix already contains shortest path values. + * Use the actual lengths provided the input for edges. + */ +static void mds_model(graph_t * g, int nG) +{ + long i, j; + node_t *v; + edge_t *e; + + for (v = agfstnode(g); v; v = agnxtnode(g, v)) { + for (e = agfstout(g, v); e; e = agnxtout(g, e)) { + i = AGID(agtail(e)); + j = AGID(aghead(e)); + if (i == j) + continue; + GD_dist(g)[i][j] = GD_dist(g)[j][i] = GD_dist(e); + } + } +} + /* kkNeato: * Solve using gradient descent a la Kamada-Kawai. */ @@ -1328,6 +1363,9 @@ static void kkNeato(Agraph_t * g, int nG, int model) agerr(AGPREV, "the graph into connected components.\n"); shortest_path(g, nG); } + } else if (model == MODEL_MDS) { + shortest_path(g, nG); + mds_model(g, nG); } else shortest_path(g, nG); initial_positions(g, nG); diff --git a/lib/neatogen/stress.c b/lib/neatogen/stress.c index f1369a73c..1ecedd7cd 100644 --- a/lib/neatogen/stress.c +++ b/lib/neatogen/stress.c @@ -1360,6 +1360,39 @@ static float *compute_weighted_apsp_packed(vtx_data * graph, int n) return Dij; } + +/* mdsModel: + * Update matrix with actual edge lengths + */ +float* +mdsModel(vtx_data * graph, int nG) +{ + int i, j, e; + float *Dij; + int shift = 0; + double delta; + + if (graph->ewgts == NULL) return 0; + + /* first, compute shortest paths to fill in non-edges */ + Dij = compute_weighted_apsp_packed(graph, nG); + + /* then, replace edge entries will user-supplied len */ + for (i = 0; i < nG; i++) { + shift += i; + for (e = 1; e < graph[i].nedges; e++) { + j = graph[i].edges[e]; + if (j < i) continue; + delta += abs(Dij[i*nG + j - shift] - graph[i].ewgts[e]); + Dij[i*nG + j - shift] = graph[i].ewgts[e]; + } + } + if (Verbose) { + fprintf (stderr, "mdsModel: delta = %f\n", delta); + } + return Dij; +} + /* compute_apsp_packed: * Assumes integral weights > 0. */ @@ -1535,6 +1568,10 @@ int stress_majorization_kD_mkernel(vtx_data * graph, /* Input graph in sparse re agerr(AGPREV, "is undefined. Reverting to the shortest path model.\n"); } + } else if (model == MODEL_MDS) { + if (Verbose) + fprintf(stderr, "Calculating MDS model"); + Dij = mdsModel(graph, n); } if (!Dij) { if (Verbose)