@woosh/meep-engine 2.134.4 → 2.135.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.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/editor/tools/v2/TransformControlsGizmo.js +1 -1
- package/editor/view/node-graph/NodeGraphEditorView.js +2 -2
- package/package.json +1 -1
- package/src/core/assert.d.ts +0 -2
- package/src/core/assert.d.ts.map +1 -1
- package/src/core/assert.js +0 -6
- package/src/core/color/Color.d.ts +0 -5
- package/src/core/color/Color.d.ts.map +1 -1
- package/src/core/color/Color.js +1 -7
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +386 -386
- package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +1 -1
- package/src/core/geom/2d/quad-tree-binary/QuadTree.js +714 -714
- package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +160 -160
- package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +96 -96
- package/src/core/geom/packing/max-rect/MaxRectanglesPacker.js +1 -1
- package/src/core/geom/packing/max-rect/findBestContainer.js +4 -4
- package/src/core/geom/packing/max-rect/packOneBox.js +2 -2
- package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts +23 -0
- package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_rigid_align_paired_unit_vectors.js +96 -0
- package/src/core/graph/layout/box/BoxLayouter.js +7 -7
- package/src/core/graph/layout/box/position_box_next_to_box.js +6 -6
- package/src/core/math/computeWholeDivisorLow.js +33 -33
- package/src/core/math/linalg/eigen/eigen_values_find_spectral_gap.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_eigenvalues_in_place.d.ts +10 -0
- package/src/core/math/linalg/eigen/matrix_eigenvalues_in_place.d.ts.map +1 -0
- package/src/core/{graph → math/linalg}/eigen/matrix_eigenvalues_in_place.js +8 -7
- package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts.map +1 -0
- package/src/core/{graph → math/linalg}/eigen/matrix_householder_in_place.js +11 -5
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +15 -0
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -0
- package/src/core/{graph → math/linalg}/eigen/matrix_qr_in_place.js +8 -2
- package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts +17 -0
- package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.d.ts.map +1 -0
- package/src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.js +107 -0
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.d.ts +19 -0
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.js +161 -0
- package/src/core/math/linalg/polynomial_real_roots_in_interval.d.ts +15 -0
- package/src/core/math/linalg/polynomial_real_roots_in_interval.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_real_roots_in_interval.js +200 -0
- package/src/core/math/solveCubic.d.ts +15 -0
- package/src/core/math/solveCubic.d.ts.map +1 -0
- package/src/core/math/solveCubic.js +82 -0
- package/src/core/math/spline/spline3_hermite_bounds_t.d.ts +23 -0
- package/src/core/math/spline/spline3_hermite_bounds_t.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_bounds_t.js +109 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts +25 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.js +44 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.d.ts +16 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.js +120 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts +11 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.js +451 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts +12 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +339 -0
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.d.ts +15 -0
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js +21 -0
- package/src/core/math/spline/spline3_hermite_to_monomial.d.ts +24 -0
- package/src/core/math/spline/spline3_hermite_to_monomial.d.ts.map +1 -0
- package/src/core/math/spline/spline3_hermite_to_monomial.js +37 -0
- package/src/core/math/spline/v3_computeCatmullRomSplineUniformDistance.js +1 -1
- package/src/core/model/node-graph/visual/NodeGraphVisualData.js +1 -1
- package/src/core/model/reactive/model/util/createRandomReactiveExpression.js +185 -185
- package/src/core/process/delay.js +16 -16
- package/src/engine/animation/async/TimeSeries.js +300 -300
- package/src/engine/animation/curve/AnimationCurve.d.ts +3 -2
- package/src/engine/animation/curve/AnimationCurve.d.ts.map +1 -1
- package/src/engine/animation/curve/AnimationCurve.js +3 -2
- package/src/engine/animation/curve/draw/position_canvas_to_curve.js +2 -2
- package/src/engine/animation/curve/draw/position_curve_to_canvas.js +2 -2
- package/src/engine/ecs/fow/shader/FogOfWarRenderer.js +145 -145
- package/src/engine/ecs/gui/position/ViewportPositionSystem.js +2 -2
- package/src/engine/ecs/parent/entity_node_compute_bounding_box.js +1 -1
- package/src/engine/ecs/transform/Transform.d.ts +0 -10
- package/src/engine/ecs/transform/Transform.d.ts.map +1 -1
- package/src/engine/ecs/transform/Transform.js +0 -12
- package/src/engine/graphics/composit/CompositLayer.js +254 -254
- package/src/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +1 -1
- package/src/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +2 -2
- package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +3 -3
- package/src/engine/graphics/particles/particular/engine/utils/volume/AttributeValue.js +201 -201
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
- package/src/engine/graphics/render/buffer/slot/parameter/ProgramValueSlotParameterSet.js +2 -2
- package/src/engine/graphics/render/forward_plus/LightManager.js +1226 -1226
- package/src/engine/graphics/render/forward_plus/model/PointLight.js +1 -1
- package/src/engine/graphics/sh3/lpv/lpv_obtain_storage_cached_volume.js +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +2 -2
- package/src/engine/graphics/texture/atlas/TextureAtlasDebugger.js +1 -1
- package/src/engine/graphics/texture/sampler/HarmonicDiffusionGrid.js +145 -145
- package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.js +2 -2
- package/src/engine/intelligence/behavior/ecs/BehaviorComponent.d.ts +2 -6
- package/src/engine/intelligence/behavior/ecs/BehaviorComponent.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/ecs/BehaviorComponent.js +0 -10
- package/src/engine/intelligence/mcts/MonteCarlo.js +275 -275
- package/src/engine/navigation/ecs/path_following/PathFollower.js +222 -222
- package/src/generation/grid/GridData.js +220 -220
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +385 -385
- package/src/view/elements/image/SvgImageView.js +1 -1
- package/src/view/elements/windrose/WindRoseDiagram.js +369 -369
- package/src/view/minimap/gl/MinimapFogOfWar.js +3 -3
- package/src/view/util/DomSizeObserver.js +1 -1
- package/src/core/binary/clz32.d.ts +0 -6
- package/src/core/binary/clz32.d.ts.map +0 -1
- package/src/core/binary/clz32.js +0 -5
- package/src/core/binary/type/dataTypeFromTypedArray.d.ts +0 -8
- package/src/core/binary/type/dataTypeFromTypedArray.d.ts.map +0 -1
- package/src/core/binary/type/dataTypeFromTypedArray.js +0 -11
- package/src/core/collection/array/computeHashIntegerArray.d.ts +0 -1
- package/src/core/collection/array/computeHashIntegerArray.d.ts.map +0 -1
- package/src/core/collection/array/computeHashIntegerArray.js +0 -7
- package/src/core/collection/array/typed/typedArrayToDataType.d.ts +0 -6
- package/src/core/collection/array/typed/typedArrayToDataType.d.ts.map +0 -1
- package/src/core/collection/array/typed/typedArrayToDataType.js +0 -6
- package/src/core/geom/3d/mat4/MATRIX_4_IDENTITY.d.ts +0 -6
- package/src/core/geom/3d/mat4/MATRIX_4_IDENTITY.d.ts.map +0 -1
- package/src/core/geom/3d/mat4/MATRIX_4_IDENTITY.js +0 -7
- package/src/core/graph/eigen/eigen_values_find_spectral_gap.d.ts.map +0 -1
- package/src/core/graph/eigen/matrix_eigenvalues_in_place.d.ts +0 -8
- package/src/core/graph/eigen/matrix_eigenvalues_in_place.d.ts.map +0 -1
- package/src/core/graph/eigen/matrix_householder_in_place.d.ts.map +0 -1
- package/src/core/graph/eigen/matrix_qr_in_place.d.ts +0 -9
- package/src/core/graph/eigen/matrix_qr_in_place.d.ts.map +0 -1
- package/src/core/math/spline/cubicCurve.d.ts +0 -6
- package/src/core/math/spline/cubicCurve.d.ts.map +0 -1
- package/src/core/math/spline/cubicCurve.js +0 -6
- package/src/core/math/spline/spline_bezier2.d.ts +0 -6
- package/src/core/math/spline/spline_bezier2.d.ts.map +0 -1
- package/src/core/math/spline/spline_bezier2.js +0 -6
- package/src/core/math/spline/spline_bezier3.d.ts +0 -6
- package/src/core/math/spline/spline_bezier3.d.ts.map +0 -1
- package/src/core/math/spline/spline_bezier3.js +0 -6
- package/src/core/math/spline/spline_bezier3_bounds.d.ts +0 -6
- package/src/core/math/spline/spline_bezier3_bounds.d.ts.map +0 -1
- package/src/core/math/spline/spline_bezier3_bounds.js +0 -6
- package/src/core/math/spline/spline_hermite3.d.ts +0 -6
- package/src/core/math/spline/spline_hermite3.d.ts.map +0 -1
- package/src/core/math/spline/spline_hermite3.js +0 -6
- package/src/core/math/spline/spline_hermite3_bounds.d.ts +0 -6
- package/src/core/math/spline/spline_hermite3_bounds.d.ts.map +0 -1
- package/src/core/math/spline/spline_hermite3_bounds.js +0 -6
- package/src/core/math/spline/spline_hermite3_to_bezier.d.ts +0 -2
- package/src/core/math/spline/spline_hermite3_to_bezier.d.ts.map +0 -1
- package/src/core/math/spline/spline_hermite3_to_bezier.js +0 -6
- package/src/engine/intelligence/behavior/decorator/RepeatUntilFailureBehavior.d.ts +0 -37
- package/src/engine/intelligence/behavior/decorator/RepeatUntilFailureBehavior.d.ts.map +0 -1
- package/src/engine/intelligence/behavior/decorator/RepeatUntilFailureBehavior.js +0 -70
- /package/src/core/{graph → math/linalg}/eigen/eigen_values_find_spectral_gap.d.ts +0 -0
- /package/src/core/{graph → math/linalg}/eigen/eigen_values_find_spectral_gap.js +0 -0
- /package/src/core/{graph → math/linalg}/eigen/matrix_householder_in_place.d.ts +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BinaryDataType } from "../../binary/type/BinaryDataType.js";
|
|
2
|
+
import { matrix_top_eigenvector_power_iteration } from "../../math/linalg/eigen/matrix_top_eigenvector_power_iteration.js";
|
|
3
|
+
import { SquareMatrix } from "../../math/matrix/SquareMatrix.js"
|
|
4
|
+
|
|
5
|
+
const scratch_horn_n = new SquareMatrix(4, BinaryDataType.Float64);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Closed-form solution for the rotation that best aligns two sets of unit
|
|
9
|
+
* vectors, via Horn (1987) "Closed-form solution of absolute orientation using
|
|
10
|
+
* unit quaternions".
|
|
11
|
+
*
|
|
12
|
+
* Given paired unit vectors {a_i} and {b_i}, finds the unit quaternion q such
|
|
13
|
+
* that rotating each b_i by q minimizes Σ |a_i − R(q)·b_i|².
|
|
14
|
+
*
|
|
15
|
+
* The matrix N is built so that the eigenvector of its largest eigenvalue
|
|
16
|
+
* IS the optimal rotation quaternion (in scalar-last form, matching meep's
|
|
17
|
+
* `Quaternion`).
|
|
18
|
+
*
|
|
19
|
+
* Inputs are unit vectors so no centroid subtraction is needed — the rotation
|
|
20
|
+
* is recovered from the cross-correlations alone.
|
|
21
|
+
*
|
|
22
|
+
* @param {Float32Array|number[]} a_xyz Source vectors — Length: count*3, unit length per triple
|
|
23
|
+
* @param {Float32Array|number[]} b_xyz Target vectors — Length: count*3, unit length per triple
|
|
24
|
+
* @param {number} count
|
|
25
|
+
* @param {Float32Array|number[]} out_quaternion Length 4 (x, y, z, w)
|
|
26
|
+
* @returns {number} The maximum eigenvalue ≈ Σ a_i · R·b_i. For a perfect alignment this equals `count`.
|
|
27
|
+
*/
|
|
28
|
+
export function v3_rigid_align_paired_unit_vectors(a_xyz, b_xyz, count, out_quaternion) {
|
|
29
|
+
|
|
30
|
+
// Cross-correlation matrix S_ij = Σ b_i_component * a_j_component
|
|
31
|
+
// Note: S is built as Σ b ⊗ aᵀ (Horn 1987 convention) — the rotation
|
|
32
|
+
// recovered will take b onto a.
|
|
33
|
+
let Sxx = 0, Sxy = 0, Sxz = 0;
|
|
34
|
+
let Syx = 0, Syy = 0, Syz = 0;
|
|
35
|
+
let Szx = 0, Szy = 0, Szz = 0;
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < count; i++) {
|
|
38
|
+
const i3 = i * 3;
|
|
39
|
+
const ax = a_xyz[i3], ay = a_xyz[i3 + 1], az = a_xyz[i3 + 2];
|
|
40
|
+
const bx = b_xyz[i3], by = b_xyz[i3 + 1], bz = b_xyz[i3 + 2];
|
|
41
|
+
|
|
42
|
+
Sxx += bx * ax;
|
|
43
|
+
Sxy += bx * ay;
|
|
44
|
+
Sxz += bx * az;
|
|
45
|
+
Syx += by * ax;
|
|
46
|
+
Syy += by * ay;
|
|
47
|
+
Syz += by * az;
|
|
48
|
+
Szx += bz * ax;
|
|
49
|
+
Szy += bz * ay;
|
|
50
|
+
Szz += bz * az;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Horn's 4x4 symmetric matrix N (scalar-last quaternion ordering: x, y, z, w).
|
|
54
|
+
//
|
|
55
|
+
// From the paper, ordered for scalar-FIRST quaternion (w, x, y, z):
|
|
56
|
+
// N00 = Sxx + Syy + Szz N01 = Syz - Szy N02 = Szx - Sxz N03 = Sxy - Syx
|
|
57
|
+
// N11 = Sxx - Syy - Szz N12 = Sxy + Syx N13 = Szx + Sxz
|
|
58
|
+
// N22 = -Sxx + Syy - Szz N23 = Syz + Szy
|
|
59
|
+
// N33 = -Sxx - Syy + Szz
|
|
60
|
+
//
|
|
61
|
+
// We rebind to (x, y, z, w):
|
|
62
|
+
// row/col 0 = x, 1 = y, 2 = z, 3 = w
|
|
63
|
+
// i.e. swap original index 0 with 3 and shift others down.
|
|
64
|
+
const Nxx = Sxx - Syy - Szz;
|
|
65
|
+
const Nyy = -Sxx + Syy - Szz;
|
|
66
|
+
const Nzz = -Sxx - Syy + Szz;
|
|
67
|
+
const Nww = Sxx + Syy + Szz;
|
|
68
|
+
const Nxy = Sxy + Syx;
|
|
69
|
+
const Nxz = Szx + Sxz;
|
|
70
|
+
const Nxw = Syz - Szy;
|
|
71
|
+
const Nyz = Syz + Szy;
|
|
72
|
+
const Nyw = Szx - Sxz;
|
|
73
|
+
const Nzw = Sxy - Syx;
|
|
74
|
+
|
|
75
|
+
const N = scratch_horn_n;
|
|
76
|
+
const d = N.data;
|
|
77
|
+
// SquareMatrix is column-major: d[col * 4 + row]
|
|
78
|
+
d[0] = Nxx;
|
|
79
|
+
d[5] = Nyy;
|
|
80
|
+
d[10] = Nzz;
|
|
81
|
+
d[15] = Nww;
|
|
82
|
+
d[1] = Nxy;
|
|
83
|
+
d[4] = Nxy;
|
|
84
|
+
d[2] = Nxz;
|
|
85
|
+
d[8] = Nxz;
|
|
86
|
+
d[3] = Nxw;
|
|
87
|
+
d[12] = Nxw;
|
|
88
|
+
d[6] = Nyz;
|
|
89
|
+
d[9] = Nyz;
|
|
90
|
+
d[7] = Nyw;
|
|
91
|
+
d[13] = Nyw;
|
|
92
|
+
d[11] = Nzw;
|
|
93
|
+
d[14] = Nzw;
|
|
94
|
+
|
|
95
|
+
return matrix_top_eigenvector_power_iteration(N, out_quaternion);
|
|
96
|
+
}
|
|
@@ -22,11 +22,11 @@ function evaluateEdgeCost(edge) {
|
|
|
22
22
|
const second = edge.target;
|
|
23
23
|
|
|
24
24
|
//compute center points
|
|
25
|
-
const x0 = first.
|
|
26
|
-
const y0 = first.
|
|
25
|
+
const x0 = first.centerX;
|
|
26
|
+
const y0 = first.centerY;
|
|
27
27
|
|
|
28
|
-
const x1 = second.
|
|
29
|
-
const y1 = second.
|
|
28
|
+
const x1 = second.centerX;
|
|
29
|
+
const y1 = second.centerY;
|
|
30
30
|
|
|
31
31
|
return Vector2._distance(x0, y0, x1, y1);
|
|
32
32
|
}
|
|
@@ -63,7 +63,7 @@ function evaluateLayout(boxes, edges) {
|
|
|
63
63
|
const footprint = computeBoundingBox(boxes);
|
|
64
64
|
|
|
65
65
|
//overall size of the layout plays a role
|
|
66
|
-
const totalArea = footprint.
|
|
66
|
+
const totalArea = footprint.height * footprint.width;
|
|
67
67
|
|
|
68
68
|
const totalConnectionLength = edges.reduce(function (sum, edge) {
|
|
69
69
|
return sum + evaluateEdgeCost(edge);
|
|
@@ -177,8 +177,8 @@ function applyPull(edges, strength) {
|
|
|
177
177
|
const first = edge.source;
|
|
178
178
|
const second = edge.target;
|
|
179
179
|
|
|
180
|
-
d.set(second.
|
|
181
|
-
d._sub(first.
|
|
180
|
+
d.set(second.centerX, second.centerY);
|
|
181
|
+
d._sub(first.centerX, first.centerY);
|
|
182
182
|
|
|
183
183
|
d.multiplyScalar(strength);
|
|
184
184
|
|
|
@@ -31,13 +31,13 @@ function compute_initial_placement(
|
|
|
31
31
|
|
|
32
32
|
const targetCenter = target.getCenter();
|
|
33
33
|
|
|
34
|
-
const targetH = target.
|
|
35
|
-
const targetW = target.
|
|
34
|
+
const targetH = target.height;
|
|
35
|
+
const targetW = target.width;
|
|
36
36
|
|
|
37
37
|
const targetDiagonal = Math.sqrt(targetH * targetH + targetW * targetW);
|
|
38
38
|
|
|
39
|
-
const boxWidth = box.
|
|
40
|
-
const boxHeight = box.
|
|
39
|
+
const boxWidth = box.width;
|
|
40
|
+
const boxHeight = box.height;
|
|
41
41
|
|
|
42
42
|
const boxWidth_2 = boxWidth / 2;
|
|
43
43
|
const boxHeight_2 = boxHeight / 2;
|
|
@@ -120,8 +120,8 @@ function compute_initial_placement(
|
|
|
120
120
|
|
|
121
121
|
let score = 0;
|
|
122
122
|
|
|
123
|
-
const availableWidth = availableSpace.
|
|
124
|
-
const availableHeight = availableSpace.
|
|
123
|
+
const availableWidth = availableSpace.width;
|
|
124
|
+
const availableHeight = availableSpace.height;
|
|
125
125
|
|
|
126
126
|
const spareWidth = availableWidth - boxWidth;
|
|
127
127
|
const spareHeight = availableHeight - boxHeight;
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { assert } from "../assert.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Compute the largest positive integer divisor of a given "product" value
|
|
5
|
-
* @param {number} product
|
|
6
|
-
* @param {number} limit
|
|
7
|
-
* @returns {number}
|
|
8
|
-
*/
|
|
9
|
-
export function computeWholeDivisorLow(product, limit) {
|
|
10
|
-
|
|
11
|
-
assert.isNumber(product, 'product');
|
|
12
|
-
assert.isInteger(product, 'product');
|
|
13
|
-
|
|
14
|
-
assert.isNumber(limit, 'limit');
|
|
15
|
-
assert.isInteger(limit, 'limit');
|
|
16
|
-
|
|
17
|
-
assert.
|
|
18
|
-
assert.
|
|
19
|
-
|
|
20
|
-
let i = limit;
|
|
21
|
-
|
|
22
|
-
while (i > 1) {
|
|
23
|
-
|
|
24
|
-
if (product % i === 0) {
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
i--;
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return i;
|
|
33
|
-
}
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compute the largest positive integer divisor of a given "product" value
|
|
5
|
+
* @param {number} product
|
|
6
|
+
* @param {number} limit
|
|
7
|
+
* @returns {number}
|
|
8
|
+
*/
|
|
9
|
+
export function computeWholeDivisorLow(product, limit) {
|
|
10
|
+
|
|
11
|
+
assert.isNumber(product, 'product');
|
|
12
|
+
assert.isInteger(product, 'product');
|
|
13
|
+
|
|
14
|
+
assert.isNumber(limit, 'limit');
|
|
15
|
+
assert.isInteger(limit, 'limit');
|
|
16
|
+
|
|
17
|
+
assert.isFinite(limit,'limit');
|
|
18
|
+
assert.isFinite(product,'product');
|
|
19
|
+
|
|
20
|
+
let i = limit;
|
|
21
|
+
|
|
22
|
+
while (i > 1) {
|
|
23
|
+
|
|
24
|
+
if (product % i === 0) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
i--;
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return i;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eigen_values_find_spectral_gap.d.ts","sourceRoot":"","sources":["../../../../../../src/core/math/linalg/eigen/eigen_values_find_spectral_gap.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,uDAHW,MAAM,EAAE,GACN,MAAM,CAoBlB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list of eigen values square matrix (allow non-symmetric)
|
|
3
|
+
* NOTE: Modifies input matrix
|
|
4
|
+
* @template T extends ArrayLike<number>
|
|
5
|
+
* @param {T} out
|
|
6
|
+
* @param {SquareMatrix} mat
|
|
7
|
+
* @return {T}
|
|
8
|
+
*/
|
|
9
|
+
export function matrix_eigenvalues_in_place<T>(out: T, mat: SquareMatrix): T;
|
|
10
|
+
//# sourceMappingURL=matrix_eigenvalues_in_place.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix_eigenvalues_in_place.d.ts","sourceRoot":"","sources":["../../../../../../src/core/math/linalg/eigen/matrix_eigenvalues_in_place.js"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,6EASC"}
|
|
@@ -3,19 +3,20 @@ import { matrix_qr_in_place } from "./matrix_qr_in_place.js";
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* list of eigen values square matrix (allow non
|
|
6
|
+
* list of eigen values square matrix (allow non-symmetric)
|
|
7
7
|
* NOTE: Modifies input matrix
|
|
8
|
+
* @template T extends ArrayLike<number>
|
|
9
|
+
* @param {T} out
|
|
8
10
|
* @param {SquareMatrix} mat
|
|
9
|
-
* @return {
|
|
11
|
+
* @return {T}
|
|
10
12
|
*/
|
|
11
|
-
export function matrix_eigenvalues_in_place(mat) {
|
|
13
|
+
export function matrix_eigenvalues_in_place(out, mat) {
|
|
12
14
|
const n = mat.size;
|
|
15
|
+
|
|
13
16
|
matrix_householder_in_place(mat.data, n);
|
|
14
17
|
matrix_qr_in_place(mat.data, n);
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mat.readDiagonal(result);
|
|
19
|
+
mat.readDiagonal(out);
|
|
19
20
|
|
|
20
|
-
return
|
|
21
|
+
return out;
|
|
21
22
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix_householder_in_place.d.ts","sourceRoot":"","sources":["../../../../../../src/core/math/linalg/eigen/matrix_householder_in_place.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,+CAHW,MAAM,EAAE,KACR,MAAM,QA0FhB"}
|
|
@@ -32,14 +32,20 @@ export function matrix_householder_in_place(a, n) {
|
|
|
32
32
|
sum = sum + u[i] * u[i];
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const u_k_1_abs = Math.abs(u_k_1);
|
|
38
|
-
if (u_k_1_abs < EPSILON) {
|
|
35
|
+
if (sum < EPSILON * EPSILON) {
|
|
36
|
+
// sub-column already zero — nothing to reduce at this k
|
|
39
37
|
continue;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
const
|
|
40
|
+
const u_k_1 = u[k + 1];
|
|
41
|
+
const u_k_1_abs = Math.abs(u_k_1);
|
|
42
|
+
|
|
43
|
+
// sigma = sign(u[k+1]) · ‖u‖. When u[k+1] = 0 the sign is arbitrary
|
|
44
|
+
// (entries below are still nonzero by the `sum` check above), so pick
|
|
45
|
+
// +‖u‖.
|
|
46
|
+
const sigma = u_k_1_abs < EPSILON
|
|
47
|
+
? Math.sqrt(sum)
|
|
48
|
+
: Math.sqrt(sum) * u_k_1 / u_k_1_abs;
|
|
43
49
|
|
|
44
50
|
u[k + 1] += sigma;
|
|
45
51
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perform QR factorization in-place.
|
|
3
|
+
* Subfunction that analyzes eigenvalues by QR decomposition.
|
|
4
|
+
*
|
|
5
|
+
* Single-shift Wilkinson iteration: deflates the trailing subdiagonal one row
|
|
6
|
+
* at a time as it converges. A complex eigenvalue pair leaves a 2×2 trailing
|
|
7
|
+
* block whose inner subdiagonal does not vanish, and this routine will spin
|
|
8
|
+
* on it indefinitely — only safe today for matrices with all-real eigenvalues.
|
|
9
|
+
*
|
|
10
|
+
* @see http://www-in.aut.ac.jp/~minemura/pub/Csimu/C/QRmethod.html
|
|
11
|
+
* @param {number[]} a Square matrix
|
|
12
|
+
* @param {number} n size of the matrix in single dimension
|
|
13
|
+
*/
|
|
14
|
+
export function matrix_qr_in_place(a: number[], n: number): void;
|
|
15
|
+
//# sourceMappingURL=matrix_qr_in_place.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix_qr_in_place.d.ts","sourceRoot":"","sources":["../../../../../../src/core/math/linalg/eigen/matrix_qr_in_place.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,sCAHW,MAAM,EAAE,KACR,MAAM,QA8GhB"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const EPSILON = 1e-10;
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Perform QR factorization in-place
|
|
5
|
-
* Subfunction that analyzes eigenvalues by QR decomposition
|
|
4
|
+
* Perform QR factorization in-place.
|
|
5
|
+
* Subfunction that analyzes eigenvalues by QR decomposition.
|
|
6
|
+
*
|
|
7
|
+
* Single-shift Wilkinson iteration: deflates the trailing subdiagonal one row
|
|
8
|
+
* at a time as it converges. A complex eigenvalue pair leaves a 2×2 trailing
|
|
9
|
+
* block whose inner subdiagonal does not vanish, and this routine will spin
|
|
10
|
+
* on it indefinitely — only safe today for matrices with all-real eigenvalues.
|
|
11
|
+
*
|
|
6
12
|
* @see http://www-in.aut.ac.jp/~minemura/pub/Csimu/C/QRmethod.html
|
|
7
13
|
* @param {number[]} a Square matrix
|
|
8
14
|
* @param {number} n size of the matrix in single dimension
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the eigenvector corresponding to the largest-magnitude eigenvalue of a
|
|
3
|
+
* symmetric square matrix using power iteration.
|
|
4
|
+
*
|
|
5
|
+
* Designed for small symmetric matrices where the dominant eigenvalue is
|
|
6
|
+
* well-separated from the rest (Horn's quaternion method on a 4x4, PCA on a
|
|
7
|
+
* 3x3 covariance, etc.). Unsuitable when the top two eigenvalues have nearly
|
|
8
|
+
* equal magnitude — convergence stalls in that regime.
|
|
9
|
+
*
|
|
10
|
+
* @param {SquareMatrix} matrix Symmetric, column-major as per SquareMatrix
|
|
11
|
+
* @param {number[]|Float32Array|Float64Array} out Eigenvector is written here, length >= matrix.size
|
|
12
|
+
* @param {number} [max_iterations=64]
|
|
13
|
+
* @param {number} [tolerance=1e-8] Convergence stops when ||v_next - v|| < tolerance
|
|
14
|
+
* @returns {number} The Rayleigh quotient (estimated eigenvalue)
|
|
15
|
+
*/
|
|
16
|
+
export function matrix_top_eigenvector_power_iteration(matrix: SquareMatrix, out: number[] | Float32Array | Float64Array, max_iterations?: number, tolerance?: number): number;
|
|
17
|
+
//# sourceMappingURL=matrix_top_eigenvector_power_iteration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix_top_eigenvector_power_iteration.d.ts","sourceRoot":"","sources":["../../../../../../src/core/math/linalg/eigen/matrix_top_eigenvector_power_iteration.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;GAcG;AACH,kFALW,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,mBAClC,MAAM,cACN,MAAM,GACJ,MAAM,CAoFlB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { assert } from "@woosh/meep-engine/src/core/assert.js";
|
|
2
|
+
|
|
3
|
+
let scratch_next = new Float64Array(16);
|
|
4
|
+
|
|
5
|
+
function ensure_scratch(n) {
|
|
6
|
+
if (scratch_next.length < n) scratch_next = new Float64Array(n);
|
|
7
|
+
return scratch_next;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Find the eigenvector corresponding to the largest-magnitude eigenvalue of a
|
|
12
|
+
* symmetric square matrix using power iteration.
|
|
13
|
+
*
|
|
14
|
+
* Designed for small symmetric matrices where the dominant eigenvalue is
|
|
15
|
+
* well-separated from the rest (Horn's quaternion method on a 4x4, PCA on a
|
|
16
|
+
* 3x3 covariance, etc.). Unsuitable when the top two eigenvalues have nearly
|
|
17
|
+
* equal magnitude — convergence stalls in that regime.
|
|
18
|
+
*
|
|
19
|
+
* @param {SquareMatrix} matrix Symmetric, column-major as per SquareMatrix
|
|
20
|
+
* @param {number[]|Float32Array|Float64Array} out Eigenvector is written here, length >= matrix.size
|
|
21
|
+
* @param {number} [max_iterations=64]
|
|
22
|
+
* @param {number} [tolerance=1e-8] Convergence stops when ||v_next - v|| < tolerance
|
|
23
|
+
* @returns {number} The Rayleigh quotient (estimated eigenvalue)
|
|
24
|
+
*/
|
|
25
|
+
export function matrix_top_eigenvector_power_iteration(
|
|
26
|
+
matrix,
|
|
27
|
+
out,
|
|
28
|
+
max_iterations = 64,
|
|
29
|
+
tolerance = 1e-8
|
|
30
|
+
) {
|
|
31
|
+
assert.defined(matrix, "matrix");
|
|
32
|
+
assert.defined(out, "out");
|
|
33
|
+
|
|
34
|
+
const n = matrix.size;
|
|
35
|
+
const data = matrix.data;
|
|
36
|
+
|
|
37
|
+
// Deterministic asymmetric initial vector. A uniform init (e.g. 1/√n in
|
|
38
|
+
// every slot) can be orthogonal to the dominant eigenvector when the matrix
|
|
39
|
+
// has block structure, stalling iteration on a sub-dominant eigenvalue.
|
|
40
|
+
// Irrational-component cosines avoid this for any reasonable n.
|
|
41
|
+
let init_norm_sq = 0;
|
|
42
|
+
for (let i = 0; i < n; i++) {
|
|
43
|
+
const v = Math.cos(i * 1.7 + 0.3);
|
|
44
|
+
out[i] = v;
|
|
45
|
+
init_norm_sq += v * v;
|
|
46
|
+
}
|
|
47
|
+
const init_inv = 1 / Math.sqrt(init_norm_sq);
|
|
48
|
+
for (let i = 0; i < n; i++) out[i] *= init_inv;
|
|
49
|
+
|
|
50
|
+
const next = ensure_scratch(n);
|
|
51
|
+
let eigenvalue = 0;
|
|
52
|
+
|
|
53
|
+
for (let iter = 0; iter < max_iterations; iter++) {
|
|
54
|
+
// next = matrix * out
|
|
55
|
+
// Column-major: data[col * n + row] is element at (row, col)
|
|
56
|
+
for (let row = 0; row < n; row++) {
|
|
57
|
+
let sum = 0;
|
|
58
|
+
for (let col = 0; col < n; col++) {
|
|
59
|
+
sum += data[col * n + row] * out[col];
|
|
60
|
+
}
|
|
61
|
+
next[row] = sum;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Rayleigh quotient = out . next (since out is unit length and matrix is symmetric)
|
|
65
|
+
let rayleigh = 0;
|
|
66
|
+
for (let i = 0; i < n; i++) {
|
|
67
|
+
rayleigh += out[i] * next[i];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Normalize next
|
|
71
|
+
let length_sqr = 0;
|
|
72
|
+
for (let i = 0; i < n; i++) {
|
|
73
|
+
length_sqr += next[i] * next[i];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (length_sqr === 0) {
|
|
77
|
+
// Degenerate input — bail out, leave `out` as-is
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const inv_length = 1 / Math.sqrt(length_sqr);
|
|
82
|
+
|
|
83
|
+
// Sign-align next with out so we can measure convergence by raw difference.
|
|
84
|
+
// (Power iteration has a sign ambiguity per step when eigenvalue is negative.)
|
|
85
|
+
let dot = 0;
|
|
86
|
+
for (let i = 0; i < n; i++) {
|
|
87
|
+
dot += next[i] * out[i];
|
|
88
|
+
}
|
|
89
|
+
const sign = dot < 0 ? -inv_length : inv_length;
|
|
90
|
+
|
|
91
|
+
let delta_sqr = 0;
|
|
92
|
+
for (let i = 0; i < n; i++) {
|
|
93
|
+
const v = next[i] * sign;
|
|
94
|
+
const d = v - out[i];
|
|
95
|
+
delta_sqr += d * d;
|
|
96
|
+
out[i] = v;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
eigenvalue = rayleigh;
|
|
100
|
+
|
|
101
|
+
if (delta_sqr < tolerance * tolerance) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return eigenvalue;
|
|
107
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find all complex roots of a univariate polynomial via Aberth–Ehrlich.
|
|
3
|
+
*
|
|
4
|
+
* The polynomial is given in ascending-power coefficient form:
|
|
5
|
+
* p(x) = coeffs[0] + coeffs[1]·x + … + coeffs[degree]·x^degree
|
|
6
|
+
* The leading coefficient `coeffs[degree]` must be nonzero.
|
|
7
|
+
*
|
|
8
|
+
* Exactly `degree` complex numbers are written into `roots_re`/`roots_im` at
|
|
9
|
+
* index `offset`, `offset + 1`, …, `offset + degree - 1`. The order they
|
|
10
|
+
* appear in is not specified.
|
|
11
|
+
*
|
|
12
|
+
* @param {Float64Array|number[]} coeffs ascending-power, length ≥ degree + 1
|
|
13
|
+
* @param {number} degree polynomial degree, ≥ 1, ≤ 64
|
|
14
|
+
* @param {Float64Array|number[]} roots_re real parts, length ≥ offset + degree
|
|
15
|
+
* @param {Float64Array|number[]} roots_im imaginary parts, length ≥ offset + degree
|
|
16
|
+
* @param {number} offset
|
|
17
|
+
*/
|
|
18
|
+
export function polynomial_complex_roots_aberth_ehrlich(coeffs: Float64Array | number[], degree: number, roots_re: Float64Array | number[], roots_im: Float64Array | number[], offset: number): void;
|
|
19
|
+
//# sourceMappingURL=polynomial_complex_roots_aberth_ehrlich.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polynomial_complex_roots_aberth_ehrlich.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.js"],"names":[],"mappings":"AA6DA;;;;;;;;;;;;;;;;GAgBG;AACH,gEANW,YAAY,GAAC,MAAM,EAAE,UACrB,MAAM,YACN,YAAY,GAAC,MAAM,EAAE,YACrB,YAAY,GAAC,MAAM,EAAE,UACrB,MAAM,QAoFhB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Find all roots of a univariate polynomial in the complex plane via
|
|
5
|
+
Aberth–Ehrlich simultaneous iteration. Real and complex roots are isolated
|
|
6
|
+
together; the caller separates real ones by inspecting the imaginary parts.
|
|
7
|
+
|
|
8
|
+
Reference: Aberth (1973), "Iteration methods for finding all zeros of a
|
|
9
|
+
polynomial simultaneously", Math. Comp. 27.
|
|
10
|
+
|
|
11
|
+
The iteration is
|
|
12
|
+
|
|
13
|
+
z_k ← z_k − w_k / (1 − w_k · Σ_{j≠k} 1/(z_k − z_j))
|
|
14
|
+
|
|
15
|
+
with w_k = p(z_k) / p'(z_k). Initial points are placed on a circle of radius
|
|
16
|
+
= Cauchy bound, with a fixed phase offset so an initial guess never lands
|
|
17
|
+
exactly on a real root (which would make the pairwise sum singular at step
|
|
18
|
+
zero). Convergence is quadratic once close.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const MAX_SUPPORTED_DEGREE = 64;
|
|
22
|
+
|
|
23
|
+
const ABERTH_MAX_ITERATIONS = 80;
|
|
24
|
+
const ABERTH_CONVERGENCE_TOLERANCE = 1e-14;
|
|
25
|
+
|
|
26
|
+
const _DERIV = new Float64Array(MAX_SUPPORTED_DEGREE);
|
|
27
|
+
const _P_EVAL = new Float64Array(2);
|
|
28
|
+
const _DP_EVAL = new Float64Array(2);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Horner evaluation of polynomial p(z) at a complex z = (zr, zi).
|
|
32
|
+
* Writes [p(z).re, p(z).im] into `out`.
|
|
33
|
+
*/
|
|
34
|
+
function poly_eval_complex(coeffs, degree, zr, zi, out) {
|
|
35
|
+
let pr = coeffs[degree];
|
|
36
|
+
let pi = 0;
|
|
37
|
+
|
|
38
|
+
for (let i = degree - 1; i >= 0; i--) {
|
|
39
|
+
const new_pr = pr * zr - pi * zi + coeffs[i];
|
|
40
|
+
const new_pi = pr * zi + pi * zr;
|
|
41
|
+
pr = new_pr;
|
|
42
|
+
pi = new_pi;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
out[0] = pr;
|
|
46
|
+
out[1] = pi;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Cauchy bound: every root z of `coeffs` satisfies |z| ≤ this value.
|
|
51
|
+
*/
|
|
52
|
+
function cauchy_root_magnitude_bound(coeffs, degree) {
|
|
53
|
+
const lead = Math.abs(coeffs[degree]);
|
|
54
|
+
let m = 0;
|
|
55
|
+
for (let i = 0; i < degree; i++) {
|
|
56
|
+
const a = Math.abs(coeffs[i]);
|
|
57
|
+
if (a > m) m = a;
|
|
58
|
+
}
|
|
59
|
+
return 1 + m / lead;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Find all complex roots of a univariate polynomial via Aberth–Ehrlich.
|
|
64
|
+
*
|
|
65
|
+
* The polynomial is given in ascending-power coefficient form:
|
|
66
|
+
* p(x) = coeffs[0] + coeffs[1]·x + … + coeffs[degree]·x^degree
|
|
67
|
+
* The leading coefficient `coeffs[degree]` must be nonzero.
|
|
68
|
+
*
|
|
69
|
+
* Exactly `degree` complex numbers are written into `roots_re`/`roots_im` at
|
|
70
|
+
* index `offset`, `offset + 1`, …, `offset + degree - 1`. The order they
|
|
71
|
+
* appear in is not specified.
|
|
72
|
+
*
|
|
73
|
+
* @param {Float64Array|number[]} coeffs ascending-power, length ≥ degree + 1
|
|
74
|
+
* @param {number} degree polynomial degree, ≥ 1, ≤ 64
|
|
75
|
+
* @param {Float64Array|number[]} roots_re real parts, length ≥ offset + degree
|
|
76
|
+
* @param {Float64Array|number[]} roots_im imaginary parts, length ≥ offset + degree
|
|
77
|
+
* @param {number} offset
|
|
78
|
+
*/
|
|
79
|
+
export function polynomial_complex_roots_aberth_ehrlich(
|
|
80
|
+
coeffs, degree,
|
|
81
|
+
roots_re, roots_im, offset
|
|
82
|
+
) {
|
|
83
|
+
assert.greaterThanOrEqual(degree, 1, 'degree');
|
|
84
|
+
assert.greaterThanOrEqual(MAX_SUPPORTED_DEGREE, degree, 'degree exceeds MAX_SUPPORTED_DEGREE');
|
|
85
|
+
assert.isNonNegativeInteger(offset, 'offset');
|
|
86
|
+
|
|
87
|
+
// derivative: _DERIV[i] = (i + 1) * coeffs[i + 1], i = 0 .. degree - 1
|
|
88
|
+
for (let i = 0; i < degree; i++) {
|
|
89
|
+
_DERIV[i] = (i + 1) * coeffs[i + 1];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const radius = cauchy_root_magnitude_bound(coeffs, degree);
|
|
93
|
+
|
|
94
|
+
// Initial points around a circle, with a small phase offset to avoid
|
|
95
|
+
// landing exactly on a real root at iteration zero.
|
|
96
|
+
const phase_offset = 0.5;
|
|
97
|
+
const two_pi_over_n = (2 * Math.PI) / degree;
|
|
98
|
+
for (let k = 0; k < degree; k++) {
|
|
99
|
+
const angle = k * two_pi_over_n + phase_offset;
|
|
100
|
+
roots_re[offset + k] = radius * Math.cos(angle);
|
|
101
|
+
roots_im[offset + k] = radius * Math.sin(angle);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (let iter = 0; iter < ABERTH_MAX_ITERATIONS; iter++) {
|
|
105
|
+
let max_correction_sq = 0;
|
|
106
|
+
|
|
107
|
+
for (let k = 0; k < degree; k++) {
|
|
108
|
+
const zr = roots_re[offset + k];
|
|
109
|
+
const zi = roots_im[offset + k];
|
|
110
|
+
|
|
111
|
+
poly_eval_complex(coeffs, degree, zr, zi, _P_EVAL);
|
|
112
|
+
const pr = _P_EVAL[0];
|
|
113
|
+
const pi = _P_EVAL[1];
|
|
114
|
+
|
|
115
|
+
poly_eval_complex(_DERIV, degree - 1, zr, zi, _DP_EVAL);
|
|
116
|
+
const dpr = _DP_EVAL[0];
|
|
117
|
+
const dpi = _DP_EVAL[1];
|
|
118
|
+
|
|
119
|
+
// w = p / p'
|
|
120
|
+
const dp_norm_sq = dpr * dpr + dpi * dpi;
|
|
121
|
+
if (dp_norm_sq === 0) continue;
|
|
122
|
+
const inv_dp_sq = 1 / dp_norm_sq;
|
|
123
|
+
const wr = (pr * dpr + pi * dpi) * inv_dp_sq;
|
|
124
|
+
const wi = (pi * dpr - pr * dpi) * inv_dp_sq;
|
|
125
|
+
|
|
126
|
+
// S = Σ_{j≠k} 1/(z_k − z_j) in complex
|
|
127
|
+
let sr = 0, si = 0;
|
|
128
|
+
for (let j = 0; j < degree; j++) {
|
|
129
|
+
if (j === k) continue;
|
|
130
|
+
const dr = zr - roots_re[offset + j];
|
|
131
|
+
const di = zi - roots_im[offset + j];
|
|
132
|
+
const denom_sq = dr * dr + di * di;
|
|
133
|
+
if (denom_sq === 0) continue;
|
|
134
|
+
const inv_d_sq = 1 / denom_sq;
|
|
135
|
+
sr += dr * inv_d_sq;
|
|
136
|
+
si += -di * inv_d_sq;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// correction = w / (1 − w·S)
|
|
140
|
+
const ws_r = wr * sr - wi * si;
|
|
141
|
+
const ws_i = wr * si + wi * sr;
|
|
142
|
+
const denom_r = 1 - ws_r;
|
|
143
|
+
const denom_i = -ws_i;
|
|
144
|
+
const denom_sq2 = denom_r * denom_r + denom_i * denom_i;
|
|
145
|
+
if (denom_sq2 === 0) continue;
|
|
146
|
+
const inv_denom_sq2 = 1 / denom_sq2;
|
|
147
|
+
const corr_r = (wr * denom_r + wi * denom_i) * inv_denom_sq2;
|
|
148
|
+
const corr_i = (wi * denom_r - wr * denom_i) * inv_denom_sq2;
|
|
149
|
+
|
|
150
|
+
roots_re[offset + k] = zr - corr_r;
|
|
151
|
+
roots_im[offset + k] = zi - corr_i;
|
|
152
|
+
|
|
153
|
+
const corr_sq = corr_r * corr_r + corr_i * corr_i;
|
|
154
|
+
if (corr_sq > max_correction_sq) max_correction_sq = corr_sq;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (max_correction_sq < ABERTH_CONVERGENCE_TOLERANCE * ABERTH_CONVERGENCE_TOLERANCE) {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|