@knowvah/dot-engine 2.6.12 → 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 (190) 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/common/htmltable-emit-fill.d.ts +20 -2
  5. package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
  6. package/dist/common/htmltable-emit.d.ts.map +1 -1
  7. package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
  8. package/dist/common/htmltable-pos-runs.d.ts +7 -4
  9. package/dist/common/htmltable-pos-runs.d.ts.map +1 -1
  10. package/dist/common/htmltable.d.ts.map +1 -1
  11. package/dist/common/libm-trig.d.ts +5 -0
  12. package/dist/common/libm-trig.d.ts.map +1 -0
  13. package/dist/common/multicolor.d.ts +21 -13
  14. package/dist/common/multicolor.d.ts.map +1 -1
  15. package/dist/common/poly-gencode.d.ts +1 -2
  16. package/dist/common/poly-gencode.d.ts.map +1 -1
  17. package/dist/common/poly-init.d.ts.map +1 -1
  18. package/dist/common/splines-clip.d.ts +7 -0
  19. package/dist/common/splines-clip.d.ts.map +1 -1
  20. package/dist/gvc/context.d.ts +6 -0
  21. package/dist/gvc/context.d.ts.map +1 -1
  22. package/dist/gvc/device-cluster.d.ts +15 -0
  23. package/dist/gvc/device-cluster.d.ts.map +1 -1
  24. package/dist/gvc/device.d.ts.map +1 -1
  25. package/dist/gvc/first-layer.d.ts +9 -0
  26. package/dist/gvc/first-layer.d.ts.map +1 -0
  27. package/dist/gvc/gvrender-set-style.d.ts +28 -0
  28. package/dist/gvc/gvrender-set-style.d.ts.map +1 -0
  29. package/dist/gvc/usershape.d.ts +18 -0
  30. package/dist/gvc/usershape.d.ts.map +1 -1
  31. package/dist/index.js +2460 -901
  32. package/dist/index.js.map +4 -4
  33. package/dist/layout/dot/compound.d.ts.map +1 -1
  34. package/dist/layout/dot/edge-route-clip.d.ts +14 -4
  35. package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
  36. package/dist/layout/dot/edge-route-routing.d.ts.map +1 -1
  37. package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts +11 -0
  38. package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts.map +1 -0
  39. package/dist/layout/neato/__fixtures__/hier-imds.d.ts +36 -0
  40. package/dist/layout/neato/__fixtures__/hier-imds.d.ts.map +1 -0
  41. package/dist/layout/neato/__fixtures__/hier-majorization.d.ts +32 -0
  42. package/dist/layout/neato/__fixtures__/hier-majorization.d.ts.map +1 -0
  43. package/dist/layout/neato/cdt-surface.d.ts.map +1 -1
  44. package/dist/layout/neato/compute-hierarchy.d.ts +24 -0
  45. package/dist/layout/neato/compute-hierarchy.d.ts.map +1 -0
  46. package/dist/layout/neato/conjgrad-mkernel.d.ts +20 -0
  47. package/dist/layout/neato/conjgrad-mkernel.d.ts.map +1 -0
  48. package/dist/layout/neato/conjgrad.d.ts +19 -0
  49. package/dist/layout/neato/conjgrad.d.ts.map +1 -1
  50. package/dist/layout/neato/constrained-majorization.d.ts +26 -0
  51. package/dist/layout/neato/constrained-majorization.d.ts.map +1 -0
  52. package/dist/layout/neato/dijkstra.d.ts +33 -16
  53. package/dist/layout/neato/dijkstra.d.ts.map +1 -1
  54. package/dist/layout/neato/gts-triangle.d.ts +14 -0
  55. package/dist/layout/neato/gts-triangle.d.ts.map +1 -0
  56. package/dist/layout/neato/init.d.ts +2 -12
  57. package/dist/layout/neato/init.d.ts.map +1 -1
  58. package/dist/layout/neato/kkutils.d.ts +20 -0
  59. package/dist/layout/neato/kkutils.d.ts.map +1 -0
  60. package/dist/layout/neato/make-graph-data.d.ts +43 -0
  61. package/dist/layout/neato/make-graph-data.d.ts.map +1 -0
  62. package/dist/layout/neato/matrix-ops.d.ts +46 -0
  63. package/dist/layout/neato/matrix-ops.d.ts.map +1 -1
  64. package/dist/layout/neato/opt-arrangement.d.ts +20 -0
  65. package/dist/layout/neato/opt-arrangement.d.ts.map +1 -0
  66. package/dist/layout/neato/quad-prog-solve.d.ts +44 -0
  67. package/dist/layout/neato/quad-prog-solve.d.ts.map +1 -0
  68. package/dist/layout/neato/smart-ini-x.d.ts +9 -0
  69. package/dist/layout/neato/smart-ini-x.d.ts.map +1 -0
  70. package/dist/layout/neato/splines.d.ts +1 -1
  71. package/dist/layout/neato/splines.d.ts.map +1 -1
  72. package/dist/layout/neato/start.d.ts +4 -1
  73. package/dist/layout/neato/start.d.ts.map +1 -1
  74. package/dist/layout/neato/stress.d.ts +8 -0
  75. package/dist/layout/neato/stress.d.ts.map +1 -1
  76. package/dist/model/edge.d.ts +1 -1
  77. package/dist/model/edge.d.ts.map +1 -1
  78. package/dist/model/lazy-attrs.d.ts +10 -0
  79. package/dist/model/lazy-attrs.d.ts.map +1 -0
  80. package/dist/model/node.d.ts +1 -1
  81. package/dist/model/node.d.ts.map +1 -1
  82. package/dist/ortho/index.d.ts.map +1 -1
  83. package/dist/render/dot/edge-draw.d.ts +1 -1
  84. package/dist/render/dot/edge-draw.d.ts.map +1 -1
  85. package/dist/render/svg-multicolor.d.ts +2 -2
  86. package/dist/render/svg-multicolor.d.ts.map +1 -1
  87. package/dist/render.js +2340 -781
  88. package/dist/render.js.map +4 -4
  89. package/package.json +1 -1
  90. package/src/common/graph-init.ts +1 -1
  91. package/src/common/htmltable-emit-fill.ts +56 -11
  92. package/src/common/htmltable-emit.ts +4 -3
  93. package/src/common/htmltable-lex-expat.ts +21 -3
  94. package/src/common/htmltable-pos-runs.ts +11 -6
  95. package/src/common/htmltable.ts +28 -116
  96. package/src/common/libm-trig.ts +43 -0
  97. package/src/common/multicolor.ts +88 -24
  98. package/src/common/poly-gencode.ts +16 -8
  99. package/src/common/poly-init.ts +19 -1
  100. package/src/common/postproc.ts +2 -2
  101. package/src/common/splines-clip.ts +15 -12
  102. package/src/common/splines-routespl.ts +2 -2
  103. package/src/common/textmeasure-lookup.ts +1 -1
  104. package/src/gvc/context.ts +8 -0
  105. package/src/gvc/device-cluster.ts +63 -8
  106. package/src/gvc/device.ts +16 -2
  107. package/src/gvc/first-layer.ts +26 -0
  108. package/src/gvc/gvrender-set-style.ts +114 -0
  109. package/src/gvc/usershape.ts +26 -0
  110. package/src/layout/dot/cluster.ts +1 -1
  111. package/src/layout/dot/compound.ts +3 -4
  112. package/src/layout/dot/conc.ts +1 -1
  113. package/src/layout/dot/edge-route-clip.ts +19 -7
  114. package/src/layout/dot/edge-route-routing.ts +11 -3
  115. package/src/layout/dot/fastgr.ts +2 -2
  116. package/src/layout/neato/__fixtures__/dijkstra-f.ts +17 -0
  117. package/src/layout/neato/__fixtures__/hier/c1554.gv +33 -0
  118. package/src/layout/neato/__fixtures__/hier/c1554.plain +26 -0
  119. package/src/layout/neato/__fixtures__/hier/c1554.xdot +161 -0
  120. package/src/layout/neato/__fixtures__/hier/cases/cycle.gv +1 -0
  121. package/src/layout/neato/__fixtures__/hier/cases/cycle.plain +10 -0
  122. package/src/layout/neato/__fixtures__/hier/cases/cycle.stderr +0 -0
  123. package/src/layout/neato/__fixtures__/hier/cases/dirnone.gv +1 -0
  124. package/src/layout/neato/__fixtures__/hier/cases/dirnone.plain +11 -0
  125. package/src/layout/neato/__fixtures__/hier/cases/dirnone.stderr +0 -0
  126. package/src/layout/neato/__fixtures__/hier/cases/epsilon.gv +1 -0
  127. package/src/layout/neato/__fixtures__/hier/cases/epsilon.plain +13 -0
  128. package/src/layout/neato/__fixtures__/hier/cases/epsilon.stderr +0 -0
  129. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.gv +1 -0
  130. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.plain +8 -0
  131. package/src/layout/neato/__fixtures__/hier/cases/levelsgap.stderr +0 -0
  132. package/src/layout/neato/__fixtures__/hier/cases/mds.gv +1 -0
  133. package/src/layout/neato/__fixtures__/hier/cases/mds.plain +10 -0
  134. package/src/layout/neato/__fixtures__/hier/cases/mds.stderr +0 -0
  135. package/src/layout/neato/__fixtures__/hier/cases/multiedge.gv +1 -0
  136. package/src/layout/neato/__fixtures__/hier/cases/multiedge.plain +10 -0
  137. package/src/layout/neato/__fixtures__/hier/cases/multiedge.stderr +0 -0
  138. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.gv +1 -0
  139. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.plain +8 -0
  140. package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.stderr +0 -0
  141. package/src/layout/neato/__fixtures__/hier/cases/startrandom.gv +1 -0
  142. package/src/layout/neato/__fixtures__/hier/cases/startrandom.plain +10 -0
  143. package/src/layout/neato/__fixtures__/hier/cases/startrandom.stderr +0 -0
  144. package/src/layout/neato/__fixtures__/hier/cases/startregular.gv +1 -0
  145. package/src/layout/neato/__fixtures__/hier/cases/startregular.plain +10 -0
  146. package/src/layout/neato/__fixtures__/hier/cases/startregular.stderr +0 -0
  147. package/src/layout/neato/__fixtures__/hier/cases/tdist.gv +1 -0
  148. package/src/layout/neato/__fixtures__/hier/cases/tdist.plain +13 -0
  149. package/src/layout/neato/__fixtures__/hier/cases/tdist.stderr +0 -0
  150. package/src/layout/neato/__fixtures__/hier/cases/undirected.gv +1 -0
  151. package/src/layout/neato/__fixtures__/hier/cases/undirected.plain +10 -0
  152. package/src/layout/neato/__fixtures__/hier/cases/undirected.stderr +0 -0
  153. package/src/layout/neato/__fixtures__/hier/hier-probe.gv +1 -0
  154. package/src/layout/neato/__fixtures__/hier/hier-probe.plain +16 -0
  155. package/src/layout/neato/__fixtures__/hier/hier-probe.xdot +62 -0
  156. package/src/layout/neato/__fixtures__/hier-imds.ts +151 -0
  157. package/src/layout/neato/__fixtures__/hier-majorization.ts +145 -0
  158. package/src/layout/neato/cdt-surface.ts +6 -16
  159. package/src/layout/neato/compute-hierarchy.ts +90 -0
  160. package/src/layout/neato/conjgrad-mkernel.ts +141 -0
  161. package/src/layout/neato/conjgrad.ts +208 -0
  162. package/src/layout/neato/constrained-majorization.ts +479 -0
  163. package/src/layout/neato/dijkstra.ts +218 -92
  164. package/src/layout/neato/edge-len.ts +2 -2
  165. package/src/layout/neato/fdp-adjust.ts +3 -3
  166. package/src/layout/neato/gts-triangle.ts +42 -0
  167. package/src/layout/neato/init.ts +57 -57
  168. package/src/layout/neato/kk.ts +2 -2
  169. package/src/layout/neato/kkutils.ts +96 -0
  170. package/src/layout/neato/make-graph-data.ts +166 -0
  171. package/src/layout/neato/matrix-ops.ts +138 -0
  172. package/src/layout/neato/opt-arrangement.ts +86 -0
  173. package/src/layout/neato/quad-prog-solve.ts +489 -0
  174. package/src/layout/neato/smart-ini-x.ts +503 -0
  175. package/src/layout/neato/splines.ts +4 -4
  176. package/src/layout/neato/start.ts +7 -6
  177. package/src/layout/neato/stress.ts +28 -0
  178. package/src/model/edge.ts +3 -2
  179. package/src/model/lazy-attrs.ts +36 -0
  180. package/src/model/node.ts +3 -2
  181. package/src/ortho/index.ts +2 -3
  182. package/src/parser/dot.js +1 -1
  183. package/src/parser/dot.pegjs +1 -1
  184. package/src/parser/index.ts +1 -1
  185. package/src/render/color-resolve.ts +2 -2
  186. package/src/render/dot/edge-draw.ts +6 -3
  187. package/src/render/dot.ts +1 -1
  188. package/src/render/svg-edge-split.ts +2 -2
  189. package/src/render/svg-multicolor.ts +4 -3
  190. package/src/render/svg-parallel-edge.ts +2 -2
