From c2e4e1b33f92e73c5197b471081a3334e45405ee Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 21 Apr 2026 12:08:37 +0200 Subject: [PATCH] Fix Cluster array extension --- Editor/ClusterInspector.cs | 7 ++- Editor/ClusterViewer.cs | 83 +++++++++++++++++---------------- Runtime/Scripts/Core/Cluster.cs | 12 +++-- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 3f8e52e..30f7605 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -197,9 +197,9 @@ namespace NanoBrain { if (this.currentNucleus is Cluster cluster) { EditorGUILayout.BeginHorizontal(); if (cluster.siblingClusters != null && cluster.siblingClusters.Length > 1) - EditorGUILayout.IntField("Array size", cluster.siblingClusters.Count()); + EditorGUILayout.IntField("Array size", cluster.siblingClusters.Count(), GUILayout.MinWidth(150)); else - EditorGUILayout.IntField("Array size", 1); + EditorGUILayout.IntField("Array size", 1, GUILayout.MinWidth(150)); if (GUILayout.Button("Add")) { Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); cluster.AddInstance(this.prefab); @@ -224,10 +224,13 @@ namespace NanoBrain { } EditorGUIUtility.wideMode = true; + float previousLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 100; + Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias); anythingChanged |= newBias != this.currentNucleus.bias; this.currentNucleus.bias = newBias; + EditorGUIUtility.labelWidth = previousLabelWidth; Nucleus[] array = null; int elementIx = -1; diff --git a/Editor/ClusterViewer.cs b/Editor/ClusterViewer.cs index 50f5fdd..e34e63f 100644 --- a/Editor/ClusterViewer.cs +++ b/Editor/ClusterViewer.cs @@ -189,11 +189,9 @@ namespace NanoBrain { if (nucleus == null) return; layer.neuroids.Add(nucleus); - //nucleus.layerIx = layer.ix; // Store its position Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); neuroidPositions[nucleus] = neuroidPosition; - } public void OnIMGUI() { @@ -224,9 +222,9 @@ namespace NanoBrain { Dag dag = GenerateGraph(this.selectedOutput); Dag.ComputeLayout(dag); // Draw edges - foreach (DagEdge e in dag.edges) { - DagNode from = dag.nodes.FirstOrDefault(x => x.id == e.fromId); - DagNode to = dag.nodes.FirstOrDefault(x => x.id == e.toId); + foreach (Dag.Edge e in dag.edges) { + Dag.Node from = dag.nodes.FirstOrDefault(x => x.id == e.fromId); + Dag.Node to = dag.nodes.FirstOrDefault(x => x.id == e.toId); if (from == null || to == null) continue; @@ -236,13 +234,13 @@ namespace NanoBrain { } // Draw nodes - foreach (DagNode n in dag.nodes) + foreach (Dag.Node n in dag.nodes) DrawNucleus(n.nucleus, n.position, 1, n.radius); // Determine graph width float width = 0; float currentNucleusPosition = 0; - foreach (DagNode node in dag.nodes) { + foreach (Dag.Node node in dag.nodes) { if (node.position.x > width) width = node.position.x; if (node.nucleus == currentNucleus) @@ -271,7 +269,7 @@ namespace NanoBrain { return dag; int ix = 0; - DagNode receiver = new() { + Dag.Node receiver = new() { id = ix, //title = nucleus.name, nucleus = rootNucleus @@ -282,9 +280,9 @@ namespace NanoBrain { return dag; } - private void DescendGraph(DagNode receiver, ref int ix, Dag dag) { + private void DescendGraph(Dag.Node receiver, ref int ix, Dag dag) { foreach (Synapse synapse in receiver.nucleus.synapses) { - DagNode synapseNode = dag.FindNode(synapse.neuron.name); + Dag.Node synapseNode = dag.FindNode(synapse.neuron.name); if (synapseNode == null) { synapseNode = new() { id = ix, @@ -292,7 +290,7 @@ namespace NanoBrain { }; dag.nodes.Add(synapseNode); } - DagEdge edge = new() { + Dag.Edge edge = new() { fromId = synapseNode.id, toId = receiver.id }; @@ -480,6 +478,11 @@ namespace NanoBrain { // continue; // drawnArrays.Add(clusterReceptor.nucleiArray); // } + if (synapse.neuron.parent is Cluster cluster) { + if (drawnArrays.Contains(cluster.siblingClusters)) + continue; + drawnArrays.Add(cluster.siblingClusters); + } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -679,13 +682,13 @@ namespace NanoBrain { else expandArray = false; } - // else if (nucleus.parent != this.currentNucleus.parent) { - // // We go to a different cluster - // // select the cluster, not the neuron in the cluster - // this.currentNucleus = nucleus.parent; - // expandArray = false; - // BuildLayers(); - // } + else if (nucleus.parent != this.currentNucleus.parent) { + // We go to a different cluster + // select the cluster, not the neuron in the cluster + this.currentNucleus = nucleus.parent; + expandArray = false; + BuildLayers(); + } else { this.currentNucleus = nucleus; expandArray = false; @@ -729,37 +732,37 @@ namespace NanoBrain { public List neuroids = new(); } - [System.Serializable] - public class DagNode { - public int id; - public Vector2 position; - public float radius = 20f; // circle radius - public Nucleus nucleus; - } - - [System.Serializable] - public class DagEdge { - public int fromId; - public int toId; - } public class Dag { - public List nodes = new(); - public List edges = new(); - public DagNode FindNode(string name) { - foreach (DagNode node in this.nodes) { + public class Node { + public int id; + public Vector2 position; + public float radius = 20f; // circle radius + public Nucleus nucleus; + } + + public class Edge { + public int fromId; + public int toId; + } + + public List nodes = new(); + public List edges = new(); + + public Node FindNode(string name) { + foreach (Node node in this.nodes) { if (node.nucleus.name == name) return node; } return null; } - public static DagNode GetNodeById(Dag dag, int id) => dag.nodes.FirstOrDefault(x => x.id == id); + public static Node GetNodeById(Dag dag, int id) => dag.nodes.FirstOrDefault(x => x.id == id); public static void ComputeLayout(Dag dag) { Dictionary> adjacency = dag.nodes.ToDictionary(n => n.id, n => new List()); Dictionary outdegree = dag.nodes.ToDictionary(node => node.id, n => 0); - foreach (DagEdge edge in dag.edges) { + foreach (Edge edge in dag.edges) { if (!adjacency.ContainsKey(edge.fromId) || !adjacency.ContainsKey(edge.toId)) continue; adjacency[edge.fromId].Add(edge.toId); @@ -771,7 +774,7 @@ namespace NanoBrain { Dictionary> parents = dag.nodes.ToDictionary(n => n.id, _ => new List()); Dictionary childCount = dag.nodes.ToDictionary(n => n.id, _ => 0); - foreach (DagEdge edge in dag.edges) { + foreach (Edge edge in dag.edges) { if (!adjacency.ContainsKey(edge.fromId) || !adjacency.ContainsKey(edge.toId)) continue; adjacency[edge.fromId].Add(edge.toId); parents[edge.toId].Add(edge.fromId); // parent of 'to' is 'from' @@ -798,7 +801,7 @@ namespace NanoBrain { // Any unreachable nodes -> assign next layers int maxLayer = layer.Count > 0 ? layer.Values.Max() : 0; - foreach (DagNode node in dag.nodes) { + foreach (Node node in dag.nodes) { if (!layer.ContainsKey(node.id)) { maxLayer++; layer[node.id] = maxLayer; @@ -846,7 +849,7 @@ namespace NanoBrain { float margin = 10 + spacing / 2; for (int i = 0; i < nodeList.Count; i++) { int index = nodeList[i]; - DagNode node = GetNodeById(dag, index); + Node node = GetNodeById(dag, index); if (node == null) continue; float x = hSpacing + layerIx * hSpacing; diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index 2fb58b2..2482247 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -281,7 +281,8 @@ namespace NanoBrain { public void AddInstance(ClusterPrefab prefab) { // Ensure siblingClusters exists - this.siblingClusters ??= new Cluster[1] { this }; + if (this.siblingClusters == null || this.siblingClusters.Length == 0) + this.siblingClusters = new Cluster[1] { this }; // Prepare the new array int newLength = this.siblingClusters.Length + 1; @@ -299,7 +300,7 @@ namespace NanoBrain { newSiblings[newLength - 1] = newCluster; // All siblingClusters need to user this array! - foreach (Cluster sibling in this.siblingClusters) + foreach (Cluster sibling in newSiblings) sibling.siblingClusters = newSiblings; } @@ -349,7 +350,7 @@ namespace NanoBrain { if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate) unusedCluster = this.siblingClusters[ix]; } - + RemoveThingCluster(unusedCluster); return unusedCluster; } @@ -534,7 +535,10 @@ namespace NanoBrain { public virtual List CollectReceivers() { List receivers = new(); - foreach (Neuron output in this.outputs) { + foreach (Nucleus outputNucleus in this.clusterNuclei) { + if (outputNucleus is not Neuron output) + continue; + foreach (Nucleus receiver in output.receivers) { // Only add receivers outside this cluster if (receiver.clusterPrefab != this.prefab)