Compare commits

..

100 Commits

Author SHA1 Message Date
91c4500b0a Fixed the evaluation order 2026-01-30 12:46:29 +01:00
b4f8e5a4d8 Add topological evaluation order 2026-01-30 12:05:44 +01:00
9ae3607911 Cleanup 2026-01-30 11:33:52 +01:00
8a414816e5 subcluster seems to work 2026-01-30 11:05:00 +01:00
728ef1767c Each boid now has its own brain (but output is still not correct) 2026-01-30 10:10:37 +01:00
5cb9e788a4 Cluster no longer clones ClusterPrefab 2026-01-29 17:41:55 +01:00
b60fc19d96 Simplyfying 2026-01-29 12:31:23 +01:00
d754457a14 The subcluster is producing (wrong) results 2026-01-29 11:48:49 +01:00
5aedb30d36 It runs without errors (not working functionaltiy yet) 2026-01-29 11:30:33 +01:00
e7dd1e50cb Merge commit '595a7be03d5dbc8d4f7da28c55c676105ad91799' as 'Assets/NanoBrain' 2026-01-29 09:11:13 +01:00
92c301b850 Cleanup 2026-01-29 09:11:09 +01:00
5ab15926e4 Delete Nanobrain to prep for subtree 2026-01-29 09:10:48 +01:00
866dee0b56 Updated Velocity asset 2026-01-29 09:01:43 +01:00
33f5af32d1 Move to ClusterPfab 2026-01-28 17:44:18 +01:00
96ed53312d Improve custer/clusterinstance 2026-01-28 14:34:52 +01:00
296b80453f Adding synapse to cluster 2026-01-27 19:31:44 +01:00
8d1a4c3b72 Add memory cell 2026-01-26 20:59:17 +01:00
f4559efe40 Further cleanup 2026-01-26 20:06:13 +01:00
c1e6df8df3 Cleanup 2026-01-26 20:02:07 +01:00
f0da7c9c9b ClusterInstance is working a bit 2026-01-21 20:39:07 +01:00
8b8e5fc33c Starting with clusterinstance 2026-01-21 17:21:06 +01:00
b556aa62fc Improved subcluster support 2026-01-21 16:52:46 +01:00
c6d9f727c0 Fix nullptr in nucleusarray 2026-01-21 15:35:17 +01:00
f309d4cec6 Fix clusterarray 2026-01-21 15:31:48 +01:00
4b72e6c712 First setup 2026-01-21 15:17:25 +01:00
14436cbfba Reliable output vector draw line 2026-01-21 13:41:50 +01:00
f2d20dd462 weight tuninh 2026-01-14 21:53:20 +01:00
e568759d40 improved synapse coloring 2026-01-14 21:37:04 +01:00
78e750925d Improved array UI 2026-01-14 20:29:02 +01:00
394df2167d Initial nucleus array UI 2026-01-13 17:18:03 +01:00
4f2f230335 Nucleus+Neuroid->Neuron, improved Receptor support 2026-01-13 16:33:16 +01:00
5f6ec71c7b move to float3 (to prep for SIMD) 2026-01-12 17:45:46 +01:00
3a67652578 Fix resizing neuron array 2026-01-12 17:31:36 +01:00
b3823ac2e6 Cleanup 2026-01-12 16:13:07 +01:00
e477ce4814 (re)added nucleus arrays 2026-01-12 16:06:12 +01:00
90350b625b It works again (without nucleus array) 2026-01-12 12:30:08 +01:00
beb88f8214 WIP cluster redesign 2026-01-12 09:56:49 +01:00
c64ccb246c Added Cluster & INucleus 2026-01-09 17:08:11 +01:00
1b5a86ce55 Improve UI style 2026-01-09 12:06:49 +01:00
Pascal Serrarens
f8dc4dc5d3 Add identity cluster 2026-01-09 10:56:16 +01:00
Pascal Serrarens
de7503bb4a Add perception array UI 2026-01-09 10:08:06 +01:00
Pascal Serrarens
5206469764 Improved network 2026-01-08 17:41:43 +01:00
Pascal Serrarens
600ecd5406 Moved activation function to after weight application 2026-01-08 14:09:31 +01:00
Pascal Serrarens
b9b942760b pre: activation function to synapse neuron 2026-01-07 17:16:35 +01:00
Pascal Serrarens
cd74c312dc neuroid value as Vector3 2026-01-07 16:43:38 +01:00
Pascal Serrarens
5dbb5654a1 Performance tweaking 2026-01-07 15:30:05 +01:00
Pascal Serrarens
6341d827e9 Spherical UpdateState (finally) 2026-01-07 14:51:15 +01:00
Pascal Serrarens
cd6ec2ee1e Merge commit '1855aa0705deb54be7886fd6572bf186365559a6' 2026-01-07 14:33:47 +01:00
Pascal Serrarens
1855aa0705 Squashed 'Assets/NanoBrain/LinearAlgebra/' changes from 672f8bf..a0bbb5b
a0bbb5b Improve unit tests
f3044db Add more ToString
e64eaa2 Fix direction  To Unity Vector3
3bcd212 Fixed Spherical.ToVector3
a232385 Merge commit '841d923fed686700610a85aeab6289e44239aa6c'