@@ -0,0 +1,145 @@
1
+ // SPDX-License-Identifier: EPL-2.0
2
+ /**
3
+ * Expected layouts for the T22 stress_majorization_with_hierarchy tests, captured
4
+ * from a native clang -O3 -flto=thin -arch arm64 (-DDIGCOLA) harness that links the
5
+ * oracle's own lib/neatogen (graphviz 16.1.0) and calls the function with a fresh
6
+ * libc rand()/drand48() stream (srand(1), srand48(seed)). Graphs are neato vtx_data
7
+ * with haveDir (edists); `g40` is a seeded random DAG (40 nodes, 70 edges).
8
+ * Generated data: do not hand-edit.
9
+ */
10
+
11
+ /** One harness invocation and its native result. */
12
+ export interface MajorizationCase {
13
+ readonly name: string;
14
+ readonly graph: 'probe' | 'c1554' | 'rdag' | 'g40';
15
+ readonly dim: number;
16
+ readonly opts: number;
17
+ readonly maxi: number;
18
+ readonly levelsGap: number;
19
+ readonly epsilon: number;
20
+ /** `srand48` seed before the call. */
21
+ readonly seed: number;
22
+ /** Native return value (iterations). */
23
+ readonly rv: number;
24
+ /** Native `d_coords`, one array per axis. */
25
+ readonly coords: readonly (readonly number[])[];
26
+ }
27
+
28
+ /** `vtx_data` rows of the `g40` graph. */
29
+ export const G40_ROWS: readonly { edges: number[]; ewgts: number[]; edists: number[] }[] = [{"edges":[0,1,3,7,9,15,19,25],"ewgts":[0,1,1,1,1,1,1,1],"edists":[0,-1,-1,-1,-1,-1,-1,-1]},{"edges":[1,0,2,6,8],"ewgts":[0,1,1,1,1],"edists":[0,1,-1,-1,-1]},{"edges":[2,1],"ewgts":[0,1],"edists":[0,1]},{"edges":[3,0,4,5,18,22],"ewgts":[0,1,1,1,1,1],"edists":[0,1,-1,-1,-1,-1]},{"edges":[4,3,12],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[5,3,8,21,36],"ewgts":[0,1,1,1,1],"edists":[0,1,-1,-1,-1]},{"edges":[6,1,10,24,31],"ewgts":[0,1,1,1,1],"edists":[0,1,-1,-1,-1]},{"edges":[7,0,16],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[8,1,5,11,20,23,28,30],"ewgts":[0,1,1,1,1,1,1,1],"edists":[0,1,1,-1,-1,-1,-1,-1]},{"edges":[9,0,31],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[10,6,32],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[11,8,19,23],"ewgts":[0,1,1,1],"edists":[0,1,-1,-1]},{"edges":[12,4,13,14,15,26],"ewgts":[0,1,1,1,1,1],"edists":[0,1,-1,-1,-1,-1]},{"edges":[13,12],"ewgts":[0,1],"edists":[0,1]},{"edges":[14,12,24],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[15,0,12,19,21,31],"ewgts":[0,1,1,1,1,1],"edists":[0,1,1,-1,-1,-1]},{"edges":[16,7,17,18],"ewgts":[0,1,1,1],"edists":[0,1,-1,-1]},{"edges":[17,16,18,20,36],"ewgts":[0,1,1,1,1],"edists":[0,1,-1,-1,-1]},{"edges":[18,3,16,17,32,33,34],"ewgts":[0,1,1,1,1,1,1],"edists":[0,1,1,1,-1,-1,-1]},{"edges":[19,0,11,15,33,36],"ewgts":[0,1,1,1,1,1],"edists":[0,1,1,1,-1,-1]},{"edges":[20,8,17,24,26],"ewgts":[0,1,1,1,1],"edists":[0,1,1,-1,-1]},{"edges":[21,5,15,27,37],"ewgts":[0,1,1,1,1],"edists":[0,1,1,-1,-1]},{"edges":[22,3],"ewgts":[0,1],"edists":[0,1]},{"edges":[23,8,11,35],"ewgts":[0,1,1,1],"edists":[0,1,1,-1]},{"edges":[24,6,14,20,38],"ewgts":[0,1,1,1,1],"edists":[0,1,1,1,-1]},{"edges":[25,0,27,29],"ewgts":[0,1,1,1],"edists":[0,1,-1,-1]},{"edges":[26,12,20,30],"ewgts":[0,1,1,1],"edists":[0,1,1,-1]},{"edges":[27,21,25,37,39],"ewgts":[0,1,1,1,1],"edists":[0,1,1,-1,-1]},{"edges":[28,8,31,33],"ewgts":[0,1,1,1],"edists":[0,1,-1,-1]},{"edges":[29,25,34],"ewgts":[0,1,1],"edists":[0,1,-1]},{"edges":[30,8,26,36],"ewgts":[0,1,1,1],"edists":[0,1,1,-1]},{"edges":[31,6,9,15,28],"ewgts":[0,1,1,1,1],"edists":[0,1,1,1,1]},{"edges":[32,10,18,39],"ewgts":[0,1,1,1],"edists":[0,1,1,-1]},{"edges":[33,18,19,28,38],"ewgts":[0,1,1,1,1],"edists":[0,1,1,1,-1]},{"edges":[34,18,29],"ewgts":[0,1,1],"edists":[0,1,1]},{"edges":[35,23,37,38],"ewgts":[0,1,1,1],"edists":[0,1,-1,-1]},{"edges":[36,5,17,19,30,39],"ewgts":[0,1,1,1,1,1],"edists":[0,1,1,1,1,-1]},{"edges":[37,21,27,35,39],"ewgts":[0,1,1,1,1],"edists":[0,1,1,1,-1]},{"edges":[38,24,33,35],"ewgts":[0,1,1,1],"edists":[0,1,1,1]},{"edges":[39,27,32,36,37],"ewgts":[0,1,1,1,1],"edists":[0,1,1,1,1]}];
30
+
31
+ export const MAJORIZATION_CASES: readonly MajorizationCase[] = [
32
+ {
33
+ name: "probe smart", graph: 'probe', dim: 2, opts: 6, maxi: 200,
34
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 25,
35
+ coords: [
36
+ [-0.8872857689857483, 0.09007769823074341, 0.6606655120849609, -0.6603541970252991, -0.0897926613688469, 0.8866894245147705],
37
+ [1.0345146656036377, 0.6522425413131714, 0.00009558413876220584, 0.00009558413876220584, -0.6516568064689636, -1.0352916717529297],
38
+ ],
39
+ },
40
+ {
41
+ name: "probe smart levelsgap", graph: 'probe', dim: 2, opts: 6, maxi: 200,
42
+ levelsGap: 0.5, epsilon: 0.0001, seed: 1, rv: 12,
43
+ coords: [
44
+ [-0.9963757991790771, -0.015388643369078636, 0.7450122237205505, -0.7450122833251953, 0.015388717874884605, 0.9963758587837219],
45
+ [1.25, 0.7500000596046448, 0.2500000596046448, -0.24999994039535522, -0.7499999403953552, -1.25],
46
+ ],
47
+ },
48
+ {
49
+ name: "probe smart one iteration", graph: 'probe', dim: 2, opts: 6, maxi: 1,
50
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 1,
51
+ coords: [
52
+ [-0.6022335886955261, 0.0778207927942276, 0.6716713309288025, -0.6716711521148682, -0.07782091200351715, 0.6022335290908813],
53
+ [1.225775957107544, 0.5940203070640564, 0.00004230230115354061, 0.00004230230115354061, -0.5944178700447083, -1.2254630327224731],
54
+ ],
55
+ },
56
+ {
57
+ name: "probe smart no iterations (initial layout only)", graph: 'probe', dim: 2, opts: 6, maxi: 0,
58
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 0,
59
+ coords: [
60
+ [-0.52421848664645, 0.07426209500899247, 0.6209262062730561, -0.6209262062730563, -0.07426209500899264, 0.52421848664645],
61
+ [1.250000000000003, 0.5833333333333612, 0.08333333333334564, -0.08333333333333418, -0.5833333333333085, -1.2499999999999796],
62
+ ],
63
+ },
64
+ {
65
+ name: "c1554 smart", graph: 'c1554', dim: 2, opts: 6, maxi: 200,
66
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 3,
67
+ coords: [
68
+ [-0.2410670518875122, -0.2410670518875122, -0.2410670518875122, -0.5535792112350464, -0.2410670518875122, 0.9464221000671387, 0.5714253187179565],
69
+ [0, 0, 0, -0, -0, 0, -0],
70
+ ],
71
+ },
72
+ {
73
+ name: "c1554 plain init", graph: 'c1554', dim: 2, opts: 2, maxi: 200,
74
+ levelsGap: 0, epsilon: 0.0001, seed: 7, rv: 43,
75
+ coords: [
76
+ [-0.2458767145872116, -0.2458767145872116, -0.22192083299160004, -0.7836974859237671, 0.8581828474998474, 0.7025991082191467, -0.06341015547513962],
77
+ [0.6164672374725342, 0.6164672374725342, 0.6364861130714417, -1.054526448249817, -0.7265203595161438, 0.27123403549194336, -0.35960766673088074],
78
+ ],
79
+ },
80
+ {
81
+ name: "rdag smart", graph: 'rdag', dim: 2, opts: 6, maxi: 200,
82
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 72,
83
+ coords: [
84
+ [2.106701612472534, -8.845921516418457, 1.4982528686523438, -2.2527546882629395, 2.649675130844116, -2.313718318939209, -1.8075244426727295, -1.0636497735977173, 0.8014016151428223, -0.03322816640138626, -1.123450517654419, -1.6615859270095825, 0.2914482355117798, 0.2493419051170349, 0.6228430271148682, -0.3555810749530792, -0.4617708921432495, 2.9189040660858154, 1.533380150794983, 0.7932320237159729, 0.1701584756374359, 1.095284104347229, 0.38050132989883423, 1.773295283317566, 1.6413025856018066, 1.0647715330123901, 0.2310933619737625, 0.4141763746738434, 0.9322999119758606, -0.6915730237960815, -1.4681257009506226, 1.2065339088439941, -0.40464577078819275, 0.10893333703279495],
85
+ [3.935408592224121, 3.935408592224121, 3.128432273864746, 3.128432273864746, 3.128432273864746, 1.9458963871002197, 1.9458963871002197, 1.726983666419983, 2.210876226425171, 1.726983666419983, 1.0466965436935425, 1.0466965436935425, 1.0466965436935425, 1.0466965436935425, 0.32058167457580566, 0.2997589111328125, 0.2997589111328125, -1.0779701471328735, -0.2633209824562073, -0.3105449080467224, -1.0779701471328735, -1.0779701471328735, -1.0779701471328735, -1.1902680397033691, -1.716605544090271, -1.716605544090271, -2.100672960281372, -2.100672960281372, -2.3096060752868652, -2.475639581680298, -3.3348419666290283, -3.3348419666290283, -3.3348419666290283, -3.41929292678833],
86
+ ],
87
+ },
88
+ {
89
+ name: "rdag smart levelsgap", graph: 'rdag', dim: 2, opts: 6, maxi: 200,
90
+ levelsGap: 0.5, epsilon: 0.0001, seed: 1, rv: 39,
91
+ coords: [
92
+ [-12301.8642578125, -40660.5, -9774.89453125, 11809.7578125, -6476.82958984375, -8734.6494140625, 6348.06201171875, -4525.720703125, -6536.2080078125, -3894.280517578125, 1880.763916015625, -4501.078125, -2043.1739501953125, 7986.6591796875, 3269.953857421875, -404.2750549316406, 1482.980224609375, 12090.8525390625, 8846.69921875, 6487.10302734375, 2671.696044921875, -1566.1962890625, 4674.43212890625, 3535.6015625, 4471.04833984375, 6479.380859375, -0.44706612825393677, -958.3173217773438, 8040.14599609375, 5781.75244140625, 420.898193359375, 1973.5867919921875, -157.3118438720703, 4284.37109375],
93
+ [4969.9560546875, 4970.4560546875, 4969.4560546875, 4968.9560546875, 4968.4560546875, 4967.4560546875, 4966.9560546875, 4965.9560546875, 4967.9560546875, 4966.4560546875, 4965.4560546875, 4963.9560546875, 4964.4560546875, 4964.9560546875, 3209.87158203125, 3208.87158203125, 3209.37158203125, -1517.34619140625, 941.6177978515625, 941.6177978515625, -1518.34619140625, -1517.84619140625, -1518.34619140625, -3001.77978515625, -3002.27978515625, -3002.77978515625, -5185.4501953125, -5185.9501953125, -6037.169921875, -8404.357421875, -10032.125, -10032.625, -10033.125, -11062.6962890625],
94
+ ],
95
+ },
96
+ {
97
+ name: "rdag smart negative levelsgap", graph: 'rdag', dim: 2, opts: 6, maxi: 200,
98
+ levelsGap: -1, epsilon: 0.0001, seed: 1, rv: 131,
99
+ coords: [
100
+ [0.975033164024353, -8.91601276397705, 0.5004842877388, 2.977956771850586, 1.6438225507736206, -0.07275602966547012, 2.1174063682556152, -1.1853382587432861, -0.04999632015824318, 0.354489266872406, 1.2431221008300781, 1.073130488395691, -0.6186935305595398, -1.086130976676941, 0.2677907943725586, -0.048997968435287476, 0.09275322407484055, 2.133812665939331, 1.1161925792694092, -0.7022860050201416, -0.21006172895431519, -0.41585826873779297, 0.19944527745246887, 1.0232882499694824, -0.009082501754164696, 0.6798028349876404, -0.6689338088035583, -1.152896523475647, 0.559933066368103, -1.5303906202316284, 1.2292211055755615, -1.478786587715149, -0.5989389419555664, 0.557475209236145],
101
+ [4.457009792327881, 3.457009792327881, 3.5111281871795654, 2.554044723510742, 3.554044723510742, 2.9412379264831543, 1.7162097692489624, 2.3648476600646973, 2.371692657470703, 1.4127448797225952, 1.007383108139038, 2.004547595977783, 1.4327563047409058, 0.4327562749385834, 0.0988132432103157, 0.9681377410888672, 0.3813791871070862, -2.0102105140686035, -0.47968974709510803, -0.47968974709510803, -0.9354557394981384, -1.598078727722168, -0.9982943534851074, -1.6566381454467773, -2.1973824501037598, -1.1973823308944702, -2.3070976734161377, -1.5450495481491089, -2.3397669792175293, -2.5018789768218994, -4.301966190338135, -3.3019661903381348, -3.345038414001465, -3.470165967941284],
102
+ ],
103
+ },
104
+ {
105
+ name: "rdag plain init levelsgap", graph: 'rdag', dim: 2, opts: 2, maxi: 200,
106
+ levelsGap: 1.5, epsilon: 0.0001, seed: 7, rv: 10,
107
+ coords: [
108
+ [-0.1714787483215332, -6.736390590667725, 0.16777358949184418, 0.7151613831520081, -0.3481586277484894, 0.7005362510681152, 0.5633029341697693, 0.25387802720069885, 0.16892887651920319, 0.2626030147075653, 0.32713907957077026, 0.8732405304908752, 0.017587635666131973, 0.18712081015110016, 0.1815183013677597, -0.21678774058818817, 0.039015546441078186, -0.8158586621284485, 0.37755346298217773, 0.8203425407409668, 0.6037594079971313, 0.3468809425830841, -0.022601669654250145, 0.09913724660873413, 0.14511209726333618, 0.3509961664676666, 0.3168884813785553, 0.2200707346200943, 0.10131124407052994, 0.3687672019004822, -0.5803648233413696, 0.3717065453529358, 0.3560970425605774, -0.04478844627737999],
109
+ [20.38235092163086, 21.88235092163086, 18.88235092163086, 17.38235092163086, 15.882349967956543, 12.882349967956543, 11.382349967956543, 8.382349967956543, 14.382349967956543, 9.882349967956543, 6.882349967956543, 2.382349967956543, 3.882349967956543, 5.382349967956543, 2.382349967956543, -0.6176499724388123, 0.8823500275611877, -2.117650032043457, -0.6176499724388123, -0.6176499724388123, -5.117650032043457, -3.617650032043457, -5.117650032043457, -6.617650032043457, -8.117650032043457, -9.617650032043457, -11.117650032043457, -12.617650032043457, -14.117650032043457, -15.617650032043457, -17.11764907836914, -18.61764907836914, -20.11764907836914, -21.61764907836914],
110
+ ],
111
+ },
112
+ {
113
+ name: "rdag plain init 3-D", graph: 'rdag', dim: 3, opts: 2, maxi: 200,
114
+ levelsGap: 0, epsilon: 0.0001, seed: 7, rv: 200,
115
+ coords: [
116
+ [1.9230509996414185, -4.450254917144775, 1.3397730588912964, -2.589007616043091, 2.468080759048462, -1.613430142402649, -2.190492868423462, -0.6790580153465271, 0.5338876843452454, 0.2040603905916214, -1.497606635093689, -1.385814905166626, -0.343102365732193, -0.14492037892341614, 0.7068026661872864, -0.5179460048675537, -0.762558102607727, 2.3182451725006104, 1.2608115673065186, 0.6364292502403259, 0.9157735705375671, 0.7901390194892883, -0.35626527667045593, 0.9255744218826294, 1.3133991956710815, 0.1679213047027588, 0.9619991779327393, 0.06195592135190964, -0.10869356244802475, 0.672370970249176, -1.7973697185516357, 1.6563245058059692, 0.33709609508514404, -0.7571752667427063],
117
+ [3.637824296951294, 3.637824296951294, 2.7765800952911377, 2.7765800952911377, 2.7765800952911377, 1.5580389499664307, 1.5580389499664307, 1.0393105745315552, 1.9450687170028687, 1.0393105745315552, 0.9515085220336914, 0.9515085220336914, 0.9515085220336914, 0.9515085220336914, 0.34407156705856323, 0.34407156705856323, 0.34407156705856323, -0.8591142892837524, -0.7320063710212708, -0.01923421397805214, -0.8591142892837524, -0.8591142892837524, -0.8845171928405762, -1.159713864326477, -1.2608681917190552, -1.2608681917190552, -1.7222142219543457, -1.7222142219543457, -1.967499017715454, -2.4355876445770264, -2.9603357315063477, -2.9603357315063477, -2.9603357315063477, -2.9603357315063477],
118
+ [1.6783900260925293, -7.6042938232421875, 1.5541224479675293, 0.6140518188476562, 1.7654837369918823, 2.535907030105591, 0.8192742466926575, 2.5690112113952637, 1.3691827058792114, 1.4288212060928345, 0.41665998101234436, 1.5223040580749512, 1.2993186712265015, -0.6007012724876404, 0.6095350384712219, 0.6627642512321472, -0.005488100461661816, -0.4538416862487793, 0.8484395146369934, -0.45605137944221497, 0.2692951560020447, -1.310333013534546, -0.4890795946121216, -0.3461270034313202, -1.5077654123306274, 0.27062326669692993, -0.7134277820587158, -1.548409104347229, -0.2979923188686371, -1.650607943534851, -1.3032701015472412, -0.3259759843349457, -0.9536048769950867, -0.6662144064903259],
119
+ ],
120
+ },
121
+ {
122
+ name: "rdag plain init tight epsilon", graph: 'rdag', dim: 2, opts: 5, maxi: 200,
123
+ levelsGap: 0.3, epsilon: 0.000001, seed: 3, rv: 138,
124
+ coords: [
125
+ [4881.32666015625, -11929.93359375, 3984.729736328125, 5013.54052734375, 5451.97216796875, 3440.62744140625, 3713.17822265625, 2185.936279296875, 2424.29541015625, 1528.0205078125, 2568.227783203125, 2554.77880859375, 830.9662475585938, 1267.5498046875, 58.524845123291016, 1124.128173828125, 921.0764770507812, 422.65399169921875, -1197.61767578125, -679.9918212890625, -1911.75341796875, -1896.5244140625, -523.93017578125, -913.9660034179688, -2868.36865234375, -1473.961669921875, -2835.732177734375, -2314.52685546875, -1578.99365234375, -3544.86962890625, -133.86082458496094, -4183.23779296875, -2921.099609375, -1463.163330078125],
126
+ [1197.1910400390625, 1197.4910888671875, 1015.1022338867188, 60.00261306762695, 59.702613830566406, 57.60552215576172, 57.30552291870117, 56.705509185791016, 59.40261459350586, 57.005523681640625, 56.40550994873047, 55.505496978759766, 55.805511474609375, 56.10551071166992, 55.50551223754883, 54.90549850463867, 55.20549774169922, 54.605499267578125, 54.90549850463867, 54.90549850463867, 54.00550079345703, 54.30550003051758, 54.00550079345703, 53.705501556396484, 53.40550231933594, 53.10550308227539, -177.1049041748047, -177.4049072265625, -177.7049102783203, -178.00491333007812, -178.30491638183594, -178.60491943359375, -1689.3165283203125, -1937.4561767578125],
127
+ ],
128
+ },
129
+ {
130
+ name: "g40 smart levelsgap", graph: 'g40', dim: 2, opts: 6, maxi: 200,
131
+ levelsGap: 0.4, epsilon: 0.0001, seed: 3, rv: 24,
132
+ coords: [
133
+ [-1.0094189643859863, 0.46773967146873474, -3.3577399253845215, -1.9939782619476318, 2.1472113132476807, -0.442900151014328, 0.8790810704231262, -3.9394562244415283, 2.4742016792297363, -1.820883870124817, -2.4455490112304688, 3.7843005657196045, 4.557663917541504, 7.654958724975586, 6.022160053253174, 0.9374023675918579, -3.5004780292510986, -1.2619199752807617, -3.0502116680145264, 0.0648970827460289, 2.897508382797241, -0.8611336350440979, -5.626335620880127, 4.28245735168457, 3.9111220836639404, -4.367393493652344, 5.062668323516846, -3.247391939163208, 1.5867946147918701, -6.725042819976807, 2.8278207778930664, 0.9058087468147278, -3.64738392829895, -0.300179660320282, -5.379117965698242, 2.9269683361053467, -0.2548547387123108, -0.4261185824871063, 2.303642749786377, -2.0369181632995605],
134
+ [6.885787487030029, 5.685787200927734, 0.8857858777046204, 6.485787391662598, 5.285787105560303, 4.085786819458008, 1.2857857942581177, 6.085787296295166, 3.6857869625091553, 3.2857868671417236, -2.718261241912842, 2.0857865810394287, 4.4857869148254395, -0.7182613015174866, 0.08173868805170059, 2.885786771774292, 4.885787010192871, 2.0857865810394287, -0.3182613253593445, 0.08173868805170059, 0.4817386865615845, -1.9182612895965576, 1.685786485671997, -1.5182613134384155, -4.318261623382568, 2.4857866764068604, -1.1182613372802734, -3.518261432647705, 0.4817386865615845, -2.31826114654541, -2.718261241912842, -3.1182613372802734, -5.138027667999268, -4.738027572631836, -5.138027667999268, -4.338027477264404, -3.9182615280151367, -5.538027763366699, -5.938027858734131, -6.3380279541015625],
135
+ ],
136
+ },
137
+ {
138
+ name: "g40 plain init", graph: 'g40', dim: 2, opts: 2, maxi: 200,
139
+ levelsGap: 0, epsilon: 0.0001, seed: 1, rv: 40,
140
+ coords: [
141
+ [-0.12023495882749557, -0.10719820857048035, 1.5805704593658447, 0.5768365263938904, 1.8122634887695312, -0.9591823816299438, -1.3762669563293457, 0.8809503316879272, -0.8322945237159729, 0.5418577790260315, -2.370654582977295, -2.0197994709014893, 1.8294569253921509, 3.072965145111084, 1.4248172044754028, 0.17721407115459442, -0.6475740671157837, -0.23643508553504944, -0.005045577418059111, -0.8544038534164429, 0.32631435990333557, -0.5968142151832581, 2.3127048015594482, -2.3471274375915527, -0.21284359693527222, 1.1981782913208008, 1.7212520837783813, 0.49165067076683044, -1.7203251123428345, 2.2751946449279785, 0.5792899131774902, -0.48429036140441895, -1.4397521018981934, -1.0145349502563477, 1.3649485111236572, -2.1717777252197266, -0.17960841953754425, -0.4082253575325012, -1.3772825002670288, -0.684794008731842],
142
+ [1.6038932800292969, 1.6038932800292969, 0.66395103931427, 1.6038932800292969, 1.6038932800292969, 0.7164790034294128, 0.66395103931427, 1.6038932800292969, 0.7164790034294128, 0.7164790034294128, -0.44643980264663696, 0.66395103931427, 0.7164790034294128, -0.2532619833946228, -0.2532619833946228, 0.66395103931427, 1.5865058898925781, 0.66395103931427, -0.2532619833946228, 0.07963717728853226, 0.07963717728853226, -0.44643980264663696, 0.66395103931427, -0.2532619833946228, -1.063781499862671, 0.66395103931427, -0.2532619833946228, -1.063781499862671, 0.07963717728853226, -0.44643980264663696, -0.44643980264663696, -0.44643980264663696, -1.1681492328643799, -1.1681492328643799, -1.3430408239364624, -1.1681492328643799, -1.063781499862671, -1.8904457092285156, -1.8904457092285156, -2.0402238368988037],
143
+ ],
144
+ },
145
+ ];
@@ -36,6 +36,7 @@
36
36
 
