@xingwangzhe/force-rs 0.2.2 → 0.2.3

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.
package/README.md CHANGED
@@ -10,12 +10,12 @@ Fast force-directed 3D graph layout powered by **Rust + a contiguous Barnes-Hut
10
10
 
11
11
  ### Force model (fully d3-force compatible)
12
12
 
13
- | Force | Implementation |
14
- |----------------|----------------------------------------------------------|
15
- | Many-body repulsion | Barnes-Hut octree, O(n log n), with `√(4/k)` correction |
16
- | Link (spring) | Degree-biased strength: `1/min(deg, deg)`, bias = other's degree ratio |
17
- | Center (translational) | Shift centroid toward origin (same as d3-force `forceCenter`) |
18
- | Distance softening | Smooth `√(d_min² × d²)` below 1.0 (same as d3-force) |
13
+ | Force | Implementation |
14
+ | ---------------------- | ---------------------------------------------------------------------- |
15
+ | Many-body repulsion | Barnes-Hut octree, O(n log n), with `√(4/k)` correction |
16
+ | Link (spring) | Degree-biased strength: `1/min(deg, deg)`, bias = other's degree ratio |
17
+ | Center (translational) | Shift centroid toward origin (same as d3-force `forceCenter`) |
18
+ | Distance softening | Smooth `√(d_min² × d²)` below 1.0 (same as d3-force) |
19
19
 
20
20
  ### Other features
21
21
 
@@ -36,15 +36,15 @@ npm install @xingwangzhe/force-rs
36
36
  Execute one tick of force-directed simulation.
37
37
 
38
38
  ```ts
39
- import { simTick } from '@xingwangzhe/force-rs';
39
+ import { simTick } from "@xingwangzhe/force-rs";
40
40
 
41
41
  const opts = {
42
- repulsion: 3000, // many-body charge strength
43
- linkDistance: 500, // natural spring length
44
- centerStrength: 0.005,// translational center gravity
45
- theta: 0.8, // Barnes-Hut approximation threshold
46
- velocityDecay: 0.60, // velocity damping per tick
47
- alphaDecay: 0.02, // cooling rate per tick
42
+ repulsion: 3000, // many-body charge strength
43
+ linkDistance: 500, // natural spring length
44
+ centerStrength: 0.005, // translational center gravity
45
+ theta: 0.8, // Barnes-Hut approximation threshold
46
+ velocityDecay: 0.6, // velocity damping per tick
47
+ alphaDecay: 0.02, // cooling rate per tick
48
48
  };
49
49
 
50
50
  // state: n*6 + 1 floats [x0,y0,z0,vx0,vy0,vz0, ..., alpha]
@@ -55,7 +55,7 @@ const newState = simTick(state, links, n, opts);
55
55
  For repeated ticks, preprocess links once and use typed arrays:
56
56
 
57
57
  ```ts
58
- import { createSimulation } from '@xingwangzhe/force-rs';
58
+ import { createSimulation } from "@xingwangzhe/force-rs";
59
59
 
60
60
  const simulation = createSimulation(new Uint32Array(links), n);
61
61
  const nextState = simulation.tick(new Float64Array(state), opts);
@@ -63,18 +63,18 @@ const nextState = simulation.tick(new Float64Array(state), opts);
63
63
 
64
64
  **ForceOptions:**
65
65
 
66
- | Field | Type | Description |
67
- |-----------------|--------|----------------------------------------|
68
- | `repulsion` | number | Many-body charge strength |
69
- | `linkDistance` | number | Natural spring length |
70
- | `centerStrength` | number | Translational center gravity |
71
- | `theta` | number | Barnes-Hut approximation threshold |
72
- | `velocityDecay` | number | Velocity damping factor per tick |
73
- | `alphaDecay` | number | Alpha cooling rate per tick |
66
+ | Field | Type | Description |
67
+ | ---------------- | ------ | -------------------------------------------------------------------- |
68
+ | `repulsion` | number | Many-body charge strength |
69
+ | `linkDistance` | number | Natural spring length |
70
+ | `centerStrength` | number | Translational center gravity |
71
+ | `theta` | number | Barnes-Hut approximation threshold |
72
+ | `velocityDecay` | number | Velocity damping factor per tick |
73
+ | `alphaDecay` | number | Alpha cooling rate per tick |
74
74
  | `algorithm` | string | `fast` (default), `linear` experimental, or `legacy` comparison path |
75
- | `distanceMax` | number | Optional finite repulsion radius |
76
- | `algorithm` | string | `fast` (default) or `legacy` comparison path |
77
- | `distanceMax` | number | Optional finite repulsion radius |
75
+ | `distanceMax` | number | Optional finite repulsion radius |
76
+ | `algorithm` | string | `fast` (default) or `legacy` comparison path |
77
+ | `distanceMax` | number | Optional finite repulsion radius |
78
78
 
79
79
  **Returns:** `Array<number>` for `simTick`, or `Float64Array` for the prepared typed-array API.
80
80
 
@@ -83,14 +83,29 @@ The default `fast` path uses a reusable SoA state layout, precomputed CSR links,
83
83
  ## Usage Example
84
84
 