git-subtree-dir: Assets/NanoBrain/LinearAlgebra
git-subtree-split: a0bbb5b5dd2e938be6d8a516bb69eb1130c4a51d
2026-01-07 14:33:10 +01:00
Pascal Serrarens
19318796da Fix direction To Unity Vector3 2026-01-07 14:30:54 +01:00
Pascal Serrarens
ccf0b16136 Fixed Spherical.ToVector3 2026-01-07 12:21:12 +01:00
Pascal Serrarens
f8fc9dabe6 Merge commit '841d923fed686700610a85aeab6289e44239aa6c' 2026-01-07 12:20:59 +01:00
Pascal Serrarens
841d923fed Squashed 'Assets/NanoBrain/LinearAlgebra/' changes from 15c08f2..672f8bf
672f8bf Spherical Average
a278b7d Fix/Improve ToVector3
09d34d1 Prepare for spherical average
b19e504 (A little) Performance improvements
2b0433f Fix normalizing direction
3e115cc Fix Direction.ToVector3
0eeedd2 Vector3 conversion fixes
3024562 Fix Unity warnings
aa23d57 Fix roaming boid
cdfe039 Improve Unity compatibility

git-subtree-dir: Assets/NanoBrain/LinearAlgebra
git-subtree-split: 672f8bfca1b1e0bc312df41142fa3c4447ce6dba
2026-01-07 11:33:48 +01:00
Pascal Serrarens
28c1fac3f8 Updated swarming brain 2026-01-07 09:53:16 +01:00
Pascal Serrarens
d026996ce2 Prepare for spherical average 2026-01-06 17:18:31 +01:00
Pascal Serrarens
1e1e5b1344 Further cleanup 2026-01-06 15:48:51 +01:00
Pascal Serrarens
a22e4b149a Cleanup 2026-01-06 15:44:31 +01:00
Pascal Serrarens
2134495045 (A little) Performance improvements 2026-01-06 15:03:52 +01:00
Pascal Serrarens
14a786246c Simplifying stale nuclei 2026-01-05 17:55:09 +01:00
Pascal Serrarens
11ecb905ee Cleanup 2026-01-05 17:46:47 +01:00
Pascal Serrarens
61bdc36e84 Using velocity receptor 2026-01-05 17:04:49 +01:00
Pascal Serrarens
cb8c9dbb7c Better swarm control 2026-01-05 15:35:39 +01:00
Pascal Serrarens
bb39435892 Fix Direction.ToVector3 2026-01-05 14:39:08 +01:00
Pascal Serrarens
c86b01ae57 Updating swarm weights 2026-01-05 13:04:53 +01:00
Pascal Serrarens
a1d1f7ba24 Vector3 conversion fixes 2026-01-05 11:34:41 +01:00
Pascal Serrarens
d102fc7b80 Fix Unity warnings 2026-01-05 11:26:13 +01:00
Pascal Serrarens
3611de5142 Fix roaming boid 2026-01-05 11:12:22 +01:00
Pascal Serrarens
a91bd6dfee Improve Unity compatibility 2026-01-05 11:02:02 +01:00
Pascal Serrarens
91950a2d19 Add linearAlgebra subtree 2026-01-05 10:55:43 +01:00
Pascal Serrarens
220e1e4ead Squashed 'Assets/NanoBrain/LinearAlgebra/' content from commit 15c08f2
git-subtree-dir: Assets/NanoBrain/LinearAlgebra
git-subtree-split: 15c08f215655988682ecc6207c2783fa047b65e3
2026-01-05 10:55:07 +01:00
Pascal Serrarens
e693ee5ceb Merge commit '220e1e4ead6d3b8a75c515d83995e6e5a4ec42bc' as 'Assets/NanoBrain/LinearAlgebra' 2026-01-05 10:55:07 +01:00
Pascal Serrarens
de74789cb5 Removed linearAlgebra submodule 2026-01-05 10:55:01 +01:00
Pascal Serrarens
a500a9e16e Move to Spherical outputvalue 2025-12-23 09:19:05 +01:00
65359ecbfa Needs tuning 2025-12-17 12:41:25 +01:00
0cee652110 Separation/Cohesion curve 2025-12-17 09:28:34 +01:00
76af037a01 Added curves 2025-12-12 16:00:23 +01:00
0adb71f306 (Dis)connect perceptoids 2025-12-11 17:37:01 +01:00
4e8d10f1bd Perceptoid pool starts to work 2025-12-11 16:50:03 +01:00
dc8ac7ef9b Improved receptor, percepoid sleep 2025-12-11 15:19:24 +01:00
21751f8cea Brain object 2025-12-11 12:27:55 +01:00
86b5053383 cleanup 2025-12-05 16:41:11 +01:00
605bdfc629 Scriptable nanobrain 2025-12-05 15:29:18 +01:00
5a9aa7161b Scriptable Object nanobrain editor 2025-12-04 12:55:55 +01:00
69c6b1e2b7 Almost flocking 2025-12-03 18:02:25 +01:00
ca48381dc2 Add neuroid details in inspector 2025-12-03 16:00:53 +01:00
fc4e1ea889 Fix boundary velocityneuroid to alignment 2025-12-03 15:54:16 +01:00
a3d49e330f removed synapse type 2025-12-03 15:15:42 +01:00
145e033d4c Simplified synapses, NanoBrain component 2025-12-03 10:16:36 +01:00
9a6ae0e071 More nucleus like neurons 2025-12-02 17:34:05 +01:00
88bf20b9c2 Neuroid is a Nucleus 2025-12-02 12:26:13 +01:00
2bae70fae2 boundary using Avoidance Nucleus 2025-12-02 11:15:29 +01:00
bb5939b6ab new boundary perception 2025-12-01 17:37:43 +01:00
fdabad2895 Move more towards pure neuroids 2025-11-28 17:15:49 +01:00
7ce787f5db Refactoring 2025-11-27 17:35:51 +01:00
1771ab7d23 Boids seem to work, but don't flock together 2025-11-27 14:08:24 +01:00
2e803179e3 improved sensoryneuroids 2025-11-26 17:40:06 +01:00
cb04a7645b Assed SensoryNeuroid 2025-11-26 15:48:00 +01:00
d91057cf97 WIP: NaN error because zero distance 2025-11-25 16:19:26 +01:00
6ded599bb8 WIP: Added boundary 2025-11-25 14:28:08 +01:00
ad410fd193 Initial commit 2025-11-25 09:25:11 +01:00
12 changed files with 399 additions and 271 deletions

