diff --git a/Cluster.cs b/Cluster.cs index 84ff4b2..aaa6429 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -15,11 +15,11 @@ public class Cluster : Nucleus { this.name = prefab.name; this.parent = parent; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); ClonePrefab(); _ = this.inputs; - this.sortedNuclei = TopologicalSort(this.nuclei); + this.sortedNuclei = TopologicalSort(this.clusterNuclei); } public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) { @@ -32,7 +32,7 @@ public class Cluster : Nucleus { ClonePrefab(); _ = this.inputs; - this.sortedNuclei = TopologicalSort(this.nuclei); + this.sortedNuclei = TopologicalSort(this.clusterNuclei); } private void ClonePrefab() { @@ -40,7 +40,7 @@ public class Cluster : Nucleus { // first clone the nuclei without their connections foreach (Nucleus nucleus in this.prefab.nuclei) nucleus.ShallowCloneTo(this); - Nucleus[] clonedNuclei = this.nuclei.ToArray(); + Nucleus[] clonedNuclei = this.clusterNuclei.ToArray(); // Now clone the connections for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { @@ -50,26 +50,27 @@ public class Cluster : Nucleus { continue; // Copy the receivers, which will also create the synapses - foreach (Nucleus receiver in prefabNucleus.receivers) { - int ix = GetNucleusIndex(prefabNuclei, receiver); - if (ix < 0) - continue; + // Clusters do not have receivers... + // foreach (Nucleus receiver in prefabNucleus.receivers) { + // int ix = GetNucleusIndex(prefabNuclei, receiver); + // if (ix < 0) + // continue; - if (clonedNuclei[ix] is not Nucleus clonedReceiver) - continue; + // if (clonedNuclei[ix] is not Nucleus clonedReceiver) + // continue; - // Find the synapse for the weight - float weight = 1; - foreach (Synapse synapse in receiver.synapses) { - // Find the weight for this synapse - if (synapse.nucleus == prefabNucleus) { - weight = synapse.weight; - break; - } - } + // // Find the synapse for the weight + // float weight = 1; + // foreach (Synapse synapse in receiver.synapses) { + // // Find the weight for this synapse + // if (synapse.nucleus == prefabNucleus) { + // weight = synapse.weight; + // break; + // } + // } - clonedReceptor.AddReceiver(clonedReceiver, weight); - } + // clonedReceptor.AddReceiver(clonedReceiver, weight); + // } } // Copy nucleus arrays @@ -116,8 +117,10 @@ public class Cluster : Nucleus { // Calculate in-degrees foreach (Nucleus node in nodes) { - foreach (Nucleus receiver in node.receivers) - inDegree[receiver]++; + if (node is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) + inDegree[receiver]++; + } } Queue queue = new(); @@ -132,10 +135,12 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } @@ -153,9 +158,9 @@ public class Cluster : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; } @@ -181,7 +186,7 @@ public class Cluster : Nucleus { [SerializeReference] - public List nuclei = new(); + public List clusterNuclei = new(); // the nuclei sorted using topological sorting // to ensure that the cluster is computer in the right order public List sortedNuclei; @@ -192,7 +197,7 @@ public class Cluster : Nucleus { get { if (this._inputs == null) { this._inputs = new(); - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { // inputs have no synapses if (nucleus.synapses.Count == 0) this._inputs.Add(nucleus); @@ -215,7 +220,7 @@ public class Cluster : Nucleus { HashSet visited = new HashSet(); // Initialize in-degrees and mark all nodes as unvisited - foreach (Nucleus node in this.nuclei) { + foreach (Nucleus node in this.clusterNuclei) { inDegree[node] = 0; } @@ -226,12 +231,14 @@ public class Cluster : Nucleus { while (queue.Count > 0) { Nucleus current = queue.Dequeue(); - foreach (Nucleus receiver in current.receivers) { - if (!visited.Contains(receiver)) { - visited.Add(receiver); - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (!visited.Contains(receiver)) { + visited.Add(receiver); + queue.Enqueue(receiver); + } + inDegree[receiver]++; } - inDegree[receiver]++; } } @@ -248,11 +255,13 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - if (visited.Contains(receiver)) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (visited.Contains(receiver)) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } } @@ -266,13 +275,15 @@ public class Cluster : Nucleus { private List TopologicalSort3(Nucleus startNode) { Dictionary inDegree = new(); - foreach (Nucleus node in this.nuclei) + foreach (Nucleus node in this.clusterNuclei) inDegree[node] = 0; // Initialize in-degree to zero // Calculate in-degrees - foreach (Nucleus node in this.nuclei) { - foreach (Nucleus receiver in node.receivers) - inDegree[receiver]++; + foreach (Nucleus node in this.clusterNuclei) { + if (node is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) + inDegree[receiver]++; + } } Queue queue = new(); @@ -283,10 +294,12 @@ public class Cluster : Nucleus { Nucleus current = queue.Dequeue(); sortedOrder.Add(current); // Process the node - foreach (Nucleus receiver in current.receivers) { - inDegree[receiver]--; - if (inDegree[receiver] == 0) // If all dependencies resolved - queue.Enqueue(receiver); + if (current is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + inDegree[receiver]--; + if (inDegree[receiver] == 0) // If all dependencies resolved + queue.Enqueue(receiver); + } } } @@ -298,22 +311,21 @@ public class Cluster : Nucleus { return sortedOrder; } - public virtual Nucleus output {//=> this.nuclei[0] as Nucleus; + public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus; get { - if (this.nuclei.Count > 0) - return this.nuclei[0]; + if (this.clusterNuclei.Count > 0) + return this.clusterNuclei[0] as Neuron; return null; } } - public List _outputs = null; - public List outputs { + private List _outputs = null; + public List outputs { get { if (this._outputs == null) { this._outputs = new(); - foreach (Nucleus nucleus in this.nuclei) { - // outputs have not receivers - if (nucleus.receivers.Count == 0) - this._outputs.Add(nucleus); + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is Neuron neuron) // && neuron.receivers.Count == 0) + this._outputs.Add(neuron); } } return this._outputs; @@ -321,7 +333,7 @@ public class Cluster : Nucleus { } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { - foreach (Nucleus receptor in this.nuclei) { + foreach (Nucleus receptor in this.clusterNuclei) { if (receptor is Nucleus nucleus) if (nucleus.name == nucleusName) { foundNucleus = nucleus; @@ -333,7 +345,7 @@ public class Cluster : Nucleus { } public Nucleus GetNucleus(string nucleusName) { - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { if (nucleus.name == nucleusName) return nucleus; } @@ -341,7 +353,7 @@ public class Cluster : Nucleus { } public Receptor GetReceptor(string receptorName) { - foreach (Nucleus nucleus in this.nuclei) { + foreach (Nucleus nucleus in this.clusterNuclei) { if (nucleus is Receptor receptor) if (receptor.name == receptorName) return receptor; @@ -349,6 +361,18 @@ public class Cluster : Nucleus { return null; } + #region Receivers + + public virtual List CollectReceivers() { + List receivers = new(); + foreach (Neuron output in this.outputs) { + receivers.AddRange(output.receivers); + } + return receivers; + } + + #endregion Receivers + #region Update public void UpdateFromNucleus(Nucleus startNucleus) { @@ -363,7 +387,7 @@ public class Cluster : Nucleus { Debug.Log($" {nucleus.name} = {nucleus.outputValue}"); } - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); @@ -383,14 +407,14 @@ public class Cluster : Nucleus { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); } public override void UpdateNuclei() { - foreach (Nucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index e58e6c6..d8dd30b 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -38,7 +38,7 @@ public class ClusterPrefab : ScriptableObject { public void RefreshOutputs() { this._outputs = new(); foreach (Nucleus nucleus in this.nuclei) { - if (nucleus.receivers.Count == 0) + if (nucleus is Neuron neuron && neuron.receivers.Count == 0) this._outputs.Add(nucleus); } } @@ -85,15 +85,15 @@ public class ClusterPrefab : ScriptableObject { } nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false); } - if (nucleus.receivers != null) { + if (nucleus is Neuron neuron && neuron.receivers != null) { HashSet visitedReceivers = new(); - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in neuron.receivers) { if (receiver != null && receiver != null) { visitedReceivers.Add(receiver); visitedNuclei.Add(receiver); } } - nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); + neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false); } } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index d6aca1b..e72cdd7 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -5,7 +5,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class ClusterReceptor : Cluster { +public class ClusterReceptor : Cluster, IReceptor { public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) { this.name = name; this.array ??= new NucleusArray(this); @@ -32,9 +32,9 @@ public class ClusterReceptor : Cluster { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; } @@ -48,21 +48,22 @@ public class ClusterReceptor : Cluster { #region Receivers private List _clusterReceivers = null; - public override List receivers { - get { - if (_clusterReceivers == null || _clusterReceivers.Count == 0) { - _clusterReceivers = new(); - foreach (Nucleus output in this.nuclei) { - _clusterReceivers.AddRange(output.receivers); - } - } - return _clusterReceivers; - } - } - public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - this.output.receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this.output, weight); - } + // public override List receivers { + // get { + // if (_clusterReceivers == null || _clusterReceivers.Count == 0) { + // _clusterReceivers = new(); + // foreach (Nucleus output in this.clusterNuclei) { + // _clusterReceivers.AddRange(output.receivers); + // } + // } + // return _clusterReceivers; + // } + // } + // public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) { + // string nucleusName = this. + // this.output.receivers.Add(receivingNucleus); + // receivingNucleus.AddSynapse(this.output, weight); + // } #endregion Receivers @@ -72,7 +73,7 @@ public class ClusterReceptor : Cluster { foreach (Nucleus nucleus in this.sortedNuclei) nucleus.UpdateStateIsolated(); - this.outputValue = this.output.outputValue; + this.outputValue = this.defaultOutput.outputValue; this.stale = 0; UpdateNuclei(); @@ -85,7 +86,7 @@ public class ClusterReceptor : Cluster { this.parent.UpdateFromNucleus(this); } - foreach (Nucleus nucleus in this.nuclei) + foreach (Nucleus nucleus in this.clusterNuclei) nucleus.UpdateNuclei(); } diff --git a/Editor/BrainEditorWindow.cs b/Editor/BrainEditorWindow.cs index aa4e292..11bba19 100644 --- a/Editor/BrainEditorWindow.cs +++ b/Editor/BrainEditorWindow.cs @@ -74,9 +74,11 @@ public class BrainEditorWindow : EditorWindow { int ix = 0; foreach (Nucleus nucleus in prefab.nuclei) { nodes.Add(new DagNode() { id = ix, title = nucleus.name }); - foreach (Nucleus receiver in nucleus.receivers) { - int receiverIx = prefab.GetNucleusIndex(receiver); - edges.Add(new DagEdge() { fromId = ix, toId = receiverIx }); + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + int receiverIx = prefab.GetNucleusIndex(receiver); + edges.Add(new DagEdge() { fromId = ix, toId = receiverIx }); + } } ix++; } @@ -191,9 +193,9 @@ public class BrainEditorWindow : EditorWindow { Handles.DrawSolidDisc(n.position, Vector3.forward, n.radius); if (GetIncomingEdges(n).Count == 0) - DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f/zoom, 12f/zoom, Color.white); + DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f / zoom, 12f / zoom, Color.white); if (GetOutgoingEdges(n).Count == 0) - DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f/zoom, 12f/zoom, Color.white); + DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f / zoom, 12f / zoom, Color.white); Handles.color = Color.white; GUIStyle style = new(EditorStyles.label) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index bafeee7..a099a5d 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -195,8 +195,8 @@ public class ClusterInspector : Editor { return; NeuroidLayer currentLayer = new() { ix = layerIx }; - if (selectedNucleus.receivers != null) { - foreach (Nucleus receiver in selectedNucleus.receivers) { + if (selectedNucleus is Neuron selectedNeuron && selectedNeuron.receivers != null) { + foreach (Nucleus receiver in selectedNeuron.receivers) { Nucleus outputNeuroid = receiver; if (outputNeuroid != null) { AddToLayer(currentLayer, outputNeuroid); @@ -357,12 +357,20 @@ public class ClusterInspector : Editor { } private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) { - int nodeCount = nucleus.receivers.Count(); + List receivers = null; + if (nucleus is Neuron neuron) + receivers = neuron.receivers; + else if (nucleus is Cluster cluster) + receivers = cluster.CollectReceivers(); + else + return; + + int nodeCount = receivers.Count(); //neuron != null ? neuron.receivers.Count() : 1; // Determine the maximum value in this layer // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in receivers) { if (receiver is Neuron neuroid) { float value = length(neuroid.outputValue); if (value > maxValue) @@ -376,7 +384,7 @@ public class ClusterInspector : Editor { int row = 0; List drawnArrays = new(); - foreach (Nucleus receiver in nucleus.receivers) { + foreach (Nucleus receiver in receivers) { if (receiver is Receptor receptor) { if (drawnArrays.Contains(receptor.array)) continue; @@ -409,7 +417,8 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(receptor.array)) continue; drawnArrays.Add(receptor.array); - } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + } + else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.array)) continue; drawnArrays.Add(clusterReceptor.array); @@ -432,7 +441,8 @@ public class ClusterInspector : Editor { if (drawnArrays.Contains(neuron.array)) continue; drawnArrays.Add(neuron.array); - } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { + } + else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { if (drawnArrays.Contains(clusterReceptor.array)) continue; drawnArrays.Add(clusterReceptor.array); @@ -731,56 +741,61 @@ public class ClusterInspector : Editor { if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { - if (synapse.nucleus != null) { - if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) - continue; - } - else { - if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.array; - } + if (synapse.nucleus == null) + continue; - EditorGUILayout.Space(); - - if (Application.isPlaying) { - Vector3 value = synapse.nucleus.outputValue * synapse.weight; - GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); - EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); - } - else { - EditorGUILayout.BeginHorizontal(); - - if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { - GUIStyle labelStyle = new(GUI.skin.label); - float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; - EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); - string[] options = synapse.nucleus.parent.nuclei.Select(n => n.name).ToArray(); - int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); - int newIndex = EditorGUILayout.Popup(selectedIndex, options); - if (newIndex != selectedIndex) { - ChangeSynapse(synapse, synapse.nucleus.parent.nuclei[newIndex]); - } - } - else - EditorGUILayout.LabelField(synapse.nucleus.name); - if (GUILayout.Button("Disconnect")) { - synapse.nucleus.RemoveReceiver(this.currentNucleus); - this.prefab.GarbageCollection(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); - } - - EditorGUI.indentLevel++; - synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); - EditorGUI.indentLevel--; + if (array != null) { + if (array.nuclei.Contains(synapse.nucleus)) + continue; + if (array.nuclei.Contains(synapse.nucleus.parent)) + continue; } + else { + if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) + array = clusterReceptor.array; + else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) + array = receptor2.array; + } + + EditorGUILayout.Space(); + + if (Application.isPlaying) { + Vector3 value = synapse.nucleus.outputValue * synapse.weight; + GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString()); + EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue)); + } + else { + EditorGUILayout.BeginHorizontal(); + + if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) { + GUIStyle labelStyle = new(GUI.skin.label); + float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x; + EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth)); + string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray(); + int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name); + int newIndex = EditorGUILayout.Popup(selectedIndex, options); + if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron) + ChangeSynapse(synapse, newNeuron); + } + else + EditorGUILayout.LabelField(synapse.nucleus.name); + if (GUILayout.Button("Disconnect") && synapse.nucleus is Neuron synapseNeuron) { + synapseNeuron.RemoveReceiver(this.currentNucleus); + this.prefab.GarbageCollection(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + } + + EditorGUI.indentLevel++; + synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); + EditorGUI.indentLevel--; } } } EditorGUILayout.EndFoldoutHeaderGroup(); } + // Activation EditorGUILayout.Space(); @@ -811,7 +826,7 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) - DeleteNeuron(this.currentNucleus); + DeleteNucleus(this.currentNucleus); if (this.currentNucleus is Cluster subCluster) { if (GUILayout.Button("Edit Cluster")) @@ -934,10 +949,10 @@ public class ClusterInspector : Editor { } protected virtual void AddReceptorArrayInput(Nucleus nucleus) { - ReceptorArray newReceptor = new(this.prefab, "New Receptor"); - newReceptor.AddReceiver(nucleus); - this.currentNucleus = newReceptor; - BuildLayers(); + // ReceptorArray newReceptor = new(this.prefab, "New Receptor"); + // newReceptor.AddReceiver(nucleus); + // this.currentNucleus = newReceptor; + // BuildLayers(); } protected virtual void AddClusterReceptorInput(Nucleus nucleus) { @@ -946,12 +961,12 @@ public class ClusterInspector : Editor { private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) { Cluster subclusterInstance = new(prefab, this.prefab); - subclusterInstance.AddReceiver(nucleus); + subclusterInstance.defaultOutput.AddReceiver(nucleus); } private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); - clusterInstance.AddReceiver(nucleus); + clusterInstance.defaultOutput.AddReceiver(nucleus); } private void EditCluster(Cluster subCluster) { @@ -962,7 +977,7 @@ public class ClusterInspector : Editor { } // Connect to another nucleus in the same cluster - protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) { + protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) { if (cluster == null) return false; @@ -980,19 +995,25 @@ public class ClusterInspector : Editor { if (selectedIndex < 0) return false; - Nucleus receptor = nuclei.ElementAt(selectedIndex); - receptor.AddReceiver(this.currentNucleus); + Nucleus nucleus = nuclei.ElementAt(selectedIndex); + if (nucleus is Neuron neuron) + neuron.AddReceiver(this.currentNucleus); + else if (nucleus is Cluster subCluster) + subCluster.defaultOutput.AddReceiver(this.currentNucleus); + return true; } - protected virtual void DeleteNeuron(Nucleus nucleus) { + protected virtual void DeleteNucleus(Nucleus nucleus) { if (nucleus == null) return; - foreach (Nucleus receiver in nucleus.receivers) { - if (receiver != null) { - this.currentNucleus = receiver; - break; + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (receiver != null) { + this.currentNucleus = receiver; + break; + } } } this.prefab.nuclei.Remove(nucleus); @@ -1021,9 +1042,17 @@ public class ClusterInspector : Editor { return true; } - protected virtual void ChangeSynapse(Synapse synapse, Nucleus newNucleus) { - synapse.nucleus.RemoveReceiver(this.currentNucleus); - newNucleus.AddReceiver(this.currentNucleus); + protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { + Neuron synapseNeuron = synapse.nucleus as Neuron; + if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) { + // it is a neuron in a subcluster + synapseNeuron.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } + else { + synapseNeuron.RemoveReceiver(this.currentNucleus); + newNucleus.AddReceiver(this.currentNucleus); + } } protected virtual void DisconnectNucleus(Neuron nucleus) { @@ -1032,10 +1061,10 @@ public class ClusterInspector : Editor { string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray(); int selectedIndex = -1; selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names); - //if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) { if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) { Synapse synapse = this.currentNucleus.synapses[selectedIndex]; - synapse.nucleus.RemoveReceiver(this.currentNucleus); + Neuron synapseNeuron = synapse.nucleus as Neuron; + synapseNeuron.RemoveReceiver(this.currentNucleus); } } diff --git a/Editor/NanoBrain_Editor.cs b/Editor/NanoBrain_Editor.cs index 6c37746..376e9f0 100644 --- a/Editor/NanoBrain_Editor.cs +++ b/Editor/NanoBrain_Editor.cs @@ -36,7 +36,7 @@ public class NanoBrainComponent_Editor : Editor { root.Add(brainField); } - ClusterInspector.CreateInspector(root, brain.prefab, brain.output, component.gameObject); + ClusterInspector.CreateInspector(root, brain.prefab, brain.defaultOutput, component.gameObject); if (Application.isPlaying == false) serializedObject.ApplyModifiedProperties(); diff --git a/IReceptor.cs b/IReceptor.cs new file mode 100644 index 0000000..94d9ae2 --- /dev/null +++ b/IReceptor.cs @@ -0,0 +1,5 @@ +public interface IReceptor { + public NucleusArray array { + get; set; + } +} \ No newline at end of file diff --git a/IReceptor.cs.meta b/IReceptor.cs.meta new file mode 100644 index 0000000..0c0ee6f --- /dev/null +++ b/IReceptor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 73f052292ad16bb53a3c07aa1694c705 \ No newline at end of file diff --git a/NanoBrain.cs b/NanoBrain.cs index 3e3ee21..831b9db 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -18,7 +18,7 @@ public class NanoBrain : MonoBehaviour { } public static void UpdateWeight(Cluster brain, string name, float weight) { - Nucleus root = brain.output; + Nucleus root = brain.defaultOutput; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { if (synapse.weight != weight) { diff --git a/Neuron.cs b/Neuron.cs index 6fa9d4b..f24eaa3 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -12,7 +12,7 @@ public class Neuron : Nucleus { public Neuron(Cluster parent, string name) { this.parent = parent; this.name = name; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); } public Neuron(ClusterPrefab prefab, string name) { this.clusterPrefab = prefab; @@ -25,7 +25,6 @@ public class Neuron : Nucleus { #region Serialization - //public Type type = Type.Neuron; public enum CombinatorType { Sum, Product, @@ -160,11 +159,14 @@ public class Neuron : Nucleus { } } } - foreach (Nucleus receiver in nucleus.receivers) { - if (receiver != null && receiver.synapses != null) - receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + if (nucleus is Neuron neuron) { + foreach (Nucleus receiver in neuron.receivers) { + if (receiver != null && receiver.synapses != null) + receiver.synapses.RemoveAll(s => s.nucleus == nucleus); + } } + if (nucleus.clusterPrefab != null) { nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus); nucleus.clusterPrefab.GarbageCollection(); @@ -259,6 +261,48 @@ public class Neuron : Nucleus { #endregion Activator + #region Receivers + + [SerializeReference] + private List _receivers = new(); + public virtual List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) { + if (this is IReceptor receptor) { + foreach (Nucleus element in receptor.array.nuclei) { + if (element is Neuron neuron) { + neuron._receivers.Add(receiverToAdd); + receiverToAdd.AddSynapse(element, weight); + } + } + } + else { + this._receivers.Add(receiverToAdd); + receiverToAdd.AddSynapse(this, weight); + } + } + + public virtual void RemoveReceiver(Nucleus receiverToRemove) { + if (this is IReceptor receptor) { + foreach (Nucleus element in receptor.array.nuclei) { + if (element is Neuron neuron) { + neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); + receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron); + } + } + } + else { + this._receivers.RemoveAll(receiver => receiver == receiverToRemove); + receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + } + + + #endregion Receivers + public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) { this.stale = 0; this.bias = inputValue; diff --git a/Nucleus.cs b/Nucleus.cs index e659008..3193686 100644 --- a/Nucleus.cs +++ b/Nucleus.cs @@ -17,7 +17,6 @@ public abstract class Nucleus { public virtual float3 outputValue { get { return _outputValue; } set { - //this.stale = 0; _outputValue = value; if (this.isFiring) WhenFiring?.Invoke(); @@ -68,29 +67,13 @@ public abstract class Nucleus { return null; } + public void RemoveSynapse(Nucleus sendingNucleus) { + this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus); + } + #endregion Synapses - #region Receivers - [SerializeReference] - private List _receivers = new(); - public virtual List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } - - public void RemoveReceiver(Nucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } - - - #endregion Receivers #region Update diff --git a/Receptor.cs b/Receptor.cs index 34c511c..7ff4011 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -3,7 +3,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [System.Serializable] -public class Receptor : Neuron { +public class Receptor : Neuron, IReceptor { public Receptor(Cluster parent, string name) : base(parent, name) { } public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { } diff --git a/ReceptorArray.cs b/ReceptorArray.cs index c8441db..2eea9f6 100644 --- a/ReceptorArray.cs +++ b/ReceptorArray.cs @@ -46,7 +46,7 @@ public class ReceptorArray : Nucleus { this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") { receptor = this }; - this.parent?.nuclei.Add(this); + this.parent?.clusterNuclei.Add(this); } public ReceptorArray(ClusterPrefab prefab, string name) { this.clusterPrefab = prefab; @@ -89,9 +89,9 @@ public class ReceptorArray : Nucleus { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); clonedSynapse.weight = synapse.weight; } - foreach (Nucleus receiver in this.receivers) { - clone.AddReceiver(receiver); - } + // foreach (Nucleus receiver in this.receivers) { + // clone.AddReceiver(receiver); + // } return clone; }