@knowvah/dot-engine 2.6.11 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/README.md +1 -1
  2. package/dist/api.js +18 -4
  3. package/dist/api.js.map +3 -3
  4. package/dist/async/render-async.d.ts.map +1 -1
  5. package/dist/common/agerr.d.ts +37 -0
  6. package/dist/common/agerr.d.ts.map +1 -0
  7. package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
  8. package/dist/common/color.d.ts.map +1 -1
  9. package/dist/common/crand.d.ts +0 -20
  10. package/dist/common/crand.d.ts.map +1 -1
  11. package/dist/common/emit-once.d.ts +6 -0
  12. package/dist/common/emit-once.d.ts.map +1 -0
  13. package/dist/common/graph-init.d.ts.map +1 -1
  14. package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
  15. package/dist/common/htmltable-emit-fill.d.ts +29 -2
  16. package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
  17. package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
  18. package/dist/common/htmltable-emit.d.ts.map +1 -1
  19. package/dist/common/htmltable-lex-expat.d.ts +1 -6
  20. package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
  21. package/dist/common/htmltable-pos-runs.d.ts +7 -4
  22. package/dist/common/htmltable-pos-runs.d.ts.map +1 -1
  23. package/dist/common/htmltable.d.ts +1 -7
  24. package/dist/common/htmltable.d.ts.map +1 -1
  25. package/dist/common/libm-trig.d.ts +5 -0
  26. package/dist/common/libm-trig.d.ts.map +1 -0
  27. package/dist/common/multicolor.d.ts +21 -13
  28. package/dist/common/multicolor.d.ts.map +1 -1
  29. package/dist/common/poly-gencode.d.ts +1 -2
  30. package/dist/common/poly-gencode.d.ts.map +1 -1
  31. package/dist/common/poly-init.d.ts.map +1 -1
  32. package/dist/common/postproc.d.ts.map +1 -1
  33. package/dist/common/random.d.ts.map +1 -1
  34. package/dist/common/render-state.d.ts +8 -0
  35. package/dist/common/render-state.d.ts.map +1 -0
  36. package/dist/common/splines-clip.d.ts +7 -0
  37. package/dist/common/splines-clip.d.ts.map +1 -1
  38. package/dist/common/splines-geom.d.ts +8 -0
  39. package/dist/common/splines-geom.d.ts.map +1 -1
  40. package/dist/common/splines-routespl.d.ts.map +1 -1
  41. package/dist/common/textmeasure-lookup.d.ts.map +1 -1
  42. package/dist/common/textmeasure.d.ts.map +1 -1
  43. package/dist/gvc/anchor.d.ts.map +1 -1
  44. package/dist/gvc/context.d.ts +6 -0
  45. package/dist/gvc/context.d.ts.map +1 -1
  46. package/dist/gvc/device-cluster.d.ts +15 -0
  47. package/dist/gvc/device-cluster.d.ts.map +1 -1
  48. package/dist/gvc/device-labels.d.ts +14 -0
  49. package/dist/gvc/device-labels.d.ts.map +1 -1
  50. package/dist/gvc/device.d.ts.map +1 -1
  51. package/dist/gvc/first-layer.d.ts +9 -0
  52. package/dist/gvc/first-layer.d.ts.map +1 -0
  53. package/dist/gvc/gvrender-set-style.d.ts +28 -0
  54. package/dist/gvc/gvrender-set-style.d.ts.map +1 -0
  55. package/dist/gvc/usershape.d.ts +18 -0
  56. package/dist/gvc/usershape.d.ts.map +1 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +3169 -1296
  59. package/dist/index.js.map +4 -4
  60. package/dist/layout/dot/cluster.d.ts.map +1 -1
  61. package/dist/layout/dot/compound.d.ts.map +1 -1
  62. package/dist/layout/dot/conc.d.ts.map +1 -1
  63. package/dist/layout/dot/decomp.d.ts.map +1 -1
  64. package/dist/layout/dot/edge-route-clip.d.ts +32 -14
  65. package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
  66. package/dist/layout/dot/edge-route-routing.d.ts.map +1 -1
  67. package/dist/layout/dot/mincross-build.d.ts.map +1 -1
  68. package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
  69. package/dist/layout/dot/rank.d.ts.map +1 -1
  70. package/dist/layout/dot/splines.d.ts.map +1 -1
  71. package/dist/layout/fdp/index.d.ts.map +1 -1
  72. package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
  73. package/dist/layout/fdp/xlayout.d.ts.map +1 -1
  74. package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts +11 -0
  75. package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts.map +1 -0
  76. package/dist/layout/neato/__fixtures__/hier-imds.d.ts +36 -0
  77. package/dist/layout/neato/__fixtures__/hier-imds.d.ts.map +1 -0
  78. package/dist/layout/neato/__fixtures__/hier-majorization.d.ts +32 -0
  79. package/dist/layout/neato/__fixtures__/hier-majorization.d.ts.map +1 -0
  80. package/dist/layout/neato/cdt-surface.d.ts.map +1 -1
  81. package/dist/layout/neato/compute-hierarchy.d.ts +24 -0
  82. package/dist/layout/neato/compute-hierarchy.d.ts.map +1 -0
  83. package/dist/layout/neato/conjgrad-mkernel.d.ts +20 -0
  84. package/dist/layout/neato/conjgrad-mkernel.d.ts.map +1 -0
  85. package/dist/layout/neato/conjgrad.d.ts +19 -0
  86. package/dist/layout/neato/conjgrad.d.ts.map +1 -1
  87. package/dist/layout/neato/constrained-majorization.d.ts +26 -0
  88. package/dist/layout/neato/constrained-majorization.d.ts.map +1 -0
  89. package/dist/layout/neato/dijkstra.d.ts +33 -16
  90. package/dist/layout/neato/dijkstra.d.ts.map +1 -1
  91. package/dist/layout/neato/edge-len.d.ts.map +1 -1
  92. package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
  93. package/dist/layout/neato/gts-triangle.d.ts +14 -0
  94. package/dist/layout/neato/gts-triangle.d.ts.map +1 -0
  95. package/dist/layout/neato/init.d.ts +6 -22
  96. package/dist/layout/neato/init.d.ts.map +1 -1
  97. package/dist/layout/neato/kk.d.ts.map +1 -1
  98. package/dist/layout/neato/kkutils.d.ts +20 -0
  99. package/dist/layout/neato/kkutils.d.ts.map +1 -0
  100. package/dist/layout/neato/make-graph-data.d.ts +43 -0
  101. package/dist/layout/neato/make-graph-data.d.ts.map +1 -0
  102. package/dist/layout/neato/matrix-ops.d.ts +46 -0
  103. package/dist/layout/neato/matrix-ops.d.ts.map +1 -1
  104. package/dist/layout/neato/multispline-router.d.ts.map +1 -1
  105. package/dist/layout/neato/multispline.d.ts.map +1 -1
  106. package/dist/layout/neato/opt-arrangement.d.ts +20 -0
  107. package/dist/layout/neato/opt-arrangement.d.ts.map +1 -0
  108. package/dist/layout/neato/poly.d.ts.map +1 -1
  109. package/dist/layout/neato/quad-prog-solve.d.ts +44 -0
  110. package/dist/layout/neato/quad-prog-solve.d.ts.map +1 -0
  111. package/dist/layout/neato/sgd.d.ts.map +1 -1
  112. package/dist/layout/neato/smart-ini-x.d.ts +9 -0
  113. package/dist/layout/neato/smart-ini-x.d.ts.map +1 -0
  114. package/dist/layout/neato/splines.d.ts +1 -1
  115. package/dist/layout/neato/splines.d.ts.map +1 -1
  116. package/dist/layout/neato/start.d.ts +4 -1
  117. package/dist/layout/neato/start.d.ts.map +1 -1
  118. package/dist/layout/neato/stress.d.ts +8 -0
  119. package/dist/layout/neato/stress.d.ts.map +1 -1
  120. package/dist/model/edge.d.ts +1 -1
  121. package/dist/model/edge.d.ts.map +1 -1
  122. package/dist/model/lazy-attrs.d.ts +10 -0
  123. package/dist/model/lazy-attrs.d.ts.map +1 -0
  124. package/dist/model/node.d.ts +1 -1
  125. package/dist/model/node.d.ts.map +1 -1
  126. package/dist/ortho/index.d.ts.map +1 -1
  127. package/dist/parser/index.d.ts.map +1 -1
  128. package/dist/render/color-resolve.d.ts +49 -1
  129. package/dist/render/color-resolve.d.ts.map +1 -1
  130. package/dist/render/dot/edge-draw.d.ts +1 -1
  131. package/dist/render/dot/edge-draw.d.ts.map +1 -1
  132. package/dist/render/public.d.ts.map +1 -1
  133. package/dist/render/svg-edge-split.d.ts +2 -0
  134. package/dist/render/svg-edge-split.d.ts.map +1 -1
  135. package/dist/render/svg-multicolor.d.ts +2 -2
  136. package/dist/render/svg-multicolor.d.ts.map +1 -1
  137. package/dist/render/xdot-public.d.ts.map +1 -1
  138. package/dist/render.js +2799 -927
  139. package/dist/render.js.map +4 -4
  140. package/package.json +1 -1
  141. package/src/async/render-async.ts +6 -0
  142. package/src/common/agerr.ts +96 -0
  143. package/src/common/arrows-shapes-poly.ts +19 -5
  144. package/src/common/color.ts +38 -10
  145. package/src/common/crand.ts +8 -2
  146. package/src/common/emit-once.ts +27 -0
  147. package/src/common/graph-init.ts +2 -1
  148. package/src/common/htmltable-attr-warn.ts +3 -4
  149. package/src/common/htmltable-emit-fill.ts +104 -11
  150. package/src/common/htmltable-emit-rules.ts +2 -0
  151. package/src/common/htmltable-emit.ts +4 -3
  152. package/src/common/htmltable-lex-expat.ts +96 -23
  153. package/src/common/htmltable-pos-runs.ts +11 -6
  154. package/src/common/htmltable.ts +28 -117
  155. package/src/common/libm-trig.ts +43 -0
  156. package/src/common/multicolor.ts +88 -24
  157. package/src/common/poly-gencode.ts +30 -10
  158. package/src/common/poly-init.ts +20 -1
  159. package/src/common/postproc.ts +4 -1
  160. package/src/common/random.ts +11 -1
  161. package/src/common/render-state.ts +36 -0
  162. package/src/common/splines-clip.ts +15 -12
  163. package/src/common/splines-geom.ts +8 -4
  164. package/src/common/splines-routespl.ts +2 -1
  165. package/src/common/textmeasure-lookup.ts +9 -2
  166. package/src/common/textmeasure.ts +45 -2
  167. package/src/gvc/anchor.ts +1 -12
  168. package/src/gvc/context.ts +8 -0
  169. package/src/gvc/device-cluster.ts +93 -10
  170. package/src/gvc/device-labels.ts +27 -0
  171. package/src/gvc/device.ts +34 -8
  172. package/src/gvc/first-layer.ts +26 -0
  173. package/src/gvc/gvrender-set-style.ts +114 -0
  174. package/src/gvc/usershape.ts +26 -0
  175. package/src/index.ts +3 -0
  176. package/src/layout/dot/cluster.ts +2 -1
  177. package/src/layout/dot/compound.ts +3 -4
  178. package/src/layout/dot/conc.ts +6 -5
  179. package/src/layout/dot/decomp.ts +3 -0
  180. package/src/layout/dot/edge-route-clip.ts +46 -28
  181. package/src/layout/dot/edge-route-routing.ts +11 -3
  182. package/src/layout/dot/fastgr.ts +2 -2
  183. package/src/layout/dot/mincross-build.ts +2 -0
  184. package/src/layout/dot/mincross-cross.ts +2 -0
  185. package/src/layout/dot/rank.ts +2 -0
  186. package/src/layout/dot/splines.ts +2 -1
  187. package/src/layout/fdp/index.ts +2 -1
  188. package/src/layout/fdp/tlayout-parms.ts +9 -2
  189. package/src/layout/fdp/xlayout.ts +10 -2
  190. package/src/layout/neato/__fixtures__/dijkstra-f.ts +17 -0
  191. package/src/layout/neato/__fixtures__/hier/c1554.gv +33 -0
  192. package/src/layout/neato/__fixtures__/hier/c1554.plain +26 -0
  193. package/src/layout/neato/__fixtures__/hier/c1554.xdot +161 -0
  194. package/src/layout/neato/__fixtures__/hier/cases/cycle.gv +1 -0
  195. package/src/layout/neato/__fixtures__/hier/cases/cycle.plain +10 -0
  196. package/src/layout/neato/__fixtures__/hier/cases/cycle.stderr +0 -0
  197. package/src/layout/neato/__fixtures__/hier/cases/dirnone.gv +1 -0
  198. package/src/layout/neato/__fixtures__/hier/cases/dirnone.plain +11 -0
  199. package/src/layout/neato/__fixtures__/hier/cases/dirnone.stderr +0 -0
  200. package/src/layout/neato/__fixtures__/hier/cases/epsilon.gv +1 -0
  201. package/src/layout/neato/__fixtures__/hier/cases/epsilon.plain +13 -0
  202. package/src/layout/neato/__fixtures__/hier/cases/epsilon.stderr +0 -0
  203. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.gv +1 -0
  204. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.plain +8 -0
  205. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.stderr +0 -0
  206. package/src/layout/neato/__fixtures__/hier/cases/mds.gv +1 -0
  207. package/src/layout/neato/__fixtures__/hier/cases/mds.plain +10 -0
  208. package/src/layout/neato/__fixtures__/hier/cases/mds.stderr +0 -0
  209. package/src/layout/neato/__fixtures__/hier/cases/multiedge.gv +1 -0
  210. package/src/layout/neato/__fixtures__/hier/cases/multiedge.plain +10 -0
  211. package/src/layout/neato/__fixtures__/hier/cases/multiedge.stderr +0 -0
  212. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.gv +1 -0
  213. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.plain +8 -0
  214. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.stderr +0 -0
  215. package/src/layout/neato/__fixtures__/hier/cases/startrandom.gv +1 -0
  216. package/src/layout/neato/__fixtures__/hier/cases/startrandom.plain +10 -0
  217. package/src/layout/neato/__fixtures__/hier/cases/startrandom.stderr +0 -0
  218. package/src/layout/neato/__fixtures__/hier/cases/startregular.gv +1 -0
  219. package/src/layout/neato/__fixtures__/hier/cases/startregular.plain +10 -0
  220. package/src/layout/neato/__fixtures__/hier/cases/startregular.stderr +0 -0
  221. package/src/layout/neato/__fixtures__/hier/cases/tdist.gv +1 -0
  222. package/src/layout/neato/__fixtures__/hier/cases/tdist.plain +13 -0
  223. package/src/layout/neato/__fixtures__/hier/cases/tdist.stderr +0 -0
  224. package/src/layout/neato/__fixtures__/hier/cases/undirected.gv +1 -0
  225. package/src/layout/neato/__fixtures__/hier/cases/undirected.plain +10 -0
  226. package/src/layout/neato/__fixtures__/hier/cases/undirected.stderr +0 -0
  227. package/src/layout/neato/__fixtures__/hier/hier-probe.gv +1 -0
  228. package/src/layout/neato/__fixtures__/hier/hier-probe.plain +16 -0
  229. package/src/layout/neato/__fixtures__/hier/hier-probe.xdot +62 -0
  230. package/src/layout/neato/__fixtures__/hier-imds.ts +151 -0
  231. package/src/layout/neato/__fixtures__/hier-majorization.ts +145 -0
  232. package/src/layout/neato/cdt-surface.ts +12 -22
  233. package/src/layout/neato/compute-hierarchy.ts +90 -0
  234. package/src/layout/neato/conjgrad-mkernel.ts +141 -0
  235. package/src/layout/neato/conjgrad.ts +208 -0
  236. package/src/layout/neato/constrained-majorization.ts +479 -0
  237. package/src/layout/neato/dijkstra.ts +218 -92
  238. package/src/layout/neato/edge-len.ts +2 -1
  239. package/src/layout/neato/fdp-adjust.ts +3 -2
  240. package/src/layout/neato/gts-triangle.ts +42 -0
  241. package/src/layout/neato/init.ts +68 -68
  242. package/src/layout/neato/kk.ts +2 -1
  243. package/src/layout/neato/kkutils.ts +96 -0
  244. package/src/layout/neato/make-graph-data.ts +166 -0
  245. package/src/layout/neato/matrix-ops.ts +138 -0
  246. package/src/layout/neato/multispline-router.ts +3 -3
  247. package/src/layout/neato/multispline.ts +3 -2
  248. package/src/layout/neato/opt-arrangement.ts +86 -0
  249. package/src/layout/neato/poly.ts +3 -2
  250. package/src/layout/neato/quad-prog-solve.ts +489 -0
  251. package/src/layout/neato/sgd.ts +5 -2
  252. package/src/layout/neato/smart-ini-x.ts +503 -0
  253. package/src/layout/neato/splines.ts +4 -4
  254. package/src/layout/neato/start.ts +19 -14
  255. package/src/layout/neato/stress.ts +28 -0
  256. package/src/model/edge.ts +3 -2
  257. package/src/model/lazy-attrs.ts +36 -0
  258. package/src/model/node.ts +3 -2
  259. package/src/ortho/index.ts +2 -1
  260. package/src/parser/dot.js +4 -1
  261. package/src/parser/dot.pegjs +5 -1
  262. package/src/parser/index.ts +4 -3
  263. package/src/render/color-resolve.ts +193 -4
  264. package/src/render/dot/edge-draw.ts +6 -3
  265. package/src/render/dot.ts +1 -1
  266. package/src/render/public.ts +2 -0
  267. package/src/render/svg-edge-split.ts +6 -4
  268. package/src/render/svg-multicolor.ts +4 -3
  269. package/src/render/svg-parallel-edge.ts +2 -2
  270. package/src/render/xdot-public.ts +2 -0
