148 lines
5.4 KiB
C#
148 lines
5.4 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
|
public class ClusterPrefab : ScriptableObject {
|
|
|
|
//public virtual Cluster cluster {get;set;}
|
|
|
|
// The ScriptableObject asset from which the runtime object has been created
|
|
//public Cluster asset;
|
|
|
|
[SerializeReference]
|
|
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 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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
// Deep clone a nucleus with its connections
|
|
public virtual ClusterPrefab Clone() {
|
|
ClusterPrefab clone = Instantiate(this);
|
|
clone.nuclei = new();
|
|
// foreach (IReceptor nucleus in this.nuclei)
|
|
// nucleus.CloneTo(clone);
|
|
|
|
IReceptor[] nucleiArray = this.nuclei.ToArray();
|
|
// first clone the nuclei without their connections
|
|
foreach (IReceptor nucleus in this.nuclei)
|
|
nucleus.ShallowCloneTo(clone);
|
|
IReceptor[] clonedNuclei = clone.nuclei.ToArray();
|
|
|
|
// Now clone the connections
|
|
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
|
|
IReceptor receptor = nucleiArray[nucleusIx];
|
|
IReceptor clonedReceptor = clonedNuclei[nucleusIx];
|
|
if (clonedReceptor == null)
|
|
continue;
|
|
|
|
// Copy the synapses
|
|
if (receptor is INucleus nucleus) {
|
|
foreach (Synapse synapse in nucleus.synapses) {
|
|
if (clonedReceptor is not INucleus clonedNucleus)
|
|
continue;
|
|
|
|
int ix = GetNucleusIndex(nucleiArray, synapse.nucleus);
|
|
if (ix < 0)
|
|
continue;
|
|
IReceptor clonedSynapseNucleus = clonedNuclei[ix];
|
|
if (clonedSynapseNucleus == null)
|
|
continue;
|
|
|
|
clonedNucleus.AddSynapse(clonedSynapseNucleus, synapse.weight);
|
|
}
|
|
}
|
|
// Copy the receivers
|
|
foreach (INucleus receiver in nucleiArray[nucleusIx].receivers) {
|
|
int ix = GetNucleusIndex(nucleiArray, receiver);
|
|
if (ix < 0)
|
|
continue;
|
|
|
|
if (clonedNuclei[ix] is not INucleus clonedReceiver)
|
|
continue;
|
|
|
|
clonedReceptor.AddReceiver(clonedReceiver);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
*/
|
|
// 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<IReceptor>();
|
|
if (nuclei.Count == 0)
|
|
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
|
}
|
|
|
|
public void GarbageCollection() {
|
|
HashSet<INucleus> visitedNuclei = new();
|
|
MarkNuclei(visitedNuclei, this.output);
|
|
//Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
|
this.nuclei.RemoveAll(nucleus => nucleus is INucleus n && visitedNuclei.Contains(n) == false);
|
|
}
|
|
|
|
public void MarkNuclei(HashSet<INucleus> visitedNuclei, INucleus nucleus) {
|
|
if (nucleus is null)
|
|
return;
|
|
|
|
visitedNuclei.Add(nucleus);
|
|
if (nucleus.synapses != null) {
|
|
HashSet<Synapse> visitedSynapses = new();
|
|
foreach (Synapse synapse in nucleus.synapses) {
|
|
if (synapse != null && synapse.nucleus != null) {
|
|
visitedSynapses.Add(synapse);
|
|
if (synapse.nucleus is INucleus synapse_nucleus)
|
|
MarkNuclei(visitedNuclei, synapse_nucleus);
|
|
}
|
|
}
|
|
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
|
}
|
|
if (nucleus.receivers != null) {
|
|
HashSet<INucleus> visitedReceivers = new();
|
|
foreach (INucleus receiver in nucleus.receivers) {
|
|
if (receiver != null && receiver != null) {
|
|
visitedReceivers.Add(receiver);
|
|
visitedNuclei.Add(receiver);
|
|
}
|
|
}
|
|
nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
|
}
|
|
}
|
|
|
|
public virtual void UpdateNuclei() {
|
|
foreach (IReceptor nucleus in this.nuclei)
|
|
nucleus.UpdateNuclei();
|
|
}
|
|
} |