From 16f0c3d3bf5c09fcd9fa9cd1e50d848984690f31 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Thu, 5 Feb 2026 12:16:37 +0100 Subject: [PATCH] NucleusArray cloning seems to work --- Cluster.cs | 86 +++++++++++++---- Neuron.cs | 128 +++++++++++++------------- Nucleus.cs | 105 +++++++++++++++++++++ Nucleus.cs.meta | 2 + Scripts/Experimental/SelectorBrain.cs | 4 +- 5 files changed, 241 insertions(+), 84 deletions(-) create mode 100644 Nucleus.cs create mode 100644 Nucleus.cs.meta diff --git a/Cluster.cs b/Cluster.cs index 5f85b04..3d601db 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -61,8 +61,8 @@ public class Cluster : INucleus { // Now clone the connections for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { IReceptor receptor = nuclei[nucleusIx]; - IReceptor clonedSender = clonedNuclei[nucleusIx]; - if (clonedSender == null) + IReceptor clonedReceptor = clonedNuclei[nucleusIx]; + if (clonedReceptor == null) continue; // Copy the receivers, which will also create the synapses @@ -76,27 +76,49 @@ public class Cluster : INucleus { // Find the synapse for the weight float weight = 1; - NucleusArray nucleusArray = null; + //NucleusArray clonedNucleusArray = null; foreach (Synapse synapse in receiver.synapses) { + // Find the weight for this synapse if (synapse.nucleus == receptor) weight = synapse.weight; - if (synapse.nucleus is INucleus synapseNucleus) { - if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { - if (nucleusArray == null) { - // copy the array - nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); - for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { - IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; - int ix2 = GetNucleusIndex(nuclei, arrayNucleus); - nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; - } - } - synapseNucleus.array = nucleusArray; - } - } + + // if (synapse.nucleus is INucleus synapseNucleus) { + // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + // Debug.Log("Clone: Nucleus array"); + // if (clonedNucleusArray == null) { + // // copy the array + // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + // } + // } + // synapseNucleus.array = clonedNucleusArray; + // } + // } } - clonedSender.AddReceiver(clonedReceiver, weight); + clonedReceptor.AddReceiver(clonedReceiver, weight); + // Nucleus clonedNucleus = clonedReceptor as Nucleus; + // if (clonedNucleus is not null) { + // Synapse clonedSynapse = clonedNucleus.GetSynapse(clonedReceiver); + // if (clonedSynapse.nucleus is INucleus synapseNucleus) { + // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + // Debug.Log("Clone: Nucleus array"); + // if (clonedNucleusArray == null) { + // // copy the array + // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + // int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + // } + // } + // synapseNucleus.array = clonedNucleusArray; + // } + // } + // } } // if (receptor is INucleus nucleus) { @@ -113,6 +135,34 @@ public class Cluster : INucleus { // } // } } + for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { + IReceptor prefabReceptor = nuclei[nucleusIx]; + if (prefabReceptor is not INucleus prefabNucleus) + continue; + + if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) + continue; + + INucleus clonedNucleus = clonedNuclei[nucleusIx] as INucleus; + if (prefabNucleus == prefabNucleus.array.nuclei[0]) { + // We clone the array only for the first entry + NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); + int arrayIx = 0; + foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) { + int arrayNucleusIx = GetNucleusIndex(nuclei, prefabArrayNucleus); + IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; + clonedArray.nuclei[arrayIx] = clonedArrayNucleus; + arrayIx++; + } + clonedNucleus.array = clonedArray; + } + else { + // The others will refer to the array created for the first nucleus in the array + int firstNucleusIx = GetNucleusIndex(nuclei, prefabNucleus.array.nuclei[0]); + INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; + clonedNucleus.array = clonedFirstNucleus.array; + } + } } // Sort the nuclei in a correct evaluation order diff --git a/Neuron.cs b/Neuron.cs index 6e33f4a..742817c 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -7,7 +7,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [Serializable] -public class Neuron : INucleus { +public class Neuron : Nucleus, INucleus { public Neuron(Cluster parent, string name) { this.parent = parent; @@ -24,30 +24,30 @@ public class Neuron : INucleus { // Debug.LogError("No neuroid network"); } - [SerializeField] - protected string _name; - public virtual string name { - get => _name; - set => _name = value; - } + // [SerializeField] + // protected string _name; + // public virtual string name { + // get => _name; + // set => _name = value; + // } - [SerializeField] - private List _synapses = new(); - public List synapses => _synapses; + // [SerializeField] + // private List _synapses = new(); + // public List synapses => _synapses; - [SerializeReference] - private List _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } + // [SerializeReference] + // private List _receivers = new(); + // public List receivers { + // get { return _receivers; } + // set { _receivers = value; } + // } - [SerializeReference] - private NucleusArray _array; - public NucleusArray array { - get { return _array; } - set { _array = value; } - } + // [SerializeReference] + // private NucleusArray _array; + // public NucleusArray array { + // get { return _array; } + // set { _array = value; } + // } #region Serialization @@ -102,8 +102,8 @@ public class Neuron : INucleus { #region Runtime state (not serialized) - public ClusterPrefab cluster { get; set; } - public Cluster parent { get; set; } + // public ClusterPrefab cluster { get; set; } + // public Cluster parent { get; set; } #region Activation @@ -153,35 +153,35 @@ public class Neuron : INucleus { #endregion Activation - protected float3 _outputValue; - public virtual float3 outputValue { - get { return _outputValue; } - set { - this.stale = 0; - // this._isSleeping = false; - _outputValue = value; - } - } + // protected float3 _outputValue; + // public virtual float3 outputValue { + // get { return _outputValue; } + // set { + // this.stale = 0; + // // this._isSleeping = false; + // _outputValue = value; + // } + // } - [NonSerialized] - private int stale = 1000; + // [NonSerialized] + // private int stale = 1000; // private bool _isSleeping = false; // public bool isSleeping => _isSleeping; - public bool isSleeping => lengthsq(this.outputValue) == 0; + // public bool isSleeping => lengthsq(this.outputValue) == 0; - public void UpdateNuclei() { - this.stale++; - // this._isSleeping = this.stale > 2; - // if (isSleeping) - if (this.stale > 2) - _outputValue = Vector3.zero; - } + // public void UpdateNuclei() { + // this.stale++; + // // this._isSleeping = this.stale > 2; + // // if (isSleeping) + // if (this.stale > 2) + // _outputValue = Vector3.zero; + // } #endregion Runtime state // this clone the nucleus without the synapses and receivers - public virtual IReceptor ShallowCloneTo(Cluster newParent) { + public override IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { array = null, curve = this.curve, @@ -192,7 +192,7 @@ public class Neuron : INucleus { return clone; } - public virtual IReceptor Clone() { + public override IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, curve = this.curve, @@ -213,22 +213,22 @@ public class Neuron : INucleus { return clone; } - public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { - this._receivers.Add(receivingNucleus); - receivingNucleus.AddSynapse(this, weight); - } + // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + // this._receivers.Add(receivingNucleus); + // receivingNucleus.AddSynapse(this, weight); + // } - public void RemoveReceiver(INucleus receiverNucleus) { - this._receivers.RemoveAll(receiver => receiver == receiverNucleus); - receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); - } + // public void RemoveReceiver(INucleus receiverNucleus) { + // this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + // } public static void Delete(INucleus nucleus) { foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Neuron synapse_nucleus) { - if (synapse_nucleus._receivers.Count > 1) { + if (synapse_nucleus.receivers.Count > 1) { // there is another nucleus feeding into this input nucleus - synapse_nucleus._receivers.RemoveAll(r => r == nucleus); + synapse_nucleus.receivers.RemoveAll(r => r == nucleus); } else { // No other links, delete it. @@ -247,11 +247,11 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { - Synapse synapse = new(sendingNucleus, weight); - this.synapses.Add(synapse); - return synapse; - } + // public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + // Synapse synapse = new(sendingNucleus, weight); + // this.synapses.Add(synapse); + // return synapse; + // } // public virtual void UpdateState() { // //UpdateState(new float3(0, 0, 0)); @@ -296,10 +296,10 @@ public class Neuron : INucleus { // UpdateResult(result); // } - public virtual void UpdateStateIsolated() { - UpdateStateIsolated(new float3(0, 0, 0)); - } - public virtual void UpdateStateIsolated(float3 bias) { + // public virtual void UpdateStateIsolated() { + // UpdateStateIsolated(new float3(0, 0, 0)); + // } + public override void UpdateStateIsolated(float3 bias) { float3 sum = bias; int n = 0; diff --git a/Nucleus.cs b/Nucleus.cs new file mode 100644 index 0000000..f7ac9ac --- /dev/null +++ b/Nucleus.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +public abstract class Nucleus : IReceptor { + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + //[Obsolete] + public ClusterPrefab cluster { get; set; } + public Cluster parent { get; set; } + + protected float3 _outputValue; + public virtual float3 outputValue { + get { return _outputValue; } + set { + this.stale = 0; + // this._isSleeping = false; + _outputValue = value; + } + } + + public bool isSleeping => lengthsq(this.outputValue) == 0; + [NonSerialized] + private int stale = 1000; + + // Cannot clone an abstract nucleus... + public virtual IReceptor ShallowCloneTo(Cluster parent) { return null; } + // Cannot clone an abstract nucleus... + public virtual IReceptor Clone() { return null; } + + #region Synapses + + [SerializeField] + private List _synapses = new(); + public List synapses => _synapses; + + public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { + Synapse synapse = new(sendingNucleus, weight); + this.synapses.Add(synapse); + return synapse; + } + + public Synapse GetSynapse(INucleus sender) { + foreach (Synapse synapse in this.synapses) + if (synapse.nucleus == sender) + return synapse; + return null; + } + + #endregion Synapses + + #region Receivers + + [SerializeReference] + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } + } + + public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this, weight); + } + + public void RemoveReceiver(INucleus receiverNucleus) { + this._receivers.RemoveAll(receiver => receiver == receiverNucleus); + receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); + } + + + #endregion Receivers + + [SerializeReference] + private NucleusArray _array; + public NucleusArray array { + get { return _array; } + set { _array = value; } + } + + #region Update + + public virtual void UpdateStateIsolated() { + UpdateStateIsolated(new float3(0, 0, 0)); + } + + public virtual void UpdateStateIsolated(float3 bias) { + } + + public void UpdateNuclei() { + this.stale++; + if (this.stale > 2) + _outputValue = Vector3.zero; + } + + #endregion Update + +} \ No newline at end of file diff --git a/Nucleus.cs.meta b/Nucleus.cs.meta new file mode 100644 index 0000000..08b3cf8 --- /dev/null +++ b/Nucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4310eea6ab77628b085387a226c1c386 \ No newline at end of file diff --git a/Scripts/Experimental/SelectorBrain.cs b/Scripts/Experimental/SelectorBrain.cs index 8b40798..7ea01b6 100644 --- a/Scripts/Experimental/SelectorBrain.cs +++ b/Scripts/Experimental/SelectorBrain.cs @@ -9,8 +9,8 @@ public class SelectorBrain : NanoBrain { public Receptor receptor2; protected void Awake() { - receptor1 = Receptor.CreateReceptor(this.brain, "Selector"); - receptor2 = Receptor.CreateReceptor(this.brain, "Selector"); + receptor1 = new Receptor(this.brain, "Receptor", "Selector"); + receptor2 = new Receptor(this.brain, "Receptor", "Selector"); } protected void Update() {