@@ -30,126 +30,252 @@ export interface TermSgd {
30
30
  }
31
31
 
32
32
  // ---------------------------------------------------------------------------
33
- // Min-heap (keyed by Float32Array distances)
33
+ // Float Dijkstra: dijkstra_f and its indexed heap (shares NgHeap and the
34
+ // exchange / assign helpers with the DistType heap below)
34
35
  // ---------------------------------------------------------------------------
35
36
 
36
- /** Push vertex index `idx` into the heap. @internal */
37
- export function heapPush(
38
- heap: number[],
39
- dist: Float32Array,
40
- idx: number,
41
- ): void {
42
- let pos = heap.length;
43
- heap.push(idx);
44
- while (pos > 0) {
45
- const parent = (pos - 1) >> 1;
46
- if (dist[heap[parent]] <= dist[heap[pos]]) break;
47
- const tmp = heap[parent];
48
- heap[parent] = heap[pos];
49
- heap[pos] = tmp;
50
- pos = parent;
51
- }
37
+ /** C `FLT_MAX`: the "unreachable" distance of dijkstra_f. */
38
+ export const FLT_MAX = 3.4028234663852886e38;
39
+
40
+ /** @see lib/neatogen/dijkstra.c:greaterPriority_f */
41
+ function greaterPriorityF(h: NgHeap, i: number, j: number, dist: Float32Array): boolean {
42
+ return dist[h.data[i]!]! < dist[h.data[j]!]!;
52
43
  }
53
44
 
54
- /** Sift the root down to restore heap order after replacing it. @internal */
55
- export function heapSiftDown(heap: number[], dist: Float32Array): void {
56
- let pos = 0;
45
+ /** @see lib/neatogen/dijkstra.c:heapify_f */
46
+ function heapifyF(h: NgHeap, start: number, dist: Float32Array): void {
47
+ let i = start;
57
48
  for (;;) {
58
- const l = 2 * pos + 1;
59
- const r = 2 * pos + 2;
60
- let smallest = pos;
61
- if (l < heap.length && dist[heap[l]] < dist[heap[smallest]]) smallest = l;
62
- if (r < heap.length && dist[heap[r]] < dist[heap[smallest]]) smallest = r;
63
- if (smallest === pos) break;
64
- const tmp = heap[smallest];
65
- heap[smallest] = heap[pos];
66
- heap[pos] = tmp;
67
- pos = smallest;
49
+ const l = ngLeft(i);
50
+ const r = ngRight(i);
51
+ let largest = ngInsideHeap(h, l) && greaterPriorityF(h, l, i, dist) ? l : i;
52
+ if (ngInsideHeap(h, r) && greaterPriorityF(h, r, largest, dist)) largest = r;
53
+ if (largest === i) break;
54
+ ngExchange(h, largest, i);
55
+ i = largest;
68
56
  }
69
57
  }
70
58
 
71
- /** Pop and return the vertex with minimum distance. @internal */
72
- export function heapPop(heap: number[], dist: Float32Array): number {
73
- const top = heap[0];
74
- const last = heap.pop()!;
75
- if (heap.length === 0) return top;
76
- heap[0] = last;
77
- heapSiftDown(heap, dist);
78
- return top;
79
- }
80
-
81
- /** Build a min-heap from all nodes except `src`. @internal */
82
- export function heapBuildExcluding(
83
- src: number,
84
- n: number,
85
- dist: Float32Array,
86
- ): number[] {
87
- const heap: number[] = [];
59
+ /** @see lib/neatogen/dijkstra.c:initHeap_f */
60
+ function initHeapF(startVertex: number, dist: Float32Array, n: number): NgHeap {
61
+ const h: NgHeap = {
62
+ data: new Array<number>(Math.max(n - 1, 0)).fill(0),
63
+ heapSize: n - 1,
64
+ index: new Int32Array(n),
65
+ };
66
+ let count = 0;
88
67
  for (let i = 0; i < n; i++) {
89
- if (i !== src) heapPush(heap, dist, i);
68
+ if (i !== startVertex) {
69
+ h.data[count] = i;
70
+ h.index[i] = count;
71
+ count++;
72
+ }
90
73
  }
91
- return heap;
74
+ for (let j = Math.trunc((n - 1) / 2); j >= 0; j--) heapifyF(h, j, dist);
75
+ return h;
92
76
  }
93
77
 
94
- // ---------------------------------------------------------------------------
95
- // dijkstra helpers
96
- // ---------------------------------------------------------------------------
78
+ /**
79
+ * Pops the closest vertex; returns -1 (C `false`) when the heap is empty.
80
+ * @see lib/neatogen/dijkstra.c:extractMax_f
81
+ */
82
+ function extractMaxF(h: NgHeap, dist: Float32Array): number {
83
+ if (h.heapSize === 0) return -1;
84
+ const max = h.data[0]!;
85
+ h.data[0] = h.data[h.heapSize - 1]!;
86
+ h.index[h.data[0]] = 0;
87
+ h.heapSize--;
88
+ heapifyF(h, 0, dist);
89
+ return max;
90
+ }
97
91
 
98
- /** Initialise dist array from source edges. @internal */
99
- export function dijkstraInitDist(
100
- src: number,
101
- graph: VtxData[],
102
- n: number,
103
- dist: Float32Array,
92
+ /** @see lib/neatogen/dijkstra.c:increaseKey_f */
93
+ function increaseKeyF(
94
+ h: NgHeap, increasedVertex: number, newDist: number, dist: Float32Array,
104
95
  ): void {
105
- for (let i = 0; i < n; i++) dist[i] = Infinity;
106
- dist[src] = 0;
107
- const v = graph[src];
108
- for (let i = 1; i < v.nedges; i++) dist[v.edges[i]] = v.ewgts[i];
96
+ if (dist[increasedVertex]! <= newDist) return;
97
+ let i = h.index[increasedVertex]!;
98
+ dist[increasedVertex] = newDist;
99
+ while (i > 0 && dist[h.data[ngParent(i)]!]! > newDist) {
100
+ ngAssign(h, i, ngParent(i));
101
+ i = ngParent(i);
102
+ }
103
+ h.data[i] = increasedVertex;
104
+ h.index[increasedVertex] = i;
109
105
  }
110
106
 
111
- /** Relax all outgoing edges of `closest`. @internal */
112
- export function dijkstraRelax(
113
- closest: number,
114
- closestDist: number,
107
+ /**
108
+ * Weighted single-source shortest paths from `vertex`; assumes a connected
109
+ * graph, unreachable vertices keep `FLT_MAX`. All arithmetic is C `float`.
110
+ *
111
+ * @see lib/neatogen/dijkstra.c:dijkstra_f
112
+ */
113
+ export function dijkstra(
114
+ vertex: number,
115
115
  graph: VtxData[],
116
+ n: number,
116
117
  dist: Float32Array,
117
- heap: number[],
118
118
  ): void {
119
- const cv = graph[closest];
120
- for (let i = 1; i < cv.nedges; i++) {
121
- const nb = cv.edges[i];
122
- const nd = closestDist + cv.ewgts[i];
123
- if (nd < dist[nb]) {
124
- dist[nb] = nd;
125
- heapPush(heap, dist, nb);
119
+ for (let i = 0; i < n; i++) dist[i] = FLT_MAX;
120
+ dist[vertex] = 0;
121
+ const vd = graph[vertex]!;
122
+ for (let i = 1; i < vd.nedges; i++) dist[vd.edges[i]!] = vd.ewgts[i]!;
123
+
124
+ const h = initHeapF(vertex, dist, n);
125
+ for (let closest = extractMaxF(h, dist); closest >= 0; closest = extractMaxF(h, dist)) {
126
+ const closestDist = dist[closest]!;
127
+ if (closestDist === FLT_MAX) break;
128
+ const cd = graph[closest]!;
129
+ for (let i = 1; i < cd.nedges; i++) {
130
+ increaseKeyF(h, cd.edges[i]!, Math.fround(closestDist + Math.fround(cd.ewgts[i]!)), dist);
126
131
  }
127
132
  }
128
133
  }
129
134
 
130
135
  // ---------------------------------------------------------------------------
131
- // Public: dijkstra (float-weight, float-output)
136
+ // Integer (DistType) Dijkstra: ngdijkstra and its max-heap
132
137
  // ---------------------------------------------------------------------------
133
138
 
139
+ /** C `(DistType)INT_MAX`. @see lib/neatogen/dijkstra.c:MAX_DIST */
140
+ export const MAX_DIST = 2147483647;
141
+
134
142
  /**
135
- * Single-source shortest paths (weighted) from `src`.
136
- * Populates `dist` with Float32 distances; unreachable nodes get Infinity.
137
- * Equivalent to `dijkstra_f` in lib/neatogen/dijkstra.c.
138
- *
139
- * @see lib/neatogen/dijkstra.c:dijkstra_f
143
+ * The heap of dijkstra.c: `data[i] = vertexNum <=> index[vertexNum] = i`, with
144
+ * the 0-rooted `left = 2i`, `right = 2i + 1`, `parent = i / 2` numbering.
145
+ * @see lib/neatogen/dijkstra.c:heap
140
146
  */
141
- export function dijkstra(
142
- src: number,
143
- graph: VtxData[],
144
- n: number,
145
- dist: Float32Array,
147
+ export interface NgHeap {
148
+ data: number[];
149
+ heapSize: number;
150
+ index: Int32Array;
151
+ }
152
+
153
+ /** @see lib/neatogen/dijkstra.c:left */
154
+ function ngLeft(i: number): number { return 2 * i; }
155
+
156
+ /** @see lib/neatogen/dijkstra.c:right */
157
+ function ngRight(i: number): number { return 2 * i + 1; }
158
+
159
+ /** @see lib/neatogen/dijkstra.c:parent */
160
+ function ngParent(i: number): number { return Math.trunc(i / 2); }
161
+
162
+ /** @see lib/neatogen/dijkstra.c:insideHeap */
163
+ function ngInsideHeap(h: NgHeap, i: number): boolean { return i < h.heapSize; }
164
+
165
+ /** @see lib/neatogen/dijkstra.c:greaterPriority */
166
+ function ngGreaterPriority(h: NgHeap, i: number, j: number, dist: Int32Array): boolean {
167
+ return dist[h.data[i]!]! < dist[h.data[j]!]!;
168
+ }
169
+
170
+ /** @see lib/neatogen/dijkstra.c:assign */
171
+ function ngAssign(h: NgHeap, i: number, j: number): void {
172
+ h.data[i] = h.data[j]!;
173
+ h.index[h.data[i]!] = i;
174
+ }
175
+
176
+ /** @see lib/neatogen/dijkstra.c:exchange */
177
+ function ngExchange(h: NgHeap, i: number, j: number): void {
178
+ const t = h.data[i]!;
179
+ h.data[i] = h.data[j]!;
180
+ h.data[j] = t;
181
+ h.index[h.data[i]!] = i;
182
+ h.index[h.data[j]!] = j;
183
+ }
184
+
185
+ /** @see lib/neatogen/dijkstra.c:heapify */
186
+ function ngHeapify(h: NgHeap, start: number, dist: Int32Array): void {
187
+ let i = start;
188
+ for (;;) {
189
+ const l = ngLeft(i);
190
+ const r = ngRight(i);
191
+ let largest = ngInsideHeap(h, l) && ngGreaterPriority(h, l, i, dist) ? l : i;
192
+ if (ngInsideHeap(h, r) && ngGreaterPriority(h, r, largest, dist)) largest = r;
193
+ if (largest === i) break;
194
+ ngExchange(h, largest, i);
195
+ i = largest;
196
+ }
197
+ }
198
+
199
+ /** @see lib/neatogen/dijkstra.c:initHeap */
200
+ export function ngInitHeap(startVertex: number, dist: Int32Array, n: number): NgHeap {
201
+ const h: NgHeap = {
202
+ data: new Array<number>(Math.max(n - 1, 0)).fill(0),
203
+ heapSize: n - 1,
204
+ index: new Int32Array(n),
205
+ };
206
+ let count = 0;
207
+ for (let i = 0; i < n; i++) {
208
+ if (i !== startVertex) {
209
+ h.data[count] = i;
210
+ h.index[i] = count;
211
+ count++;
212
+ }
213
+ }
214
+ for (let j = Math.trunc((n - 1) / 2); j >= 0; j--) ngHeapify(h, j, dist);
215
+ return h;
216
+ }
217
+
218
+ /**
219
+ * Pops the closest vertex; returns -1 (C `false`) when the heap is empty.
220
+ * @see lib/neatogen/dijkstra.c:extractMax
221
+ */
222
+ export function ngExtractMax(h: NgHeap, dist: Int32Array): number {
223
+ if (h.heapSize === 0) return -1;
224
+ const max = h.data[0]!;
225
+ h.data[0] = h.data[h.heapSize - 1]!;
226
+ h.index[h.data[0]] = 0;
227
+ h.heapSize--;
228
+ ngHeapify(h, 0, dist);
229
+ return max;
230
+ }
231
+
232
+ /** @see lib/neatogen/dijkstra.c:increaseKey */
233
+ export function ngIncreaseKey(
234
+ h: NgHeap, increasedVertex: number, newDist: number, dist: Int32Array,
146
235
  ): void {
147
- dijkstraInitDist(src, graph, n, dist);
148
- const heap = heapBuildExcluding(src, n, dist);
149
- while (heap.length > 0) {
150
- const closest = heapPop(heap, dist);
151
- const closestDist = dist[closest];
152
- if (!isFinite(closestDist)) break;
153
- dijkstraRelax(closest, closestDist, graph, dist, heap);
236
+ if (dist[increasedVertex]! <= newDist) return;
237
+ let i = h.index[increasedVertex]!;
238
+ dist[increasedVertex] = newDist;
239
+ while (i > 0 && dist[h.data[ngParent(i)]!]! > newDist) {
240
+ ngAssign(h, i, ngParent(i));
241
+ i = ngParent(i);
242
+ }
243
+ h.data[i] = increasedVertex;
244
+ h.index[increasedVertex] = i;
245
+ }
246
+
247
+ /** C `(DistType)` of a float edge weight (truncation toward zero). */
248
+ function toDistType(w: number): number {
249
+ return Math.trunc(Math.fround(w));
250
+ }
251
+
252
+ /**
253
+ * Single-source shortest paths on the int-truncated edge weights `ewgts`;
254
+ * unreachable vertices get `prevClosestDist + 10` (INT_MAX when that would
255
+ * overflow).
256
+ * @see lib/neatogen/dijkstra.c:ngdijkstra
257
+ */
258
+ export function ngdijkstra(vertex: number, graph: VtxData[], n: number, dist: Int32Array): void {
259
+ let prevClosestDist = MAX_DIST;
260
+ for (let i = 0; i < n; i++) dist[i] = MAX_DIST;
261
+ dist[vertex] = 0;
262
+ const vd = graph[vertex]!;
263
+ for (let i = 1; i < vd.nedges; i++) dist[vd.edges[i]!] = toDistType(vd.ewgts[i]!);
264
+
265
+ const h = ngInitHeap(vertex, dist, n);
266
+ for (let closest = ngExtractMax(h, dist); closest >= 0; closest = ngExtractMax(h, dist)) {
267
+ const closestDist = dist[closest]!;
268
+ if (closestDist === MAX_DIST) break;
269
+ const cd = graph[closest]!;
270
+ for (let i = 1; i < cd.nedges; i++) {
271
+ ngIncreaseKey(h, cd.edges[i]!, (closestDist + toDistType(cd.ewgts[i]!)) | 0, dist);
272
+ }
273
+ prevClosestDist = closestDist;
274
+ }
275
+
276
+ for (let i = 0; i < n; i++) {
277
+ if (dist[i] === MAX_DIST) {
278
+ dist[i] = MAX_DIST - prevClosestDist < 10 ? MAX_DIST : prevClosestDist + 10;
279
+ }
154
280
  }
155
281
  }
@@ -9,6 +9,7 @@
9
9
 
10
10
  import type { Graph } from '../../model/graph.js';
11
11
  import type { Edge } from '../../model/edge.js';
12
+ import { agwarningf } from '../../common/agerr.js';
12
13
 
13
14
  /** `dfltlen` passed by scan_graph_mode. @see lib/neatogen/stuff.c:scan_graph_mode */
14
15
  export const DEFAULT_EDGE_LEN = 1.0;
@@ -24,7 +25,7 @@ export function lenattr(ep: Edge, g: Graph): number {
24
25
  const val = /^\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(s);
25
26
  const len = val === null ? Number.NaN : parseFloat(val[0]);
26
27
  if (Number.isNaN(len) || len < 0 || len === 0) {
27
- console.warn(`bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
28
+ agwarningf(`bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
28
29
  return DEFAULT_EDGE_LEN;
29
30
  }
30
31
  return len;
@@ -26,6 +26,7 @@ import { vpscAdjust } from './vpsc-adjust.js';
26
26
  import { sepFactor } from './sep-factor.js';
27
27
  import { lateDouble } from '../../common/nodeinit.js';
28
28
  import { RenderError } from '../../errors.js';
29
+ import { agwarningf } from '../../common/agerr.js';
29
30
 
30
31
  /** @see lib/neatogen/adjust.c:DFLT_MARGIN (points) */
31
32
  const DFLT_MARGIN = 4;
@@ -161,7 +162,7 @@ export function warnUnrecognizedOverlap(flag: string | undefined): void {
161
162
  const s = flag.toLowerCase();
162
163
  if (s.startsWith('prism') || NAMED_MODES.has(s)) return;
163
164
  if (mapBoolDflt(flag, false) === mapBoolDflt(flag, true)) return;
164
- console.warn(`Unrecognized overlap value "${flag}" - using false`);
165
+ agwarningf(`Unrecognized overlap value "${flag}" - using false`);
165
166
  }
166
167
 
167
168
  /**
@@ -203,7 +204,7 @@ function adjustLate(g: Graph, am: AdjustData): number {
203
204
  case AM_IPSEP: return 0;
204
205
  case AM_VPSC: return vpscAdjust(g);
205
206
  default:
206
- console.warn(`Unhandled adjust option ${am.print}`);
207
+ agwarningf(`Unhandled adjust option ${am.print}`);
207
208
  return 0;
208
209
  }
209
210
  }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: EPL-2.0
2
+ /**
3
+ * GTS's enclosing triangle, split from cdt-surface.ts to mirror the GTS source
4
+ * file it ports (the oracle links libgts 0.7.6 for neato's constrained
5
+ * Delaunay triangulation).
6
+ * @see gts-0.7.6 src/triangle.c
7
+ */
8
+
9
+ import { fma } from '../../common/fma.js';
10
+
11
+ /** `#define SQRT3 1.73205080757` (gts-0.7.6 src/triangle.c). */
12
+ const SQRT3 = 1.73205080757;
13
+
14
+ /**
15
+ * Vertices of the triangle enclosing points (px[0..n), py[0..n)). The oracle's
16
+ * libgts (arm64) fuses r*SQRT3 + xo, r*2 + yo, xo - r*SQRT3 and
17
+ * dx*dx + dy*dy (fmadd/fmsub in _gts_triangle_enclosing), so those are fma.
18
+ * @see gts-0.7.6 src/triangle.c:gts_triangle_enclosing
19
+ */
20
+ export function gtsTriangleEnclosing(
21
+ px: number[], py: number[], n: number, scale: number,
22
+ ): [[number, number], [number, number], [number, number]] {
23
+ let xmin = px[0]!; let xmax = px[0]!;
24
+ let ymin = py[0]!; let ymax = py[0]!;
25
+ for (let i = 1; i < n; i++) {
26
+ if (px[i]! > xmax) xmax = px[i]!;
27
+ else if (px[i]! < xmin) xmin = px[i]!;
28
+ if (py[i]! > ymax) ymax = py[i]!;
29
+ else if (py[i]! < ymin) ymin = py[i]!;
30
+ }
31
+ const xo = (xmax + xmin) / 2;
32
+ const yo = (ymax + ymin) / 2;
33
+ const dx = xmax - xo;
34
+ const dy = ymax - yo;
35
+ let r = scale * Math.sqrt(fma(dx, dx, dy * dy));
36
+ if (r === 0) r = scale;
37
+ return [
38
+ [fma(r, SQRT3, xo), yo - r],
39
+ [xo, fma(r, 2, yo)],
40
+ [fma(-r, SQRT3, xo), yo - r],
41
+ ];
42
+ }
@@ -16,15 +16,22 @@ import type { Edge } from '../../model/edge.js';
16
16
  import type { VtxData } from './dijkstra.js';
17
17
  import {
18
18
  DFLT_ITERATIONS,
19
+ OPT_SMART_INIT as STRESS_OPT_SMART_INIT,
19
20
  MODEL_MDS as STRESS_MODEL_MDS,
20
21
  MODEL_CIRCUIT as STRESS_MODEL_CIRCUIT,
21
22
  MODEL_SUBSET as STRESS_MODEL_SUBSET,
22
23
  } from './stress.js';
23
24
  import { sgdLayout } from './sgd.js';
24
25
  import { kkNeato } from './kk.js';
25
- import { checkStart, assertSupported, parseStart, INIT_RANDOM, INIT_REGULAR } from './start.js';
26
-
27
- export { checkStart };
26
+ import {
27
+ checkStart, assertSupported, parseStart, INIT_RANDOM, INIT_REGULAR, INIT_SELF,
28
+ } from './start.js';
29
+ import { makeGraphDataC, graphHasLen } from './make-graph-data.js';
30
+ import type { DirectedVtxData } from './opt-arrangement.js';
31
+ import { stressMajorizationWithHierarchy } from './constrained-majorization.js';
32
+ import { agerr } from '../../common/agerr.js';
33
+
34
+ export { makeGraphDataC, graphHasLen, checkStart };
28
35
  import { mapbool } from '../dot/rank.js';
29
36
  import {
30
37
  computeApspPacked,
@@ -50,6 +57,7 @@ export const MODE_HIER = 2;
50
57
  export const MODE_IPSEP = 3;
51
58
  /** Stochastic gradient descent. @see lib/neatogen/neatoprocs.h */
52
59
  export const MODE_SGD = 4;
60
+ /** `MaxIter` under MODE_SGD. @see neatoinit.c:1285 */ const SGD_ITERATIONS = 30;
53
61
 
54
62
  // ---------------------------------------------------------------------------
55
63
  // Model constants — @see lib/neatogen/defs.h
@@ -321,79 +329,75 @@ export function mapModelToStress(model: number): number {
321
329
  // solveModel helpers
322
330
  // ---------------------------------------------------------------------------
323
331
 
324
- /** Run stress majorization and write positions back. @see lib/neatogen/neatoinit.c:majorization */
325
- export function runMajorization(g: Graph, mode: number, model: number): void {
326
- void model; // only MODEL_SHORTPATH distances are exercised by the suite
327
- const nodeList = assignNodeIds(g);
332
+ /** `MaxIter` per mode; `maxiter` goes through C `atoi` (no digits -> 0). @see neatoinit.c:1280-1287 */
333
+ export function neatoMaxIter(maxiter: string | undefined, mode: number, n: number): number {
334
+ if (maxiter !== undefined) return parseInt(maxiter, 10) || 0;
335
+ if (mode === MODE_MAJOR) return DFLT_ITERATIONS;
336
+ return mode === MODE_SGD ? SGD_ITERATIONS : 100 * n;
337
+ }
338
+
339
+ /** `late_double(g, "levelsgap", 0.0, -DBL_MAX)`. @see lib/neatogen/neatoinit.c:majorization */
340
+ const levelsGapOf = (g: Graph): number =>
341
+ lateDouble(g.root.attrs.get('levelsgap'), 0.0, -Number.MAX_VALUE);
342
+
343
+ /** What `majorization` was called with, plus the options derived from it. */
344
+ interface MajorizationCtx {
345
+ readonly g: Graph;
346
+ readonly mode: number;
347
+ readonly model: number;
348
+ readonly haveLen: boolean;
349
+ /** `opt_*` bits from `checkExp` and `checkStart`. */
350
+ readonly opts: number;
351
+ }
352
+
353
+ /**
354
+ * The solver step of `majorization`: `stress_majorization_with_hierarchy` for
355
+ * MODE_HIER, else the kD_mkernel (MODE_IPSEP without constraints runs it too).
356
+ * Returns C's `rv`; the coordinates are left in `dCoords`.
357
+ * @see lib/neatogen/neatoinit.c:majorization
358
+ */
359
+ function solveStress(
360
+ c: MajorizationCtx, vtx: DirectedVtxData[], dCoords: Float64Array[], nodeList: Node[],
361
+ ): number {
362
+ const { g, mode, model, haveLen, opts } = c;
328
363
  const n = nodeList.length;
329
- const haveLen = graphHasLen(g);
330
- const vtx = makeGraphDataC(g, nodeList, haveLen, mode === MODE_HIER || mode === MODE_IPSEP);
331
- checkStart(g); // C: srand48(seed) immediately before initLayout draws
332
- const maxi = lateDouble(g.attrs.get('maxiter'), DFLT_ITERATIONS, 0);
364
+ const maxi = neatoMaxIter(g.attrs.get('maxiter'), mode, n);
333
365
  const epsilon = lateDouble(g.attrs.get('epsilon'), 1e-4, 0); // DFLT_TOLERANCE
366
+ if (mode === MODE_HIER) {
367
+ return stressMajorizationWithHierarchy(vtx, n, dCoords, nodeList, {
368
+ dim: DFLT_DIM, opts, model, maxi, epsilon, levelsGap: levelsGapOf(g),
369
+ });
370
+ }
334
371
  // C ipsep (stress_majorization_cola, constrained_majorization_ipsep.c:150) always uses
335
372
  // compute_apsp_packed; kD_mkernel uses the weighted APSP iff graph->ewgts (stress.c:855).
336
373
  const weighted = haveLen && mode !== MODE_IPSEP;
337
374
  const Dij = weighted ? computeWeightedApspPacked(vtx, n) : computeApspPacked(vtx, n);
338
- const dCoords = [new Float64Array(n), new Float64Array(n)];
339
- stressMajorizationKDMkernel(Dij, n, dCoords, nodeList, {
340
- dim: DFLT_DIM, opts: OPT_EXP_FLAG, maxi, epsilon,
375
+ return stressMajorizationKDMkernel(Dij, n, dCoords, nodeList, {
376
+ dim: DFLT_DIM, opts, maxi, epsilon,
341
377
  });
342
- for (let i = 0; i < n; i++) {
343
- nodeList[i]!.info.pos = [dCoords[0]![i]!, dCoords[1]![i]!];
344
- }
345
378
  }
346
379
 
347
- /** Any edge carries a len attr (C: agattr_text(g, AGEDGE, "len")). */
348
- export function graphHasLen(g: Graph): boolean {
349
- for (const e of g.edges) {
350
- if (e.attrs.has('len')) return true;
380
+ /** Run stress majorization and write positions back. @see lib/neatogen/neatoinit.c:majorization */
381
+ export function runMajorization(g: Graph, mode: number, model: number): void {
382
+ const nodeList = assignNodeIds(g);
383
+ const n = nodeList.length;
384
+ const haveLen = graphHasLen(g);
385
+ // C: srand48(seed) immediately before initLayout draws; hier starts from self
386
+ const init = checkStart(g, n, mode === MODE_HIER ? INIT_SELF : INIT_RANDOM);
387
+ const opts = init === INIT_SELF ? OPT_EXP_FLAG | STRESS_OPT_SMART_INIT : OPT_EXP_FLAG;
388
+ const haveDir = mode === MODE_HIER || mode === MODE_IPSEP;
389
+ const vtx = makeGraphDataC(g, nodeList, haveLen, haveDir, mode);
390
+ const dCoords = [new Float64Array(n), new Float64Array(n)];
391
+ if (solveStress({ g, mode, model, haveLen, opts }, vtx, dCoords, nodeList) < 0) {
392
+ agerr('prev', 'layout aborted');
393
+ return;
351
394
  }
352
- return false;
353
- }
354
-
355
- /**
356
- * C makeGraphData's vtx_data: per node out-edges then in-edges (agfstedge order), self at
357
- * index 0, duplicate neighbours merged (len keeps the max). ewgts: lens (default 1.0) if any
358
- * len attr, else 1.0 under haveDir (hier/ipsep), else absent (C NULL). eweights (haveWt)
359
- * and edists are not built: nothing on a supported path reads them.
360
- * @see lib/neatogen/neatoinit.c:makeGraphData
361
- * @see lib/neatogen/stuff.c:setEdgeLen
362
- */
363
- export function makeGraphDataC(
364
- g: Graph, nodeList: Node[], haveLen: boolean, haveDir: boolean,
365
- ): VtxData[] {
366
- const vtx: VtxData[] = nodeList.map((_, i) => ({
367
- nedges: 1, edges: [i], ewgts: haveLen || haveDir ? [0] : [],
368
- }));
369
- for (const np of nodeList) {
370
- const i = np.info.id!;
371
- const entry = vtx[i]!;
372
- const seen = new Map<number, number>();
373
- for (const ep of [...np.outEdges(g), ...np.inEdges(g)]) {
374
- if (ep.head === ep.tail) continue;
375
- const vp = ep.tail === np ? ep.head : ep.tail;
376
- const vid = vp.info.id!;
377
- const dist = haveLen ? lateDouble(ep.attrs.get('len'), 1.0, 0) : 1.0;
378
- const idx = seen.get(vid);
379
- if (idx !== undefined) {
380
- if (haveLen) entry.ewgts[idx] = Math.max(entry.ewgts[idx]!, dist);
381
- continue;
382
- }
383
- seen.set(vid, entry.nedges);
384
- entry.edges.push(vid);
385
- if (haveLen || haveDir) entry.ewgts.push(dist); // C neatoinit.c:827: haveDir 1.0
386
- entry.nedges++;
387
- }
395
+ for (let i = 0; i < n; i++) {
396
+ nodeList[i]!.info.pos = [dCoords[0]![i]!, dCoords[1]![i]!];
388
397
  }
389
- return vtx;
390
398
  }
391
399
 
392
- /**
393
- * Dispatch to the appropriate layout solver for the given mode.
394
- *
395
- * @see lib/neatogen/neatoinit.c:neatoLayout
396
- */
400
+ /** Dispatch to the layout solver for the mode. @see lib/neatogen/neatoinit.c:neatoLayout */
397
401
  export function solveModel(g: Graph, mode: number, model: number): void {
398
402
  if (g.nodes.size < 2) return;
399
403
  assertSupported(g, mode, model);
@@ -411,11 +415,7 @@ export function solveModel(g: Graph, mode: number, model: number): void {
411
415
  // neatoTranslate helpers
412
416
  // ---------------------------------------------------------------------------
413
417
 
414
- /**
415
- * Find minimum X and Y across all node positions.
416
- *
417
- * @see lib/neatogen/neatoinit.c (translate logic)
418
- */
418
+ /** Minimum X and Y across all node positions. @see lib/neatogen/neatoinit.c (translate logic) */
419
419
  export function findMinPos(g: Graph): { minX: number; minY: number } {
420
420
  let minX = Infinity;
421
421
  let minY = Infinity;
@@ -27,6 +27,7 @@ import { MODEL_MDS } from './init.js';
27
27
  import { solve } from './kk-solve.js';
28
28
  import { lenattr } from './edge-len.js';
29
29
  import { newPathState, shortestPath, mdsModel, type Neighbour } from './kk-paths.js';
30
+ import { agwarningf } from '../../common/agerr.js';
30
31
 
31
32
  /** `Ndim`: layout dimension (this port lays out in 2-D only). */
32
33
  const NDIM = 2;
@@ -289,7 +290,7 @@ function moveNode(st: KkState, m: number): void {
289
290
  function solveModel(g: Graph, st: KkState): void {
290
291
  for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
291
292
  if (st.move === st.maxIter) {
292
- console.warn(`Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
293
+ agwarningf(`Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
293
294
  }
294
295
  }
295
296