View File

@ -4,12 +4,9 @@ using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[System.Serializable] [Serializable]
public class Cluster : INucleus { public class Cluster : INucleus {
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
public readonly ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
[SerializeField] [SerializeField]
protected string _name; protected string _name;
@ -18,17 +15,113 @@ public class Cluster : INucleus {
set => _name = value; set => _name = value;
} }
// Hmm, a cluster instance can never be part of a scriptable object...(Cluster) #region Init
public Cluster(ClusterPrefab parent, ClusterPrefab prefab) {
public Cluster(ClusterPrefab prefab, Cluster parent) {
this.prefab = prefab; this.prefab = prefab;
this.name = prefab.name;
this.parent = parent;
this.parent?.nuclei.Add(this);
ClonePrefab();
this.sortedNuclei = TopologicalSort(this.nuclei);
}
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
this.prefab = prefab;
this.name = prefab.name;
this.cluster = parent; this.cluster = parent;
if (this.cluster != null) if (this.cluster != null)
this.cluster.nuclei.Add(this); this.cluster.nuclei.Add(this);
// foreach (IReceptor nucleus in this.prefab.nuclei) { ClonePrefab();
// IReceptor clone = nucleus.CloneTo(null); this.sortedNuclei = TopologicalSort(this.nuclei);
// this.dynamicNuclei.Add(clone); }
// public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
// this.prefab = realPrefab;
// this.name = realPrefab.name;
// this.cluster = parent;
// if (this.cluster != null)
// this.cluster.nuclei.Add(this);
// ClonePrefab();
// } // }
private void ClonePrefab() {
IReceptor[] nucleiArray = this.prefab.nuclei.ToArray();
// first clone the nuclei without their connections
foreach (IReceptor nucleus in this.prefab.nuclei)
nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
IReceptor receptor = nucleiArray[nucleusIx];
IReceptor clonedSender = clonedNuclei[nucleusIx];
if (clonedSender == null)
continue;
// Copy the receivers, which will also create the synapses
foreach (INucleus receiver in receptor.receivers) {
int ix = GetNucleusIndex(nucleiArray, receiver);
if (ix < 0)
continue;
if (clonedNuclei[ix] is not INucleus clonedReceiver)
continue;
// Find the synapse for the weight
float weight = 1;
foreach (Synapse synapse in receiver.synapses) {
if (synapse.nucleus == receptor) {
weight = synapse.weight;
break;
}
}
clonedSender.AddReceiver(clonedReceiver, weight);
}
}
}
// Sort the nuclei in a correct evaluation order
private List<IReceptor> TopologicalSort(List<IReceptor> nodes) {
Dictionary<IReceptor, int> inDegree = new();
foreach (IReceptor node in nodes)
inDegree[node] = 0; // Initialize in-degree to zero
// Calculate in-degrees
foreach (IReceptor node in nodes) {
foreach (INucleus receiver in node.receivers)
inDegree[receiver]++;
}
Queue<IReceptor> queue = new();
foreach (IReceptor node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node);
}
List<IReceptor> sortedOrder = new();
while (queue.Count > 0) {
IReceptor current = queue.Dequeue();
sortedOrder.Add(current); // Process the node
foreach (INucleus receiver in current.receivers) {
inDegree[receiver]--;
if (inDegree[receiver] == 0) // If all dependencies resolved
queue.Enqueue(receiver);
}
}
// Check for cycles in the graph
if (sortedOrder.Count != nodes.Count)
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
return sortedOrder;
} }
public virtual IReceptor Clone() { public virtual IReceptor Clone() {
@ -46,6 +139,59 @@ public class Cluster : INucleus {
return clone; return clone;
} }
public IReceptor ShallowCloneTo(Cluster parent) {
Cluster clone = new(this.prefab, parent) {
name = this.name,
};
return clone;
}
private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) {
for (int i = 0; i < nucleiArray.Length; i++) {
if (nucleus == nucleiArray[i])
return i;
}
return -1;
}
#endregion Init
public ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; }
[SerializeReference]
public List<IReceptor> nuclei = new();
// the nuclei sorted using topological sorting
// to ensure that the cluster is computer in the right order
public List<IReceptor> sortedNuclei;
public List<INucleus> _inputs = null;
public virtual List<INucleus> inputs {
get {
if (this._inputs == null) {
this._inputs = new();
foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
}
}
return this._inputs;
}
}
public virtual INucleus output {//=> this.nuclei[0] as INucleus;
get {
if (this.nuclei.Count > 0)
return this.nuclei[0] as INucleus;
return null;
}
}
// Not sure if this belongs here... // Not sure if this belongs here...
[SerializeReference] [SerializeReference]
private NucleusArray _array; private NucleusArray _array;
@ -56,27 +202,14 @@ public class Cluster : INucleus {
#region Synapses #region Synapses
// class ClusterSynapse : Synapse {
// public IReceptor receptor;
// public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) {
// this.receptor = receptor;
// }
// }
[SerializeField] [SerializeField]
private List<Synapse> _synapses = new(); private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses; public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(IReceptor sendingNucleus) { public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]); Synapse synapse = new(sendingNucleus, weight);
this._synapses.Add(synapse); this._synapses.Add(synapse);
return synapse; return synapse;
// else {
// INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName);
// ClusterSynapse synapse = new(sendingNucleus, receptor);
// receptor.AddSynapse(sendingNucleus);
// }
// // Add synapse to which neuron?
// return null;
} }
// Does this even exist already? // Does this even exist already?
@ -95,9 +228,9 @@ public class Cluster : INucleus {
set { _receivers = value; } set { _receivers = value; }
} }
public virtual void AddReceiver(INucleus receivingNucleus) { public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this); receivingNucleus.AddSynapse(this, weight);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -105,48 +238,6 @@ public class Cluster : INucleus {
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
} }
// public void AddReceiver(INucleus receivingNucleus) {
// int newLength = this._receivers.Count + 1;
// INucleus[] newReceivers = new INucleus[newLength];
// // Copy the existing receivers
// for (int ix = 0; ix < this._receivers.Count; ix++)
// newReceivers[ix] = this._receivers[ix];
// // Add the new receivers
// newReceivers[this._receivers.Count] = receivingNucleus;
// // Replace the receivers with the new receivers
// this._receivers = new(newReceivers);
// receivingNucleus.AddSynapse(this);
// }
// public void RemoveReceiver(INucleus receivingNucleus) {
// Debug.Log("Clusterinstance. remote receiver");
// int newLength = this._receivers.Count - 1;
// if (newLength < 0)
// // Array was empty, so we cannot remove anything
// return;
// INucleus[] newReceivers = new INucleus[newLength];
// int newIx = 0;
// // Copy all receivers except receivingNucleus
// for (int ix = 0; ix < this._receivers.Count; ix++) {
// if (this._receivers[ix] == receivingNucleus)
// // skip the receiver we want to remote
// continue;
// if (newIx >= newLength)
// // We want to copy more elements than expected
// // the receivingNucleus is not found
// // and the original array is returned
// return;
// newReceivers[newIx] = this._receivers[ix];
// newIx++;
// }
// this._receivers = new(newReceivers);
// }
#endregion Receivers #endregion Receivers
#region Runtime #region Runtime
@ -171,16 +262,55 @@ public class Cluster : INucleus {
UpdateState(new float3(0, 0, 0)); UpdateState(new float3(0, 0, 0));
} }
public void UpdateState(float3 inputValue) { public void UpdateState(float3 bias) {
float3 sum = inputValue; // new(0, 0, 0); float3 sum = bias; // new(0, 0, 0);
//Applying the weight factgors //Applying the weight factors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue; sum += synapse.weight * synapse.nucleus.outputValue;
} }
// This does not work because the prefab nucleus does not have a state //this.inputs[0].UpdateState(sum);
this.prefab.inputs[0].UpdateState(sum); this.inputs[0].UpdateStateIsolated(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
UpdateResult(this.output.outputValue);
}
public void UpdateStateIsolated() {
float3 bias = new(0,0,0);
UpdateStateIsolated(bias);
}
public void UpdateStateIsolated(float3 bias) {
float3 sum = bias; // new(0, 0, 0);
//Applying the weight factors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
}
//this.inputs[0].UpdateState(sum);
this.inputs[0].UpdateStateIsolated(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
this.outputValue = this.output.outputValue;
}
public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) {
// //Debug.Log($"insignificant update: {d}");
// return;
// }
this.outputValue = result;
foreach (INucleus receiver in this.receivers)
receiver.UpdateState();
} }
public void UpdateNuclei() { public void UpdateNuclei() {
@ -188,72 +318,12 @@ public class Cluster : INucleus {
if (this.stale > 2) if (this.stale > 2)
_outputValue = Vector3.zero; _outputValue = Vector3.zero;
foreach (IReceptor nucleus in this.prefab.nuclei) //foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (IReceptor nucleus in this.nuclei)
nucleus.UpdateNuclei(); nucleus.UpdateNuclei();
} }
#endregion Update #endregion Update
#endregion Runtime #endregion Runtime
/*
[SerializeField]
private List<IReceptor> _dynamicNuclei;
public List<IReceptor> dynamicNuclei {// = new();
get {
if (_dynamicNuclei == null) {
this._dynamicNuclei = new();
foreach (IReceptor nucleus in this.prefab.nuclei) {
IReceptor clone = nucleus.CloneTo(null);
this._dynamicNuclei.Add(clone);
}
}
return this._dynamicNuclei;
}
}
public List<INucleus> _inputs = null;
public List<INucleus> inputs {
get {
this._inputs = new();
if (this.dynamicNuclei != null) {
foreach (IReceptor receptor in this.dynamicNuclei) {
if (receptor is INucleus nucleus)
this._inputs.Add(nucleus);
}
}
return this._inputs;
}
}
public INucleus output => this.dynamicNuclei[0] as INucleus;
public float3 outputValue => this.output.outputValue;
public IReceptor CloneTo(ClusterPrefab parent) {
Cluster clone = new(parent, this.prefab);
return clone;
}
public IReceptor Clone() {
Cluster clone = new(this.cluster, this.prefab);
return clone;
}
#region Properties
public string name {
get { return prefab.name; }
set { prefab.name = value; }
}
public bool isSleeping => lengthsq(this.outputValue) == 0;
public NucleusArray array { get; set; }
#endregion Properties
*/
} }

