From 19f929606a3132d6beab77d777abc8f343ec6fd4 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 17 Apr 2026 16:34:21 +0200 Subject: [PATCH] Simplifications --- Editor/ClusterInspector.cs | 170 +++++++------- Editor/ClusterViewer.cs | 293 ++++++++++++++---------- Runtime/Scripts/Core/Cluster.cs | 63 ++--- Runtime/Scripts/Core/ClusterReceptor.cs | 4 +- Runtime/Scripts/Core/IReceptor.cs | 133 +++++------ Runtime/Scripts/Core/Neuron.cs | 50 ++-- Runtime/Scripts/Core/Nucleus.cs | 2 +- Runtime/Scripts/Core/NucleusArray.cs | 4 +- Runtime/Scripts/Core/Receptor.cs | 62 ++--- 9 files changed, 421 insertions(+), 360 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 2b94851..b9f2cdc 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -174,23 +174,24 @@ namespace NanoBrain { memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); } - if (this.currentNucleus is IReceptor receptor1) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); - if (GUILayout.Button("Add")) { - Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - receptor1.AddReceptorElement(this.prefab); - anythingChanged = true; - } - if (GUILayout.Button("Del")) { - Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - receptor1.RemoveReceptorElement(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); + // if (this.currentNucleus is IReceptor receptor1) { + // EditorGUILayout.BeginHorizontal(); + // EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); + // if (GUILayout.Button("Add")) { + // Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + // receptor1.AddReceptorElement(this.prefab); + // anythingChanged = true; + // } + // if (GUILayout.Button("Del")) { + // Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + // receptor1.RemoveReceptorElement(); + // anythingChanged = true; + // } + // EditorGUILayout.EndHorizontal(); - } - else if (this.currentNucleus is Cluster cluster) { + // } + // else + if (this.currentNucleus is Cluster cluster) { EditorGUILayout.BeginHorizontal(); if (cluster.siblingClusters != null && cluster.siblingClusters.Length > 1) EditorGUILayout.IntField("Array size", cluster.siblingClusters.Count()); @@ -211,7 +212,7 @@ namespace NanoBrain { // Synapses - if (this.currentNucleus is not Receptor && this.currentNucleus is not ClusterReceptor) { + if (this.currentNucleus is not Receptor) { //} && this.currentNucleus is not ClusterReceptor) { showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses"); if (showSynapses) { if (this.currentNucleus is Neuron neuron2) { @@ -248,11 +249,11 @@ namespace NanoBrain { continue; } else { - if (synapse.neuron.parent is IReceptor iReceptor) { - array = iReceptor.nucleiArray; - if (iReceptor is Cluster iCluster) - elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron); - } + // if (synapse.neuron.parent is IReceptor iReceptor) { + // array = iReceptor.nucleiArray; + // if (iReceptor is Cluster iCluster) + // elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron); + // } // else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) // array = receptor2.nucleiArray; } @@ -299,14 +300,14 @@ namespace NanoBrain { EditorGUI.indentLevel++; float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight); if (newWeight != synapse.weight) { - if (synapse.neuron.parent is IReceptor receptor) { - Nucleus[] receptorArray = receptor.nucleiArray; - foreach (Synapse s in this.currentNucleus.synapses) { - if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray) - s.weight = newWeight; - } - } - else + // if (synapse.neuron.parent is IReceptor receptor) { + // Nucleus[] receptorArray = receptor.nucleiArray; + // foreach (Synapse s in this.currentNucleus.synapses) { + // if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray) + // s.weight = newWeight; + // } + // } + // else synapse.weight = newWeight; anythingChanged = true; } @@ -340,10 +341,10 @@ namespace NanoBrain { neuron.curvePreset = newPreset; EditorGUILayout.EndHorizontal(); } - if (neuron is Receptor receptor2) { - if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) - receptor2.array = new NucleusArray(neuron); - } + // if (neuron is Receptor receptor2) { + // if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) + // receptor2.array = new NucleusArray(neuron); + // } } EditorGUILayout.Space(); @@ -377,22 +378,22 @@ namespace NanoBrain { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - if (this.currentNucleus is IReceptor receptor) { - foreach (Nucleus nucleus in receptor.nucleiArray) { - if (nucleus is Neuron neuron) { - Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - } - } - else { + // if (this.currentNucleus is IReceptor receptor) { + // foreach (Nucleus nucleus in receptor.nucleiArray) { + // if (nucleus is Neuron neuron) { + // Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue); + // Handles.color = Color.yellow; + // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + // } + // } + // } + // else { if (this.currentNucleus is Neuron currentNeuron) { Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); } - } + // } } } @@ -452,15 +453,15 @@ namespace NanoBrain { BuildLayers(); } - protected virtual void AddClusterReceptorInput(Nucleus nucleus) { - ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster"); - } - private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { - ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); - clusterInstance.defaultOutput.AddReceiver(nucleus); - this.currentNucleus = clusterInstance; - BuildLayers(); - } + // protected virtual void AddClusterReceptorInput(Nucleus nucleus) { + // ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster"); + // } + // private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) { + // ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name); + // clusterInstance.defaultOutput.AddReceiver(nucleus); + // this.currentNucleus = clusterInstance; + // BuildLayers(); + // } private void EditCluster(Cluster subCluster) { // May be used with storedPrefab... @@ -502,9 +503,10 @@ namespace NanoBrain { EditorGUILayout.EndHorizontal(); if (connecting) { Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus); - if (nucleus is IReceptor receptor) - receptor.AddArrayReceiver(this.currentNucleus); - else if (nucleus is Neuron neuron) + // if (nucleus is IReceptor receptor) + // receptor.AddArrayReceiver(this.currentNucleus); + // else + if (nucleus is Neuron neuron) neuron.AddReceiver(this.currentNucleus); else if (nucleus is Cluster subCluster) subCluster.defaultOutput.AddReceiver(this.currentNucleus); @@ -563,37 +565,37 @@ namespace NanoBrain { protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) { Neuron synapseNeuron = synapse.neuron as Neuron; if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) { - if (synapse.neuron.parent is ClusterReceptor receptor) { - // the new nucleus is part of a (cluster) receptor, - // so we have to change all synapses to this nucleus array elements - int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.neuron); - int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); - foreach (Nucleus element in receptor.nucleiArray) { - if (element is not ClusterReceptor clusterReceptor) - continue; - // Get the same neuron as the synapse.nucleus in a different element - // of the ClusterReceptor array - Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx]; - if (oldElementNucleus is not Neuron oldElementNeuron) - continue; - // Get the same neuron as newNucleus in a different element - // of the ClusterReceptor array - Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx]; - if (newElementNucleus is not Neuron newElementNeuron) - continue; + // if (synapse.neuron.parent is ClusterReceptor receptor) { + // // the new nucleus is part of a (cluster) receptor, + // // so we have to change all synapses to this nucleus array elements + // int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.neuron); + // int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); + // foreach (Nucleus element in receptor.nucleiArray) { + // if (element is not ClusterReceptor clusterReceptor) + // continue; + // // Get the same neuron as the synapse.nucleus in a different element + // // of the ClusterReceptor array + // Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx]; + // if (oldElementNucleus is not Neuron oldElementNeuron) + // continue; + // // Get the same neuron as newNucleus in a different element + // // of the ClusterReceptor array + // Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx]; + // if (newElementNucleus is not Neuron newElementNeuron) + // continue; - oldElementNeuron.RemoveReceiver(this.currentNucleus); - newElementNeuron.AddReceiver(this.currentNucleus); - // Now find the synapse which pointed to the old Neuron - // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron); - // synapseForUpdate.nucleus = newElementNeuron; - } - } - else { + // oldElementNeuron.RemoveReceiver(this.currentNucleus); + // newElementNeuron.AddReceiver(this.currentNucleus); + // // Now find the synapse which pointed to the old Neuron + // // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron); + // // synapseForUpdate.nucleus = newElementNeuron; + // } + // } + // else { // it is a neuron in a subcluster synapseNeuron.RemoveReceiver(this.currentNucleus); newNucleus.AddReceiver(this.currentNucleus); - } + // } } else { synapseNeuron.RemoveReceiver(this.currentNucleus); diff --git a/Editor/ClusterViewer.cs b/Editor/ClusterViewer.cs index c2f55c8..2cc0233 100644 --- a/Editor/ClusterViewer.cs +++ b/Editor/ClusterViewer.cs @@ -186,67 +186,67 @@ namespace NanoBrain { // Draw selected Nucleus if (expandArray) { - if (this.currentNucleus is IReceptor receptor1) { - float maxValue = 0; - foreach (Nucleus nucleus in receptor1.nucleiArray) { - if (nucleus is Neuron neuron) { - float value = neuron.outputMagnitude; - if (value > maxValue) - maxValue = value; - } - } + // if (this.currentNucleus is IReceptor receptor1) { + // float maxValue = 0; + // foreach (Nucleus nucleus in receptor1.nucleiArray) { + // if (nucleus is Neuron neuron) { + // float value = neuron.outputMagnitude; + // if (value > maxValue) + // maxValue = value; + // } + // } - float spacing = 400f / receptor1.nucleiArray.Count(); - float margin = 10 + spacing / 2; - float xMin = 150 - size; - float xMax = 150 + size; - float yMin = 10 + margin - size / 2; - float yMax = 400 - margin + size; - Vector3[] verts = new Vector3[4] { - new(xMin, yMin, 0), - new(xMax, yMin, 0), - new(xMax, yMax, 0), - new(xMin, yMax, 0) - }; - Handles.color = Color.black; - Handles.DrawAAConvexPolygon(verts); - int row = 0; - foreach (Nucleus nucleus in receptor1.nucleiArray) { - Vector3 pos = new(150, margin + row * spacing, 0.0f); - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); - DrawNucleus(nucleus, pos, maxValue, size); - row++; - } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new(150, yMax + size + 5, 0); - string receptorName = receptor1.GetName(); - int colonPos = receptorName.IndexOf(":"); - if (colonPos > 0) { - string baseName = receptorName[..colonPos]; - Handles.Label(labelPos, baseName, style); - } - else - Handles.Label(labelPos, receptorName, style); - } - else { - Handles.color = Color.white; - // The selected nucleus highlight ring - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - float maxValue = 1; - if (this.currentNucleus is Neuron neuron) - maxValue = neuron.outputMagnitude; - else if (this.currentNucleus is Cluster cluster) - maxValue = cluster.defaultOutput.outputMagnitude; + // float spacing = 400f / receptor1.nucleiArray.Count(); + // float margin = 10 + spacing / 2; + // float xMin = 150 - size; + // float xMax = 150 + size; + // float yMin = 10 + margin - size / 2; + // float yMax = 400 - margin + size; + // Vector3[] verts = new Vector3[4] { + // new(xMin, yMin, 0), + // new(xMax, yMin, 0), + // new(xMax, yMax, 0), + // new(xMin, yMax, 0) + // }; + // Handles.color = Color.black; + // Handles.DrawAAConvexPolygon(verts); + // int row = 0; + // foreach (Nucleus nucleus in receptor1.nucleiArray) { + // Vector3 pos = new(150, margin + row * spacing, 0.0f); + // Handles.color = Color.white; + // // The selected nucleus highlight ring + // Handles.DrawSolidDisc(pos, Vector3.forward, size + 2); + // DrawNucleus(nucleus, pos, maxValue, size); + // row++; + // } + // GUIStyle style = new(EditorStyles.label) { + // alignment = TextAnchor.UpperCenter, + // normal = { textColor = Color.white }, + // fontStyle = FontStyle.Bold, + // }; + // Vector3 labelPos = new(150, yMax + size + 5, 0); + // string receptorName = receptor1.GetName(); + // int colonPos = receptorName.IndexOf(":"); + // if (colonPos > 0) { + // string baseName = receptorName[..colonPos]; + // Handles.Label(labelPos, baseName, style); + // } + // else + // Handles.Label(labelPos, receptorName, style); + // } + // else { + Handles.color = Color.white; + // The selected nucleus highlight ring + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + float maxValue = 1; + if (this.currentNucleus is Neuron neuron) + maxValue = neuron.outputMagnitude; + else if (this.currentNucleus is Cluster cluster) + maxValue = cluster.defaultOutput.outputMagnitude; - DrawNucleus(this.currentNucleus, position, maxValue, 20); + DrawNucleus(this.currentNucleus, position, maxValue, 20); - } + // } } else { Handles.color = Color.white; @@ -290,11 +290,11 @@ namespace NanoBrain { int row = 0; List drawnArrays = new(); foreach (Nucleus receiver in receivers) { - if (receiver is Receptor receptor) { - if (drawnArrays.Contains(receptor.nucleiArray)) - continue; - drawnArrays.Add(receptor.nucleiArray); - } + // if (receiver is Receptor receptor) { + // if (drawnArrays.Contains(receptor.nucleiArray)) + // continue; + // drawnArrays.Add(receptor.nucleiArray); + // } Nucleus receiverNucleus = receiver; if (receiverNucleus == null) @@ -321,26 +321,21 @@ namespace NanoBrain { if (synapse.neuron == null) continue; - if (synapse.neuron is Receptor receptor) { - if (drawnArrays.Contains(receptor.nucleiArray)) - continue; - drawnArrays.Add(receptor.nucleiArray); - } - else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.nucleiArray)) - continue; - drawnArrays.Add(clusterReceptor.nucleiArray); - } - else if (synapse.neuron.parent is Cluster cluster && cluster.siblingClusters != null) { + // if (synapse.neuron is Receptor receptor) { + // if (drawnArrays.Contains(receptor.nucleiArray)) + // continue; + // drawnArrays.Add(receptor.nucleiArray); + // } + // else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { + // if (drawnArrays.Contains(clusterReceptor.nucleiArray)) + // continue; + // drawnArrays.Add(clusterReceptor.nucleiArray); + // } + if (synapse.neuron.parent is Cluster cluster && cluster.siblingClusters != null) { if (drawnArrays.Contains(cluster.siblingClusters)) continue; drawnArrays.Add(cluster.siblingClusters); } - // else if (synapse.neuron.parent is Cluster cluster && cluster.clusterArray != null) { - // if (drawnArrays.Contains(cluster.clusterArray.clusters)) - // continue; - // drawnArrays.Add(cluster.clusterArray.clusters); - // } if (synapse.neuron is Neuron synapseNeuron) { float value = synapseNeuron.outputMagnitude * synapse.weight; // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); @@ -360,16 +355,16 @@ namespace NanoBrain { if (synapse.neuron is null) continue; - if (synapse.neuron is Receptor neuron) { - if (drawnArrays.Contains(neuron.nucleiArray)) - continue; - drawnArrays.Add(neuron.nucleiArray); - } - else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.nucleiArray)) - continue; - drawnArrays.Add(clusterReceptor.nucleiArray); - } + // if (synapse.neuron is Receptor neuron) { + // if (drawnArrays.Contains(neuron.nucleiArray)) + // continue; + // drawnArrays.Add(neuron.nucleiArray); + // } + // else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) { + // if (drawnArrays.Contains(clusterReceptor.nucleiArray)) + // continue; + // drawnArrays.Add(clusterReceptor.nucleiArray); + // } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -384,11 +379,9 @@ namespace NanoBrain { } if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) { // the synapse nucleus is part of a subcluster - DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color); + //DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color); + DrawNucleus(synapse.neuron, pos, maxValue, size, color); } - // else if (synapse.nucleus.cluster != null && synapse.nucleus.cluster != this.currentNucleus.cluster) { - // DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color); - // } else { DrawNucleus(synapse.neuron, pos, maxValue, size, color); } @@ -428,7 +421,29 @@ namespace NanoBrain { fontStyle = FontStyle.Bold, }; - if (nucleus is IReceptor receptor1) { + // if (nucleus is IReceptor receptor1) { + // if (expandArray) { + // // Put array indices above elements + // style.alignment = TextAnchor.LowerCenter; + // Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc + // int colonPos1 = nucleus.name.IndexOf(":"); + // if (colonPos1 > 0) { + // string extName = nucleus.name[(colonPos1 + 2)..]; + // Handles.Label(labelPos1, extName, style); + // } + // } + // else { + // // draw the array size label + // if (color.grayscale > 0.5f) + // style.normal.textColor = Color.black; + // else + // style.normal.textColor = Color.white; + // Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style); + // style.normal.textColor = Color.white; + // } + // } + // else + if (nucleus.parent != null && nucleus.parent is Cluster parentCluster) { if (expandArray) { // Put array indices above elements style.alignment = TextAnchor.LowerCenter; @@ -440,13 +455,15 @@ namespace NanoBrain { } } else { - // draw the array size label - if (color.grayscale > 0.5f) - style.normal.textColor = Color.black; - else + if (parentCluster.siblingClusters != null && parentCluster.siblingClusters.Length > 1) { + // draw the array size label + if (color.grayscale > 0.5f) + style.normal.textColor = Color.black; + else + style.normal.textColor = Color.white; + Handles.Label(labelPosition, parentCluster.siblingClusters.Length.ToString(), style); style.normal.textColor = Color.white; - Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style); - style.normal.textColor = Color.white; + } } } else if (nucleus is Cluster cluster) { @@ -478,25 +495,46 @@ namespace NanoBrain { Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron style.alignment = TextAnchor.UpperCenter; - nucleus.name ??= ""; - int colonPos = nucleus.name.IndexOf(":"); - if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { - // if it is an array, we should not show the :0 of the first element - string baseName = nucleus.name[..colonPos]; - Handles.Label(labelPos, baseName, style); + if (nucleus.parent != null && nucleus.parent is Cluster parentCluster1) { + parentCluster1.name ??= ""; + string baseName = ""; + if (parentCluster1 != currentNucleus.parent) { + int colonPos = parentCluster1.name.IndexOf(":"); + if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2) + baseName = parentCluster1.name[..colonPos] + "."; + else + baseName = parentCluster1.name + "."; + } + // if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2) { + // // if it is an array, we should not show the :0 of the first element + // //baseName = baseName[..colonPos]; + // Handles.Label(labelPos, baseName + nucleus.name, style); + // } + // else + Handles.Label(labelPos, baseName + nucleus.name, style); + } + else { + nucleus.name ??= ""; + int colonPos = nucleus.name.IndexOf(":"); + if (colonPos > 0 && colonPos < nucleus.name.Length - 2) { + // if it is an array, we should not show the :0 of the first element + string baseName = nucleus.name[..colonPos]; + Handles.Label(labelPos, baseName, style); + } + else + Handles.Label(labelPos, nucleus.name, style); } - else - Handles.Label(labelPos, nucleus.name, style); } // Draw Cluster ring - if (nucleus is Cluster) { + if (nucleus.parent != currentNucleus.parent || nucleus is Cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 5); } // Tooltip Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); Event e = Event.current; EventType et = e.GetTypeForControl(id); @@ -507,7 +545,10 @@ namespace NanoBrain { if (e.type == EventType.MouseDown && e.button == 0) { // Consume the event so the scene doesn't also handle it e.Use(); - HandleClicked(nucleus); + if (nucleus.parent != null && nucleus.parent is Cluster parentCluster2) + HandleClicked(parentCluster2); + else + HandleClicked(nucleus); } } } @@ -533,7 +574,7 @@ namespace NanoBrain { private void HandleClicked(Nucleus nucleus) { if (nucleus == this.currentNucleus) { - if (nucleus is Receptor || nucleus is ClusterReceptor) + if (nucleus is Receptor) // || nucleus is ClusterReceptor) expandArray = !expandArray; else expandArray = false; @@ -547,22 +588,22 @@ namespace NanoBrain { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - if (this.currentNucleus is IReceptor receptor) { - foreach (Nucleus nucleus in receptor.nucleiArray) { - if (nucleus is Neuron neuron) { - Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - } - } - else { - if (this.currentNucleus is Neuron currentNeuron) { - Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue); - Handles.color = Color.yellow; - Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } + // if (this.currentNucleus is IReceptor receptor) { + // foreach (Nucleus nucleus in receptor.nucleiArray) { + // if (nucleus is Neuron neuron) { + // Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue); + // Handles.color = Color.yellow; + // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); + // } + // } + // } + // else { + if (this.currentNucleus is Neuron currentNeuron) { + Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue); + Handles.color = Color.yellow; + Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); } + // } } } diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index c96ea65..12d105a 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -117,6 +117,7 @@ namespace NanoBrain { } } + /* // Copy nucleus arrays for receptors for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { Nucleus prefabNucleus = prefabNuclei[nucleusIx]; @@ -152,6 +153,7 @@ namespace NanoBrain { clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray; } } + */ foreach (Nucleus nucleus in this.clusterNuclei) { if (nucleus is Cluster clonedSubCluster) @@ -225,16 +227,19 @@ namespace NanoBrain { clonedSynapse.weight = synapse.weight; } - foreach (Neuron output in this.outputs) { - foreach (Nucleus receiver in output.receivers) { - int ix = GetNucleusIndex(this.clusterNuclei.ToArray(), output); - if (ix < 0) - continue; + foreach (Nucleus nucleus in this.clusterNuclei) { + if (nucleus is Neuron output) { + foreach (Nucleus receiver in output.receivers) { + int ix = GetNucleusIndex(this.clusterNuclei, output); + Debug.Log($"{output.name} -> {receiver.name}: {ix}"); + if (ix < 0) + continue; - if (clone.clusterNuclei[ix] is not Neuron clonedOutput) - continue; + if (clone.clusterNuclei[ix] is not Neuron clonedOutput) + continue; - clonedOutput.AddReceiver(receiver); + clonedOutput.AddReceiver(receiver); + } } } @@ -313,43 +318,41 @@ namespace NanoBrain { public void AddInstance(ClusterPrefab prefab) { - // if (this.siblingClusters.Length == 0) { - // Debug.LogError("Empty perceptoid array, cannot add"); - // return; - // } + // Ensure siblingClusters exists this.siblingClusters ??= new Cluster[1] { this }; + // Prepare the new array int newLength = this.siblingClusters.Length + 1; Cluster[] newSiblings = new Cluster[newLength]; + for (int i = 0; i < newSiblings.Length - 1; i++) + newSiblings[i] = this.siblingClusters[i]; + + Cluster newCluster = this.Clone(prefab) as Cluster; string baseName = this.name; int colonPos = baseName.IndexOf(":"); if (colonPos > 0) baseName = baseName[..colonPos]; - - for (int i = 0; i < newSiblings.Length - 1; i++) - newSiblings[i] = this.siblingClusters[i]; - // Cluster sourceCluster = this.siblingClusters[0]; - Cluster newCluster = this.Clone(prefab) as Cluster; newCluster.name = $"{baseName}: {newLength - 1}"; - //newCluster.clusterArray = this; newSiblings[newLength - 1] = newCluster; - this.siblingClusters = newSiblings; - newCluster.siblingClusters = newSiblings; + // All siblingClusters need to user this array! + foreach (Cluster sibling in this.siblingClusters) + sibling.siblingClusters = newSiblings; } public void RemoveInstance() { - int newLength = this.siblingClusters.Length - 1; - if (newLength == 0) { - Debug.LogWarning("Perceptoid array cannot be empty"); + if (this.siblingClusters == null || this.siblingClusters.Length <= 1) return; - } + + // Prepare the new array + int newLength = this.siblingClusters.Length - 1; Cluster[] newClusters = new Cluster[newLength]; + for (int i = 0; i < newLength; i++) newClusters[i] = this.siblingClusters[i]; - // Delete the last perception - //Cluster.Delete(nucleus); + + Neuron.Delete(this.siblingClusters[^1]); this.siblingClusters = newClusters; } @@ -601,9 +604,11 @@ namespace NanoBrain { if (startNucleus.trace) Debug.Log($"Update from {startNucleus.name}"); foreach (Nucleus nucleus in computeOrder) { - nucleus.UpdateStateIsolated(); - if (startNucleus.trace && nucleus is Neuron neuron) - Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {neuron.outputValue}"); + if (nucleus is not Cluster) { + nucleus.UpdateStateIsolated(); + if (startNucleus.trace && nucleus is Neuron neuron) + Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}]"); // = {neuron.outputValue}"); + } } // continue in parent diff --git a/Runtime/Scripts/Core/ClusterReceptor.cs b/Runtime/Scripts/Core/ClusterReceptor.cs index a6c7e52..ac99b2d 100644 --- a/Runtime/Scripts/Core/ClusterReceptor.cs +++ b/Runtime/Scripts/Core/ClusterReceptor.cs @@ -1,3 +1,4 @@ +/* using System; using System.Collections.Generic; using UnityEngine; @@ -275,4 +276,5 @@ namespace NanoBrain { } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/Runtime/Scripts/Core/IReceptor.cs b/Runtime/Scripts/Core/IReceptor.cs index 4c4b373..1f8cbcd 100644 --- a/Runtime/Scripts/Core/IReceptor.cs +++ b/Runtime/Scripts/Core/IReceptor.cs @@ -17,17 +17,17 @@ namespace NanoBrain { /// The array of nuclei used to track multiple things sending stimuli /// /// The size of the array determines the maximum number of things which can be distinguished - public Nucleus[] nucleiArray { get; set; } + // public Nucleus[] nucleiArray { get; set; } /// /// Extends the nucleiArray with an additional element /// /// A prefab of the nucleus to add? - public void AddReceptorElement(ClusterPrefab prefab); + // public void AddReceptorElement(ClusterPrefab prefab); /// /// Removes the last element from the nucleiArray /// - public void RemoveReceptorElement(); + // public void RemoveReceptorElement(); /// /// Add a receiver for this receptor array @@ -35,7 +35,7 @@ namespace NanoBrain { /// The receiving Nucleus /// The initial weight to use for the synapses /// This function will add a synapse to the receiver for each element in the nucleiArray. - public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1); + // public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1); /// /// Process an external stimulus @@ -47,77 +47,78 @@ namespace NanoBrain { } public static class IReceptorHelpers { + /* + /// + /// Implementation for the NanoBrain::IReceptor::AddReceptorElement which can be used for all implementations of IReceptor + /// + /// The IReceptor which needs to extend its nucleiArray + /// A prefab of the nucleus to add? + public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) { + if (receptor.nucleiArray.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + } + int newLength = receptor.nucleiArray.Length + 1; + Nucleus[] newArray = new Nucleus[newLength]; - /// - /// Implementation for the NanoBrain::IReceptor::AddReceptorElement which can be used for all implementations of IReceptor - /// - /// The IReceptor which needs to extend its nucleiArray - /// A prefab of the nucleus to add? - public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) { - if (receptor.nucleiArray.Length == 0) { - Debug.LogError("Empty perceptoid array, cannot add"); - } - int newLength = receptor.nucleiArray.Length + 1; - Nucleus[] newArray = new Nucleus[newLength]; + string baseName = receptor.GetName(); + int colonPos = baseName.IndexOf(":"); + if (colonPos > 0) + baseName = baseName[..colonPos]; - string baseName = receptor.GetName(); - int colonPos = baseName.IndexOf(":"); - if (colonPos > 0) - baseName = baseName[..colonPos]; + for (int i = 0; i < receptor.nucleiArray.Length; i++) + newArray[i] = receptor.nucleiArray[i]; + if (receptor.nucleiArray[0] is Nucleus nucleus) { + newArray[newLength - 1] = nucleus.Clone(prefab); + newArray[newLength - 1].name = $"{baseName}: {newLength - 1}"; + } - for (int i = 0; i < receptor.nucleiArray.Length; i++) - newArray[i] = receptor.nucleiArray[i]; - if (receptor.nucleiArray[0] is Nucleus nucleus) { - newArray[newLength - 1] = nucleus.Clone(prefab); - newArray[newLength - 1].name = $"{baseName}: {newLength - 1}"; - } - - foreach (Nucleus element in receptor.nucleiArray) { - if (element is IReceptor receptorElement) { - receptorElement.nucleiArray = newArray; + foreach (Nucleus element in receptor.nucleiArray) { + if (element is IReceptor receptorElement) { + receptorElement.nucleiArray = newArray; + } + } } - } - } - /// - /// Implementation for the NanoBrain::IReceptor::RemoteReceptorElement which can be used for all implementations of IReceptor - /// - /// The IReceptor which needs to shorten its nucleiArray - public static void RemoveReceptorElement(IReceptor receptor) { - int newLength = receptor.nucleiArray.Length - 1; - if (newLength == 0) { - Debug.LogWarning("Perceptoid array cannot be empty"); - } - Nucleus[] newArray = new Nucleus[newLength]; - for (int i = 0; i < newLength; i++) - newArray[i] = receptor.nucleiArray[i]; - // Delete the last perception - if (receptor.nucleiArray[newLength] is Nucleus nucleus) - Neuron.Delete(nucleus); + /// + /// Implementation for the NanoBrain::IReceptor::RemoteReceptorElement which can be used for all implementations of IReceptor + /// + /// The IReceptor which needs to shorten its nucleiArray + public static void RemoveReceptorElement(IReceptor receptor) { + int newLength = receptor.nucleiArray.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + } + Nucleus[] newArray = new Nucleus[newLength]; + for (int i = 0; i < newLength; i++) + newArray[i] = receptor.nucleiArray[i]; + // Delete the last perception + if (receptor.nucleiArray[newLength] is Nucleus nucleus) + Neuron.Delete(nucleus); + + foreach (Nucleus element in receptor.nucleiArray) { + if (element is IReceptor receptorElement) { + receptorElement.nucleiArray = newArray; + } + } - foreach (Nucleus element in receptor.nucleiArray) { - if (element is IReceptor receptorElement) { - receptorElement.nucleiArray = newArray; } - } - } + /// + /// Implementation for the NanoBreain::IRceptor::AddArrayReceiver which can be used for all implementations of IReceptor + /// + /// The IReceptor for which a receiving nuclues needs to be added + /// The nucleus to receive input from the receptor + /// The initial weight for the synapses + public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) { + foreach (Nucleus element in receptor.nucleiArray) { + if (element is Cluster cluster) + cluster.defaultOutput.AddReceiver(receiverToAdd, weight); + if (element is Neuron neuron) + neuron.AddReceiver(receiverToAdd, weight); + } - /// - /// Implementation for the NanoBreain::IRceptor::AddArrayReceiver which can be used for all implementations of IReceptor - /// - /// The IReceptor for which a receiving nuclues needs to be added - /// The nucleus to receive input from the receptor - /// The initial weight for the synapses - public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) { - foreach (Nucleus element in receptor.nucleiArray) { - if (element is Cluster cluster) - cluster.defaultOutput.AddReceiver(receiverToAdd, weight); - if (element is Neuron neuron) - neuron.AddReceiver(receiverToAdd, weight); - } + } - } + */ } - } \ No newline at end of file diff --git a/Runtime/Scripts/Core/Neuron.cs b/Runtime/Scripts/Core/Neuron.cs index fa48b56..16d4a1a 100644 --- a/Runtime/Scripts/Core/Neuron.cs +++ b/Runtime/Scripts/Core/Neuron.cs @@ -171,7 +171,7 @@ namespace NanoBrain { AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear); } return curve; - + } public static AnimationCurve Binary() { return AnimationCurve.Linear(0, 0, 1, 1); @@ -270,9 +270,11 @@ namespace NanoBrain { } else if (nucleus is Cluster cluster) { // remove all receivers for this cluster - foreach (Neuron output in cluster.outputs) { - foreach (Nucleus receiver in output.receivers) { - receiver.synapses.RemoveAll(s => s.neuron == output); + foreach (Nucleus clusterNucleus in cluster.clusterNuclei) { + if (clusterNucleus is Neuron output) { + foreach (Nucleus receiver in output.receivers) { + receiver.synapses.RemoveAll(s => s.neuron == output); + } } } } @@ -426,9 +428,9 @@ namespace NanoBrain { return float3(value, value, value); } - protected float3 ActivatorNormalized(float3 input) { + protected float3 ActivatorNormalized(float3 input) { if (lengthsq(input) == 0) - return input; + return input; float3 result = normalize(input); return result; } @@ -497,31 +499,31 @@ namespace NanoBrain { } public virtual void RemoveReceiver(Nucleus receiverToRemove) { - if (this is IReceptor receptor) { - foreach (Nucleus element in receptor.nucleiArray) { - if (element is Neuron neuron) { - neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); - receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron); - } - } - } - else { - this._receivers.RemoveAll(receiver => receiver == receiverToRemove); - receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this); - } + // if (this is IReceptor receptor) { + // foreach (Nucleus element in receptor.nucleiArray) { + // if (element is Neuron neuron) { + // neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); + // receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron); + // } + // } + // } + // else { + this._receivers.RemoveAll(receiver => receiver == receiverToRemove); + receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this); + // } } #endregion Receivers - public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - if (this.parent is ClusterReceptor clusterReceptor) - clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); - else - ProcessStimulusDirect(inputValue, thingId, thingName); + public override void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = null) { + // if (this.parent is ClusterReceptor clusterReceptor) + // clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); + // else + ProcessStimulusDirect(inputValue); //, thingId, thingName); } - public void ProcessStimulusDirect(Vector3 inputValue, int thingId = 0, string thingName = null) { + public void ProcessStimulusDirect(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) { this.stale = 0; this.bias = inputValue; this.parent.UpdateFromNucleus(this); diff --git a/Runtime/Scripts/Core/Nucleus.cs b/Runtime/Scripts/Core/Nucleus.cs index 1491957..25f958f 100644 --- a/Runtime/Scripts/Core/Nucleus.cs +++ b/Runtime/Scripts/Core/Nucleus.cs @@ -138,7 +138,7 @@ public abstract class Nucleus { /// The value of the stimulus /// The id of the thing causing the stimulus /// The name of the thing causing the stimulus - public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = "") { + public virtual void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = "") { } #endregion Update diff --git a/Runtime/Scripts/Core/NucleusArray.cs b/Runtime/Scripts/Core/NucleusArray.cs index 60a4a21..672f523 100644 --- a/Runtime/Scripts/Core/NucleusArray.cs +++ b/Runtime/Scripts/Core/NucleusArray.cs @@ -1,3 +1,4 @@ +/* using System.Linq; using System.Collections.Generic; using UnityEngine; @@ -194,4 +195,5 @@ namespace NanoBrain { } } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/Runtime/Scripts/Core/Receptor.cs b/Runtime/Scripts/Core/Receptor.cs index ef2e800..6e9efaf 100644 --- a/Runtime/Scripts/Core/Receptor.cs +++ b/Runtime/Scripts/Core/Receptor.cs @@ -10,16 +10,16 @@ namespace NanoBrain { /// Basic IReceptor to receive external input /// [System.Serializable] - public class Receptor : Neuron, IReceptor { + public class Receptor : Neuron { //}, IReceptor { /// /// Create a new Receptor in a Cluster instance /// /// The Cluster in which the Receptor is created /// The name of the new Receptor public Receptor(Cluster parent, string name) : base(parent, name) { - this.array = new NucleusArray(this); - if (this.name.IndexOf(":") < 0) - this.name += ": 0"; + //this.array = new NucleusArray(this); + // if (this.name.IndexOf(":") < 0) + // this.name += ": 0"; } /// /// Create a new Receptor in a Cluster Prefab @@ -27,7 +27,7 @@ namespace NanoBrain { /// The Cluster Prefab in which the Receptor is created /// The name of the new Receptor public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { - this.array = new NucleusArray(this); + //this.array = new NucleusArray(this); } public string GetName() { @@ -45,7 +45,7 @@ namespace NanoBrain { /// \copydoc NanoBrain::Neuron::Clone public override Nucleus Clone(ClusterPrefab prefab) { Receptor clone = new(prefab, name) { - array = this._array + //array = this._array }; CloneFields(clone); // Adding receivers will also add synapses to the receivers @@ -55,28 +55,30 @@ namespace NanoBrain { return clone; } - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - set { _array = value; } - } + /* + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + set { _array = value; } + } - public Nucleus[] nucleiArray { - get { return _array.nuclei; } - set { _array.nuclei = value; } - } + public Nucleus[] nucleiArray { + get { return _array.nuclei; } + set { _array.nuclei = value; } + } - public void AddReceptorElement(ClusterPrefab prefab) { - IReceptorHelpers.AddReceptorElement(this, prefab); - } + public void AddReceptorElement(ClusterPrefab prefab) { + IReceptorHelpers.AddReceptorElement(this, prefab); + } - public void RemoveReceptorElement() { - IReceptorHelpers.RemoveReceptorElement(this); - } + public void RemoveReceptorElement() { + IReceptorHelpers.RemoveReceptorElement(this); + } - public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { - IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight); - } + public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { + IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight); + } + */ public override void UpdateStateIsolated() { this.outputValue = this.bias; @@ -104,10 +106,14 @@ namespace NanoBrain { #endif - public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this._array ??= new NucleusArray(this.parent); - this._array.ProcessStimulus(thingId, inputValue, thingName); + public override void ProcessStimulus(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) { + // this._array ??= new NucleusArray(this.parent); + // this._array.ProcessStimulus(thingId, inputValue, thingName); + + this.stale = 0; + this.bias = inputValue; + this.parent.UpdateFromNucleus(this); } - + } } \ No newline at end of file