286 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[System.Serializable]
public class Cluster : INucleus {
// The ScriptableObject asset from which the runtime object has been created
[SerializeField]
public ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
[SerializeField]
protected string _name;
public virtual string name {
get => _name;
set => _name = value;
}
public Cluster(ClusterPrefab prefab) {
this.prefab = UnityEngine.Object.Instantiate(prefab);
this.name = prefab.name;
this.cluster = null;
if (this.cluster != null)
this.cluster.nuclei.Add(this);
}
// Hmm, a cluster instance can never be part of a scriptable object...(Cluster)
public Cluster(ClusterPrefab parent, ClusterPrefab prefab) {
this.prefab = prefab.Clone(); //UnityEngine.Object.Instantiate(prefab);
this.name = prefab.name;
this.cluster = parent;
if (this.cluster != null)
this.cluster.nuclei.Add(this);
// foreach (IReceptor nucleus in this.prefab.nuclei) {
// IReceptor clone = nucleus.CloneTo(null);
// this.dynamicNuclei.Add(clone);
// }
}
public virtual IReceptor Clone() {
Neuron clone = new(this.cluster, this.name) {
array = this.array,
};
foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
clonedSynapse.weight = synapse.weight;
}
foreach (INucleus receiver in this.receivers) {
clone.AddReceiver(receiver);
}
return clone;
}
public INucleus output => prefab.output;
// Not sure if this belongs here...
[SerializeReference]
private NucleusArray _array;
public NucleusArray array {
get { return _array; }
set { _array = value; }
}
#region Synapses
// class ClusterSynapse : Synapse {
// public IReceptor receptor;
// public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) {
// this.receptor = receptor;
// }
// }
[SerializeField]
private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(IReceptor sendingNucleus) {
Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]);
this._synapses.Add(synapse);
return synapse;
// else {
// INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName);
// ClusterSynapse synapse = new(sendingNucleus, receptor);
// receptor.AddSynapse(sendingNucleus);
// }
// // Add synapse to which neuron?
// return null;
}
// Does this even exist already?
public void RemoveSynapse() {
}
#endregion Synapses
#region Receivers
[SerializeReference]
private List<INucleus> _receivers = new();
public List<INucleus> receivers {
get { return _receivers; }
set { _receivers = value; }
}
public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this);
}
public void RemoveReceiver(INucleus receiverNucleus) {
this._receivers.RemoveAll(receiver => receiver == receiverNucleus);
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
}
// public void AddReceiver(INucleus receivingNucleus) {
// int newLength = this._receivers.Count + 1;
// INucleus[] newReceivers = new INucleus[newLength];
// // Copy the existing receivers
// for (int ix = 0; ix < this._receivers.Count; ix++)
// newReceivers[ix] = this._receivers[ix];
// // Add the new receivers
// newReceivers[this._receivers.Count] = receivingNucleus;
// // Replace the receivers with the new receivers
// this._receivers = new(newReceivers);
// receivingNucleus.AddSynapse(this);
// }
// public void RemoveReceiver(INucleus receivingNucleus) {
// Debug.Log("Clusterinstance. remote receiver");
// int newLength = this._receivers.Count - 1;
// if (newLength < 0)
// // Array was empty, so we cannot remove anything
// return;
// INucleus[] newReceivers = new INucleus[newLength];
// int newIx = 0;
// // Copy all receivers except receivingNucleus
// for (int ix = 0; ix < this._receivers.Count; ix++) {
// if (this._receivers[ix] == receivingNucleus)
// // skip the receiver we want to remote
// continue;
// if (newIx >= newLength)
// // We want to copy more elements than expected
// // the receivingNucleus is not found
// // and the original array is returned
// return;
// newReceivers[newIx] = this._receivers[ix];
// newIx++;
// }
// this._receivers = new(newReceivers);
// }
#endregion Receivers
#region Runtime
[NonSerialized]
private int stale = 1000;
public bool isSleeping => lengthsq(this.outputValue) == 0;
[NonSerialized]
protected float3 _outputValue;
public virtual float3 outputValue {
get { return _outputValue; }
set {
this.stale = 0;
_outputValue = value;
}
}
#region Update
public virtual void UpdateState() {
UpdateState(new float3(0, 0, 0));
}
public void UpdateState(float3 inputValue) {
float3 sum = inputValue; // new(0, 0, 0);
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
}
// This does not work because the prefab nucleus does not have a state
this.prefab.inputs[0].UpdateState(sum);
//this._outputValue = this.output.outputValue;
UpdateResult(this.output.outputValue);
}
public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) {
// //Debug.Log($"insignificant update: {d}");
// return;
// }
this.outputValue = result;
foreach (INucleus receiver in this.receivers)
receiver.UpdateState();
}
public void UpdateNuclei() {
this.stale++;
if (this.stale > 2)
_outputValue = Vector3.zero;
foreach (IReceptor nucleus in this.prefab.nuclei)
nucleus.UpdateNuclei();
}
#endregion Update
#endregion Runtime
/*
[SerializeField]
private List<IReceptor> _dynamicNuclei;
public List<IReceptor> dynamicNuclei {// = new();
get {
if (_dynamicNuclei == null) {
this._dynamicNuclei = new();
foreach (IReceptor nucleus in this.prefab.nuclei) {
IReceptor clone = nucleus.CloneTo(null);
this._dynamicNuclei.Add(clone);
}
}
return this._dynamicNuclei;
}
}
public List<INucleus> _inputs = null;
public List<INucleus> inputs {
get {
this._inputs = new();
if (this.dynamicNuclei != null) {
foreach (IReceptor receptor in this.dynamicNuclei) {
if (receptor is INucleus nucleus)
this._inputs.Add(nucleus);
}
}
return this._inputs;
}
}
public INucleus output => this.dynamicNuclei[0] as INucleus;
public float3 outputValue => this.output.outputValue;
public IReceptor CloneTo(ClusterPrefab parent) {
Cluster clone = new(parent, this.prefab);
return clone;
}
public IReceptor Clone() {
Cluster clone = new(this.cluster, this.prefab);
return clone;
}
#region Properties
public string name {
get { return prefab.name; }
set { prefab.name = value; }
}
public bool isSleeping => lengthsq(this.outputValue) == 0;
public NucleusArray array { get; set; }
#endregion Properties
*/
}