86 if (
Ndim >= 3 && sscanf(p,
"%lf,%lf,%lf%c", pvec, pvec+1, pvec+2, &c) >= 3){
90 for (i = 0; i <
Ndim; i++)
99 else if (sscanf(p,
"%lf,%lf%c", pvec, pvec + 1, &c) >= 2) {
103 for (i = 0; i <
Ndim; i++)
107 if (
N_z && (p =
agxget(np,
N_z)) && sscanf(p,
"%lf",&
z) == 1) {
122 agerrorf(
"node %s, position %s, expected two doubles\n",
179 while ((c = *pos) && !
gv_isspace(c) && c !=
';')
190 lp =
agget(obj, name);
191 if (lp && sscanf(lp,
"%lf,%lf", &x, &y) == 2) {
198static cluster_data cluster_map(
graph_t *mastergraph,
graph_t *g) {
203 cluster_data
cdata = {0};
205 size_t nclusters = 0;
213 cdata.nclusters = nclusters;
214 size_t **cs =
cdata.clusters =
gv_calloc(nclusters,
sizeof(
size_t *));
215 size_t *cn =
cdata.clustersizes =
gv_calloc(nclusters,
sizeof(
size_t));
221 size_t *c = *cs++ =
gv_calloc(*cn++,
sizeof(
size_t));
238 for (
size_t i = j = 0; i <
agnnodes_z(g); i++) {
240 cdata.toplevel[j++] = i;
248static void freeClusterData(cluster_data c) {
249 if (c.nclusters > 0) {
252 free(c.clustersizes);
268 bool sflag =
false, eflag =
false;
269 pointf sp = { 0, 0 }, ep = { 0, 0};
271 static atomic_flag warned;
273 const char *pos =
agxget(e, E_pos);
277 uint32_t stype, etype;
279 for (
bool more =
true; more; ) {
281 if (sscanf(pos,
"s,%lf,%lf%n", &x, &y, &nc) == 2) {
288 if (sscanf(pos,
" e,%lf,%lf%n", &x, &y, &nc) == 2) {
291 ep = (
pointf){.x = x, .y = y};
295 if (npts < 4 || npts % 3 != 1) {
297 if (!atomic_flag_test_and_set(&warned)) {
304 for (
size_t n = npts; n > 0; --n) {
305 if (sscanf(pos,
"%lf,%lf%n", &x, &y, &nc) < 2) {
306 if (!atomic_flag_test_and_set(&warned)) {
314 *pp = (
pointf){.
x = x, .y = y};
326 newspl->
sflag = stype;
330 newspl->
eflag = etype;
333 for (
size_t i = 0; i < npts; i++) {
334 newspl->
list[i] = ps[i];
375 if (!E_pos ||
Nop < 2)
419 if (sscanf(
s,
"%lf,%lf,%lf,%lf", &bb.
LL.
x, &bb.
LL.
y, &bb.
UR.
x,
466 dfs(sg, parentg, G_lp, G_bb);
484 if (sscanf(
s,
"%lf,%lf", &x, &y) == 2) {
493 dfs(subg, g, G_lp, G_bb);
529 agerrorf(
"node %s in graph %s has no position\n",
546 if (
adjust &&
Nop == 1 && !haveBackground)
575 if (translate && !haveBackground && (
GD_bb(g).LL.x != 0||
GD_bb(g).LL.y != 0))
579 if (posEdges !=
NoEdges && (didShift || didAdjust)) {
589 return haveBackground;
606 char *p =
agget(g,
"model");
608 if (!p ||
streq(p,
""))
610 if (
streq(p,
"circuit"))
612 if (
streq(p,
"subset"))
614 if (
streq(p,
"shortpath"))
616 if (
streq(p,
"mds")) {
621 "edges in graph %s have no len attribute. Hence, the mds model\n",
agnameof(g));
622 agerr(
AGPREV,
"is inappropriate. Reverting to the shortest path model.\n");
627 "Unknown value %s for attribute \"model\" in graph %s - ignored\n",
655 "Illegal value %s for attribute \"mode\" in graph %s - ignored\n",
693 for (
size_t e = 1; e <
graph[i].nedges; e++) {
694 if (
graph[i].edists[e] == 1)
continue;
695 j =
graph[i].edges[e];
698 graph[i].edists[e] = x;
700 for (f = 1; f <
graph[j].nedges &&
graph[j].edges[f] != i; f++) ;
702 graph[j].edists[f] = -1;
717 for (i = 0; i < nv; i++) {
722 for (i = 0; i < nv; i++) {
723 if (
ND_mark(nodes[i]))
continue;
753 float *eweights =
NULL;
755 int8_t *edists =
NULL;
761 bool haveLen =
false;
771 const size_t edges_size = (size_t)(2 * ne + nv);
772 int *edges =
gv_calloc(edges_size,
sizeof(
int));
773 if (haveLen || haveDir)
774 ewgts =
gv_calloc(edges_size,
sizeof(
float));
776 eweights =
gv_calloc(edges_size,
sizeof(
float));
779 edists =
gv_calloc(edges_size,
sizeof(int8_t));
787 assert(
ND_id(np) == i);
789 graph[i].edges = edges++;
790 if (haveLen || haveDir)
791 graph[i].ewgts = ewgts++;
795 graph[i].eweights = eweights++;
800 graph[i].edists = edists++;
822 *edges++ =
ND_id(vp);
831 char *
s =
agget(ep,
"dir");
835 *edists++ = np ==
aghead(ep) ? 1 : -1;
843 graph[i].nedges = i_nedges;
844 graph[i].edges[0] = i;
860 ewgts =
gv_recalloc(
graph[0].ewgts, edges_size, 2 * ne + nv,
sizeof(
float));
862 eweights =
gv_recalloc(
graph[0].eweights, edges_size, 2 * ne + nv,
sizeof(
float));
864 for (i = 0; i < nv; i++) {
865 const size_t sz =
graph[i].nedges;
866 graph[i].edges = edges;
869 graph[i].ewgts = ewgts;
873 graph[i].eweights = eweights;
905#define SLEN(s) (sizeof(s)-1)
907#define REGULAR "regular"
908#define RANDOM "random"
921 char *p =
agget(
G,
"start");
924 if (!p || *p ==
'\0')
return dflt;
957#define exp_name "stresswt"
962 if (exp == 0 || exp > 2) {
986 agwarningf(
"node positions are ignored unless start=random\n");
999 fprintf(stderr,
"#nodes %d #edges %d\n", nv, ne);
1003 for (i = 0; i < nv; i++) {
1004 const size_t n = gp[i].
nedges;
1005 fprintf(stderr,
"[%d] %" PRISIZE_T "\n", i, n);
1006 for (
size_t j = 0; j < n; j++) {
1007 fprintf(stderr,
" %3d", gp[i].edges[j]);
1009 fputs(
"\n", stderr);
1011 fputs(
" ewgts", stderr);
1012 for (
size_t j = 0; j < n; j++) {
1013 fprintf(stderr,
" %3f", gp[i].ewgts[j]);
1015 fputs(
"\n", stderr);
1017 if (gp[i].eweights) {
1018 fputs(
" eweights", stderr);
1019 for (
size_t j = 0; j < n; j++) {
1020 fprintf(stderr,
" %3f", gp[i].eweights[j]);
1022 fputs(
"\n", stderr);
1025 fputs(
" edists", stderr);
1026 for (
size_t j = 0; j < n; j++) {
1027 fprintf(stderr,
" %" PRId8, gp[i].edists[j]);
1029 fputs(
"\n", stderr);
1031 fputs(
"\n", stderr);
1035void dumpClusterData (cluster_data* dp)
1038 PRISIZE_T "\n", dp->nvars, dp->nclusters, dp->ntoplevel);
1039 fprintf (stderr,
"Clusters:\n");
1040 for (
size_t i = 0; i < dp->nclusters; i++) {
1041 const size_t sz = dp->clustersizes[i];
1043 for (
size_t j = 0; j < sz; j++)
1044 fprintf (stderr,
" %" PRISIZE_T, dp->clusters[i][j]);
1045 fprintf (stderr,
"\n");
1049 fprintf (stderr,
"Toplevel:\n");
1050 for (
size_t i = 0; i < dp->ntoplevel; i++)
1051 fprintf (stderr,
" %" PRISIZE_T "\n", dp->toplevel[i]);
1053 fprintf (stderr,
"Boxes:\n");
1054 for (
size_t i = 0; i < dp->nclusters; i++) {
1055 boxf bb = dp->bb[i];
1056 fprintf (stderr,
" (%f,%f) (%f,%f)\n", bb.
LL.
x, bb.
LL.
y, bb.
UR.
x, bb.
UR.
y);
1059void dumpOpts (ipsep_options* opp,
int nv)
1063 fprintf (stderr,
"diredges %d edge_gap %f noverlap %d gap (%f,%f)\n", opp->diredges, opp->edge_gap, opp->noverlap, opp->gap.x, opp->gap.y);
1064 for (i = 0; i < nv; i++)
1065 fprintf (stderr,
" (%f,%f)\n", opp->nsize[i].x, opp->nsize[i].y);
1067 dumpClusterData (opp->clusters);
1079#if !defined(DIGCOLA) || !defined(IPSEPCOLA)
1097 for (
int i = 1; i <
Ndim; i++) {
1098 coords[i] = coords[0] + i * nv;
1101 fprintf(stderr,
"model %d smart_init %d stresswt %d iterations %d tol %f\n",
1103 fprintf(stderr,
"convert graph: ");
1105 fprintf(stderr,
"majorization\n");
1110 fprintf(stderr,
"%d nodes %.2f sec\n", nv,
elapsed_sec());
1117 rv = stress_majorization_with_hierarchy(gp, nv, coords, nodes,
Ndim,
1124 cluster_data cs = cluster_map(mg,g);
1126 opt.edge_gap = lgap;
1129 str =
agget(g,
"diredgeconstraints");
1133 fprintf(stderr,
"Generating Edge Constraints...\n");
1134 }
else if (
str && !strncasecmp(
str,
"hier",4)) {
1137 fprintf(stderr,
"Generating DiG-CoLa Edge Constraints...\n");
1139 else opt.diredges = 0;
1143 fprintf(stderr,
"Generating Non-overlap Constraints...\n");
1147 fprintf(stderr,
"Removing overlaps as postprocess...\n");
1149 else opt.noverlap = 0;
1158 fprintf(stderr,
"gap=%f,%f\n",opt.gap.x,opt.gap.y);
1168 fprintf (stderr,
"nv %d ne %d Ndim %d model %d MaxIter %d\n", nv, ne,
Ndim, model,
MaxIter);
1169 fprintf (stderr,
"Nodes:\n");
1170 for (
int i = 0; i < nv; i++) {
1171 fprintf (stderr,
" %s (%f,%f)\n", nodes[i]->name, coords[0][i], coords[1][i]);
1173 fprintf (stderr,
"\n");
1174 dumpData(g, gp, nv, ne);
1175 fprintf (stderr,
"\n");
1176 dumpOpts (&opt, nv);
1178 rv = stress_majorization_cola(gp, nv, coords, nodes,
Ndim, model,
MaxIter, &opt);
1179 freeClusterData(cs);
1193 for (
int i = 0; i <
Ndim; i++) {
1194 ND_pos(v)[i] = coords[i][idx];
1210 for (i = 0; i < nG; i++) {
1211 for (j = 0; j < nG; j++) {
1248 "graph %s is disconnected. Hence, the circuit model\n",
1251 "is undefined. Reverting to the shortest path model.\n");
1253 "Alternatively, consider running neato using -Gpack=true or decomposing\n");
1254 agerr(
AGPREV,
"the graph into connected components.\n");
1265 fprintf(stderr,
"Solving model %d iterations %d tol %f\n",
1295 sgd(g, layoutModel);
1375 if (
Pack < 0 && layoutMode)
1378 }
else if (
Pack < 0)
1390 for (
size_t i = 0; i < n_cc; i++) {
1420 for (
size_t i = 0; i < n_cc; i++) {
expand_t sepFactor(graph_t *g)
int adjustNodes(graph_t *G)
void graphAdjustMode(graph_t *G, adjust_data *dp, char *dflt)
int removeOverlapWith(graph_t *G, adjust_data *am)
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
static void * gv_calloc(size_t nmemb, size_t size)
void arrow_flags(Agedge_t *e, uint32_t *sflag, uint32_t *eflag)
API for compacted arrays of booleans.
static bitarray_t bitarray_new(size_t size_bits)
create an array of the given element length
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
static void bitarray_set(bitarray_t *self, size_t index, bool value)
set or clear the value of the given element
static void bitarray_reset(bitarray_t *self)
free underlying resources and leave a bit array empty
abstract graph C library, Cgraph API
int circuit_model(graph_t *g, int nG)
bool mapbool(const char *p)
void setEdgeType(graph_t *g, int defaultValue)
int late_int(void *obj, attrsym_t *attr, int defaultValue, int minimum)
void common_init_node(node_t *n)
double late_double(void *obj, attrsym_t *attr, double defaultValue, double minimum)
void common_init_edge(edge_t *e)
double get_inputscale(graph_t *g)
void compute_bb(graph_t *g)
void gv_nodesize(node_t *n, bool flip)
bool is_a_cluster(Agraph_t *g)
void freeGraphData(vtx_data *graph)
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 const char adjust[]
#define PS2INCH(a_points)
static int cnt(Dict_t *d, Dtlink_t **set)
int agnedges(Agraph_t *g)
int agnnodes(Agraph_t *g)
size_t agnnodes_z(const Agraph_t *g)
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
int agset(void *obj, char *name, const char *value)
int agxset(void *obj, Agsym_t *sym, const char *value)
char * agget(void *obj, char *name)
char * agxget(void *obj, Agsym_t *sym)
#define agfindedgeattr(g, a)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
void agwarningf(const char *fmt,...)
void agerrorf(const char *fmt,...)
int agerr(agerrlevel_t level, const char *fmt,...)
#define agfindgraphattr(g, a)
#define GD_neato_nlist(g)
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
#define agfindnodeattr(g, a)
Agraph_t * agraphof(void *obj)
char * agnameof(void *)
returns a string descriptor for the object.
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Agraph_t * agroot(void *obj)
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
int agdelrec(void *obj, const char *name)
deletes a named record from one object
Agraph_t * agfstsubg(Agraph_t *g)
Agraph_t * agnxtsubg(Agraph_t *subg)
Agraph_t * graph(char *name)
replacements for ctype.h functions
static bool gv_isdigit(int c)
static bool gv_isalpha(int c)
static bool gv_isspace(int c)
Arithmetic helper functions.
textitem scanner parser str
DistType ** compute_apsp_artificial_weights(vtx_data *graph, int n)
void free_label(textlabel_t *p)
Agraph_t ** pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned)
std::unordered_map< std::pair< int, int >, int, PointHash > PointMap
static void add_cluster(Agraph_t *g, Agraph_t *subg)
static void kkNeato(Agraph_t *g, int nG, int model)
solve using gradient descent a la Kamada-Kawai
static void neato_init_graph(Agraph_t *g)
bool user_pos(attrsym_t *posptr, attrsym_t *pinptr, node_t *np, int nG)
static vtx_data * makeGraphData(graph_t *g, int nv, int *nedges, int mode, int model, node_t ***nodedata)
static int checkEdge(PointMap *pm, edge_t *ep, int idx)
int init_nop(Agraph_t *g, int adjust)
static void neato_init_edge(edge_t *e)
static void majorization(graph_t *mg, graph_t *g, int nv, int mode, int model, int dim, adjust_data *am)
static void initRegular(graph_t *G, int nG)
static void mds_model(graph_t *g)
static void neatoLayout(Agraph_t *mg, Agraph_t *g, int layoutMode, int layoutModel, adjust_data *am)
use stress optimization to layout a single component
static void neato_cleanup_graph(graph_t *g)
static void dfs(Agraph_t *subg, Agraph_t *parentg, attrsym_t *G_lp, attrsym_t *G_bb)
static pos_edge nop_init_edges(Agraph_t *g)
static void nop_init_graphs(Agraph_t *, attrsym_t *, attrsym_t *)
static int neatoModel(graph_t *g)
static void freeEdgeInfo(Agraph_t *g)
void neato_cleanup(graph_t *g)
static size_t numFields(const char *pos)
static int checkExp(graph_t *G)
int checkStart(graph_t *G, int nG, int dflt)
static void set_label(void *obj, textlabel_t *l, char *name)
void neato_layout(Agraph_t *g)
int setSeed(graph_t *G, int dflt, long *seedp)
static int user_spline(attrsym_t *E_pos, edge_t *e)
static int chkBB(Agraph_t *g, attrsym_t *G_bb, boxf *bbp)
static int neatoMode(graph_t *g)
static void addZ(Agraph_t *g)
void neato_init_node(node_t *n)
static void subset_model(Agraph_t *G, int nG)
static void neato_init_node_edge(graph_t *g)
NEATOPROCS_API void spline_edges(Agraph_t *)
NEATOPROCS_API void neato_translate(Agraph_t *g)
NEATOPROCS_API void spline_edges0(Agraph_t *, bool)
NEATOPROCS_API void free_scan_graph(graph_t *)
NEATOPROCS_API void solve_model(graph_t *, int)
NEATOPROCS_API void initial_positions(graph_t *, int)
NEATOPROCS_API void jitter_d(Agnode_t *, int, int)
NEATOPROCS_API void diffeq_model(graph_t *, int)
NEATOPROCS_API bool neato_set_aspect(graph_t *g)
NEATOPROCS_API void jitter3d(Agnode_t *, int)
NEATOPROCS_API int scan_graph(graph_t *)
NEATOPROCS_API void shortest_path(graph_t *, int)
NEATOPROCS_API int scan_graph_mode(graph_t *G, int mode)
pack_mode getPackModeInfo(Agraph_t *g, pack_mode dflt, pack_info *pinfo)
int getPack(Agraph_t *g, int not_def, int dflt)
int packGraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info)
support for connected components
void clearPM(PointMap *ps)
int insertPM(PointMap *pm, int x, int y, int value)
void freePM(PointMap *ps)
point containers PointSet and PointMap
void gv_postprocess(Agraph_t *g, int allowTranslation)
bezier * new_spline(edge_t *e, size_t sz)
create and attach a new Bézier of size sz to the edge d
void gv_cleanup_edge(Agedge_t *e)
void gv_free_splines(edge_t *e)
void gv_cleanup_node(Agnode_t *n)
static int nedges
total no. of edges used in routing
void sgd(graph_t *G, int model)
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
platform abstraction for case-insensitive string functions
static bool streq(const char *a, const char *b)
are a and b equal?
int stress_majorization_kD_mkernel(vtx_data *graph, int n, double **d_coords, node_t **nodes, int dim, int opts, int model, int maxi)
at present, if any nodes have pos set, smart_ini is false
Agraph_t * root
subgraphs - ancestors
bool doSplines
use splines in constructing graph shape
size_t nedges
no. of neighbors, including self