From 04010903f512d2c171ce5afe2721224bb0abc399 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 28 Apr 2026 17:46:06 +0200 Subject: [PATCH] Created runtime sibling, but not the synapses yet --- Runtime/Scripts/Core/Cluster.cs | 270 +++++++++++++++++++------------- 1 file changed, 165 insertions(+), 105 deletions(-) diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index c358f14..c027f90 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -164,94 +164,117 @@ namespace NanoBrain { // clonedNeuron.AddReceiver(clonedReceiver, weight); // } } + + if (Application.isPlaying) { + // Only create cluster siblings at runtime + foreach (Nucleus clonedNucleus in clonedNuclei) { + if (clonedNucleus is not Cluster clonedCluster) + continue; + + // if (clonedCluster.instanceCount <= 1) + // continue; + + for (int instanceIx = 1; instanceIx < clonedCluster.instanceCount; instanceIx++) { + //ClusterPrefab prefabCluster = clonedCluster.prefab; + // Create another sibling + Debug.Log($"create {clonedCluster.prefab.name} sibling"); + Cluster sibling = new(clonedCluster.prefab, this) { + name = this.name, + clusterPrefab = this.clusterPrefab, + instanceCount = this.instanceCount, + }; + RestoreAllExternalReceivers(clonedCluster, clonedCluster.prefab, this); + } + } + } /* - // Copy the siblings for clusters - for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) { - Nucleus prefabNucleus = prefabNuclei[nucleusIx]; - if (prefabNucleus is not Cluster prefabCluster) + for (int nucleusIx = 0; nucleusIx < clonedNuclei.Length; nucleusIx++) { + Nucleus prefabNucleus = prefabNuclei[nucleusIx]; + if (prefabNucleus is not Cluster prefabCluster) + continue; + + if (prefabCluster.instanceCount <= 1) + continue; + + Cluster clonedNucleus = clonedNuclei[nucleusIx] as Cluster; + if (prefabCluster == prefabCluster.siblingClusters[0]) { + // We clone the array only for the first entry + //NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length); + Cluster[] clonedArray = new Cluster[prefabCluster.siblingClusters.Length]; + int arrayIx = 0; + foreach (Cluster prefabArrayNucleus in prefabCluster.siblingClusters) { + int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); + if (arrayNucleusIx >= 0) { + Cluster clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Cluster; + clonedArray[arrayIx] = clonedArrayNucleus; + } + else { + Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones"); + } + arrayIx++; + } + clonedNucleus.siblingClusters = clonedArray; + } + else { + // The others will refer to the array created for the first nucleus in the array + int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabCluster.siblingClusters[0]); + Cluster clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Cluster; + clonedNucleus.siblingClusters = clonedFirstNucleus.siblingClusters; + } + } + } + + /* + // Collect the subclusters + List subClusters = new(); + foreach (Nucleus nucleus in prefabNuclei) { + foreach (Synapse synapse in nucleus.synapses) { + Nucleus synapseNucleus = synapse.neuron; + Cluster subCluster = synapseNucleus.parent; + if (subCluster is null || + synapseNucleus.clusterPrefab == this.clusterPrefab) { + continue; - - if (prefabCluster.siblingClusters == null || prefabCluster.siblingClusters.Length == 0) + } + // if (synapseNucleus is not Cluster subCluster) + // continue; + if (subClusters.Contains(subCluster)) continue; - - Cluster clonedNucleus = clonedNuclei[nucleusIx] as Cluster; - if (prefabCluster == prefabCluster.siblingClusters[0]) { - // We clone the array only for the first entry - //NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length); - Cluster[] clonedArray = new Cluster[prefabCluster.siblingClusters.Length]; - int arrayIx = 0; - foreach (Cluster prefabArrayNucleus in prefabCluster.siblingClusters) { - int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); - if (arrayNucleusIx >= 0) { - Cluster clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Cluster; - clonedArray[arrayIx] = clonedArrayNucleus; - } - else { - Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones"); - } - arrayIx++; - } - clonedNucleus.siblingClusters = clonedArray; - } - else { - // The others will refer to the array created for the first nucleus in the array - int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabCluster.siblingClusters[0]); - Cluster clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Cluster; - clonedNucleus.siblingClusters = clonedFirstNucleus.siblingClusters; - } + subClusters.Add(subCluster); } - - /* - // Collect the subclusters - List subClusters = new(); - foreach (Nucleus nucleus in prefabNuclei) { - foreach (Synapse synapse in nucleus.synapses) { - Nucleus synapseNucleus = synapse.neuron; - Cluster subCluster = synapseNucleus.parent; - if (subCluster is null || - synapseNucleus.clusterPrefab == this.clusterPrefab) { - + } + // Create the subcluster instances + foreach (Cluster subCluster in subClusters) { + for (int ix = 0; ix < subCluster.instanceCount; ix++) { + // create the new instance + Cluster clusterInstance = new(subCluster.prefab); + // connect it + foreach ((Neuron sender, Nucleus receiver) in subCluster.CollectConnections()) { + int receiverIx = GetNucleusIndex(prefabNuclei, receiver); + if (receiverIx < 0) continue; - } - // if (synapseNucleus is not Cluster subCluster) - // continue; - if (subClusters.Contains(subCluster)) + + if (clonedNuclei[receiverIx] is not Nucleus clonedReceiver) continue; - subClusters.Add(subCluster); - } - } - // Create the subcluster instances - foreach (Cluster subCluster in subClusters) { - for (int ix = 0; ix < subCluster.instanceCount; ix++) { - // create the new instance - Cluster clusterInstance = new(subCluster.prefab); - // connect it - foreach ((Neuron sender, Nucleus receiver) in subCluster.CollectConnections()) { - int receiverIx = GetNucleusIndex(prefabNuclei, receiver); - if (receiverIx < 0) - continue; - if (clonedNuclei[receiverIx] 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.neuron == sender) { - 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.neuron == sender) { + weight = synapse.weight; + break; } - - if (clusterInstance.GetNucleus(sender.name) is not Neuron clonedSender) - continue; - - clonedSender.AddReceiver(clonedReceiver, weight); } + + if (clusterInstance.GetNucleus(sender.name) is not Neuron clonedSender) + continue; + + clonedSender.AddReceiver(clonedReceiver, weight); } } - */ + } + */ // foreach (Nucleus nucleus in this.clusterNuclei) { // if (nucleus is Cluster clonedSubCluster) @@ -259,6 +282,38 @@ namespace NanoBrain { // } } + private void CloneSynapses(Neuron prefabNeuron, Neuron clonedNeuron) { + foreach (Synapse prefabSynapse in prefabNeuron.synapses) { + Neuron synapseNeuron = prefabSynapse.neuron; + if (synapseNeuron.clusterPrefab != null && synapseNeuron.clusterPrefab != this.prefab) { + // Neuron is in another cluster, find the cloned cluster first + ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab; + Cluster clonedCluster = this.clusterNuclei.Find(n => n.name == prefabCluster.name) as Cluster; + if (clonedCluster == null) + continue; + + // Now find the neuron in that cloned cluster + int neuronIx = GetNucleusIndex(prefabCluster.nuclei, prefabSynapse.neuron.name); + if (neuronIx < 0) + // Could not find the neuron in the prefab cluster + continue; + if (clonedCluster.clusterNuclei[neuronIx] is not Neuron clonedSender) + // Could not find the neuron in the cloned cluster + continue; + + clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight); + //Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]"); + } + else { + Neuron clonedSender = this.clusterNuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron; + // Copy the receivers which will also create the synapse + clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight); + // Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}"); + } + } + + } + /// /// Sort the nuclei in a correct evaluation order /// @@ -349,6 +404,7 @@ namespace NanoBrain { Cluster clone = new(this.prefab, parent) { name = this.name, clusterPrefab = this.clusterPrefab, + instanceCount = this.instanceCount, }; // Somehow siblingClusters should be cloned too. Believe I do this in ClonePrefab right now. @@ -356,40 +412,44 @@ namespace NanoBrain { } private static void RestoreAllExternalReceivers(Cluster clonedCluster, ClusterPrefab prefabParent, Cluster clonedParent) { - int clonedClusterIx = GetNucleusIndex(clonedParent.clusterNuclei, clonedCluster); - if (prefabParent.nuclei[clonedClusterIx] is not Cluster sourceCluster) - return; - for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) { - Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx]; - if (sourceNucleus is not Neuron sourceNeuron) - continue; - if (clonedCluster.clusterNuclei[nucleusIx] is not Neuron clonedNeuron) - continue; + // int clonedClusterIx = GetNucleusIndex(clonedParent.clusterNuclei, clonedCluster); + // if (prefabParent.nuclei[clonedClusterIx] is not Cluster sourceCluster) + // return; - // copy the receivers (and thus synapses) from the source to the clone - foreach (Nucleus receiver in sourceNeuron.receivers) { - int ix = GetNucleusIndex(prefabParent.nuclei, receiver); - if (ix < 0 || ix >= clonedParent.clusterNuclei.Count) - continue; + // for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) { + // Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx]; + // if (sourceNucleus is not Neuron sourceNeuron) + // continue; - Nucleus clonedReceiver = clonedParent.clusterNuclei[ix]; + // if (clonedCluster.clusterNuclei[nucleusIx] is not Neuron clonedNeuron) + // continue; - // Find the synapse for the weight - float weight = 1; - foreach (Synapse synapse in receiver.synapses) { - // Find the weight for this synapse - if (synapse.neuron == sourceNucleus) { - weight = synapse.weight; - break; - } - } + // // copy the receivers (and thus synapses) from the source to the clone + // foreach (Nucleus receiver in sourceNeuron.receivers) { + // int ix = GetNucleusIndex(prefabParent.nuclei, receiver); + // if (ix < 0 || ix >= clonedParent.clusterNuclei.Count) + // continue; - clonedNeuron.AddReceiver(clonedReceiver, weight); - // Debug.Log($"external: {clonedReceiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}"); - } - } + // Nucleus clonedReceiver = clonedParent.clusterNuclei[ix]; + + // // Find the synapse for the weight + // float weight = 1; + // foreach (Synapse synapse in receiver.synapses) { + // // Find the weight for this synapse + // if (synapse.neuron == sourceNucleus) { + // weight = synapse.weight; + // break; + // } + // } + + // clonedNeuron.AddReceiver(clonedReceiver, weight); + // Debug.Log($"external: {clonedReceiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}"); + // } + // } + + } protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) {