Pascal Serrarens 4ae9a15fc6 Squashed 'NanoBrain/' changes from 832d849..cc9a845
cc9a845 Fix sleeping for product combinator
e4ba7f8 Better cross-cluster monitoring
4f8a6ab Improved (but not fixed) cross-cluster monitoring
b12616b Fix neuron output visualisation
96439cc Visualize all outputs
d583e67 WIP cluster references/instance
04bab92 Fix links to multiple cluster neurons & cleanup
e17a249 Cross-cluster editor links
0ab2d21 Migrating and cleaning up
b6630ad First steps to using instanceCount for clusters
8801fa2 Cluster reimport fixes
befb69d full graph with collapsed clusters
1a1919f Fix expansion of clsuter arrays
c708f4d Improved clusterarray support
c2e4e1b Fix Cluster array extension
02047a4 Adde full graph scrollbar
471ed36 Completed full graph integration
830e3e7 Added full graph view mode
249e888 Improve full graph view
308a6a1 The Entities are battling
75d9d1c Cleanup
c8f0f0c Fix aging of neurons
e2e169c small fixes
619ced6 Removed the use of Receptors
19f9296 Simplifications
bc0a796 Integrated clusterarray in cluster
e40dd23 Fixed clusterViewer for clusterarrays
b0f4b41 Status quo adding clusterArrays
1fc75a8 Added ClusterArray
0023920 Cover seeking(-ish) behaviour
1c7b8e7 Added Tanh Activation
a99d40c BrainViewer added
db43655 Pew pew!
18ef4cd Merge commit '89017475984bbbf1899fb38846c5bb0e7775dedd' into NanoBrain

git-subtree-dir: NanoBrain
git-subtree-split: cc9a845b643ffb4a9abe4f7da787ac5c5b14dae8
2026-04-23 15:22:02 +02:00

142 lines
5.5 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace NanoBrain {
/// <summary>
/// The Unity ScriptableObject to implement re-usable Cluster Prefabs
/// </summary>
[CreateAssetMenu(menuName = "Passer/Cluster")]
public class ClusterPrefab : ScriptableObject {
/// The nuclei in this cluster
[SerializeReference]
// This list should not include any clusters...
public List<Nucleus> nuclei = new();
/// <summary>
/// The output of this cluster
/// </summary>
/// <deprecated>This only returens the first(default) nucleus. Use outputs[0] instead</deprecated>
public virtual Nucleus output => this.nuclei[0] as Nucleus;
/// <summary>
/// The nuclei in this cluster which are meant for receiving signals from outside the cluster
/// </summary>
/// <remark>This is currently the nuclei which do not have any incoming synapse</remark>
public List<Nucleus> _inputs = null;
public virtual List<Nucleus> inputs {
get {
if (this._inputs == null) {
this._inputs = new();
foreach (Nucleus receptor in this.nuclei) {
if (receptor is Nucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
}
}
return this._inputs;
}
}
/// <summary>
/// The nuclei in this cluster which are meant for sending signals onward
/// </summary>
private List<Nucleus> _outputs = null;
public List<Nucleus> outputs {
get {
if (this._outputs == null)
RefreshOutputs();
return this._outputs;
}
}
/// <summary>
/// Redetermine the outpus in the cluster
/// </summary>
public void RefreshOutputs() {
this._outputs = new();
foreach (Nucleus nucleus in this.nuclei) {
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
this._outputs.Add(nucleus);
}
}
/// <summary>
/// Retrieve a nucleus in this cluster
/// </summary>
/// <param name="nucleusName">The name of the nucleus</param>
/// <returns>The Nucleus with the given name or null if no such Nucleus could be found</returns>
public Nucleus GetNucleus(string nucleusName) {
foreach (Nucleus nucleus in this.nuclei) {
if (nucleus.name == nucleusName)
return nucleus;
}
return null;
}
// Call this function to ensure that there is at least one nucleus
// This is an invariant and should be ensured before the nucleus is used
// because output requires it.
public void EnsureInitialization() {
nuclei ??= new List<Nucleus>();
if (nuclei.Count == 0)
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
}
public void GarbageCollection() {
HashSet<Nucleus> visitedNuclei = new();
foreach (Nucleus output in this.outputs)
MarkNuclei(visitedNuclei, output);
//Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
}
public void MarkNuclei(HashSet<Nucleus> visitedNuclei, Nucleus nucleus) {
if (nucleus is null)
return;
if (nucleus.parent != null && nucleus.parent.prefab != this)
visitedNuclei.Add(nucleus.parent);
else
visitedNuclei.Add(nucleus);
if (nucleus.synapses != null) {
HashSet<Synapse> visitedSynapses = new();
foreach (Synapse synapse in nucleus.synapses) {
if (synapse != null && synapse.neuron != null) {
visitedSynapses.Add(synapse);
if (synapse.neuron is Nucleus synapse_nucleus)
MarkNuclei(visitedNuclei, synapse_nucleus);
}
}
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
}
if (nucleus is Neuron neuron && neuron.receivers != null) {
HashSet<Nucleus> visitedReceivers = new();
foreach (Nucleus receiver in neuron.receivers) {
if (receiver != null && receiver != null) {
visitedReceivers.Add(receiver);
visitedNuclei.Add(receiver);
}
}
neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
}
}
public virtual void UpdateNuclei() {
foreach (Nucleus nucleus in this.nuclei)
nucleus.UpdateNuclei();
}
public int GetNucleusIndex(Nucleus receiver) {
int ix = 0;
foreach (Nucleus nucleus in this.nuclei) {
if (receiver == nucleus)
return ix;
ix++;
}
return -1;
}
}
}