37
37
  import { incircle, orient2d } from './delaunay.js';
38
38
  import { InternalError } from '../../errors.js';
39
+ import { gtsTriangleEnclosing } from './gts-triangle.js';
39
40
 
40
41
  /** Triangulated surface. @see lib/neatogen/delaunay.h:surface_t */
41
42
  export interface Surface {
@@ -644,8 +645,6 @@ class Cdt {
644
645
  }
645
646
  }
646
647
 
647
- const SQRT3 = 1.73205080756887729;
648
-
649
648
  /**
650
649
  * Build the constrained Delaunay surface over n points with nsegs directed
651
650
  * constraint segments (segs[2k], segs[2k+1]), removing hole faces.
@@ -659,21 +658,12 @@ export function mkSurface(
659
658
  const py = y.slice(0, n);
660
659
 
661
660
  // gts_triangle_enclosing(points, scale=100)
662
- let xmin = px[0]!; let xmax = px[0]!;
663
- let ymin = py[0]!; let ymax = py[0]!;
664
- for (let i = 1; i < n; i++) {
665
- if (px[i]! > xmax) xmax = px[i]!;
666
- else if (px[i]! < xmin) xmin = px[i]!;
667
- if (py[i]! > ymax) ymax = py[i]!;
668
- else if (py[i]! < ymin) ymin = py[i]!;
669
- }
670
- const xo = (xmax + xmin) / 2;
671
- const yo = (ymax + ymin) / 2;
672
- let r = 100 * Math.hypot(xmax - xo, ymax - yo);
673
- if (r === 0) r = 100;
674
661
  const s0 = n;
675
- px.push(xo + r * SQRT3, xo, xo - r * SQRT3);
676
- py.push(yo - r, yo + 2 * r, yo - r);
662
+ const enc = gtsTriangleEnclosing(px, py, n, 100);
663
+ for (const [ex, ey] of enc) {
664
+ px.push(ex);
665
+ py.push(ey);
666
+ }
677
667
 
678
668
  const cdt = new Cdt(px, py);
679
669
  // tri(): constraint edges are created BEFORE the vertices are inserted,
@@ -0,0 +1,90 @@
1
+ // SPDX-License-Identifier: EPL-2.0
2
+
3
+ /**
4
+ * Partition graph nodes into levels by the minimizer of the hierarchy energy.
5
+ *
6
+ * @see lib/neatogen/compute_hierarchy.c
7
+ */
8
+
9
+ import type { VtxData } from './dijkstra.js';
10
+ import { quicksortPlace } from './kkutils.js';
11
+ import { computeYCoords } from './opt-arrangement.js';
12
+
13
+ /** Result of `compute_hierarchy` on success (C return value 0). */
14
+ export interface Hierarchy {
15
+ /** Node ids sorted by `y`; level `k` is `ordering[levels[k-1]..levels[k])`. */
16
+ ordering: Int32Array;
17
+ /** Start index (in `ordering`) of every level but the first; `[n]` when there is one level. */
18
+ levels: Int32Array;
19
+ /** C `*num_levelsp` (0 means a single level, `levels = [n]`). */
20
+ numLevels: number;
21
+ }
22
+
23
+ /**
24
+ * Count the gaps wider than `tol` between consecutive sorted `y` values.
25
+ * @see lib/neatogen/compute_hierarchy.c:compute_hierarchy
26
+ */
27
+ function countLevels(y: Float64Array, ordering: Int32Array, n: number, tol: number): number {
28
+ let numLevels = 0;
29
+ for (let i = 1; i < n; i++) {
30
+ if (y[ordering[i]!]! - y[ordering[i - 1]!]! > tol) numLevels++;
31
+ }
32
+ return numLevels;
33
+ }
34
+
35
+ /**
36
+ * Fill the level start indices (a SINGLE_LINK clustering).
37
+ * @see lib/neatogen/compute_hierarchy.c:compute_hierarchy
38
+ */
39
+ function fillLevels(
40
+ y: Float64Array,
41
+ ordering: Int32Array,
42
+ n: number,
43
+ tol: number,
44
+ numLevels: number,
45
+ ): Int32Array {
46
+ if (numLevels === 0) {
47
+ const levels = new Int32Array(1);
48
+ levels[0] = n;
49
+ return levels;
50
+ }
51
+ const levels = new Int32Array(numLevels);
52
+ let count = 0;
53
+ for (let i = 1; i < n; i++) {
54
+ if (y[ordering[i]!]! - y[ordering[i - 1]!]! > tol) levels[count++] = i;
55
+ }
56
+ return levels;
57
+ }
58
+
59
+ /**
60
+ * Order the nodes by `y` (computed by `computeYCoords` unless `given` is
61
+ * supplied) and cut a new level wherever consecutive values differ by more
62
+ * than `max(absTol, relTol * span / (n - 1))`. Returns `null` where C returns
63
+ * nonzero (`compute_y_coords` failed).
64
+ * @see lib/neatogen/compute_hierarchy.c:compute_hierarchy
65
+ */
66
+ export function computeHierarchy(
67
+ graph: VtxData[],
68
+ n: number,
69
+ absTol: number,
70
+ relTol: number,
71
+ given: Float64Array | null,
72
+ ): Hierarchy | null {
73
+ let y: Float64Array;
74
+ if (given) {
75
+ y = given;
76
+ } else {
77
+ y = new Float64Array(n);
78
+ if (computeYCoords(graph, n, y, n)) return null;
79
+ }
80
+ const ordering = new Int32Array(n);
81
+ for (let i = 0; i < n; i++) ordering[i] = i;
82
+ quicksortPlace(y, ordering, n);
83
+
84
+ const hierarchySpan = y[ordering[n - 1]!]! - y[ordering[0]!]!;
85
+ // C `MAX(a, b)` is `a > b ? a : b` (differs from Math.max only for NaN operands)
86
+ const relative = relTol * hierarchySpan / (n - 1);
87
+ const tol = absTol > relative ? absTol : relative;
88
+ const numLevels = countLevels(y, ordering, n, tol);
89
+ return { ordering, levels: fillLevels(y, ordering, n, tol, numLevels), numLevels };
90
+ }
@@ -0,0 +1,141 @@
1
+ // SPDX-License-Identifier: EPL-2.0
2
+
3
+ /**
4
+ * `conjugate_gradient_mkernel` and `right_mult_with_vector_ff` as the 16.1
5
+ * oracle executes them. The oracle is built `-O3 -flto=thin` for arm64, so a
6
+ * C statement `a += b * c` on floats is one `fmadd`/`fmla` (clang's default
7
+ * contraction), and a reduction the vectoriser took in blocks of 16 rounds
8
+ * the products of those leading elements before its in-order adds (strict FP
9
+ * forbids reassociation) while the scalar remainder is fused. `stress-kernel.ts`
10
+ * keeps the unfused rounding of these loops; the constrained-majorization driver
11
+ * needs the oracle's bits.
12
+ *
13
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_mkernel
14
+ * @see lib/neatogen/matrix_ops.c:right_mult_with_vector_ff
15
+ */
16
+
17
+ import { agerrorf } from '../../common/agerr.js';
18
+ import {
19
+ copyVectorF, maxAbsF, orthog1f, vectorsInnerProductF, vectorsSubtractionF,
20
+ } from './matrix-ops.js';
21
+ import { fmaf } from './quad-prog-solve.js';
22
+
23
+ const fr = Math.fround;
24
+
25
+ /** Width of the vectorised reduction block of `right_mult_with_vector_ff`. */
26
+ const RIGHT_MULT_BLOCK = 16;
27
+
28
+ /** The unexpected-zero-residual diagnostic. @see lib/neatogen/conjgrad.c */
29
+ const ZERO_LENGTH_MESSAGE = 'conjugate_gradient: unexpected length 0 vector\n';
30
+
31
+ /**
32
+ * `result = packed_matrix * vector` for the packed upper triangle of a
33
+ * symmetric matrix: per row the first `16*floor(len/16)` products of the
34
+ * reduction are rounded before their adds, the rest fused; the scatter into
35
+ * `result[j]` is fused throughout.
36
+ * @see lib/neatogen/matrix_ops.c:right_mult_with_vector_ff
37
+ */
38
+ export function rightMultWithVectorFFFused(
39
+ m: Float32Array, n: number, vector: Float32Array, result: Float32Array,
40
+ ): void {
41
+ for (let i = 0; i < n; i++) result[i] = 0;
42
+ let index = 0;
43
+ for (let i = 0; i < n; i++) {
44
+ const vi = vector[i]!;
45
+ let res = fmaf(m[index++]!, vi, 0); // deal with main diag
46
+ const len = n - i - 1;
47
+ const blockEnd = i + 1 + (len - (len % RIGHT_MULT_BLOCK));
48
+ for (let j = i + 1; j < n; j++, index++) {
49
+ const mij = m[index]!;
50
+ res = j < blockEnd ? fr(res + fr(mij * vector[j]!)) : fmaf(mij, vector[j]!, res);
51
+ result[j] = fmaf(mij, vi, result[j]!);
52
+ }
53
+ result[i] = result[i]! + res;
54
+ }
55
+ }
56
+
57
+ /** `vector1 += alpha * vector2`, fused. @see lib/neatogen/matrix_ops.c:vectors_mult_additionf */
58
+ function vectorsMultAdditionFused(n: number, v1: Float32Array, alpha: number, v2: Float32Array): void {
59
+ for (let i = 0; i < n; i++) v1[i] = fmaf(alpha, v2[i]!, v1[i]!);
60
+ }
61
+
62
+ /** Conjugate-gradient working vectors and the running `r.r`. */
63
+ interface CgState {
64
+ n: number;
65
+ r: Float32Array;
66
+ p: Float32Array;
67
+ Ap: Float32Array;
68
+ rR: number;
69
+ }
70
+
71
+ /** What one conjugate-gradient iteration decided. */
72
+ const CgStep = { CONTINUE: 0, STOP: 1, ERROR: 2 } as const;
73
+
74
+ /** Options of {@link conjugateGradientMkernelFused} (C's trailing `tol`, `max_iterations`). */
75
+ export interface CgMkernelOptions {
76
+ tol: number;
77
+ maxIterations: number;
78
+ }
79
+
80
+ /**
81
+ * The residual `r = b - A*x` of the centred inputs, and `p = r`.
82
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_mkernel
83
+ */
84
+ function initialState(A: Float32Array, x: Float32Array, b: Float32Array, n: number): CgState {
85
+ const Ax = new Float32Array(n);
86
+ const st: CgState = { n, r: new Float32Array(n), p: new Float32Array(n), Ap: new Float32Array(n), rR: 0 };
87
+ orthog1f(n, x); // centering x and b
88
+ orthog1f(n, b);
89
+ rightMultWithVectorFFFused(A, n, x, Ax);
90
+ orthog1f(n, Ax); // centering Ax
91
+ vectorsSubtractionF(n, b, Ax, st.r);
92
+ copyVectorF(n, st.r, st.p);
93
+ st.rR = vectorsInnerProductF(n, st.r, st.r);
94
+ return st;
95
+ }
96
+
97
+ /**
98
+ * One iteration: the step along `p`, then (unless last) the new residual and
99
+ * search direction.
100
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_mkernel
101
+ */
102
+ function cgIteration(A: Float32Array, x: Float32Array, st: CgState, last: boolean): number {
103
+ const { n, r, p, Ap } = st;
104
+ orthog1f(n, p);
105
+ orthog1f(n, x);
106
+ orthog1f(n, r);
107
+ rightMultWithVectorFFFused(A, n, p, Ap);
108
+ orthog1f(n, Ap); // centering Ap
109
+ const pAp = vectorsInnerProductF(n, p, Ap);
110
+ if (pAp === 0) return CgStep.STOP;
111
+ const alpha = st.rR / pAp;
112
+ vectorsMultAdditionFused(n, x, fr(alpha), p); // derive new x
113
+ if (last) return CgStep.CONTINUE;
114
+ vectorsMultAdditionFused(n, r, fr(-alpha), Ap);
115
+ const rRNew = vectorsInnerProductF(n, r, r);
116
+ if (st.rR === 0) {
117
+ agerrorf(ZERO_LENGTH_MESSAGE);
118
+ return CgStep.ERROR;
119
+ }
120
+ const beta = fr(rRNew / st.rR);
121
+ st.rR = rRNew;
122
+ for (let j = 0; j < n; j++) p[j] = fmaf(beta, p[j]!, r[j]!);
123
+ return CgStep.CONTINUE;
124
+ }
125
+
126
+ /**
127
+ * Solve `A*x = b` by conjugate gradients, `A` packed symmetric; `x` and `b` are
128
+ * centred. Returns 1 on an unexpected zero residual, else 0.
129
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_mkernel
130
+ */
131
+ export function conjugateGradientMkernelFused(
132
+ A: Float32Array, x: Float32Array, b: Float32Array, n: number, o: CgMkernelOptions,
133
+ ): number {
134
+ const st = initialState(A, x, b, n);
135
+ for (let i = 0; i < o.maxIterations && maxAbsF(n, st.r) > o.tol; i++) {
136
+ const step = cgIteration(A, x, st, i >= o.maxIterations - 1);
137
+ if (step === CgStep.STOP) break;
138
+ if (step === CgStep.ERROR) return 1;
139
+ }
140
+ return 0;
141
+ }
@@ -1,4 +1,19 @@
1
1
  // SPDX-License-Identifier: EPL-2.0
