diff --git a/Cluster.cs b/Cluster.cs index d5cd988..e581690 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -15,41 +15,45 @@ public class Cluster : INucleus { set => _name = value; } - public ClusterPrefab storedPrefab; + #region Init + + public Cluster(ClusterPrefab prefab, Cluster parent) { + this.prefab = prefab; + this.name = prefab.name; - public Cluster(Cluster parent, ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; this.parent = parent; this.parent?.nuclei.Add(this); ClonePrefab(); + this.sortedNuclei = TopologicalSort(this.nuclei); } - public Cluster(ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; - this.name = realPrefab.name; - this.cluster = null; - if (this.cluster != null) - this.cluster.nuclei.Add(this); - - ClonePrefab(); - } - - public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { - this.storedPrefab = realPrefab; - //this.prefab = realPrefab.Clone(); - this.name = realPrefab.name; + public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { + this.prefab = prefab; + this.name = prefab.name; this.cluster = parent; + if (this.cluster != null) this.cluster.nuclei.Add(this); ClonePrefab(); + this.sortedNuclei = TopologicalSort(this.nuclei); } + // public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) { + // this.prefab = realPrefab; + // this.name = realPrefab.name; + // this.cluster = parent; + // if (this.cluster != null) + // this.cluster.nuclei.Add(this); + + // ClonePrefab(); + // } + private void ClonePrefab() { - IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray(); + IReceptor[] nucleiArray = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (IReceptor nucleus in this.storedPrefab.nuclei) + foreach (IReceptor nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); IReceptor[] clonedNuclei = this.nuclei.ToArray(); @@ -83,6 +87,43 @@ public class Cluster : INucleus { } } + // Sort the nuclei in a correct evaluation order + private List TopologicalSort(List nodes) { + Dictionary inDegree = new(); + foreach (IReceptor node in nodes) + inDegree[node] = 0; // Initialize in-degree to zero + + // Calculate in-degrees + foreach (IReceptor node in nodes) { + foreach (INucleus receiver in node.receivers) + inDegree[receiver]++; + } + + Queue queue = new(); + foreach (IReceptor node in nodes) { + if (inDegree[node] == 0) // Nodes with no dependencies + queue.Enqueue(node); + } + + List sortedOrder = new(); + while (queue.Count > 0) { + IReceptor current = queue.Dequeue(); + sortedOrder.Add(current); // Process the node + + foreach (INucleus receiver in current.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } + } + + // Check for cycles in the graph + if (sortedOrder.Count != nodes.Count) + throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + + return sortedOrder; + } + public virtual IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, @@ -99,7 +140,7 @@ public class Cluster : INucleus { } public IReceptor ShallowCloneTo(Cluster parent) { - Cluster clone = new(parent, this.storedPrefab) { + Cluster clone = new(this.prefab, parent) { name = this.name, }; return clone; @@ -113,11 +154,18 @@ public class Cluster : INucleus { return -1; } + #endregion Init + + public ClusterPrefab prefab; + public ClusterPrefab cluster { get; set; } public Cluster parent { get; set; } [SerializeReference] public List nuclei = new(); + // the nuclei sorted using topological sorting + // to ensure that the cluster is computer in the right order + public List sortedNuclei; public List _inputs = null; public virtual List inputs { diff --git a/MemoryCell.cs b/MemoryCell.cs index fe81c1c..1e35ace 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -29,10 +29,6 @@ public class MemoryCell : Neuron { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } result += synapse.weight * synapse.nucleus.outputValue; if (lengthsq(synapse.nucleus.outputValue) != 0) n++; diff --git a/Neuron.cs b/Neuron.cs index d4444b6..92cda57 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -154,7 +154,6 @@ public class Neuron : INucleus { // private bool _isSleeping = false; // public bool isSleeping => _isSleeping; public bool isSleeping => lengthsq(this.outputValue) == 0; - public float lastTime { get; private set; } public void UpdateNuclei() { this.stale++; @@ -292,10 +291,6 @@ public class Neuron : INucleus { //Applying the weight factgors foreach (Synapse synapse in this.synapses) { - if (synapse.nucleus == this) { - float deltaTime = Time.time - this.lastTime; - synapse.weight = deltaTime; - } sum += synapse.weight * synapse.nucleus.outputValue; // Perhaps synapses should be removed when the output value goes to 0.... @@ -340,7 +335,6 @@ public class Neuron : INucleus { Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}"); } - this.lastTime = Time.time; foreach (INucleus receiver in this.receivers) receiver.UpdateState(); diff --git a/VisualEditor/Editor/ClusterInspector.cs b/VisualEditor/Editor/ClusterInspector.cs index a8c2922..8e8d4df 100644 --- a/VisualEditor/Editor/ClusterInspector.cs +++ b/VisualEditor/Editor/ClusterInspector.cs @@ -621,7 +621,7 @@ public class ClusterInspector : Editor { } private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { - Cluster subclusterInstance = new(this.cluster, prefab); + Cluster subclusterInstance = new(prefab, this.cluster); subclusterInstance.AddReceiver(nucleus); // This does not work somehow // this.currentNucleus = subclusterInstance; @@ -630,9 +630,9 @@ public class ClusterInspector : Editor { private void EditCluster(Cluster subCluster) { // May be used with storedPrefab... - Selection.activeObject = subCluster.storedPrefab; - EditorGUIUtility.PingObject(subCluster.storedPrefab); - var editor = Editor.CreateEditor(subCluster.storedPrefab); + Selection.activeObject = subCluster.prefab; + EditorGUIUtility.PingObject(subCluster.prefab); + var editor = Editor.CreateEditor(subCluster.prefab); } // Connect to another nucleus in the same cluster diff --git a/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/VisualEditor/Editor/NanoBrainComponent_Editor.cs index 8b15fe6..4d4b54b 100644 --- a/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor { }); if (brain != null && board != null) - board.SetGraph(component.gameObject, brain.storedPrefab, brain.output, inspectorContainer); + board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); // else // Debug.LogWarning(" No brain!");