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