From 1e5a19c1ab31ec78b11356f44610009f85353ed8 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 17:32:01 +0100 Subject: [PATCH] Removed the use of INucleus --- Cluster.cs | 94 +++++------ ClusterPrefab.cs | 30 ++-- Editor/ClusterInspector.cs | 74 ++++----- Editor/NeuroidWindow.cs | 302 ----------------------------------- Editor/NeuroidWindow.cs.meta | 2 - INucleus.cs | 18 ++- MemoryCell.cs | 2 +- NanoBrain.cs | 2 +- Neuron.cs | 14 +- Nucleus.cs | 21 ++- NucleusArray.cs | 34 ++-- Selector.cs | 2 +- Synapse.cs | 4 +- 13 files changed, 148 insertions(+), 451 deletions(-) delete mode 100644 Editor/NeuroidWindow.cs delete mode 100644 Editor/NeuroidWindow.cs.meta diff --git a/Cluster.cs b/Cluster.cs index f1a0d74..351176e 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -42,26 +42,26 @@ public class Cluster : Nucleus { } private void ClonePrefab() { - INucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); + Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray(); // first clone the nuclei without their connections - foreach (INucleus nucleus in this.prefab.nuclei) + foreach (Nucleus nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); - INucleus[] clonedNuclei = this.nuclei.ToArray(); + Nucleus[] clonedNuclei = this.nuclei.ToArray(); // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - INucleus receptor = prefabNuclei[nucleusIx]; - INucleus clonedReceptor = clonedNuclei[nucleusIx]; + Nucleus receptor = prefabNuclei[nucleusIx]; + Nucleus clonedReceptor = clonedNuclei[nucleusIx]; if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses - foreach (INucleus receiver in receptor.receivers) { + foreach (Nucleus receiver in receptor.receivers) { int ix = GetNucleusIndex(prefabNuclei, receiver); if (ix < 0) continue; - if (clonedNuclei[ix] is not INucleus clonedReceiver) + if (clonedNuclei[ix] is not Nucleus clonedReceiver) continue; // Find the synapse for the weight @@ -80,21 +80,21 @@ public class Cluster : Nucleus { // Copy nucleus arrays for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - INucleus prefabReceptor = prefabNuclei[nucleusIx]; - if (prefabReceptor is not INucleus prefabNucleus) + Nucleus prefabReceptor = prefabNuclei[nucleusIx]; + if (prefabReceptor is not Nucleus prefabNucleus) continue; if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) continue; - INucleus clonedNucleus = clonedNuclei[nucleusIx] as INucleus; + Nucleus clonedNucleus = clonedNuclei[nucleusIx] as Nucleus; if (prefabNucleus == prefabNucleus.array.nuclei[0]) { // We clone the array only for the first entry NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); int arrayIx = 0; - foreach (INucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { + foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); - INucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; clonedArray.nuclei[arrayIx] = clonedArrayNucleus; arrayIx++; } @@ -103,36 +103,36 @@ public class Cluster : Nucleus { else { // The others will refer to the array created for the first nucleus in the array int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); - INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; + Nucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Nucleus; clonedNucleus.array = clonedFirstNucleus.array; } } } // Sort the nuclei in a correct evaluation order - private List TopologicalSort(List nodes) { - Dictionary inDegree = new(); - foreach (INucleus node in nodes) + private List TopologicalSort(List nodes) { + Dictionary inDegree = new(); + foreach (Nucleus node in nodes) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees - foreach (INucleus node in nodes) { - foreach (INucleus receiver in node.receivers) + foreach (Nucleus node in nodes) { + foreach (Nucleus receiver in node.receivers) inDegree[receiver]++; } - Queue queue = new(); - foreach (INucleus node in nodes) { + Queue queue = new(); + foreach (Nucleus node in nodes) { if (inDegree[node] == 0) // Nodes with no dependencies queue.Enqueue(node); } - List sortedOrder = new(); + List sortedOrder = new(); while (queue.Count > 0) { - INucleus current = queue.Dequeue(); + Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (INucleus receiver in current.receivers) { + foreach (Nucleus receiver in current.receivers) { inDegree[receiver]--; if (inDegree[receiver] == 0) // If all dependencies resolved queue.Enqueue(receiver); @@ -146,7 +146,7 @@ public class Cluster : Nucleus { return sortedOrder; } - public override INucleus Clone() { + public override Nucleus Clone() { //Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.parent, this.name) { array = this.array, @@ -156,20 +156,20 @@ public class Cluster : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.receivers) { + foreach (Nucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; } - public override INucleus ShallowCloneTo(Cluster parent) { + public override Nucleus ShallowCloneTo(Cluster parent) { Cluster clone = new(this.prefab, parent) { name = this.name, }; return clone; } - private int GetNucleusIndex(INucleus[] nucleiArray, INucleus nucleus) { + private int GetNucleusIndex(Nucleus[] nucleiArray, Nucleus nucleus) { for (int i = 0; i < nucleiArray.Length; i++) { if (nucleus == nucleiArray[i]) return i; @@ -185,18 +185,18 @@ public class Cluster : Nucleus { // public Cluster parent { get; set; } [SerializeReference] - public List nuclei = new(); + 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 sortedNuclei; - public List _inputs = null; - public virtual List inputs { + public List _inputs = null; + public virtual List inputs { get { if (this._inputs == null) { this._inputs = new(); - foreach (INucleus receptor in this.nuclei) { - if (receptor is INucleus nucleus) { + foreach (Nucleus receptor in this.nuclei) { + if (receptor is Nucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -207,10 +207,10 @@ public class Cluster : Nucleus { } } - public virtual INucleus output {//=> this.nuclei[0] as INucleus; + public virtual Nucleus output {//=> this.nuclei[0] as Nucleus; get { if (this.nuclei.Count > 0) - return this.nuclei[0] as INucleus; + return this.nuclei[0]; return null; } } @@ -224,7 +224,7 @@ public class Cluster : Nucleus { // } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { - foreach (INucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) { foundNucleus = nucleus; @@ -236,7 +236,7 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (INucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.nuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) return nucleus; @@ -250,7 +250,7 @@ public class Cluster : Nucleus { // private List _synapses = new(); // public List synapses => _synapses; - // public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { + // public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { // Synapse synapse = new(sendingNucleus, weight); // this._synapses.Add(synapse); // return synapse; @@ -266,18 +266,18 @@ public class Cluster : Nucleus { #region Receivers // [SerializeReference] - // private List _receivers = new(); - // public List receivers { + // private List _receivers = new(); + // public List receivers { // get { return _receivers; } // set { _receivers = value; } // } - // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + // public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { // this._receivers.Add(receivingNucleus); // receivingNucleus.AddSynapse(this, weight); // } - // public void RemoveReceiver(INucleus receiverNucleus) { + // public void RemoveReceiver(Nucleus receiverNucleus) { // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); // } @@ -317,7 +317,7 @@ public class Cluster : Nucleus { // //this.inputs[0].UpdateState(sum); // this.inputs[0].UpdateStateIsolated(sum); // foreach (IReceptor receptor in this.sortedNuclei) { - // if (receptor is INucleus nucleus && nucleus != this.inputs[0]) + // if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) // nucleus.UpdateStateIsolated(); // } @@ -341,8 +341,8 @@ public class Cluster : Nucleus { //this.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum); - foreach (INucleus receptor in this.sortedNuclei) { - if (receptor is INucleus nucleus && nucleus != this.inputs[0]) { + foreach (Nucleus receptor in this.sortedNuclei) { + if (receptor is Nucleus nucleus && nucleus != this.inputs[0]) { //if (nucleus.isSleeping == false) nucleus.UpdateStateIsolated(); } @@ -360,7 +360,7 @@ public class Cluster : Nucleus { // // } // this.outputValue = result; - // foreach (INucleus receiver in this.receivers) + // foreach (Nucleus receiver in this.receivers) // receiver.UpdateState(); // } @@ -370,7 +370,7 @@ public class Cluster : Nucleus { _outputValue = Vector3.zero; //foreach (IReceptor nucleus in this.prefab.nuclei) - foreach (INucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 694efaf..5a390e8 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -3,22 +3,22 @@ using UnityEngine; [CreateAssetMenu(menuName = "Passer/Cluster")] public class ClusterPrefab : ScriptableObject { - // The ScriptableObject asset from which the runtime object has been created + public string hello = "hello"; [SerializeReference] - public List nuclei = new(); + public List nuclei = new(); - public virtual INucleus output => this.nuclei[0] as INucleus; + public virtual Nucleus output => this.nuclei[0] as Nucleus; - public List _inputs = null; - public virtual List inputs { + public List _inputs = null; + public virtual List inputs { get { if (this._inputs == null) { this._inputs = new(); - foreach (INucleus receptor in this.nuclei) { - if (receptor is INucleus nucleus) { + foreach (Nucleus receptor in this.nuclei) { + if (receptor is Nucleus nucleus) { // inputs have no incoming synapses yet. if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -33,19 +33,19 @@ public class ClusterPrefab : ScriptableObject { // This is an invariant and should be ensured before the nucleus is used // because output requires it. public void EnsureInitialization() { - nuclei ??= new List(); + nuclei ??= new List(); if (nuclei.Count == 0) new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } public void GarbageCollection() { - HashSet visitedNuclei = new(); + HashSet visitedNuclei = new(); MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); - this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false); + this.nuclei.RemoveAll(nucleus => nucleus is Nucleus n && visitedNuclei.Contains(n) == false); } - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { + public void MarkNuclei(HashSet visitedNuclei, Nucleus nucleus) { if (nucleus is null) return; @@ -55,15 +55,15 @@ public class ClusterPrefab : ScriptableObject { foreach (Synapse synapse in nucleus.synapses) { if (synapse != null && synapse.nucleus != null) { visitedSynapses.Add(synapse); - if (synapse.nucleus is INucleus synapse_nucleus) + if (synapse.nucleus is Nucleus synapse_nucleus) MarkNuclei(visitedNuclei, synapse_nucleus); } } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } if (nucleus.receivers != null) { - HashSet visitedReceivers = new(); - foreach (INucleus receiver in nucleus.receivers) { + HashSet visitedReceivers = new(); + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); @@ -74,7 +74,7 @@ public class ClusterPrefab : ScriptableObject { } public virtual void UpdateNuclei() { - foreach (INucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.nuclei) nucleus.UpdateNuclei(); } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 333f8a5..45950e1 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -68,10 +68,10 @@ public class ClusterInspector : Editor { public class GraphView : VisualElement { ClusterPrefab cluster; SerializedObject serializedBrain; - INucleus currentNucleus; + Nucleus currentNucleus; GameObject gameObject; private List layers = new(); - private readonly Dictionary neuroidPositions = new(); + private readonly Dictionary neuroidPositions = new(); private bool expandArray = false; ClusterWrapper currentWrapper; @@ -108,7 +108,7 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, ClusterPrefab brain, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.cluster = brain; if (Application.isPlaying == false) @@ -136,14 +136,14 @@ public class ClusterInspector : Editor { this.layers = new(); int layerIx = 0; - INucleus selectedNucleus = this.currentNucleus; + Nucleus selectedNucleus = this.currentNucleus; if (selectedNucleus == null) return; NeuroidLayer currentLayer = new() { ix = layerIx }; if (selectedNucleus.receivers != null) { - foreach (INucleus receiver in selectedNucleus.receivers) { - INucleus outputNeuroid = receiver; + foreach (Nucleus receiver in selectedNucleus.receivers) { + Nucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); // Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); @@ -165,7 +165,7 @@ public class ClusterInspector : Editor { if (selectedNucleus.synapses != null) { foreach (Synapse synapse in selectedNucleus.synapses) { - INucleus input = synapse.nucleus; + Nucleus input = synapse.nucleus; AddToLayer(currentLayer, input); // Debug.Log($"layer {layerIx} nucleus {input.name}"); } @@ -175,7 +175,7 @@ public class ClusterInspector : Editor { } } - private void AddToLayer(NeuroidLayer layer, INucleus nucleus) { + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { if (nucleus == null) return; layer.neuroids.Add(nucleus); @@ -210,7 +210,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { float maxValue = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (Nucleus nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -255,13 +255,13 @@ public class ClusterInspector : Editor { } } - private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { + private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.receivers.Count(); // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -275,12 +275,12 @@ public class ClusterInspector : Editor { int row = 0; List drawnArrays = new(); - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (drawnArrays.Contains(receiver.array)) continue; drawnArrays.Add(receiver.array); - INucleus receiverNucleus = receiver; + Nucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; @@ -293,7 +293,7 @@ public class ClusterInspector : Editor { } } - private void DrawSynapses(INucleus nucleus, Vector3 parentPos, float size) { + private void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) { int nodeCount = nucleus.synapses.Count; // Determine the maximum value in this layer @@ -344,7 +344,7 @@ public class ClusterInspector : Editor { } } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) { + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) { Color color; if (nucleus.isSleeping) color = Color.darkRed; @@ -359,7 +359,7 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, position, maxValue, size, color); } - private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size, Color color) { + private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size, Color color) { if (nucleus is MemoryCell memory) { Handles.color = Color.white; Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); @@ -377,7 +377,7 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is INucleus neuron) { + if (nucleus is Nucleus neuron) { if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0) neuron.array = new NucleusArray(neuron); @@ -386,7 +386,7 @@ public class ClusterInspector : Editor { } if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) { int arrayIx = 0; - foreach (INucleus n in neuron.array.nuclei) { + foreach (Nucleus n in neuron.array.nuclei) { if (n == neuron) break; arrayIx++; @@ -426,9 +426,9 @@ public class ClusterInspector : Editor { } } - private void HandleMouseHover(INucleus nucleus, Rect rect) { + private void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; - // if (nucleus is INucleus n) { + // if (nucleus is Nucleus n) { // tooltip = new( // $"{nucleus.name}" + // //$"\nsynapse count {n.synapses.Count}" + @@ -449,14 +449,14 @@ public class ClusterInspector : Editor { GUI.Box(tooltipRect, tooltip); } - private void HandleClicked(INucleus nucleus) { + private void HandleClicked(Nucleus nucleus) { if (nucleus == this.currentNucleus) { - if (nucleus is INucleus n) { + if (nucleus is Nucleus n) { expandArray = !expandArray; return; } } - else if (nucleus is INucleus n) { + else if (nucleus is Nucleus n) { this.currentNucleus = n; BuildLayers(); } @@ -598,7 +598,7 @@ public class ClusterInspector : Editor { } } - protected virtual void AddInput(int selectedInputType, INucleus nucleus) { + protected virtual void AddInput(int selectedInputType, Nucleus nucleus) { switch (selectedInputType) { case 0: // Neuron AddInputNeuron(nucleus); @@ -615,7 +615,7 @@ public class ClusterInspector : Editor { } } - protected virtual void AddInputNeuron(INucleus nucleus) { + protected virtual void AddInputNeuron(Nucleus nucleus) { //Neuron newNeuroid = new(this.cluster, "New neuron"); Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); @@ -623,12 +623,12 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected virtual void DeleteNeuron(INucleus nucleus) { + protected virtual void DeleteNeuron(Nucleus nucleus) { if (nucleus == null) return; if (nucleus.cluster != null) this.currentNucleus = nucleus.cluster.output; - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null) { this.currentNucleus = receiver; break; @@ -638,25 +638,25 @@ public class ClusterInspector : Editor { BuildLayers(); } - protected void AddSelectorInput(INucleus nucleus) { + protected void AddSelectorInput(Nucleus nucleus) { Selector newSelector = new(this.cluster, "New Selector"); newSelector.AddReceiver(nucleus); this.currentNucleus = newSelector; BuildLayers(); } - protected virtual void AddInputMemoryCell(INucleus nucleus) { + protected virtual void AddInputMemoryCell(Nucleus nucleus) { MemoryCell newMemory = new(this.cluster, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); } - protected virtual void AddCluster(INucleus nucleus) { + protected virtual void AddCluster(Nucleus nucleus) { ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { + private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.cluster); subclusterInstance.AddReceiver(nucleus); // This does not work somehow @@ -672,7 +672,7 @@ public class ClusterInspector : Editor { } // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { + protected virtual void ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { if (cluster == null) return; @@ -692,7 +692,7 @@ public class ClusterInspector : Editor { // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // n.AddReceiver(this.currentNucleus); // } - INucleus receptor = cluster.nuclei[selectedIndex]; + Nucleus receptor = cluster.nuclei[selectedIndex]; receptor.AddReceiver(this.currentNucleus); } } @@ -734,17 +734,17 @@ public class ClusterInspector : Editor { public class NeuroidLayer { public int ix = 0; - public List neuroids = new(); + public List neuroids = new(); } public class ClusterWrapper : ScriptableObject { // expose fields that map to GraphNode //public string title; public Vector2 position; - INucleus node; + Nucleus node; ClusterPrefab graph; // needed to write back and mark dirty - public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { + public ClusterWrapper Init(Nucleus node, ClusterPrefab graphAsset) { this.node = node; this.graph = graphAsset; //this.title = " A " + node.name; diff --git a/Editor/NeuroidWindow.cs b/Editor/NeuroidWindow.cs deleted file mode 100644 index 187df35..0000000 --- a/Editor/NeuroidWindow.cs +++ /dev/null @@ -1,302 +0,0 @@ -/* -using UnityEditor; -using UnityEngine; -using System.Linq; -using System.Collections.Generic; - -public class NeuroidLayer { - public int ix = 0; - public List neuroids = new(); -} - -public class GraphEditorWindow : EditorWindow { - private Nucleus currentNucleus; - private List allNeuroids; - private Dictionary neuroidPositions = new(); - - private List layers = new(); - - private void OnEnable() { - EditorApplication.update += EditorUpdate; - Selection.selectionChanged += OnSelectionChange; - SelectNeuron(); - } - - private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { - layer.neuroids.Add(nucleus); - nucleus.layerIx = layer.ix; - // Store its position - Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); - neuroidPositions[nucleus] = neuroidPosition; - - } - - private void BuildLayers() { - // A temporary list to track what's been added to layers - this.layers = new(); - int layerIx = 0; - - Nucleus selectedNucleus = this.currentNucleus; - if (selectedNucleus == null) - return; - NeuroidLayer currentLayer = new() { ix = layerIx }; - - //foreach (Nucleus outputNeuroid in selectedNucleus.receivers) { - foreach (Receiver receiver in selectedNucleus.receivers) { - Nucleus outputNeuroid = receiver.nucleus; - if (outputNeuroid != null) { - AddToLayer(currentLayer, outputNeuroid); - Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); - } - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - currentLayer = new() { ix = layerIx }; - } - - AddToLayer(currentLayer, selectedNucleus); - this.layers.Add(currentLayer); - Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); - - layerIx++; - currentLayer = new() { ix = layerIx }; - - int six = 0; - // foreach (Synapse synapse in selectedNucleus.synapses.Values) { - // Debug.Log($"Synapse {six}"); - // Nucleus input = synapse.neuroid; - //foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { - //foreach ((Nucleus input, float weight) in selectedNucleus.synapses) { - foreach (Synapse synapse in selectedNucleus.synapses) { - Nucleus input = synapse.nucleus; - if (input != null) { - AddToLayer(currentLayer, input); - Debug.Log($"layer {layerIx} nucleus {input.name}"); - } - six++; - } - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - } - } - - private void BuildLayers_old(List neuroids) { - if (neuroids == null) - return; - - // A temporary list to track what's been added to layers - this.layers = new(); - HashSet neuronVisited = new(); - int layerIx = 0; - - // While there are unvisited neuroid - while (neuroids.Any(neuroid => !neuronVisited.Contains(neuroid))) { - // Create the next layer - NeuroidLayer currentLayer = new() { ix = layerIx }; - int neuroidIx = 0; - - foreach (Neuroid neuroid in neuroids) { - // Skip neurons we already processed - if (neuronVisited.Contains(neuroid)) - continue; - - // if (neuroid.IsStale()) { - // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}"); - // neuronVisited.Add(neuroid); - // continue; - // } - - // If the output neuroid is visited - // Note: this does not yet work for multiple outputs yet (see the use of First()) - // if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - // || (neuronVisited.Contains(neuroid.receivers.First()) && neuroid.receivers.First().layerIx == layerIx - 1)) { - if (neuroid.receivers.Count == 0 // make sure the root neuroids are processed directly - || (neuronVisited.Contains(neuroid.receivers.First().nucleus) && neuroid.receivers.First().nucleus.layerIx == layerIx - 1)) { - // Add it to the next layer - currentLayer.neuroids.Add(neuroid); - neuroid.layerIx = layerIx; - // Register it as visited - neuronVisited.Add(neuroid); - // Store its position - Vector2Int neuroidPosition = new(layerIx, neuroidIx); - neuroidPositions[neuroid] = neuroidPosition; - neuroidIx++; - Debug.Log($"Layer {layerIx} neuron {neuroidIx} name {neuroid.name}"); - } - } - - if (currentLayer.neuroids.Count > 0) { - this.layers.Add(currentLayer); - layerIx++; - } - } - } - - private void OnDisable() { - EditorApplication.update -= EditorUpdate; - Selection.selectionChanged -= OnSelectionChange; - } - - private void OnSelectionChange() { - SelectNeuron(); - Repaint(); - } - - private void EditorUpdate() { - if (EditorApplication.isPlaying) - Repaint(); - } - - private void OnGUI() { - GUILayout.Label("Graph Visualizer", EditorStyles.boldLabel); - - DrawGraph(); - } - - private void DrawGraph() { - if (currentNucleus == null) - return; - - foreach (NeuroidLayer layer in layers) - DrawLayer(layer); - } - - private void DrawLayer(NeuroidLayer layer) { - int column = layer.ix * 100; - int nodeCount = layer.neuroids.Count; - float maxValue = 0; - foreach (Nucleus nucleus in layer.neuroids) { - if (nucleus is Neuroid neuroid) { - float value = neuroid.outputValue.magnitude; - if (value > maxValue) - maxValue = value; - } - } - float spacing = 400f / nodeCount; - float margin = 100 + spacing / 2; - foreach (Nucleus layerNucleus in layer.neuroids) { - if (layerNucleus is Neuroid layerNeuroid) { - Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; - Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); - - int i = 0; - float inputSpacing = 400f / layerNeuroid.synapses.Count; - float inputMargin = 100 + inputSpacing / 2; - // foreach (Synapse synapse in layerNeuroid.synapses.Values) { - // if (synapse.neuroid != null) { - // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - - // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; - //foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { - //foreach ((Nucleus neuroid, float weight) in layerNeuroid.synapses) { - foreach (Synapse synapse in layerNeuroid.synapses) { - Nucleus neuroid = synapse.nucleus; - float weight = synapse.weight; - if (neuroid != null) { - if (this.neuroidPositions.ContainsKey(neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; - if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { - Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); - - //float brightness = synapse.weight / 10.0f; - float brightness = weight / 10.0f; - Handles.color = new Color(brightness, brightness, brightness); - Handles.DrawLine(parentPos, pos); - } - } - } - } - - float size = 20; - if (layerNeuroid.isSleeping) - Handles.color = Color.black; - else { - float brightness = layerNeuroid.outputValue.magnitude / maxValue; - Handles.color = new Color(brightness, brightness, brightness); - } - Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis - GUIStyle style = new GUIStyle(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold - }; - Handles.Label(labelPos, layerNeuroid.name, style); - - Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); - Event e = Event.current; - if (e != null && neuronRect.Contains(e.mousePosition)) { - HandleMouseHover(layerNeuroid, neuronRect); - // Process click - if (e.type == EventType.MouseDown && e.button == 0) { - // Consume the event so the scene doesn't also handle it - e.Use(); - HandleDiscClicked(layerNeuroid); - } - } - i++; - } - } - } - - private void HandleMouseHover(Neuroid neuroid, Rect rect) { - GUIContent tooltip; - // if (neuroid is SensoryNeuroid sensoryNeuroid) { - // tooltip = new( - // $"{sensoryNeuroid.name}" + - // $"\nThing {sensoryNeuroid.receptor.thingType}" + - // $"\nValue: {neuroid.outputValue}"); - // } - // else { - tooltip = new( - $"{neuroid.name}" + - $"\nsynapse count {neuroid.synapses.Count}" + - $"\nValue: {neuroid.outputValue}"); - // } - - Vector2 mousePosition = Event.current.mousePosition; - - // Display tooltip with some offset - Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); - Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - - GUI.Box(tooltipRect, tooltip); - } - - private void HandleDiscClicked(Nucleus nucleus) { - this.currentNucleus = nucleus; - BuildLayers(); - } - - // Update node colors based on selected GameObjects - private void SelectNeuron() { - GameObject[] selectedObjects = Selection.gameObjects; - if (selectedObjects.Length == 0) - return; - - GameObject selectedObject = selectedObjects[0]; - Boid boid = selectedObject.GetComponent(); - if (boid == null) - return; - - // Nucleus neuroid = boid.behaviour; - // this.currentNucleus = neuroid; - // if (neuroid == null) - // this.allNeuroids = new(); - // else - // this.allNeuroids = neuroid.brain.neuroids; - - - // Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); - // BuildLayers(); - // Debug.Log($"Layercount = {this.layers.Count}"); - - } - - [MenuItem("Window/Neuroid Visualizer")] - public static void ShowWindow() { - GetWindow("Neuroid Visualizer"); - } -} -*/ \ No newline at end of file diff --git a/Editor/NeuroidWindow.cs.meta b/Editor/NeuroidWindow.cs.meta deleted file mode 100644 index a8a1aa1..0000000 --- a/Editor/NeuroidWindow.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 26e68838038ea5243ae57bc81f4db8a8 \ No newline at end of file diff --git a/INucleus.cs b/INucleus.cs index 4869d33..17199fc 100644 --- a/INucleus.cs +++ b/INucleus.cs @@ -1,3 +1,4 @@ +/* using System.Collections.Generic; using Unity.Mathematics; @@ -11,7 +12,7 @@ public interface INucleus { // Senders public List synapses { get; } - public Synapse AddSynapse(INucleus sender, float weight = 1.0f); + public Synapse AddSynapse(Nucleus sender, float weight = 1.0f); public NucleusArray array { get; set; } @@ -21,8 +22,8 @@ public interface INucleus { // public void UpdateState(); // public void UpdateState(float3 inputValue); - public void UpdateStateIsolated(); - public void UpdateStateIsolated(float3 inputValue); + // public void UpdateStateIsolated(); + // public void UpdateStateIsolated(float3 inputValue); #endregion dynamic state @@ -31,10 +32,10 @@ public interface INucleus { public string name { get; set; } // Receivers - public List receivers { get; set; } + // public List receivers { get; set; } - public void AddReceiver(INucleus receiver, float weight = 1); - public void RemoveReceiver(INucleus receiverNucleus); + // public void AddReceiver(Nucleus receiver, float weight = 1); + // public void RemoveReceiver(Nucleus receiverNucleus); #endregion static @@ -48,10 +49,11 @@ public interface INucleus { #endregion dynamic - public INucleus ShallowCloneTo(Cluster parent); - public INucleus Clone(); + // public INucleus ShallowCloneTo(Cluster parent); + // public INucleus Clone(); } // public interface IReceptor { // } +*/ \ No newline at end of file diff --git a/MemoryCell.cs b/MemoryCell.cs index ab45440..5341220 100644 --- a/MemoryCell.cs +++ b/MemoryCell.cs @@ -13,7 +13,7 @@ public class MemoryCell : Neuron { // this.parent?.nuclei.Add(this); // } - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { MemoryCell clone = new(newParent, this.name) { array = this.array, curve = this.curve, diff --git a/NanoBrain.cs b/NanoBrain.cs index 5fc7643..930c6a1 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -30,7 +30,7 @@ public class NanoBrain : MonoBehaviour { public static void UpdateWeight(Cluster brain, string name, float weight) { - INucleus root = brain.output; + Nucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { if (synapse.weight != weight) { diff --git a/Neuron.cs b/Neuron.cs index ba861a0..41b41e8 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -181,7 +181,7 @@ public class Neuron : Nucleus { #endregion Runtime state // this clone the nucleus without the synapses and receivers - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, curve = this.curve, @@ -192,9 +192,9 @@ public class Neuron : Nucleus { return clone; } - public override INucleus Clone() { - //Neuron clone = new(this.cluster, this.name) { - Neuron clone = new(this.parent, this.name) { + public override Nucleus Clone() { + Neuron clone = new(this.cluster, this.name) { + //Neuron clone = new(this.parent, this.name) { array = this.array, curve = this.curve, curvePreset = this.curvePreset, @@ -208,7 +208,7 @@ public class Neuron : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (INucleus receiver in this.receivers) { + foreach (Nucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; @@ -224,7 +224,7 @@ public class Neuron : Nucleus { // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); // } - public static void Delete(INucleus nucleus) { + public static void Delete(Nucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { if (synapse_nucleus.receivers.Count > 1) { @@ -237,7 +237,7 @@ public class Neuron : Nucleus { } } } - foreach (INucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in nucleus.receivers) { if (receiver != null && receiver.synapses != null) receiver.synapses.RemoveAll(s => s.nucleus == nucleus); } diff --git a/Nucleus.cs b/Nucleus.cs index f3621c0..9847a68 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -4,7 +4,8 @@ using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; -public abstract class Nucleus : INucleus { +[Serializable] +public abstract class Nucleus { [SerializeField] protected string _name; public virtual string name { @@ -31,10 +32,8 @@ public abstract class Nucleus : INucleus { [NonSerialized] public int stale = 1000; - // Cannot clone an abstract nucleus... - public virtual INucleus ShallowCloneTo(Cluster parent) { return null; } - // Cannot clone an abstract nucleus... - public virtual INucleus Clone() { return null; } + public abstract Nucleus ShallowCloneTo(Cluster parent); + public abstract Nucleus Clone(); #region Synapses @@ -42,13 +41,13 @@ public abstract class Nucleus : INucleus { private List _synapses = new(); public List synapses => _synapses; - public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) { + public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) { Synapse synapse = new(sendingNucleus, weight); this.synapses.Add(synapse); return synapse; } - public Synapse GetSynapse(INucleus sender) { + public Synapse GetSynapse(Nucleus sender) { foreach (Synapse synapse in this.synapses) if (synapse.nucleus == sender) return synapse; @@ -60,18 +59,18 @@ public abstract class Nucleus : INucleus { #region Receivers [SerializeReference] - private List _receivers = new(); - public List receivers { + private List _receivers = new(); + public List receivers { get { return _receivers; } set { _receivers = value; } } - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this, weight); } - public void RemoveReceiver(INucleus receiverNucleus) { + public void RemoveReceiver(Nucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } diff --git a/NucleusArray.cs b/NucleusArray.cs index 36d2417..af9bd63 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -5,26 +5,26 @@ using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - private INucleus[] _nuclei; - public INucleus[] nuclei { + private Nucleus[] _nuclei; + public Nucleus[] nuclei { get { return _nuclei; } } public string name; - public NucleusArray(INucleus nucleus) { + public NucleusArray(Nucleus nucleus) { this.name = nucleus.name; - this._nuclei = new INucleus[1]; + this._nuclei = new Nucleus[1]; this._nuclei[0] = nucleus; } public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; - this._nuclei = new INucleus[0]; + this._nuclei = new Nucleus[0]; } public NucleusArray(int size, string name) { this.name = name; - this._nuclei = new INucleus[size]; + this._nuclei = new Nucleus[size]; } @@ -34,12 +34,12 @@ public class NucleusArray { return; } int newLength = this._nuclei.Length + 1; - INucleus[] newArray = new INucleus[newLength]; + Nucleus[] newArray = new Nucleus[newLength]; for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; - if (this._nuclei[0] is INucleus nucleus) - newArray[newLength - 1] = (INucleus)nucleus.Clone(); + if (this._nuclei[0] is Nucleus nucleus) + newArray[newLength - 1] = nucleus.Clone(); this._nuclei = newArray; } @@ -50,25 +50,25 @@ public class NucleusArray { Debug.LogWarning("Perceptoid array cannot be empty"); return; } - INucleus[] newPerceptei = new INucleus[newLength]; + Nucleus[] newPerceptei = new Nucleus[newLength]; for (int i = 0; i < newLength; i++) newPerceptei[i] = this._nuclei[i]; // Delete the last perception - if (this._nuclei[newLength] is INucleus nucleus) + if (this._nuclei[newLength] is Nucleus nucleus) Neuron.Delete(nucleus); //this._nuclei[newLength]); this._nuclei = newPerceptei; } - public Dictionary thingReceivers = new(); + public Dictionary thingReceivers = new(); public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { CleanupReceivers(); - if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) { + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { Debug.Log($"No receiver found for {thingId}"); - foreach (INucleus receptor in this.nuclei) { - if (receptor is not INucleus receiver) + foreach (Nucleus receptor in this.nuclei) { + if (receptor is not Nucleus receiver) continue; if (thingReceivers.ContainsValue(receiver) == false) { @@ -97,7 +97,7 @@ public class NucleusArray { private void CleanupReceivers() { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); - foreach (KeyValuePair item in thingReceivers) { + foreach (KeyValuePair item in thingReceivers) { if (item.Value.isSleeping) { Nucleus n = item.Value as Nucleus; Debug.Log($"{item.Value.name} is sleeping, stale = {n.stale}"); @@ -105,7 +105,7 @@ public class NucleusArray { } } foreach (int thingId in receiversToRemove) { - INucleus selectedReceiver = thingReceivers[thingId]; + Nucleus selectedReceiver = thingReceivers[thingId]; thingReceivers.Remove(thingId); Debug.Log($"Cleanup receiver for {thingId}"); diff --git a/Selector.cs b/Selector.cs index 8cfe378..d4893fe 100644 --- a/Selector.cs +++ b/Selector.cs @@ -7,7 +7,7 @@ public class Selector : Neuron { public Selector(Cluster parent, string name) : base(parent, name) { } public Selector(ClusterPrefab parent, string name) : base(parent, name) {} - public override INucleus ShallowCloneTo(Cluster newParent) { + public override Nucleus ShallowCloneTo(Cluster newParent) { Selector clone = new(newParent, this.name) { array = this.array, curve = this.curve, diff --git a/Synapse.cs b/Synapse.cs index b56f241..53a7a51 100644 --- a/Synapse.cs +++ b/Synapse.cs @@ -4,11 +4,11 @@ using UnityEngine; [Serializable] public class Synapse { [SerializeReference] - public INucleus nucleus; + public Nucleus nucleus; public float weight; - public Synapse(INucleus nucleus, float weight = 1.0f) { + public Synapse(Nucleus nucleus, float weight = 1.0f) { this.nucleus = nucleus; this.weight = weight; }