View File

@ -4,18 +4,11 @@ using UnityEngine;
[CreateAssetMenu(menuName = "Passer/Cluster")] [CreateAssetMenu(menuName = "Passer/Cluster")]
public class ClusterPrefab : ScriptableObject { public class ClusterPrefab : ScriptableObject {
//public virtual Cluster cluster {get;set;}
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
//public Cluster asset;
[SerializeReference] [SerializeReference]
public List<IReceptor> nuclei = new(); public List<IReceptor> nuclei = new();
// public List<Cluster> subClusters = new();
// public void AddSubCluster(ClusterInstance subCluster) {
// this.nuclei.Add(subCluster);
// }
public virtual INucleus output => this.nuclei[0] as INucleus; public virtual INucleus output => this.nuclei[0] as INucleus;
@ -25,10 +18,13 @@ public class ClusterPrefab : ScriptableObject {
if (this._inputs == null) { if (this._inputs == null) {
this._inputs = new(); this._inputs = new();
foreach (IReceptor receptor in this.nuclei) { foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) if (receptor is INucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus); this._inputs.Add(nucleus);
} }
} }
}
return this._inputs; return this._inputs;
} }
} }

View File

@ -10,7 +10,7 @@ public interface INucleus : IReceptor {
// Senders // Senders
public List<Synapse> synapses { get; } public List<Synapse> synapses { get; }
public Synapse AddSynapse(IReceptor sender); public Synapse AddSynapse(IReceptor sender, float weight = 1.0f);
public NucleusArray array { get; set; } public NucleusArray array { get; set; }
@ -20,7 +20,8 @@ public interface INucleus : IReceptor {
public void UpdateState(); public void UpdateState();
public void UpdateState(float3 inputValue); public void UpdateState(float3 inputValue);
public void UpdateStateIsolated();
public void UpdateStateIsolated(float3 inputValue);
#endregion dynamic state #endregion dynamic state
} }
@ -33,7 +34,7 @@ public interface IReceptor {
// Receivers // Receivers
public List<INucleus> receivers { get; set; } public List<INucleus> receivers { get; set; }
public void AddReceiver(INucleus receiver); public void AddReceiver(INucleus receiver, float weight = 1);
public void RemoveReceiver(INucleus receiverNucleus); public void RemoveReceiver(INucleus receiverNucleus);
#endregion static #endregion static
@ -48,7 +49,7 @@ public interface IReceptor {
#endregion dynamic #endregion dynamic
//public IReceptor CloneTo(ClusterPrefab parent); public IReceptor ShallowCloneTo(Cluster parent);
public IReceptor Clone(); public IReceptor Clone();
} }

