using System.Collections.Generic; using UnityEngine; namespace NanoBrain { /// /// The Unity ScriptableObject to implement re-usable Cluster Prefabs /// [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 nuclei = new(); /// /// The output of this cluster /// /// This only returens the first(default) nucleus. Use outputs[0] instead public virtual Nucleus output => this.nuclei[0] as Nucleus; /// /// The nuclei in this cluster which are meant for receiving signals from outside the cluster /// /// This is currently the nuclei which do not have any incoming synapse public List _inputs = null; public virtual List 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; } } /// /// The nuclei in this cluster which are meant for sending signals onward /// private List _outputs = null; public List outputs { get { if (this._outputs == null) RefreshOutputs(); return this._outputs; } } /// /// Redetermine the outpus in the cluster /// 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); } } */ /// /// Retrieve a nucleus in this cluster /// /// The name of the nucleus /// The Nucleus with the given name or null if no such Nucleus could be found 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.prefab = this; this.cluster.name = this.name; this.cluster.nuclei ??= new List(); if (this.cluster.nuclei.Count <= 0) new Neuron(this.cluster, "Output"); // Every cluster should have at least 1 neuron this.cluster.instanceCount = 1; // nuclei ??= new List(); // if (nuclei.Count == 0) // new Neuron(this, "Output"); // Every cluster should have at least 1 neuron } public void GarbageCollection() { // HashSet 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 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 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 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; // } } }