From 5dbb5654a147af70e81fdd008d93e9cf0034173d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 7 Jan 2026 15:30:05 +0100 Subject: [PATCH] Performance tweaking --- .../NanoBrain/LinearAlgebra/src/Spherical.cs | 195 +++--------------- .../LinearAlgebra/test/SphericalTest.cs | 20 +- Assets/NanoBrain/Neuroid.cs | 22 +- Assets/NanoBrain/Nucleus.cs | 10 +- ProjectSettings/ProjectSettings.asset | 11 +- 5 files changed, 74 insertions(+), 184 deletions(-) diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index 2d6b6ed..aee6a64 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -68,32 +68,11 @@ namespace LinearAlgebra { #if UNITY_5_3_OR_NEWER public static Spherical FromVector3(Vector3 v) { float distance = v.magnitude; - // if (distance == 0.0f) - // return Spherical.zero; - // else { - // float verticalAngle = (float)(Math.PI / 2 - Math.Acos(v.y / distance)) * AngleFloat.Rad2Deg; - // float horizontalAngle = (float)Math.Atan2(v.x, v.z) * AngleFloat.Rad2Deg; - // return Degrees(distance, horizontalAngle, verticalAngle); - // } - Direction direction = Direction.FromVector3(v.normalized); + Direction direction = Direction.FromVector3(v / distance); return new Spherical(distance, direction); } public readonly Vector3 ToVector3() { - // float verticalRad = (AngleFloat.deg90 - this.direction.vertical).inRadians; - // float horizontalRad = this.direction.horizontal.inRadians; - // float cosVertical = (float)Math.Cos(verticalRad); - // float sinVertical = (float)Math.Sin(verticalRad); - // float cosHorizontal = (float)Math.Cos(horizontalRad); - // float sinHorizontal = (float)Math.Sin(horizontalRad); - - // float x = this.distance * sinVertical * sinHorizontal; - // float y = this.distance * cosVertical; - // float z = this.distance * sinVertical * cosHorizontal; - - // Vector3 v = new(x, y, z); - // return v; - Vector3 v = this.direction.ToVector3(); v *= this.distance; return v; @@ -247,150 +226,44 @@ namespace LinearAlgebra { return Spherical.Radians(rAvg, azAvgRad, elAvgRad); } - /* - public static Spherical Average(List vectors) { - // float sumSinPhiCosTheta = 0.0f; - // float sumSinPhiSinTheta = 0.0f; - // float sumCosPhi = 0.0f; - // int n = vectors.Count; + public static Spherical Sum(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - // // Step 1: Accumulate sine and cosine components - // foreach(Spherical v in vectors) { - // float sinHorizontal = AngleFloat.Sin(v.direction.horizontal); - // sumSinPhiCosTheta += v.distance * sinHorizontal * AngleFloat.Cos(v.direction.vertical); - // sumSinPhiSinTheta += v.distance * sinHorizontal * AngleFloat.Sin(v.direction.vertical); - // sumCosPhi += v.distance * AngleFloat.Cos(v.direction.horizontal); - // } +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + foreach (Spherical v in vectors) + sum += v.ToVector3(); - // // Step 2: Calculate average components - // float avgSinPhiCosTheta = sumSinPhiCosTheta / n; - // float avgSinPhiSinTheta = sumSinPhiSinTheta / n; - // float avgCosPhi = sumCosPhi / n; - - // // Step 3: Calculate the magnitude of the average vector - // float rAvg = MathF.Sqrt(avgSinPhiCosTheta * avgSinPhiCosTheta + - // avgSinPhiSinTheta * avgSinPhiSinTheta + - // avgCosPhi * avgCosPhi); - - // // Step 4: Calculate average angles - // AngleFloat horizontalAvg = AngleFloat.Acos(avgCosPhi / rAvg); // Handle rAvg != 0 case - // AngleFloat verticalAvg = AngleFloat.Atan2(avgSinPhiSinTheta, avgSinPhiCosTheta); - - // return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); - - if (vectors == null || vectors.Count == 0) - throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); - - float sumX = 0f, sumY = 0f, sumZ = 0f; - int n = vectors.Count; - - foreach (var v in vectors) { - // AngleFloat -> radians; assume AngleFloat provides Radians property - float theta = v.direction.horizontal.inRadians; // azimuth - float phi = v.direction.vertical.inRadians; // elevation - - float cosPhi = MathF.Cos(phi); - float sinPhi = MathF.Sin(phi); - float cosTheta = MathF.Cos(theta); - float sinTheta = MathF.Sin(theta); - - float x = v.distance * cosPhi * cosTheta; - float y = v.distance * cosPhi * sinTheta; - float z = v.distance * sinPhi; - - sumX += x; - sumY += y; - sumZ += z; - } - - float avgX = sumX / n; - float avgY = sumY / n; - float avgZ = sumZ / n; - - float rAvg = MathF.Sqrt(avgX * avgX + avgY * avgY + avgZ * avgZ); - - if (rAvg == 0f) { - return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); - } - - // elevation = asin(z / r) - AngleFloat verticalAvg = AngleFloat.Asin(avgZ / rAvg); // -90..90 - // azimuth = atan2(y, x) -> -pi..pi - AngleFloat horizontalAvg = AngleFloat.Atan2(avgY, avgX); // -180..180 - - return new Spherical(rAvg, new Direction(horizontalAvg, verticalAvg)); - } - */ - - - public static Spherical Average(IEnumerable vectors) { - const float EPS = 1e-6f; - if (vectors == null) throw new ArgumentNullException(nameof(vectors)); - - float sumRx = 0f, sumRy = 0f, sumRz = 0f; - float sumDistances = 0f; - int count = 0; - - bool firstSet = false; - float firstAz = 0f, firstEl = 0f; - bool allSameDirection = true; - - foreach (var v in vectors) { - float az = v.direction.horizontal.inRadians; // horizontal (azimuth) - float el = v.direction.vertical.inRadians; // vertical (elevation) - - if (!firstSet) { - firstSet = true; - firstAz = az; - firstEl = el; - } - else { - if (MathF.Abs(MathF.IEEERemainder(az - firstAz, MathF.PI * 2f)) >= EPS || - MathF.Abs(el - firstEl) >= EPS) { - allSameDirection = false; - } - } - - float cosEl = MathF.Cos(el); - float ux = cosEl * MathF.Cos(az); // x - float uy = cosEl * MathF.Sin(az); // y - float uz = MathF.Sin(el); // z - - sumRx += v.distance * ux; - sumRy += v.distance * uy; - sumRz += v.distance * uz; - - sumDistances += v.distance; - count++; - } - - if (count == 0) throw new ArgumentException("Sequence contains no elements", nameof(vectors)); - - // All directions equal -> preserve exact angles, average distance - if (allSameDirection) { - float rAvg = sumDistances / count; - return new Spherical(rAvg, Direction.Radians(firstAz, firstEl)); - } - - // Total vector sum V - float Vx = sumRx; - float Vy = sumRy; - float Vz = sumRz; - float Vmag = MathF.Sqrt(Vx * Vx + Vy * Vy + Vz * Vz); - - if (Vmag < EPS) { - // Directions cancel out -> zero distance, angles arbitrary - return Spherical.Radians(0f, 0f, 0f); - } - - float azAvg = MathF.Atan2(Vy, Vx); - float elAvg = MathF.Asin(Float.Clamp(Vz / Vmag, -1f, 1f)); - float rAvgFinal = Vmag / count; - - return Spherical.Radians(rAvgFinal, azAvg, elAvg); + return FromVector3(sum); } + public static Spherical Average(List vectors) { + if (vectors == null || vectors.Count == 0) + throw new ArgumentException("vectors must contain at least one element", nameof(vectors)); + +#if UNITY_5_3_OR_NEWER + Vector3 sum = Vector3.zero; +#else + Vector3Float sum = Vector3Float.zero; +#endif + int n = 0; + foreach (Spherical v in vectors) { + sum += v.ToVector3(); + n++; + } + var avg = sum / n; + + // if (avg.sqrMagnitude == 0f) + // return new Spherical(0f, new Direction(AngleFloat.Radians(0f), AngleFloat.Radians(0f))); + // else + return FromVector3(avg); + } + } } \ No newline at end of file diff --git a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs b/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs index 48db8d9..b28b9d9 100644 --- a/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs +++ b/Assets/NanoBrain/LinearAlgebra/test/SphericalTest.cs @@ -1,4 +1,4 @@ -#if !UNITY_5_6_OR_NEWER +//#if !UNITY_5_6_OR_NEWER using System; using System.Collections.Generic; using NUnit.Framework; @@ -11,7 +11,11 @@ namespace LinearAlgebra.Test { [Test] public void FromVector3() { +#if UNITY_5_6_OR_NEWER + UnityEngine.Vector3 v = new(0, 0, 1); +#else Vector3Float v = new(0, 0, 1); +#endif Spherical s = Spherical.FromVector3(v); Assert.AreEqual(1.0f, s.distance, "s.distance 0 0 1"); Assert.AreEqual(0.0f, s.direction.horizontal.inDegrees, "s.hor 0 0 1"); @@ -46,7 +50,7 @@ namespace LinearAlgebra.Test { v2 = Spherical.Degrees(1, 0, 90); r = v1 + v2; Assert.AreEqual(Math.Sqrt(2), r.distance, 1.0E-05F, "Addition(1 0 90)"); - Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, "Addition(1 0 90)"); + Assert.AreEqual(45.0f, r.direction.horizontal.inDegrees, 1e-5f, "Addition(1 0 90)"); Assert.AreEqual(45.0f, r.direction.vertical.inDegrees, 1.0E-05F, "Addition(1 0 90)"); } @@ -166,7 +170,7 @@ namespace LinearAlgebra.Test { [Test] public void Average_SingleElement() { Spherical s = Spherical.Radians(1.234f, 0.3f, -0.7f); - Spherical avg = Spherical.Average([s]); + Spherical avg = Spherical.Average(new List { s }); Assert.AreEqual(s.distance, avg.distance, 1e-5f); Assert.AreEqual(s.direction.horizontal.inRadians, avg.direction.horizontal.inRadians, 1e-5f); @@ -178,7 +182,7 @@ namespace LinearAlgebra.Test { // Two opposite vectors: same distance, horizontal opposite (pi apart), same vertical Spherical v1 = Spherical.Radians(1f, 0f, 0f); Spherical v2 = Spherical.Radians(1f, MathF.PI, 0f); - Spherical avg = Spherical.Average([v1, v2]); + Spherical avg = Spherical.Average(new List { v1, v2 }); Assert.AreEqual(0f, avg.distance, 1e-4f); // When distance is zero, angles may be undefined; allow any angle but ensure near-zero magnitude @@ -190,7 +194,7 @@ namespace LinearAlgebra.Test { Direction dir = Direction.Radians(MathF.PI / 3f, MathF.PI / 4f); Spherical a = new(1f, dir); Spherical b = new(3f, dir); - Spherical avg = Spherical.Average([a, b]); + Spherical avg = Spherical.Average(new List { a, b }); // average distance should be (1+3)/2 = 2 Assert.AreEqual(2f, avg.distance, 1e-5f); @@ -248,7 +252,11 @@ namespace LinearAlgebra.Test { Spherical avg = Spherical.Average(dirs); +#if UNITY_5_3_OR_NEWER + UnityEngine.Vector3 r = UnityEngine.Vector3.zero; +#else Vector3Float r = Vector3Float.zero; +#endif foreach (Spherical dir in dirs) { r += dir.ToVector3(); } @@ -260,4 +268,4 @@ namespace LinearAlgebra.Test { } } -#endif \ No newline at end of file +//#endif \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 7196a11..e1f382a 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -75,23 +75,29 @@ public class Neuroid : Nucleus { } public override void UpdateState() { - List sVectors = new(); + Vector3 sum = Vector3.zero; + int n = 0; foreach (Synapse synapse in this.synapses) { if (synapse.nucleus.isSleeping) continue; + Spherical outputValue = synapse.nucleus.outputValue; float weight = synapse.weight; - float activatedValue = curve.Evaluate(synapse.nucleus.outputValue.magnitude); + float activatedValue = curve.Evaluate(outputValue.magnitude); float magnitude = weight * activatedValue; - Spherical sVector = new(magnitude, synapse.nucleus.outputValue.direction); - sVectors.Add(sVector); + Spherical sVector = new(magnitude, outputValue.direction); + + sum += sVector.ToVector3(); + n++; } - Spherical sResult = Spherical.Average(sVectors); - if (average == false) - sResult *= sVectors.Count; + Spherical result; + if (average) + result = Spherical.FromVector3(sum / n); + else + result = Spherical.FromVector3(sum); - UpdateResult(sResult); + UpdateResult(result); } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 94e2e64..d29bdc3 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -154,11 +154,11 @@ public class Nucleus { public virtual void UpdateState() { } public void UpdateResult(Spherical result) { - float d = Spherical.Distance(result, this.outputValue); - if (d < 0.1f) { - //Debug.Log($"insignificant update: {d}"); - return; - } + // float d = Spherical.Distance(result, this.outputValue); + // if (d < 0.1f) { + // //Debug.Log($"insignificant update: {d}"); + // return; + // } this.outputValue = result; foreach (Receiver receiver in this.receivers) diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index eb3e21f..a47eafd 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -176,9 +176,10 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 23 + AndroidMinSdkVersion: 25 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 + AndroidPreferredDataLocation: 1 aotOptions: stripEngineCode: 1 iPhoneStrippingLevel: 0 @@ -193,11 +194,11 @@ PlayerSettings: VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 iOSSimulatorArchitecture: 0 - iOSTargetOSVersionString: 13.0 + iOSTargetOSVersionString: 15.0 tvOSSdkVersion: 0 tvOSSimulatorArchitecture: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 13.0 + tvOSTargetOSVersionString: 15.0 VisionOSSdkVersion: 0 VisionOSTargetOSVersionString: 1.0 uIPrerenderedIcon: 0 @@ -267,6 +268,7 @@ PlayerSettings: useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 2 + AndroidAllowedArchitectures: -1 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: @@ -569,7 +571,7 @@ PlayerSettings: locationUsageDescription: microphoneUsageDescription: bluetoothUsageDescription: - macOSTargetOSVersion: 11.0 + macOSTargetOSVersion: 12.0 switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 @@ -937,3 +939,4 @@ PlayerSettings: androidVulkanAllowFilterList: [] androidVulkanDeviceFilterListAsset: {fileID: 0} d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3