Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
stuff.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12#include "config.h"
13#include <cgraph/alloc.h>
14#include <math.h>
15#include <neatogen/neato.h>
16#include <neatogen/stress.h>
17#include <stdlib.h>
18#include <time.h>
19#ifndef _WIN32
20#include <unistd.h>
21#endif
22
23static double Epsilon2;
24static Agnode_t *choose_node(graph_t *, int);
25static void make_spring(graph_t *, Agnode_t *, Agnode_t *, double);
26static void move_node(graph_t *, int, Agnode_t *);
27
28static double fpow32(double x)
29{
30 x = sqrt(x);
31 return x * x * x;
32}
33
34static double distvec(double *p0, double *p1, double *vec)
35{
36 int k;
37 double dist = 0.0;
38
39 for (k = 0; k < Ndim; k++) {
40 vec[k] = p0[k] - p1[k];
41 dist += vec[k] * vec[k];
42 }
43 dist = sqrt(dist);
44 return dist;
45}
46
47double **new_array(int m, int n, double ival)
48{
49 int i, j;
50
51 double **rv = gv_calloc(m, sizeof(double*));
52 double *mem = gv_calloc(m * n, sizeof(double));
53 for (i = 0; i < m; i++) {
54 rv[i] = mem;
55 mem += n;
56 for (j = 0; j < n; j++)
57 rv[i][j] = ival;
58 }
59 return rv;
60}
61
62void free_array(double **rv)
63{
64 if (rv) {
65 free(rv[0]);
66 free(rv);
67 }
68}
69
70
71static double ***new_3array(int m, int n, int p, double ival)
72{
73 int i, j, k;
74
75 double ***rv = gv_calloc(m + 1, sizeof(double**));
76 for (i = 0; i < m; i++) {
77 rv[i] = gv_calloc(n + 1, sizeof(double*));
78 for (j = 0; j < n; j++) {
79 rv[i][j] = gv_calloc(p, sizeof(double));
80 for (k = 0; k < p; k++)
81 rv[i][j][k] = ival;
82 }
83 rv[i][j] = NULL; /* NULL terminate so we can clean up */
84 }
85 rv[i] = NULL;
86 return rv;
87}
88
89static void free_3array(double ***rv)
90{
91 int i, j;
92
93 if (rv) {
94 for (i = 0; rv[i]; i++) {
95 for (j = 0; rv[i][j]; j++)
96 free(rv[i][j]);
97 free(rv[i]);
98 }
99 free(rv);
100 }
101}
102
103
104/* lenattr:
105 * Return 1 if attribute not defined
106 * Return 2 if attribute string bad
107 */
108static int lenattr(edge_t* e, Agsym_t* index, double* val)
109{
110 char* s;
111
112 if (index == NULL)
113 return 1;
114
115 s = agxget(e, index);
116 if (*s == '\0') return 1;
117
118 if (sscanf(s, "%lf", val) < 1 || *val < 0 || (*val == 0 && !Nop)) {
119 agwarningf("bad edge len \"%s\"", s);
120 return 2;
121 }
122 else
123 return 0;
124}
125
126
127/* degreeKind;
128 * Returns degree of n ignoring loops and multiedges.
129 * Returns 0, 1 or many (2)
130 * For case of 1, returns other endpoint of edge.
131 */
132static int degreeKind(graph_t * g, node_t * n, node_t ** op)
133{
134 edge_t *ep;
135 int deg = 0;
136 node_t *other = NULL;
137
138 for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) {
139 if (aghead(ep) == agtail(ep))
140 continue; /* ignore loops */
141 if (deg == 1) {
142 if ((agtail(ep) == n && aghead(ep) == other) || /* ignore multiedge */
143 (agtail(ep) == other && aghead(ep) == n))
144 continue;
145 return 2;
146 } else { /* deg == 0 */
147 if (agtail(ep) == n)
148 other = aghead(ep);
149 else
150 other = agtail(ep);
151 *op = other;
152 deg++;
153 }
154 }
155 return deg;
156}
157
158
159/* prune:
160 * np is at end of a chain. If its degree is 0, remove it.
161 * If its degree is 1, remove it and recurse.
162 * If its degree > 1, stop.
163 * The node next is the next node to be visited during iteration.
164 * If it is equal to a node being deleted, set it to next one.
165 * Delete from root graph, since G may be a connected component subgraph.
166 * Return next.
167 */
168static node_t *prune(graph_t * G, node_t * np, node_t * next)
169{
170 node_t *other;
171 int deg;
172
173 while (np) {
174 deg = degreeKind(G, np, &other);
175 if (deg == 0) {
176 if (next == np)
177 next = agnxtnode(G, np);
178 agdelete(G->root, np);
179 np = 0;
180 } else if (deg == 1) {
181 if (next == np)
182 next = agnxtnode(G, np);
183 agdelete(G->root, np);
184 np = other;
185 } else
186 np = 0;
187
188 }
189 return next;
190}
191
192static double setEdgeLen(graph_t * G, node_t * np, Agsym_t* lenx, double dfltlen)
193{
194 edge_t *ep;
195 double total_len = 0.0;
196 double len;
197 int err;
198
199 for (ep = agfstout(G, np); ep; ep = agnxtout(G, ep)) {
200 if ((err = lenattr(ep, lenx, &len))) {
201 if (err == 2) agerr(AGPREV, " in %s - setting to %.02f\n", agnameof(G), dfltlen);
202 len = dfltlen;
203 }
204 ED_dist(ep) = len;
205 total_len += len;
206 }
207 return total_len;
208}
209
210/* scan_graph_mode:
211 * Prepare the graph and data structures depending on the layout mode.
212 * If Reduce is true, eliminate singletons and trees. Since G may be a
213 * subgraph, we remove the nodes from the root graph.
214 * Return the number of nodes in the reduced graph.
215 */
217{
218 int i, nV, nE, deg;
219 char *str;
220 node_t *np, *xp, *other;
221 double total_len = 0.0;
222 double dfltlen = 1.0;
223 Agsym_t* lenx;
224
225 if (Verbose)
226 fprintf(stderr, "Scanning graph %s, %d nodes\n", agnameof(G),
227 agnnodes(G));
228
229
230 /* Eliminate singletons and trees */
231 if (Reduce) {
232 for (np = agfstnode(G); np; np = xp) {
233 xp = agnxtnode(G, np);
234 deg = degreeKind(G, np, &other);
235 if (deg == 0) { /* singleton node */
236 agdelete(G->root, np);
237 } else if (deg == 1) {
238 agdelete(G->root, np);
239 xp = prune(G, other, xp);
240 }
241 }
242 }
243
244 nV = agnnodes(G);
245 nE = agnedges(G);
246
247 lenx = agattr(G, AGEDGE, "len", 0);
248 if (mode == MODE_KK) {
249 Epsilon = .0001 * nV;
250 getdouble(G, "epsilon", &Epsilon);
251 if ((str = agget(G->root, "Damping")))
252 Damping = atof(str);
253 else
254 Damping = .99;
255 GD_neato_nlist(G) = gv_calloc(nV + 1, sizeof(node_t*));
256 for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
257 GD_neato_nlist(G)[i] = np;
258 ND_id(np) = i++;
259 ND_heapindex(np) = -1;
260 total_len += setEdgeLen(G, np, lenx, dfltlen);
261 }
262 } else if (mode == MODE_SGD) {
263 Epsilon = .01;
264 getdouble(G, "epsilon", &Epsilon);
265 GD_neato_nlist(G) = gv_calloc(nV + 1, sizeof(node_t*)); // not sure why but sometimes needs the + 1
266 for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
267 GD_neato_nlist(G)[i] = np;
268 ND_id(np) = i++;
269 total_len += setEdgeLen(G, np, lenx, dfltlen);
270 }
271 } else {
273 getdouble(G, "epsilon", &Epsilon);
274 for (i = 0, np = agfstnode(G); np; np = agnxtnode(G, np)) {
275 ND_id(np) = i++;
276 total_len += setEdgeLen(G, np, lenx, dfltlen);
277 }
278 }
279
280 str = agget(G, "defaultdist");
281 if (str && str[0])
282 Initial_dist = fmax(Epsilon, atof(str));
283 else
284 Initial_dist = total_len / (nE > 0 ? nE : 1) * sqrt(nV) + 1;
285
286 if (!Nop && mode == MODE_KK) {
287 GD_dist(G) = new_array(nV, nV, Initial_dist);
288 GD_spring(G) = new_array(nV, nV, 1.0);
289 GD_sum_t(G) = new_array(nV, Ndim, 1.0);
290 GD_t(G) = new_3array(nV, nV, Ndim, 0.0);
291 }
292
293 return nV;
294}
295
297{
298 return scan_graph_mode(g, MODE_KK);
299}
300
302{
304 if (!Nop) {
308 free_3array(GD_t(g));
309 GD_t(g) = NULL;
310 }
311}
312
313void jitter_d(node_t * np, int nG, int n)
314{
315 int k;
316 for (k = n; k < Ndim; k++)
317 ND_pos(np)[k] = nG * drand48();
318}
319
320void jitter3d(node_t * np, int nG)
321{
322 jitter_d(np, nG, 2);
323}
324
325void randompos(node_t * np, int nG)
326{
327 ND_pos(np)[0] = nG * drand48();
328 ND_pos(np)[1] = nG * drand48();
329 if (Ndim > 2)
330 jitter3d(np, nG);
331}
332
334{
335 int init, i;
336 node_t *np;
337 static int once = 0;
338
339 if (Verbose)
340 fprintf(stderr, "Setting initial positions\n");
341
343 if (init == INIT_REGULAR)
344 return;
345 if (init == INIT_SELF && once == 0) {
346 agwarningf("start=0 not supported with mode=self - ignored\n");
347 once = 1;
348 }
349
350 for (i = 0; (np = GD_neato_nlist(G)[i]); i++) {
351 if (hasPos(np))
352 continue;
353 randompos(np, 1);
354 }
355}
356
357void diffeq_model(graph_t * G, int nG)
358{
359 int i, j, k;
360 double dist, **D, **K, del[MAXDIM], f;
361 node_t *vi, *vj;
362 edge_t *e;
363
364 if (Verbose) {
365 fprintf(stderr, "Setting up spring model: ");
366 start_timer();
367 }
368 /* init springs */
369 K = GD_spring(G);
370 D = GD_dist(G);
371 for (i = 0; i < nG; i++) {
372 for (j = 0; j < i; j++) {
373 f = Spring_coeff / (D[i][j] * D[i][j]);
374 if ((e = agfindedge(G, GD_neato_nlist(G)[i], GD_neato_nlist(G)[j])))
375 f = f * ED_factor(e);
376 K[i][j] = K[j][i] = f;
377 }
378 }
379
380 /* init differential equation solver */
381 for (i = 0; i < nG; i++)
382 for (k = 0; k < Ndim; k++)
383 GD_sum_t(G)[i][k] = 0.0;
384
385 for (i = 0; (vi = GD_neato_nlist(G)[i]); i++) {
386 for (j = 0; j < nG; j++) {
387 if (i == j)
388 continue;
389 vj = GD_neato_nlist(G)[j];
390 dist = distvec(ND_pos(vi), ND_pos(vj), del);
391 for (k = 0; k < Ndim; k++) {
392 GD_t(G)[i][j][k] =
393 GD_spring(G)[i][j] * (del[k] -
394 GD_dist(G)[i][j] * del[k] /
395 dist);
396 GD_sum_t(G)[i][k] += GD_t(G)[i][j][k];
397 }
398 }
399 }
400 if (Verbose) {
401 fprintf(stderr, "%.2f sec\n", elapsed_sec());
402 }
403}
404
405/* total_e:
406 * Return 2*energy of system.
407 */
408static double total_e(graph_t * G, int nG)
409{
410 int i, j, d;
411 double e = 0.0; /* 2*energy */
412 double t0; /* distance squared */
413 double t1;
414 node_t *ip, *jp;
415
416 for (i = 0; i < nG - 1; i++) {
417 ip = GD_neato_nlist(G)[i];
418 for (j = i + 1; j < nG; j++) {
419 jp = GD_neato_nlist(G)[j];
420 for (t0 = 0.0, d = 0; d < Ndim; d++) {
421 t1 = ND_pos(ip)[d] - ND_pos(jp)[d];
422 t0 += t1 * t1;
423 }
424 e = e + GD_spring(G)[i][j] *
425 (t0 + GD_dist(G)[i][j] * GD_dist(G)[i][j]
426 - 2.0 * GD_dist(G)[i][j] * sqrt(t0));
427 }
428 }
429 return e;
430}
431
432void solve_model(graph_t * G, int nG)
433{
434 node_t *np;
435
437
438 while ((np = choose_node(G, nG))) {
439 move_node(G, nG, np);
440 }
441 if (Verbose) {
442 fprintf(stderr, "\nfinal e = %f", total_e(G, nG));
443 fprintf(stderr, " %d%s iterations %.2f sec\n",
444 GD_move(G), GD_move(G) == MaxIter ? "!" : "",
445 elapsed_sec());
446 }
447 if (GD_move(G) == MaxIter)
448 agwarningf("Max. iterations (%d) reached on graph %s\n",
449 MaxIter, agnameof(G));
450}
451
452static void update_arrays(graph_t * G, int nG, int i)
453{
454 int j, k;
455 double del[MAXDIM], dist, old;
456 node_t *vi, *vj;
457
458 vi = GD_neato_nlist(G)[i];
459 for (k = 0; k < Ndim; k++)
460 GD_sum_t(G)[i][k] = 0.0;
461 for (j = 0; j < nG; j++) {
462 if (i == j)
463 continue;
464 vj = GD_neato_nlist(G)[j];
465 dist = distvec(ND_pos(vi), ND_pos(vj), del);
466 for (k = 0; k < Ndim; k++) {
467 old = GD_t(G)[i][j][k];
468 GD_t(G)[i][j][k] =
469 GD_spring(G)[i][j] * (del[k] -
470 GD_dist(G)[i][j] * del[k] / dist);
471 GD_sum_t(G)[i][k] += GD_t(G)[i][j][k];
472 old = GD_t(G)[j][i][k];
473 GD_t(G)[j][i][k] = -GD_t(G)[i][j][k];
474 GD_sum_t(G)[j][k] += GD_t(G)[j][i][k] - old;
475 }
476 }
477}
478
479#define Msub(i,j) M[(i)*Ndim+(j)]
480static void D2E(graph_t * G, int nG, int n, double *M)
481{
482 int i, l, k;
483 node_t *vi, *vn;
484 double scale, sq, t[MAXDIM];
485 double **K = GD_spring(G);
486 double **D = GD_dist(G);
487
488 vn = GD_neato_nlist(G)[n];
489 for (l = 0; l < Ndim; l++)
490 for (k = 0; k < Ndim; k++)
491 Msub(l, k) = 0.0;
492 for (i = 0; i < nG; i++) {
493 if (n == i)
494 continue;
495 vi = GD_neato_nlist(G)[i];
496 sq = 0.0;
497 for (k = 0; k < Ndim; k++) {
498 t[k] = ND_pos(vn)[k] - ND_pos(vi)[k];
499 sq += (t[k] * t[k]);
500 }
501 scale = 1 / fpow32(sq);
502 for (k = 0; k < Ndim; k++) {
503 for (l = 0; l < k; l++)
504 Msub(l, k) += K[n][i] * D[n][i] * t[k] * t[l] * scale;
505 Msub(k, k) +=
506 K[n][i] * (1.0 - D[n][i] * (sq - t[k] * t[k]) * scale);
507 }
508 }
509 for (k = 1; k < Ndim; k++)
510 for (l = 0; l < k; l++)
511 Msub(k, l) = Msub(l, k);
512}
513
515{
516 int i, k;
517 double m, max;
518 node_t *choice, *np;
519 static int cnt = 0;
520
521 cnt++;
522 if (GD_move(G) >= MaxIter)
523 return NULL;
524 max = 0.0;
525 choice = NULL;
526 for (i = 0; i < nG; i++) {
527 np = GD_neato_nlist(G)[i];
528 if (ND_pinned(np) > P_SET)
529 continue;
530 for (m = 0.0, k = 0; k < Ndim; k++)
531 m += GD_sum_t(G)[i][k] * GD_sum_t(G)[i][k];
532 /* could set the color=energy of the node here */
533 if (m > max) {
534 choice = np;
535 max = m;
536 }
537 }
538 if (max < Epsilon2)
539 choice = NULL;
540 else {
541 if (Verbose && cnt % 100 == 0) {
542 fprintf(stderr, "%.3f ", sqrt(max));
543 if (cnt % 1000 == 0)
544 fprintf(stderr, "\n");
545 }
546 }
547 return choice;
548}
549
550void move_node(graph_t * G, int nG, node_t * n)
551{
552 int i, m;
553 double b[MAXDIM] = {0};
554 double c[MAXDIM] = {0};
555
556 m = ND_id(n);
557 double *a = gv_calloc((size_t)Ndim * Ndim, sizeof(double));
558 D2E(G, nG, m, a);
559 for (i = 0; i < Ndim; i++)
560 c[i] = -GD_sum_t(G)[m][i];
561 solve(a, b, c, Ndim);
562 for (i = 0; i < Ndim; i++) {
563 b[i] = (Damping + 2 * (1 - Damping) * drand48()) * b[i];
564 ND_pos(n)[i] += b[i];
565 }
566 GD_move(G)++;
567 update_arrays(G, nG, m);
568 if (test_toggle()) {
569 double sum = 0;
570 for (i = 0; i < Ndim; i++) {
571 sum += fabs(b[i]);
572 } /* Why not squared? */
573 sum = sqrt(sum);
574 fprintf(stderr, "%s %.3f\n", agnameof(n), sum);
575 }
576 free(a);
577}
578
579static node_t **Heap;
580static int Heapsize;
581static node_t *Src;
582
583static void heapup(node_t * v)
584{
585 int i, par;
586 node_t *u;
587
588 for (i = ND_heapindex(v); i > 0; i = par) {
589 par = (i - 1) / 2;
590 u = Heap[par];
591 if (ND_dist(u) <= ND_dist(v))
592 break;
593 Heap[par] = v;
594 ND_heapindex(v) = par;
595 Heap[i] = u;
596 ND_heapindex(u) = i;
597 }
598}
599
600static void heapdown(node_t * v)
601{
602 int i, left, right, c;
603 node_t *u;
604
605 i = ND_heapindex(v);
606 while ((left = 2 * i + 1) < Heapsize) {
607 right = left + 1;
608 if ((right < Heapsize)
609 && (ND_dist(Heap[right]) < ND_dist(Heap[left])))
610 c = right;
611 else
612 c = left;
613 u = Heap[c];
614 if (ND_dist(v) <= ND_dist(u))
615 break;
616 Heap[c] = v;
617 ND_heapindex(v) = c;
618 Heap[i] = u;
619 ND_heapindex(u) = i;
620 i = c;
621 }
622}
623
625{
626 int i;
627
628 assert(ND_heapindex(v) < 0);
629 i = Heapsize++;
630 ND_heapindex(v) = i;
631 Heap[i] = v;
632 if (i > 0)
633 heapup(v);
634}
635
637{
638 int i;
639 node_t *rv, *v;
640
641 if (Heapsize == 0)
642 return NULL;
643 rv = Heap[0];
644 i = --Heapsize;
645 v = Heap[i];
646 Heap[0] = v;
647 ND_heapindex(v) = 0;
648 if (i > 1)
649 heapdown(v);
650 ND_heapindex(rv) = -1;
651 return rv;
652}
653
654void shortest_path(graph_t * G, int nG)
655{
656 node_t *v;
657
658 Heap = gv_calloc(nG + 1, sizeof(node_t*));
659 if (Verbose) {
660 fprintf(stderr, "Calculating shortest paths: ");
661 start_timer();
662 }
663 for (v = agfstnode(G); v; v = agnxtnode(G, v))
664 s1(G, v);
665 if (Verbose) {
666 fprintf(stderr, "%.2f sec\n", elapsed_sec());
667 }
668 free(Heap);
669}
670
672{
673 node_t *v, *u;
674 edge_t *e;
675 int t;
676 double f;
677
678 for (t = 0; (v = GD_neato_nlist(G)[t]); t++)
680 Src = node;
681 ND_dist(Src) = 0;
682 ND_hops(Src) = 0;
684
685 while ((v = neato_dequeue())) {
686 if (v != Src)
687 make_spring(G, Src, v, ND_dist(v));
688 for (e = agfstedge(G, v); e; e = agnxtedge(G, e, v)) {
689 if ((u = agtail(e)) == v)
690 u = aghead(e);
691 f = ND_dist(v) + ED_dist(e);
692 if (ND_dist(u) > f) {
693 ND_dist(u) = f;
694 if (ND_heapindex(u) >= 0)
695 heapup(u);
696 else {
697 ND_hops(u) = ND_hops(v) + 1;
698 neato_enqueue(u);
699 }
700 }
701 }
702 }
703}
704
705void make_spring(graph_t * G, node_t * u, node_t * v, double f)
706{
707 int i, j;
708
709 i = ND_id(u);
710 j = ND_id(v);
711 GD_dist(G)[i][j] = GD_dist(G)[j][i] = f;
712}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define Epsilon
Definition arcball.h:210
#define right(i)
Definition closest.c:77
int test_toggle(void)
Definition utils.c:411
double drand48(void)
Definition utils.c:1570
#define P_SET
Definition const.h:261
#define MAXDIM
Definition const.h:169
#define Spring_coeff
Definition const.h:167
mode
Definition cvtgxl.c:33
static char * err
Definition delaunay.c:746
#define left
Definition dthdr.h:12
static void del(Dict_t *d, Dtlink_t **set, Agedge_t *e)
Definition edge.c:156
static void init(int argc, char *argv[], double *angle, double *accuracy, int *check_edges_with_same_endpoint, int *seed, char **color_scheme, int *lightness)
static double dist(int dim, double *x, double *y)
#define G
Definition gdefs.h:7
static pointf scale(double c, pointf p)
Definition geomprocs.h:130
double Initial_dist
Definition globals.h:67
int MaxIter
Definition globals.h:63
int Nop
Definition globals.h:57
bool Reduce
Definition globals.h:54
unsigned short Ndim
Definition globals.h:64
double Damping
Definition globals.h:68
static double len(glCompPoint p)
Definition glutils.c:150
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
int agnedges(Agraph_t *g)
Definition graph.c:164
int agnnodes(Agraph_t *g)
Definition graph.c:158
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:341
char * agget(void *obj, char *name)
Definition attr.c:442
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:458
#define ED_dist(e)
Definition types.h:602
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:23
#define agtail(e)
Definition cgraph.h:889
#define agfindedge(g, t, h)
Definition types.h:609
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:93
#define ED_factor(e)
Definition types.h:585
#define aghead(e)
Definition cgraph.h:890
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:84
void agwarningf(const char *fmt,...)
Definition agerror.c:173
int agerr(agerrlevel_t level, const char *fmt,...)
Definition agerror.c:155
@ AGPREV
Definition cgraph.h:858
#define GD_sum_t(g)
Definition types.h:404
#define GD_move(g)
Definition types.h:388
#define GD_t(g)
Definition types.h:405
#define GD_dist(g)
Definition types.h:357
#define GD_spring(g)
Definition types.h:403
#define GD_neato_nlist(g)
Definition types.h:392
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_pinned(n)
Definition types.h:519
#define ND_heapindex(n)
Definition types.h:497
#define ND_hops(n)
Definition types.h:499
#define ND_pos(n)
Definition types.h:520
#define ND_dist(n)
Definition types.h:491
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:19
@ AGEDGE
Definition cgraph.h:207
#define D
Definition hierarchy.c:119
agxbuf * str
Definition htmlparse.c:97
void getdouble(graph_t *g, char *name, double *result)
Definition input.c:494
#define hasPos(n)
Definition macros.h:18
#define ND_id(n)
Definition mm2gv.c:39
#define INIT_SELF
Definition neato.h:27
#define MODE_SGD
Definition neato.h:24
#define MODE_KK
Definition neato.h:20
#define INIT_RANDOM
Definition neato.h:29
#define INIT_REGULAR
Definition neato.h:28
int checkStart(graph_t *G, int nG, int dflt)
Definition neatoinit.c:1018
NEATOPROCS_API void solve(double *, double *, double *, size_t)
Definition solve.c:26
#define M
Definition randomkit.c:98
#define DFLT_TOLERANCE
Definition stress.h:23
graph or subgraph
Definition cgraph.h:425
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:639
static void heapup(node_t *v)
Definition stuff.c:583
static void update_arrays(graph_t *G, int nG, int i)
Definition stuff.c:452
static void make_spring(graph_t *, Agnode_t *, Agnode_t *, double)
Definition stuff.c:705
static double Epsilon2
Definition stuff.c:23
void solve_model(graph_t *G, int nG)
Definition stuff.c:432
void randompos(node_t *np, int nG)
Definition stuff.c:325
int scan_graph(graph_t *g)
Definition stuff.c:296
void s1(graph_t *G, node_t *node)
Definition stuff.c:671
#define Msub(i, j)
Definition stuff.c:479
void jitter3d(node_t *np, int nG)
Definition stuff.c:320
void shortest_path(graph_t *G, int nG)
Definition stuff.c:654
static node_t * prune(graph_t *G, node_t *np, node_t *next)
Definition stuff.c:168
static void D2E(graph_t *G, int nG, int n, double *M)
Definition stuff.c:480
static double setEdgeLen(graph_t *G, node_t *np, Agsym_t *lenx, double dfltlen)
Definition stuff.c:192
node_t * neato_dequeue(void)
Definition stuff.c:636
void jitter_d(node_t *np, int nG, int n)
Definition stuff.c:313
static node_t ** Heap
Definition stuff.c:579
int scan_graph_mode(graph_t *G, int mode)
Definition stuff.c:216
void free_array(double **rv)
Definition stuff.c:62
void free_scan_graph(graph_t *g)
Definition stuff.c:301
void diffeq_model(graph_t *G, int nG)
Definition stuff.c:357
static void move_node(graph_t *, int, Agnode_t *)
Definition stuff.c:550
void initial_positions(graph_t *G, int nG)
Definition stuff.c:333
static Agnode_t * choose_node(graph_t *, int)
Definition stuff.c:514
static int degreeKind(graph_t *g, node_t *n, node_t **op)
Definition stuff.c:132
static void heapdown(node_t *v)
Definition stuff.c:600
static void free_3array(double ***rv)
Definition stuff.c:89
static double total_e(graph_t *G, int nG)
Definition stuff.c:408
static double fpow32(double x)
Definition stuff.c:28
void neato_enqueue(node_t *v)
Definition stuff.c:624
static double distvec(double *p0, double *p1, double *vec)
Definition stuff.c:34
static double *** new_3array(int m, int n, int p, double ival)
Definition stuff.c:71
static node_t * Src
Definition stuff.c:581
static int Heapsize
Definition stuff.c:580
static int lenattr(edge_t *e, Agsym_t *index, double *val)
Definition stuff.c:108
double ** new_array(int m, int n, double ival)
Definition stuff.c:47
double elapsed_sec(void)
Definition timing.c:48
void start_timer(void)
Definition timing.c:43
Definition grammar.c:93