View File

@ -4,35 +4,38 @@ using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[Serializable] [Serializable]
public class MemoryCell : Neuron { public class MemoryCell : Neuron, INucleus {
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { }
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
// this.parent = parent;
// this.name = name;
// this.parent?.nuclei.Add(this);
// }
#region Parameters public override IReceptor ShallowCloneTo(Cluster newParent) {
MemoryCell clone = new(newParent, this.name) {
// Returns the memorized value weighted by time array = this.array,
// return lastValue * (current time - last time) curve = this.curve,
[SerializeField] curvePreset = this.curvePreset,
public bool deltaValue = false; curveMax = this.curveMax,
average = this.average
#endregion Parameters };
return clone;
}
#region State #region State
private float3 _memorizedValue; private float3 _memorizedValue;
private float _memorizedTime; private float _memorizedTime;
public override void UpdateState() { public override void UpdateState(float3 bias) {
// A memorycell does not have an activation function // A memorycell does not have an activation function
float3 result = new(0, 0, 0); float3 result = bias;
int n = 0; int n = 0;
//Applying the weight factgors //Applying the weight factgors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
result += synapse.weight * synapse.nucleus.outputValue; result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0) if (lengthsq(synapse.nucleus.outputValue) != 0)
n++; n++;
@ -44,14 +47,40 @@ public class MemoryCell : Neuron {
UpdateResult(result); UpdateResult(result);
} }
public override void UpdateStateIsolated() {
float3 bias = new(0, 0, 0);
UpdateStateIsolated(bias);
}
public override void UpdateStateIsolated(float3 bias) {
// A memorycell does not have an activation function
float3 result = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average)
result /= n;
this.outputValue = this._memorizedValue;
// Store the result for the next time
this._memorizedValue = result;
this._memorizedTime = Time.time;
}
public override void UpdateResult(Vector3 result) { public override void UpdateResult(Vector3 result) {
// output value is the previous value // output value is the previous value
if (this.deltaValue) { // if (this.deltaValue) {
float deltaTime = Time.time - this._memorizedTime; // float deltaTime = Time.time - this._memorizedTime;
this._outputValue = this._memorizedValue * deltaTime; // this._outputValue = this._memorizedValue * deltaTime;
} // }
else //else
this._outputValue = this._memorizedValue; this.outputValue = this._memorizedValue;
// Store the result for the next time // Store the result for the next time
this._memorizedValue = result; this._memorizedValue = result;

View File

@ -88,6 +88,7 @@ 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; }
#region Activation #region Activation
@ -153,7 +154,6 @@ public class Neuron : INucleus {
// 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 float lastTime { get; private set; }
public void UpdateNuclei() { public void UpdateNuclei() {
this.stale++; this.stale++;
@ -165,6 +165,11 @@ public class Neuron : INucleus {
#endregion Runtime state #endregion Runtime state
public Neuron(Cluster parent, string name) {
this.parent = parent;
this.name = name;
this.parent?.nuclei.Add(this);
}
public Neuron(ClusterPrefab parent, string name) { public Neuron(ClusterPrefab parent, string name) {
this.cluster = parent; this.cluster = parent;
this.name = name; this.name = name;
@ -175,9 +180,27 @@ public class Neuron : INucleus {
// Debug.LogError("No neuroid network"); // Debug.LogError("No neuroid network");
} }
// public Neuron(string name) { // this clone the nucleus without the synapses and receivers
// this._name = name; public virtual IReceptor ShallowCloneTo(Cluster newParent) {
// } Neuron clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
public virtual IReceptor ShallowCloneTo(ClusterPrefab newParent) {
Neuron clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
public virtual IReceptor CloneTo(ClusterPrefab parent) { public virtual IReceptor CloneTo(ClusterPrefab parent) {
Neuron clone = new(parent, this.name) { Neuron clone = new(parent, this.name) {
@ -187,8 +210,6 @@ public class Neuron : INucleus {
curveMax = this.curveMax, curveMax = this.curveMax,
average = this.average average = this.average
}; };
// if (clone.cluster != null)
// clone.cluster.nuclei.Add(clone);
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
@ -220,9 +241,9 @@ public class Neuron : INucleus {
return clone; return clone;
} }
public virtual void AddReceiver(INucleus receivingNucleus) { public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this); receivingNucleus.AddSynapse(this, weight);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -254,27 +275,25 @@ public class Neuron : INucleus {
} }
} }
public Synapse AddSynapse(IReceptor sendingNucleus) { public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus); 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));
this.parent?.UpdateState();
} }
public virtual void UpdateState(float3 inputValue) { public virtual void UpdateState(float3 inputValue) {
float3 sum = inputValue;//new(0, 0, 0); float3 sum = inputValue;
int n = 0; int n = 0;
//Applying the weight factgors //Applying the weight factgors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
sum += synapse.weight * synapse.nucleus.outputValue; sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0.... // Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0) if (lengthsq(synapse.nucleus.outputValue) != 0)
n++; n++;
@ -305,6 +324,47 @@ public class Neuron : INucleus {
UpdateResult(result); UpdateResult(result);
} }
public virtual void UpdateStateIsolated() {
UpdateStateIsolated(new float3(0, 0, 0));
}
public virtual void UpdateStateIsolated(float3 bias) {
float3 sum = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average && n > 0)
sum /= n;
// Activation function
Vector3 result;
switch (this.curvePreset) {
case CurvePresets.Linear:
result = sum;
break;
case CurvePresets.Sqrt:
result = normalize(sum) * System.MathF.Sqrt(length(sum));
break;
case CurvePresets.Power:
result = normalize(sum) * System.MathF.Pow(length(sum), 2);
break;
case CurvePresets.Reciprocal:
result = normalize(sum) * (1 / length(sum));
break;
default:
float activatedValue = this.curve.Evaluate(length(sum));
result = normalize(sum) * activatedValue;
break;
}
this.outputValue = result;
}
public virtual void UpdateResult(Vector3 result) { public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue); // float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) { // if (d < 0.5f) {
@ -313,7 +373,10 @@ public class Neuron : INucleus {
// } // }
this.outputValue = result; this.outputValue = result;
this.lastTime = Time.time; if (lengthsq(outputValue) != 0) {
Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}");
}
foreach (INucleus receiver in this.receivers) foreach (INucleus receiver in this.receivers)
receiver.UpdateState(); receiver.UpdateState();

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
@ -6,6 +7,7 @@ using static Unity.Mathematics.math;
public class Receptor : IReceptor { public class Receptor : IReceptor {
private ClusterPrefab cluster; private ClusterPrefab cluster;
private Cluster parent;
[SerializeField] [SerializeField]
protected string _name; protected string _name;
@ -14,6 +16,11 @@ public class Receptor : IReceptor {
set => _name = value; set => _name = value;
} }
public Receptor(Cluster parent) {
this.parent = parent;
if (parent != null)
parent.nuclei.Add(this);
}
public Receptor(ClusterPrefab cluster) { public Receptor(ClusterPrefab cluster) {
this.cluster = cluster; this.cluster = cluster;
if (cluster != null) if (cluster != null)
@ -27,15 +34,13 @@ public class Receptor : IReceptor {
this.AddReceiver(nucleus); this.AddReceiver(nucleus);
} }
public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { public static Receptor CreateReceptor(Cluster cluster, string nucleusName) {
if (cluster == null) if (cluster == null)
return null; return null;
Receptor receptor = new(cluster); Receptor receptor = new(cluster);
foreach (INucleus nucleus in cluster.inputs) { foreach (INucleus nucleus in cluster.inputs) {
if (nucleus != null && nucleus.name == nucleusName) { if (nucleus != null && nucleus.name == nucleusName) {
// Receptor receptor = new(cluster, nucleus);
// return receptor;
receptor.AddReceiver(nucleus); receptor.AddReceiver(nucleus);
} }
} }
@ -45,6 +50,15 @@ public class Receptor : IReceptor {
return receptor; return receptor;
} }
public virtual IReceptor ShallowCloneTo(Cluster parent) {
Receptor clone = new(parent);
return clone;
}
public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) {
Receptor clone = new(parent);
return clone;
}
public virtual IReceptor CloneTo(ClusterPrefab parent) { public virtual IReceptor CloneTo(ClusterPrefab parent) {
Receptor clone = new(parent); Receptor clone = new(parent);
@ -84,9 +98,9 @@ public class Receptor : IReceptor {
protected int[] thingIds; // every receiver can handle a thing with this id protected int[] thingIds; // every receiver can handle a thing with this id
public virtual void AddReceiver(INucleus receivingNucleus) { public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this); receivingNucleus.AddSynapse(this, weight);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -122,6 +136,8 @@ public class Receptor : IReceptor {
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
this.localPosition = newLocalPositionVector; this.localPosition = newLocalPositionVector;
if (this._receivers == null)
return;
thingIds ??= new int[this._receivers.Count]; thingIds ??= new int[this._receivers.Count];

View File

@ -11,26 +11,20 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
m_Name: Velocity m_Name: Velocity
m_EditorClassIdentifier: Assembly-CSharp::Cluster m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab
nuclei: nuclei:
- rid: 2243601403683012671 - rid: 2243601425629446539
- rid: 2243601403683012676
references: references:
version: 2 version: 2
RefIds: RefIds:
- rid: -2 - rid: 2243601425629446539
type: {class: , ns: , asm: }
- rid: 2243601403683012671
type: {class: Neuron, ns: , asm: Assembly-CSharp} type: {class: Neuron, ns: , asm: Assembly-CSharp}
data: data:
_name: Output _name: Output
_synapses: _synapses: []
- nucleus:
rid: -2
weight: 1
_receivers: [] _receivers: []
_array: _array:
rid: 2243601403683012672 rid: 2243601425629446540
_curvePreset: 0 _curvePreset: 0
curve: curve:
serializedVersion: 2 serializedVersion: 2
@ -58,51 +52,9 @@ MonoBehaviour:
m_RotationOrder: 4 m_RotationOrder: 4
curveMax: 1 curveMax: 1
average: 0 average: 0
- rid: 2243601403683012672 - rid: 2243601425629446540
type: {class: NucleusArray, ns: , asm: Assembly-CSharp} type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data: data:
_nuclei: _nuclei:
- rid: 2243601403683012671 - rid: 2243601425629446539
name: Output name: Output
- rid: 2243601403683012676
type: {class: Neuron, ns: , asm: Assembly-CSharp}
data:
_name: Position
_synapses: []
_receivers:
- rid: 2243601403683012671
_array:
rid: 2243601403683012677
_curvePreset: 0
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 1
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1000
value: 1000
inSlope: 1
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
curveMax: 1
average: 0
- rid: 2243601403683012677
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data:
_nuclei:
- rid: 2243601403683012676
name: New neuron

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: dd622ac7ed09e70ea8edac595047ac82 guid: c61aecac62c26de4aaefb2612bcc9a5d
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 11400000 mainObjectFileID: 11400000

View File

@ -3,14 +3,14 @@ using UnityEngine;
using System; using System;
using System.Linq; using System.Linq;
public class BrainPickerWindow : EditorWindow { public class ClusterPickerWindow : EditorWindow {
private Vector2 scroll; private Vector2 scroll;
private ClusterPrefab[] items = new ClusterPrefab[0]; private ClusterPrefab[] items = new ClusterPrefab[0];
private Action<ClusterPrefab> onPicked; private Action<ClusterPrefab> onPicked;
private string search = ""; private string search = "";
public static void ShowPicker(Action<ClusterPrefab> onPicked, string title = "Select Cluster") { public static void ShowPicker(Action<ClusterPrefab> onPicked, string title = "Select Cluster") {
var w = CreateInstance<BrainPickerWindow>(); var w = CreateInstance<ClusterPickerWindow>();
w.titleContent = new GUIContent(title); w.titleContent = new GUIContent(title);
w.minSize = new Vector2(360, 320); w.minSize = new Vector2(360, 320);
w.onPicked = onPicked; w.onPicked = onPicked;
@ -21,7 +21,7 @@ public class BrainPickerWindow : EditorWindow {
private void OnEnable() => RefreshList(); private void OnEnable() => RefreshList();
private void RefreshList() { private void RefreshList() {
var guids = AssetDatabase.FindAssets("t:Cluster"); var guids = AssetDatabase.FindAssets("t:ClusterPrefab");
items = guids items = guids
.Select(g => AssetDatabase.LoadAssetAtPath<ClusterPrefab>(AssetDatabase.GUIDToAssetPath(g))) .Select(g => AssetDatabase.LoadAssetAtPath<ClusterPrefab>(AssetDatabase.GUIDToAssetPath(g)))
.Where(b => b != null) .Where(b => b != null)

View File

@ -617,22 +617,22 @@ public class ClusterInspector : Editor {
} }
protected virtual void AddCluster(INucleus nucleus) { protected virtual void AddCluster(INucleus nucleus) {
BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
} }
private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) {
Cluster subclusterInstance = new(this.cluster, subCluster); Cluster subclusterInstance = new(prefab, this.cluster);
//this.cluster.AddSubCluster(subclusterInstance);
//this.cluster.nuclei.Add(subclusterInstance);
subclusterInstance.AddReceiver(nucleus); subclusterInstance.AddReceiver(nucleus);
// This does not work somehow
// this.currentNucleus = subclusterInstance;
// BuildLayers();
} }
private void EditCluster(Cluster subCluster) { private void EditCluster(Cluster subCluster) {
//var currentActiveObject = Selection.activeObject; // May be used with storedPrefab...
Selection.activeObject = subCluster.prefab; Selection.activeObject = subCluster.prefab;
EditorGUIUtility.PingObject(subCluster.prefab); EditorGUIUtility.PingObject(subCluster.prefab);
var editor = Editor.CreateEditor(subCluster.prefab); var editor = Editor.CreateEditor(subCluster.prefab);
//Selection.activeObject = currentActiveObject;
} }
// Connect to another nucleus in the same cluster // Connect to another nucleus in the same cluster

View File

@ -22,8 +22,8 @@ public class NanoBrainComponent_Editor : Editor {
} }
public override VisualElement CreateInspectorGUI() { public override VisualElement CreateInspectorGUI() {
//NanoBrainComponent component = target as NanoBrainComponent; //ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain;
ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; Cluster brain = component.brain;
if (Application.isPlaying == false) if (Application.isPlaying == false)
serializedObject.Update(); serializedObject.Update();
@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor {
}); });
if (brain != null && board != null) if (brain != null && board != null)
board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer); board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer);
// else // else
// Debug.LogWarning(" No brain!"); // Debug.LogWarning(" No brain!");

View File

@ -1,14 +1,15 @@
using System;
using UnityEngine; using UnityEngine;
public class NanoBrainComponent : MonoBehaviour { public class NanoBrainComponent : MonoBehaviour {
public ClusterPrefab defaultBrain; public ClusterPrefab defaultBrain;
private ClusterPrefab brainInstance;
public INucleus root => brainInstance.output; [NonSerialized]
public ClusterPrefab brain { private Cluster brainInstance;
public Cluster brain {
get { get {
if (brainInstance == null && defaultBrain != null) { if (brainInstance == null && defaultBrain != null) {
brainInstance = Instantiate(defaultBrain); brainInstance = new Cluster(defaultBrain); //Instantiate(defaultBrain);
brainInstance.name = defaultBrain.name + " (Instance)"; brainInstance.name = defaultBrain.name + " (Instance)";
SwarmControl sc = FindFirstObjectByType<SwarmControl>(); SwarmControl sc = FindFirstObjectByType<SwarmControl>();
@ -23,7 +24,7 @@ public class NanoBrainComponent : MonoBehaviour {
} }
} }
public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { public static void UpdateWeight(Cluster brain, string name, float weight) {
INucleus root = brain.output; INucleus root = brain.output;
foreach (Synapse synapse in root.synapses) { foreach (Synapse synapse in root.synapses) {
if (synapse.nucleus.name == name) { if (synapse.nucleus.name == name) {