From 527abb51786888cd2bb5f07ea8c39b7ab2f337f0 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 13 Aug 2026 12:54:11 +0200 Subject: [PATCH] Proper mutation with one parent --- Runtime/Scripts/Core/Cluster.cs | 34 +++++++++++++++++++++++++++++++-- Runtime/Scripts/Core/Neuron.cs | 23 +++++++++++++++++++++- Runtime/Scripts/Core/Nucleus.cs | 27 ++++++++++++++++++++++++++ Runtime/Scripts/Core/Synapse.cs | 4 ++++ 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index f6e20be..25c27ce 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -556,7 +556,7 @@ namespace NanoBrain { if (_computeOrders == null || _computeOrders.Count == 0) { _computeOrders = new(); foreach (Nucleus nucleus in this.nuclei) - _computeOrders[nucleus] = TopologicalSort2(nucleus); + _computeOrders[nucleus] = TopologicalSort(nucleus); } return _computeOrders; } @@ -568,7 +568,7 @@ namespace NanoBrain { this._computeOrders = null; } - private List TopologicalSort2(Nucleus startNode) { + private List TopologicalSort(Nucleus startNode) { Dictionary inDegree = new(); //HashSet visited = new(); @@ -796,6 +796,36 @@ namespace NanoBrain { return true; } + public static bool EqualStructure(Cluster cluster1, Cluster cluster2) { + int n1 = cluster1.nuclei.Count; + int n2 = cluster2.nuclei.Count; + if (n1 != n2) + return false; + + for (int i = 0; i < cluster1.nuclei.Count; i++) { + if (EqualStructure(cluster1.nuclei[i], cluster2.nuclei[i]) == false) + return false; + } + return true; + } + + public bool CopyWeightsTo(Cluster destination) { + if (EqualStructure(this, destination) == false) { + Debug.LogWarning("Tried to copy weight to a cluster with different structure. Copy is not executed."); + return false; + } + + for (int i = 0; i < this.nuclei.Count; i++) { + if (this.nuclei[i] is Neuron thisNeuron && + destination.nuclei[i] is Neuron destinationNeuron) { + + thisNeuron.CopyWeightsTo(destinationNeuron); + } + } + + return true; + } + #region Receivers /// diff --git a/Runtime/Scripts/Core/Neuron.cs b/Runtime/Scripts/Core/Neuron.cs index 7f2f2c7..77918d0 100644 --- a/Runtime/Scripts/Core/Neuron.cs +++ b/Runtime/Scripts/Core/Neuron.cs @@ -300,6 +300,27 @@ namespace NanoBrain { clone.breakOnUpdate = this.breakOnUpdate; } + public static bool EqualStructure(Neuron neuron1, Neuron neuron2) { + int synapseCount1 = neuron1.synapses.Count; + int synapseCount2 = neuron2.synapses.Count; + if (synapseCount1 != synapseCount2) + return false; + + for (int i = 0; i < synapseCount1; i++) { + if (Synapse.EqualStructure(neuron1.synapses[i], neuron2.synapses[i]) == false) + return false; + } + return true; + } + + public void CopyWeightsTo(Neuron destination) { + for (int i = 0; i < this.synapses.Count; i++) { + Synapse thisSynapse = this.synapses[i]; + Synapse destinationSynapse = destination.synapses[i]; + destinationSynapse.weight = thisSynapse.weight; + } + } + /// /// Delete the give neuron /// @@ -771,7 +792,7 @@ namespace NanoBrain { } } - protected async void ResetStimulus() { + protected void ResetStimulus() { //Debug.Log("reset stimulus"); this.bias = Vector3.zero; this.parent?.UpdateFromNucleus(this); diff --git a/Runtime/Scripts/Core/Nucleus.cs b/Runtime/Scripts/Core/Nucleus.cs index fe06919..bed8f87 100644 --- a/Runtime/Scripts/Core/Nucleus.cs +++ b/Runtime/Scripts/Core/Nucleus.cs @@ -50,6 +50,33 @@ namespace NanoBrain { #endregion Update + public static bool EqualStructure(Nucleus nucleus1, Nucleus nucleus2) { + if (nucleus1.parent != null && nucleus2.parent != null) { + if (nucleus1.parent.baseName != nucleus2.parent.baseName) + return false; + } else { + // mainly to check one is null, other is not. + if (nucleus1.parent != nucleus2.parent) + return false; + } + + if (nucleus1 is Neuron neuron1) { + if (nucleus2 is not Neuron neuron2) + return false; + if (neuron1.name != neuron2.name) + return false; + return Neuron.EqualStructure(neuron1, neuron2); + } + else if (nucleus1 is Cluster cluster1) { + if (nucleus2 is not Cluster cluster2) + return false; + if (cluster1.baseName != cluster2.baseName) + return false; + return Cluster.EqualStructure(cluster1, cluster2); + } + + return false; + } } } \ No newline at end of file diff --git a/Runtime/Scripts/Core/Synapse.cs b/Runtime/Scripts/Core/Synapse.cs index a791a74..1317720 100644 --- a/Runtime/Scripts/Core/Synapse.cs +++ b/Runtime/Scripts/Core/Synapse.cs @@ -36,6 +36,10 @@ namespace NanoBrain { this.weight = weight; } + public static bool EqualStructure(Synapse synapse1, Synapse synapse2) { + return synapse1.neuron.name == synapse2.neuron.name; + } + public virtual void BackPropagation(Neuron receiver, float derivative, float learningRate) { switch (receiver.activator) { case Neuron.ActivationType.Linear: