diff --git a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs index e1e3ab6..db829dc 100644 --- a/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs +++ b/Assets/NanoBrain/LinearAlgebra/src/Spherical.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; + #if UNITY_5_3_OR_NEWER using Vector3 = UnityEngine.Vector3; #endif @@ -137,6 +139,19 @@ namespace LinearAlgebra { return r; } + public static Spherical operator *(Spherical v, float d) { + Spherical r = new(v.distance * d, v.direction); + return r; + } + + public static bool operator ==(Spherical v1, Spherical v2) { + return (v1.distance == v2.distance && v1.direction == v2.direction); + } + + public static bool operator !=(Spherical v1, Spherical v2) { + return (v1.distance != v2.distance || v1.direction != v2.direction); + } + public static float Distance(Spherical v1, Spherical v2) { // Convert degrees to radians float thetaARadians = v1.direction.horizontal.inRadians; @@ -162,5 +177,37 @@ namespace LinearAlgebra { return distance; } + + public static Spherical Average(List vectors) { + float sumSinPhiCosTheta = 0.0f; + float sumSinPhiSinTheta = 0.0f; + float sumCosPhi = 0.0f; + + int n = vectors.Count; + + // 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); + } + + // 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)); + } } } \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 6e192ec..301ce03 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine; using LinearAlgebra; @@ -73,7 +74,7 @@ public class Neuroid : Nucleus { UpdateState(); } - public virtual void UpdateState() { + public override void UpdateState() { Vector3 resultVector = Vector3.zero; foreach (Synapse synapse in this.synapses) { Nucleus synapseNucleus = synapse.nucleus; @@ -93,18 +94,23 @@ public class Neuroid : Nucleus { resultVector /= this.synapses.Count; Spherical result = Spherical.FromVector3(resultVector); - float d = Spherical.Distance(result, this.outputValue); - if (d < 0.1f) { - //Debug.Log($"insignificant update: {d}"); - return; - } - this.outputValue = result; + // List vectors = new(); + // foreach (Synapse synapse in this.synapses) { + // if (synapse.nucleus.isSleeping) + // continue; + + // vectors.Add(synapse.nucleus.outputValue); + // } + // Spherical result2 = Spherical.Average(vectors); + // if (average == false) + // result2 *= vectors.Count; - foreach (Receiver receiver in this.receivers) { - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); - } + // if (result2 != result) + // Debug.Log($"update error {result2} != {result}"); + + UpdateResult(result); + } } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index dcf1b5b..94e2e64 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -151,6 +151,20 @@ public class Nucleus { synapses.Add(newSynapse); } + 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; + } + + this.outputValue = result; + foreach (Receiver receiver in this.receivers) + receiver.nucleus.UpdateState(); + + } } [System.Serializable] diff --git a/Assets/NanoBrain/Perceptoid.cs b/Assets/NanoBrain/Perceptoid.cs index d46f9dc..4f5b5a9 100644 --- a/Assets/NanoBrain/Perceptoid.cs +++ b/Assets/NanoBrain/Perceptoid.cs @@ -74,19 +74,9 @@ public class Perceptoid : Neuroid { this.receivers = new(); } - public void UpdateState(int thingId, Spherical receptorValue) { - this.thingId = thingId; - Spherical result = receptorValue; - - 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) - if (receiver.nucleus is Neuroid neuroid) - neuroid.SetInput(this); + public override void UpdateState() { + Spherical result = this.receptor.localPosition; + UpdateResult(result); } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 45f3697..47e215f 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -87,6 +87,7 @@ public class Receptor { return; } // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - selectedPerceptoid.UpdateState(thingId, this.localPosition); + selectedPerceptoid.thingId = thingId; + selectedPerceptoid.UpdateState(); } } \ No newline at end of file