85
85
  ```ts
86
- import { simTick } from '@xingwangzhe/force-rs';
86
+ import { simTick } from "@xingwangzhe/force-rs";
87
87
 
88
88
  // 3 nodes: positions + velocities + alpha
89
89
  const state = [
90
- 0, 0, 0, 0, 0, 0, // node 0
91
- 100, 0, 0, 0, 0, 0, // node 1
92
- 0, 100, 0, 0, 0, 0, // node 2
93
- 1.0 // alpha
90
+ 0,
91
+ 0,
92
+ 0,
93
+ 0,
94
+ 0,
95
+ 0, // node 0
96
+ 100,
97
+ 0,
98
+ 0,
99
+ 0,
100
+ 0,
101
+ 0, // node 1
102
+ 0,
103
+ 100,
104
+ 0,
105
+ 0,
106
+ 0,
107
+ 0, // node 2
108
+ 1.0, // alpha
94
109
  ];
95
110
  const links = [0, 1, 0, 2]; // node 0 connected to 1 and 2
96
111
 
@@ -99,7 +114,7 @@ const opts = {
99
114
  linkDistance: 500,
100
115
  centerStrength: 0.005,
101
116
  theta: 0.8,
102
- velocityDecay: 0.60,
117
+ velocityDecay: 0.6,
103
118
  alphaDecay: 0.02,
104
119
  };
105
120
 
@@ -112,13 +127,17 @@ while (s[s.length - 1] > 0.001) {
112
127
 
113
128
  ## Real-world Performance
114
129
 
115
- | Platform | 47K nodes × 89K edges | Notes |
116
- |----------|----------------------|-------|
117
- | 16-core | **~0.01s/tick** | Rayon `par_iter` across 16 threads |
118
- | 1-core | ~0.15s/tick | Auto-fallback to sequential |
130
+ | Platform | 47K nodes × 89K edges | Notes |
131
+ | -------- | --------------------- | ---------------------------------- |
132
+ | 16-core | **~0.01s/tick** | Rayon `par_iter` across 16 threads |
133
+ | 1-core | ~0.15s/tick | Auto-fallback to sequential |
119
134
 
120
135
  Measured on AMD EPYC / Intel Xeon build servers. The Barnes-Hut tree is custom-built in `src/lib.rs` (no external tree crate dependency); nodes are stored contiguously to reduce pointer chasing and allocator pressure.
121
136
 
122
137
  ## License
123
138
 
124
139
  MIT
140
+
141
+ ## Runtime-focused release builds
142
+
143
+ Native CI artifacts use full LTO, one code-generation unit, and O3, while preserving the existing CPU instruction baseline. CI trains a profile-guided optimization (PGO) candidate using representative graph workloads and publishes it only when the runtime comparison passes; otherwise it publishes the unprofiled release. `bun run build:pgo` produces the optimized addon; `bun run benchmark:pgo` compares it with an unprofiled release. Install `llvm-tools-preview` with the same Rust toolchain first. Details and measurement limits: [scripts/PERFORMANCE.md](scripts/PERFORMANCE.md).
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,32 +1,46 @@
1
1
  {
2
2
  "name": "@xingwangzhe/force-rs",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Fast force-directed 3D graph layout powered by Rust + Barnes-Hut octree. Fully compatible with d3-force-3d force model (repulsion, spring with correct degree-biased strength, translational center gravity). Parallelized with Rayon — 47K nodes × 89K edges in ~0.01s/tick on 16 cores.",
5
- "main": "index.js",
6
- "types": "index.d.ts",
7
- "license": "MIT",
8
- "author": "xingwangzhe",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/xingwangzhe/force-rs.git"
12
- },
13
5
  "keywords": [
14
- "force-layout",
6
+ "3d",
15
7
  "barnes-hut",
16
8
  "d3-force",
17
9
  "d3-force-3d",
18
- "napi-rs",
19
- "rust",
20
- "graph-layout",
21
10
  "force-directed",
22
- "3d",
23
- "octree"
11
+ "force-layout",
12
+ "graph-layout",
13
+ "napi-rs",
14
+ "octree",
15
+ "rust"
24
16
  ],
17
+ "license": "MIT",
18
+ "author": "xingwangzhe",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/xingwangzhe/force-rs.git"
22
+ },
25
23
  "files": [
26
24
  "index.d.ts",
27
25
  "index.js",
28
26
  "force-rs.*.node"
29
27
  ],
28
+ "main": "index.js",
29
+ "types": "index.d.ts",
30
+ "scripts": {
31
+ "build": "napi build --platform --release",
32
+ "test": "node --test force.test.mjs",
33
+ "benchmark": "node benchmark.mjs",
34
+ "lint": "oxlint",
35
+ "artifacts": "napi artifacts",
36
+ "build:pgo": "node scripts/build-pgo.mjs",
37
+ "benchmark:pgo": "node scripts/build-pgo.mjs --compare"
38
+ },
39
+ "devDependencies": {
40
+ "@napi-rs/cli": "^3.10.5",
41
+ "oxlint": "^1.85.0",
42
+ "typescript": "^7.0.2"
43
+ },
30
44
  "napi": {
31
45
  "binaryName": "force-rs",
32
46
  "targets": [
@@ -40,17 +54,5 @@
40
54
  },
41
55
  "engines": {
42
56
  "node": ">= 18"
43
- },
44
- "scripts": {
45
- "build": "napi build --platform --release",
46
- "test": "node --test force.test.mjs",
47
- "benchmark": "node benchmark.mjs",
48
- "lint": "oxlint",
49
- "artifacts": "napi artifacts"
50
- },
51
- "devDependencies": {
52
- "@napi-rs/cli": "^3.10.5",
53
- "oxlint": "^1.85.0",
54
- "typescript": "^7.0.2"
55
57
  }
56
58
  }