Performance tweaking

This commit is contained in:
Pascal Serrarens 2026-01-07 15:30:05 +01:00
parent 6341d827e9
commit 5dbb5654a1
5 changed files with 74 additions and 184 deletions

View File

@ -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<Spherical> vectors) {
// float sumSinPhiCosTheta = 0.0f;
// float sumSinPhiSinTheta = 0.0f;
// float sumCosPhi = 0.0f;
// int n = vectors.Count;
public static Spherical Sum(List<Spherical> 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<Spherical> 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<Spherical> 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);
}
}
}

View File

@ -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<Spherical> { 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<Spherical> { 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<Spherical> { 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
//#endif

View File

@ -75,23 +75,29 @@ public class Neuroid : Nucleus {
}
public override void UpdateState() {
List<Spherical> 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);
}
}

View File

@ -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)

View File

@ -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