]> granicus.if.org Git - graphviz/commitdiff
Add support for mds model, in which user-supplied edge distances are
authorerg <devnull@localhost>
Wed, 29 Apr 2009 00:48:48 +0000 (00:48 +0000)
committererg <devnull@localhost>
Wed, 29 Apr 2009 00:48:48 +0000 (00:48 +0000)
used rather than weighted shortest paths.

lib/neatogen/neatoinit.c
lib/neatogen/stress.c

index 3b03c00d2c780558c4e3eb72c426bf102726f796..5d3d99efb5aa562e09bb920324c3946bb18450dc 100644 (file)
@@ -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);
index f1369a73c8f88eb1ea809ada9620a34715c19318..1ecedd7cd59d59ca6d9e2b9d711ed18d731c5f91 100644 (file)
@@ -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)