2
+ import { agerrorf } from '../../common/agerr.js';
3
+ import type { VtxData } from './dijkstra.js';
4
+ import {
5
+ BLOCK_NONE,
6
+ copyVector,
7
+ innerProduct,
8
+ maxAbs,
9
+ orthog1,
10
+ rightMultWithVector,
11
+ rightMultWithVectorF,
12
+ vectorsAddition,
13
+ vectorsScalarMult,
14
+ vectorsSubtraction,
15
+ } from './matrix-ops.js';
16
+
2
17
  /**
3
18
  * Conjugate gradient solvers for packed symmetric float matrices.
4
19
  * @see lib/neatogen/conjgrad.c
@@ -157,3 +172,196 @@ export function conjugateGradientMkernel(
157
172
  }
158
173
  return 0;
159
174
  }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Double-precision solvers (conjugate_gradient, conjugate_gradient_f)
178
+ // ---------------------------------------------------------------------------
179
+
180
+ /**
181
+ * Unfused block widths of the 16.1 arm64 `-O3 -flto=thin` build, which inlines
182
+ * `vectors_inner_product` into `conjugate_gradient` and compiles each of the
183
+ * three call sites differently (disassembly of `libgvplugin_neato_layout`):
184
+ * the initial `r.r` is vectorized in blocks of 4, `p.Ap` in blocks of 8, and
185
+ * the in-loop `r.r` is a plain scalar loop. In a vectorized block the products
186
+ * are rounded before the in-order adds; the scalar loop contracts to fmadd.
187
+ */
188
+ const BLOCK_INITIAL_RR = 4;
189
+ const BLOCK_P_AP = 8;
190
+
191
+ /** Working vectors of `conjugate_gradient`. @internal */
192
+ interface CgWork {
193
+ r: Float64Array;
194
+ p: Float64Array;
195
+ Ap: Float64Array;
196
+ alphap: Float64Array;
197
+ }
198
+
199
+ /**
200
+ * One CG step after `x += alpha*p`: update residual and direction.
201
+ * Returns the new `r.r`, or null for C's `goto cleanup0` (rv = 1).
202
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient
203
+ */
204
+ function cgNextDirection(n: number, w: CgWork, alpha: number, rR: number): number | null {
205
+ vectorsScalarMult(n, w.Ap, alpha, w.Ap);
206
+ vectorsSubtraction(n, w.r, w.Ap, w.r); // fast computation of r, the residual
207
+ const rRNew = innerProduct(n, w.r, w.r, BLOCK_NONE);
208
+ if (rR === 0) {
209
+ agerrorf('conjugate_gradient: unexpected length 0 vector\n');
210
+ return null;
211
+ }
212
+ const beta = rRNew / rR;
213
+ vectorsScalarMult(n, w.p, beta, w.p);
214
+ vectorsAddition(n, w.r, w.p, w.p);
215
+ return rRNew;
216
+ }
217
+
218
+ /**
219
+ * Residual setup of `conjugate_gradient`: `r = orth_b - A x`, `p = r`; `x` and
220
+ * `b` are orthogonalized against 1.
221
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient
222
+ */
223
+ function cgStart(A: VtxData[], x: Float64Array, b: Float64Array, n: number): CgWork {
224
+ const w: CgWork = {
225
+ r: new Float64Array(n), p: new Float64Array(n),
226
+ Ap: new Float64Array(n), alphap: new Float64Array(n),
227
+ };
228
+ const Ax = new Float64Array(n);
229
+ const orthB = Float64Array.from(b.subarray(0, n));
230
+ orthog1(n, orthB);
231
+ orthog1(n, x);
232
+ rightMultWithVector(A, n, x, Ax);
233
+ vectorsSubtraction(n, orthB, Ax, w.r);
234
+ w.p.set(w.r.subarray(0, n));
235
+ return w;
236
+ }
237
+
238
+ /**
239
+ * Solve `A x = b` by conjugate gradients; `x` and `b` are orthogonalized
240
+ * against 1. Returns C's `rv` (1 on the zero-length-residual failure).
241
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient
242
+ */
243
+ export function conjugateGradient(
244
+ A: VtxData[],
245
+ x: Float64Array,
246
+ b: Float64Array,
247
+ n: number,
248
+ tol: number,
249
+ maxIterations: number,
250
+ ): number {
251
+ const w = cgStart(A, x, b, n);
252
+ let rR = innerProduct(n, w.r, w.r, BLOCK_INITIAL_RR);
253
+
254
+ for (let i = 0; i < maxIterations && maxAbs(n, w.r) > tol; i++) {
255
+ rightMultWithVector(A, n, w.p, w.Ap);
256
+ const pAp = innerProduct(n, w.p, w.Ap, BLOCK_P_AP);
257
+ if (pAp === 0) break;
258
+ const alpha = rR / pAp;
259
+ vectorsScalarMult(n, w.p, alpha, w.alphap); // derive new x
260
+ vectorsAddition(n, x, w.alphap, x);
261
+ if (i < maxIterations - 1) { // not last iteration
262
+ const next = cgNextDirection(n, w, alpha, rR);
263
+ if (next === null) return 1;
264
+ rR = next;
265
+ }
266
+ }
267
+ return 0;
268
+ }
269
+
270
+ /**
271
+ * Block widths of conjugate_gradient_f's inlined sites in the same build:
272
+ * the initial `A x` and the in-loop `A p` row reductions and the initial
273
+ * `r.r` are blocks of 4, `p.Ap` blocks of 8, the in-loop `r.r` scalar.
274
+ * Verified bit for bit against the oracle's own libneatogen.a over random
275
+ * float matrices (n = 5..40, ortho1 on and off).
276
+ */
277
+ const CGF_BLOCK_AX = 4;
278
+ const CGF_BLOCK_AP = 4;
279
+ const CGF_BLOCK_INITIAL_RR = 4;
280
+ const CGF_BLOCK_P_AP = 8;
281
+
282
+ /** Work vectors of one conjugate_gradient_f call. @internal */
283
+ interface CgfState {
284
+ r: Float64Array;
285
+ p: Float64Array;
286
+ Ap: Float64Array;
287
+ alphap: Float64Array;
288
+ rr: number;
289
+ }
290
+
291
+ /**
292
+ * Residual setup: r = orth_b - A x, p = r. `x` is centred when `ortho1`.
293
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_f
294
+ */
295
+ function cgfInit(
296
+ A: readonly Float32Array[], x: Float64Array, b: Float64Array, n: number, ortho1: boolean,
297
+ ): CgfState {
298
+ const orthB = new Float64Array(n);
299
+ copyVector(n, b, orthB);
300
+ if (ortho1) {
301
+ orthog1(n, orthB);
302
+ orthog1(n, x);
303
+ }
304
+ const Ax = new Float64Array(n);
305
+ rightMultWithVectorF(A, n, x, Ax, CGF_BLOCK_AX);
306
+ const r = new Float64Array(n);
307
+ vectorsSubtraction(n, orthB, Ax, r);
308
+ const p = new Float64Array(n);
309
+ copyVector(n, r, p);
310
+ return {
311
+ r, p, Ap: new Float64Array(n), alphap: new Float64Array(n),
312
+ rr: innerProduct(n, r, r, CGF_BLOCK_INITIAL_RR),
313
+ };
314
+ }
315
+
316
+ /**
317
+ * Residual and direction update of a non-last iteration; returns C's `rv`
318
+ * (1 after reporting a zero-length residual).
319
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_f
320
+ */
321
+ function cgfUpdate(n: number, alpha: number, st: CgfState): number {
322
+ vectorsScalarMult(n, st.Ap, alpha, st.Ap);
323
+ vectorsSubtraction(n, st.r, st.Ap, st.r);
324
+ const rrNew = innerProduct(n, st.r, st.r, BLOCK_NONE);
325
+ if (st.rr === 0) {
326
+ agerrorf('conjugate_gradient: unexpected length 0 vector\n');
327
+ return 1;
328
+ }
329
+ const beta = rrNew / st.rr;
330
+ st.rr = rrNew;
331
+ vectorsScalarMult(n, st.p, beta, st.p);
332
+ vectorsAddition(n, st.r, st.p, st.p);
333
+ return 0;
334
+ }
335
+
336
+ /** Stopping rule and centring of {@link conjugateGradientF} (C's trailing parameters). */
337
+ export interface CgfOptions {
338
+ tol: number;
339
+ maxIterations: number;
340
+ ortho1: boolean;
341
+ }
342
+
343
+ /**
344
+ * Solves A x = b for a float** matrix with double x, b (x, b centred when
345
+ * `ortho1`). Returns 0, or 1 after a zero-length residual (callers test `< 0`).
346
+ * @see lib/neatogen/conjgrad.c:conjugate_gradient_f
347
+ */
348
+ export function conjugateGradientF(
349
+ A: readonly Float32Array[],
350
+ x: Float64Array,
351
+ b: Float64Array,
352
+ n: number,
353
+ opts: CgfOptions,
354
+ ): number {
355
+ const { tol, maxIterations, ortho1 } = opts;
356
+ const st = cgfInit(A, x, b, n, ortho1);
357
+ for (let i = 0; i < maxIterations && maxAbs(n, st.r) > tol; i++) {
358
+ rightMultWithVectorF(A, n, st.p, st.Ap, CGF_BLOCK_AP);
359
+ const pAp = innerProduct(n, st.p, st.Ap, CGF_BLOCK_P_AP);
360
+ if (pAp === 0) break;
361
+ const alpha = st.rr / pAp;
362
+ vectorsScalarMult(n, st.p, alpha, st.alphap);
363
+ vectorsAddition(n, x, st.alphap, x);
364
+ if (i < maxIterations - 1 && cgfUpdate(n, alpha, st) === 1) return 1;
365
+ }
366
+ return 0;
367
+ }