NucleusArray cloning seems to work

This commit is contained in:
Pascal Serrarens 2026-02-05 12:16:37 +01:00
parent 3cc5f56f61
commit 16f0c3d3bf
5 changed files with 241 additions and 84 deletions

View File

@ -61,8 +61,8 @@ public class Cluster : INucleus {
// Now clone the connections // Now clone the connections
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) {
IReceptor receptor = nuclei[nucleusIx]; IReceptor receptor = nuclei[nucleusIx];
IReceptor clonedSender = clonedNuclei[nucleusIx]; IReceptor clonedReceptor = clonedNuclei[nucleusIx];
if (clonedSender == null) if (clonedReceptor == null)
continue; continue;
// Copy the receivers, which will also create the synapses // Copy the receivers, which will also create the synapses
@ -76,27 +76,49 @@ public class Cluster : INucleus {
// Find the synapse for the weight // Find the synapse for the weight
float weight = 1; float weight = 1;
NucleusArray nucleusArray = null; //NucleusArray clonedNucleusArray = null;
foreach (Synapse synapse in receiver.synapses) { foreach (Synapse synapse in receiver.synapses) {
// Find the weight for this synapse
if (synapse.nucleus == receptor) if (synapse.nucleus == receptor)
weight = synapse.weight; weight = synapse.weight;
if (synapse.nucleus is INucleus synapseNucleus) {
if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { // if (synapse.nucleus is INucleus synapseNucleus) {
if (nucleusArray == null) { // if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) {
// copy the array // Debug.Log("Clone: Nucleus array");
nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); // if (clonedNucleusArray == null) {
for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { // // copy the array
IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; // clonedNucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array");
int ix2 = GetNucleusIndex(nuclei, arrayNucleus); // for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) {
nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; // IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx];
} // int ix2 = GetNucleusIndex(nuclei, arrayNucleus);
} // clonedNucleusArray.nuclei[arrayIx] = clonedNuclei[ix2];
synapseNucleus.array = nucleusArray; // }
} // }
} // 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) { // 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 // Sort the nuclei in a correct evaluation order

128
Neuron.cs
View File

@ -7,7 +7,7 @@ using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[Serializable] [Serializable]
public class Neuron : INucleus { public class Neuron : Nucleus, INucleus {
public Neuron(Cluster parent, string name) { public Neuron(Cluster parent, string name) {
this.parent = parent; this.parent = parent;
@ -24,30 +24,30 @@ public class Neuron : INucleus {
// Debug.LogError("No neuroid network"); // Debug.LogError("No neuroid network");
} }
[SerializeField] // [SerializeField]
protected string _name; // protected string _name;
public virtual string name { // public virtual string name {
get => _name; // get => _name;
set => _name = value; // set => _name = value;
} // }
[SerializeField] // [SerializeField]
private List<Synapse> _synapses = new(); // private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses; // public List<Synapse> synapses => _synapses;
[SerializeReference] // [SerializeReference]
private List<INucleus> _receivers = new(); // private List<INucleus> _receivers = new();
public List<INucleus> receivers { // public List<INucleus> receivers {
get { return _receivers; } // get { return _receivers; }
set { _receivers = value; } // set { _receivers = value; }
} // }
[SerializeReference] // [SerializeReference]
private NucleusArray _array; // private NucleusArray _array;
public NucleusArray array { // public NucleusArray array {
get { return _array; } // get { return _array; }
set { _array = value; } // set { _array = value; }
} // }
#region Serialization #region Serialization
@ -102,8 +102,8 @@ public class Neuron : INucleus {
#region Runtime state (not serialized) #region Runtime state (not serialized)
public ClusterPrefab cluster { get; set; } // public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; } // public Cluster parent { get; set; }
#region Activation #region Activation
@ -153,35 +153,35 @@ public class Neuron : INucleus {
#endregion Activation #endregion Activation
protected float3 _outputValue; // protected float3 _outputValue;
public virtual float3 outputValue { // public virtual float3 outputValue {
get { return _outputValue; } // get { return _outputValue; }
set { // set {
this.stale = 0; // this.stale = 0;
// this._isSleeping = false; // // this._isSleeping = false;
_outputValue = value; // _outputValue = value;
} // }
} // }
[NonSerialized] // [NonSerialized]
private int stale = 1000; // private int stale = 1000;
// private bool _isSleeping = false; // private bool _isSleeping = false;
// public bool isSleeping => _isSleeping; // public bool isSleeping => _isSleeping;
public bool isSleeping => lengthsq(this.outputValue) == 0; // public bool isSleeping => lengthsq(this.outputValue) == 0;
public void UpdateNuclei() { // public void UpdateNuclei() {
this.stale++; // this.stale++;
// this._isSleeping = this.stale > 2; // // this._isSleeping = this.stale > 2;
// if (isSleeping) // // if (isSleeping)
if (this.stale > 2) // if (this.stale > 2)
_outputValue = Vector3.zero; // _outputValue = Vector3.zero;
} // }
#endregion Runtime state #endregion Runtime state
// this clone the nucleus without the synapses and receivers // 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) { Neuron clone = new(newParent, this.name) {
array = null, array = null,
curve = this.curve, curve = this.curve,
@ -192,7 +192,7 @@ public class Neuron : INucleus {
return clone; return clone;
} }
public virtual IReceptor Clone() { public override IReceptor Clone() {
Neuron clone = new(this.cluster, this.name) { Neuron clone = new(this.cluster, this.name) {
array = this.array, array = this.array,
curve = this.curve, curve = this.curve,
@ -213,22 +213,22 @@ public class Neuron : INucleus {
return clone; return clone;
} }
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { // public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
this._receivers.Add(receivingNucleus); // this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight); // receivingNucleus.AddSynapse(this, weight);
} // }
public void RemoveReceiver(INucleus receiverNucleus) { // public void RemoveReceiver(INucleus receiverNucleus) {
this._receivers.RemoveAll(receiver => receiver == receiverNucleus); // this._receivers.RemoveAll(receiver => receiver == receiverNucleus);
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); // receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
} // }
public static void Delete(INucleus nucleus) { public static void Delete(INucleus nucleus) {
foreach (Synapse synapse in nucleus.synapses) { foreach (Synapse synapse in nucleus.synapses) {
if (synapse.nucleus is Neuron synapse_nucleus) { 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 // there is another nucleus feeding into this input nucleus
synapse_nucleus._receivers.RemoveAll(r => r == nucleus); synapse_nucleus.receivers.RemoveAll(r => r == nucleus);
} }
else { else {
// No other links, delete it. // No other links, delete it.
@ -247,11 +247,11 @@ public class Neuron : INucleus {
} }
} }
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { // public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight); // Synapse synapse = new(sendingNucleus, weight);
this.synapses.Add(synapse); // this.synapses.Add(synapse);
return synapse; // return synapse;
} // }
// public virtual void UpdateState() { // public virtual void UpdateState() {
// //UpdateState(new float3(0, 0, 0)); // //UpdateState(new float3(0, 0, 0));
@ -296,10 +296,10 @@ public class Neuron : INucleus {
// UpdateResult(result); // UpdateResult(result);
// } // }
public virtual void UpdateStateIsolated() { // public virtual void UpdateStateIsolated() {
UpdateStateIsolated(new float3(0, 0, 0)); // UpdateStateIsolated(new float3(0, 0, 0));
} // }
public virtual void UpdateStateIsolated(float3 bias) { public override void UpdateStateIsolated(float3 bias) {
float3 sum = bias; float3 sum = bias;
int n = 0; int n = 0;

105
Nucleus.cs Normal file
View File

@ -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<Synapse> _synapses = new();
public List<Synapse> 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<INucleus> _receivers = new();
public List<INucleus> 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
}

2
Nucleus.cs.meta Normal file
View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4310eea6ab77628b085387a226c1c386

View File

@ -9,8 +9,8 @@ public class SelectorBrain : NanoBrain {
public Receptor receptor2; public Receptor receptor2;
protected void Awake() { protected void Awake() {
receptor1 = Receptor.CreateReceptor(this.brain, "Selector"); receptor1 = new Receptor(this.brain, "Receptor", "Selector");
receptor2 = Receptor.CreateReceptor(this.brain, "Selector"); receptor2 = new Receptor(this.brain, "Receptor", "Selector");
} }
protected void Update() { protected void Update() {