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
142 lines
5.5 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
}
|