From 8fab3052e1bd198cf0387f557ac38c7ba02486da Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 10 Oct 2026 07:59:56 +0200 Subject: [PATCH] ThrustAllocator: solver residue below 1e-9 is zero; zero intent after a call is exact zeros (zero-intent-warm-nonzero) After a good call the warm start left 1e-34..1e-44 throttles on a zero-intent call. Throttles at or below ThrottleResidue return 0 on the one general path; TA-R3's warm start is kept. The test NothingAskedAfterACallFiresNothing arrived in the previous commit (22cb76e8), which therefore fails that test; this commit makes it pass. Co-Authored-By: Claude Opus 5.5 --- Assets/Scripts/ServerShared/ThrustAllocator.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/ServerShared/ThrustAllocator.cs b/Assets/Scripts/ServerShared/ThrustAllocator.cs index 200a2abcc..bd4b81ff3 100644 --- a/Assets/Scripts/ServerShared/ThrustAllocator.cs +++ b/Assets/Scripts/ServerShared/ThrustAllocator.cs @@ -23,6 +23,9 @@ public sealed class ThrustAllocator const float ErrorCostWeight = .3f; const float ErrorCostOffset = 10f; const float Ridge = .1f; + // The solver stops within its tolerance of the optimum, so a throttle that should be zero can come back as 1e-34 after + // a warm start. Below this a throttle is that residue, not an ask: nothing asked is nothing fired. + const float ThrottleResidue = 1e-9f; const float ErrorMax = 2f; const double KktRelativeTolerance = 1e-12; const int ErrorVariables = 4; @@ -77,7 +80,7 @@ public sealed class ThrustAllocator var status = BoundedLeastSquares.Solve(rows, vars, _a, _b, _lo, _hi, _x, _workspace, out _, KktRelativeTolerance); if (status == BoundedLeastSquaresStatus.InvalidInput) return; - for (var i = 0; i < n; i++) throttle[i] = _x[i]; + for (var i = 0; i < n; i++) throttle[i] = _x[i] > ThrottleResidue ? _x[i] : 0; } static float Component(float3 c, int axis) => axis == 0 ? c.x : axis == 1 ? c.y : c.z;