151 lines
6.4 KiB
C#
151 lines
6.4 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 {
|
|
|
|
public Cluster cluster;
|
|
/*
|
|
/// 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) {
|
|
return cluster.GetNucleus(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() {
|
|
this.cluster.nuclei ??= new List<Nucleus>();
|
|
if (this.cluster.nuclei.Count <= 0)
|
|
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
|
// 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 is Neuron neuron) {
|
|
if (neuron.synapses != null) {
|
|
HashSet<Synapse> visitedSynapses = new();
|
|
foreach (Synapse synapse in neuron.synapses) {
|
|
if (synapse != null && synapse.neuron != null) {
|
|
visitedSynapses.Add(synapse);
|
|
if (synapse.neuron is Nucleus synapse_nucleus)
|
|
MarkNuclei(visitedNuclei, synapse_nucleus);
|
|
}
|
|
}
|
|
neuron.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
|
}
|
|
if (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;
|
|
// }
|
|
}
|
|
|
|
}
|