diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index cc796da..cd3cc27 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -73,7 +73,6 @@ - @@ -81,6 +80,7 @@ + diff --git a/Assets/NanoBrain/Cluster.cs b/Assets/NanoBrain/Cluster.cs index 973ab4e..44f68ed 100644 --- a/Assets/NanoBrain/Cluster.cs +++ b/Assets/NanoBrain/Cluster.cs @@ -1,84 +1,259 @@ +using System; using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; -[CreateAssetMenu(menuName = "Passer/Cluster")] -public class Cluster : ScriptableObject { - - public Cluster cluster => this; - +[System.Serializable] +public class Cluster : INucleus { // The ScriptableObject asset from which the runtime object has been created - public Cluster asset; + public readonly ClusterPrefab prefab; + + public ClusterPrefab cluster { get; set; } + + [SerializeField] + protected string _name; + public virtual string name { + get => _name; + set => _name = value; + } + + // Hmm, a cluster instance can never be part of a scriptable object...(Cluster) + public Cluster(ClusterPrefab parent, ClusterPrefab prefab) { + this.prefab = prefab; + 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; + } + + // 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 _synapses = new(); + public List 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] - public List nuclei = new(); - - // public List subClusters = new(); - public void AddSubCluster(ClusterInstance subCluster) { - this.nuclei.Add(subCluster); + private List _receivers = new(); + public List receivers { + get { return _receivers; } + set { _receivers = value; } } - public INucleus output => this.nuclei[0] as INucleus; + public virtual void AddReceiver(INucleus receivingNucleus) { + this._receivers.Add(receivingNucleus); + receivingNucleus.AddSynapse(this); + } - public List _inputs = null; - public List inputs { - get { - if (this._inputs == null) { - this._inputs = new(); - foreach (IReceptor receptor in this.nuclei) { - if (receptor is INucleus nucleus) - this._inputs.Add(nucleus); - } - } - return this._inputs; + 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; } } - // 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(); - if (nuclei.Count == 0) - new Neuron(this, "Output"); // Every cluster should have at least 1 neuron + #region Update + + public virtual void UpdateState() { + UpdateState(new float3(0, 0, 0)); } - public void GarbageCollection() { - HashSet 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 UpdateState(float3 inputValue) { + float3 sum = inputValue; // new(0, 0, 0); - public void MarkNuclei(HashSet visitedNuclei, INucleus nucleus) { - if (nucleus is null) - return; - - visitedNuclei.Add(nucleus); - if (nucleus.synapses != null) { - HashSet 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 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); + //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); } public void UpdateNuclei() { - foreach (IReceptor nucleus in this.nuclei) + this.stale++; + if (this.stale > 2) + _outputValue = Vector3.zero; + + foreach (IReceptor nucleus in this.prefab.nuclei) nucleus.UpdateNuclei(); } -} \ No newline at end of file + + #endregion Update + + #endregion Runtime + + /* + [SerializeField] + private List _dynamicNuclei; + public List 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 _inputs = null; + public List 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 + + + */ + +} diff --git a/Assets/NanoBrain/Cluster.cs.meta b/Assets/NanoBrain/Cluster.cs.meta index ee35e0b..a10caff 100644 --- a/Assets/NanoBrain/Cluster.cs.meta +++ b/Assets/NanoBrain/Cluster.cs.meta @@ -1,2 +1,2 @@ fileFormatVersion: 2 -guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file +guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterInstance.cs b/Assets/NanoBrain/ClusterInstance.cs deleted file mode 100644 index 7236fbe..0000000 --- a/Assets/NanoBrain/ClusterInstance.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using Unity.Mathematics; -using static Unity.Mathematics.math; - -[System.Serializable] -public class ClusterInstance : INucleus { - // The ScriptableObject asset from which the runtime object has been created - public Cluster asset; - - public Cluster cluster => this.asset; - - public List dynamicNuclei = new(); - - public INucleus output => this.asset.nuclei[0] as INucleus; - public float3 outputValue => this.output.outputValue; - - public ClusterInstance(Cluster asset) { - this.asset = asset; - foreach (IReceptor nucleus in this.asset.nuclei) - dynamicNuclei.Add(nucleus.Clone()); - } - - public IReceptor Clone() { - ClusterInstance clone = new(this.asset); - return clone; - } - - #region Properties - - public string name { - get { return asset.name; } - set { asset.name = value; } - } - - public bool isSleeping => lengthsq(this.outputValue) == 0; - - public NucleusArray array { get; set; } - - #endregion Properties - - #region Synapses - - [SerializeReference] - private List _synapses = new(); - public List synapses => new(_synapses); - - public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { - if (nucleusName == null) { - Synapse synapse = new(sendingNucleus); - this._synapses.Add(synapse); - // Nice, but this is not yet connected to the nucleusName - } else { - INucleus receptor = (INucleus)this.asset.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName); - 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 _receivers = new(); - public List receivers { - get { return _receivers; } - set { _receivers = value; } - } - - 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) { - 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 Update - - public void UpdateState() { - float3 sum = new(0, 0, 0); - - //Applying the weight factgors - foreach (Synapse synapse in this.synapses) { - sum += synapse.weight * synapse.nucleus.outputValue; - } - this.asset.inputs[0].UpdateState(); - } - - public void UpdateNuclei() { - foreach (IReceptor nucleus in this.asset.nuclei) - nucleus.UpdateNuclei(); - } - - #endregion Update -} diff --git a/Assets/NanoBrain/ClusterInstance.cs.meta b/Assets/NanoBrain/ClusterInstance.cs.meta deleted file mode 100644 index a10caff..0000000 --- a/Assets/NanoBrain/ClusterInstance.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f13cdc4a175a9f379a00317ae68d8bea \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs b/Assets/NanoBrain/ClusterPrefab.cs new file mode 100644 index 0000000..db65b70 --- /dev/null +++ b/Assets/NanoBrain/ClusterPrefab.cs @@ -0,0 +1,84 @@ +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 nuclei = new(); + + // public List subClusters = new(); + // public void AddSubCluster(ClusterInstance subCluster) { + // this.nuclei.Add(subCluster); + // } + + public virtual INucleus output => this.nuclei[0] as INucleus; + + public List _inputs = null; + public virtual List inputs { + get { + if (this._inputs == null) { + this._inputs = new(); + foreach (IReceptor receptor in this.nuclei) { + if (receptor is INucleus nucleus) + this._inputs.Add(nucleus); + } + } + return this._inputs; + } + } + + // 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(); + if (nuclei.Count == 0) + new Neuron(this, "Output"); // Every cluster should have at least 1 neuron + } + + public void GarbageCollection() { + HashSet 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 visitedNuclei, INucleus nucleus) { + if (nucleus is null) + return; + + visitedNuclei.Add(nucleus); + if (nucleus.synapses != null) { + HashSet 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 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(); + } +} \ No newline at end of file diff --git a/Assets/NanoBrain/ClusterPrefab.cs.meta b/Assets/NanoBrain/ClusterPrefab.cs.meta new file mode 100644 index 0000000..ee35e0b --- /dev/null +++ b/Assets/NanoBrain/ClusterPrefab.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60a957541c24c57e78018c202ebb1d9b \ No newline at end of file diff --git a/Assets/NanoBrain/INucleus.cs b/Assets/NanoBrain/INucleus.cs index a4b7657..f7272f3 100644 --- a/Assets/NanoBrain/INucleus.cs +++ b/Assets/NanoBrain/INucleus.cs @@ -6,11 +6,11 @@ public interface INucleus : IReceptor { #region static struct // Cluster - public Cluster cluster { get; } + public ClusterPrefab cluster { get; } // Senders public List synapses { get; } - public Synapse AddSynapse(IReceptor sender, string nucleusName = null); + public Synapse AddSynapse(IReceptor sender); public NucleusArray array { get; set; } @@ -19,6 +19,7 @@ public interface INucleus : IReceptor { #region dynamic state public void UpdateState(); + public void UpdateState(float3 inputValue); #endregion dynamic state @@ -47,6 +48,7 @@ public interface IReceptor { #endregion dynamic + //public IReceptor CloneTo(ClusterPrefab parent); public IReceptor Clone(); } diff --git a/Assets/NanoBrain/Identity.asset b/Assets/NanoBrain/Identity.asset index 94ece11..076c284 100644 --- a/Assets/NanoBrain/Identity.asset +++ b/Assets/NanoBrain/Identity.asset @@ -12,123 +12,19 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Identity m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} nuclei: - - rid: 2243601242842202241 + - rid: 2243601383627161705 references: version: 2 RefIds: - - rid: -2 - type: {class: , ns: , asm: } - - rid: 2243601242842202241 + - rid: 2243601383627161705 type: {class: Neuron, ns: , asm: Assembly-CSharp} data: _name: Output - _synapses: - - basicNucleus: - rid: 2243601249170358348 - cluster: - rid: -2 - weight: 1 - curveMax: 1 - _receivers: [] - _array: - rid: 2243601242842202242 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601242842202242 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601242842202241 - name: Output - - rid: 2243601249170358348 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: New neuron _synapses: [] - _receivers: - - rid: 2243601249170358349 - _array: - rid: 2243601249170358350 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601249170358349 - type: {class: ClusterInstance, ns: , asm: Assembly-CSharp} - data: - asset: {fileID: 11400000} - _receivers: - - rid: 2243601249170358351 - - rid: 2243601249170358350 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601249170358348 - name: New neuron - - rid: 2243601249170358351 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: - - basicNucleus: - rid: 2243601249170358349 - cluster: - rid: -2 - weight: 1 - curveMax: 1 _receivers: [] _array: - rid: 2243601249170358352 + rid: 2243601383627161706 _curvePreset: 0 curve: serializedVersion: 2 @@ -156,9 +52,9 @@ MonoBehaviour: m_RotationOrder: 4 curveMax: 1 average: 0 - - rid: 2243601249170358352 + - rid: 2243601383627161706 type: {class: NucleusArray, ns: , asm: Assembly-CSharp} data: _nuclei: - - rid: 2243601249170358351 + - rid: 2243601383627161705 name: Output diff --git a/Assets/NanoBrain/MemoryCell.cs b/Assets/NanoBrain/MemoryCell.cs index 5e32009..6e20a75 100644 --- a/Assets/NanoBrain/MemoryCell.cs +++ b/Assets/NanoBrain/MemoryCell.cs @@ -6,7 +6,7 @@ using static Unity.Mathematics.math; [Serializable] public class MemoryCell : Neuron { - public MemoryCell(Cluster cluster, string name) : base(cluster, name) {} + public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {} #region Parameters diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs index 17ed928..099ceab 100644 --- a/Assets/NanoBrain/Neuron.cs +++ b/Assets/NanoBrain/Neuron.cs @@ -87,7 +87,7 @@ public class Neuron : INucleus { #region Runtime state (not serialized) - public Cluster cluster { get; set; } + public ClusterPrefab cluster { get; set; } #region Activation @@ -165,20 +165,40 @@ public class Neuron : INucleus { #endregion Runtime state - public Neuron(Cluster brain, string name) { - this.cluster = brain; + public Neuron(ClusterPrefab parent, string name) { + this.cluster = parent; this.name = name; if (this.cluster != null) { this.cluster.nuclei.Add(this); } - else - Debug.LogError("No neuroid network"); + // else + // Debug.LogError("No neuroid network"); } // public Neuron(string name) { // this._name = name; // } + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Neuron clone = new(parent, this.name) { + array = this.array, + curve = this.curve, + curvePreset = this.curvePreset, + curveMax = this.curveMax, + average = this.average + }; + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); + + 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 virtual IReceptor Clone() { Neuron clone = new(this.cluster, this.name) { array = this.array, @@ -187,8 +207,8 @@ public class Neuron : INucleus { curveMax = this.curveMax, average = this.average }; - if (clone.cluster != null) - clone.cluster.nuclei.Add(clone); + // if (clone.cluster != null) + // clone.cluster.nuclei.Add(clone); foreach (Synapse synapse in this.synapses) { Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); @@ -234,14 +254,18 @@ public class Neuron : INucleus { } } - public Synapse AddSynapse(IReceptor sendingNucleus, string nucleusName = null) { + public Synapse AddSynapse(IReceptor sendingNucleus) { Synapse synapse = new(sendingNucleus); this.synapses.Add(synapse); return synapse; } public virtual void UpdateState() { - float3 sum = new(0, 0, 0); + UpdateState(new float3(0, 0, 0)); + } + + public virtual void UpdateState(float3 inputValue) { + float3 sum = inputValue;//new(0, 0, 0); int n = 0; //Applying the weight factgors @@ -255,7 +279,7 @@ public class Neuron : INucleus { if (lengthsq(synapse.nucleus.outputValue) != 0) n++; } - if (this.average) + if (this.average && n > 0) sum /= n; // Activation function diff --git a/Assets/NanoBrain/NucleusArray.cs b/Assets/NanoBrain/NucleusArray.cs index ed14af8..82a3b0e 100644 --- a/Assets/NanoBrain/NucleusArray.cs +++ b/Assets/NanoBrain/NucleusArray.cs @@ -6,7 +6,7 @@ using UnityEngine; public class NucleusArray { [SerializeReference] private INucleus[] _nuclei; - private Cluster[] _clusters; + private ClusterPrefab[] _clusters; public IEnumerable nuclei { get { // if (_nuclei == null) @@ -23,12 +23,12 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; - this._clusters = new Cluster[0]; + this._clusters = new ClusterPrefab[0]; } - public NucleusArray(Cluster cluster) { + public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; this._nuclei = new INucleus[0]; - this._clusters = new Cluster[1]; + this._clusters = new ClusterPrefab[1]; this._clusters[0] = cluster; } diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 18443e5..72ef7df 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -5,7 +5,7 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - private Cluster cluster; + private ClusterPrefab cluster; [SerializeField] protected string _name; @@ -14,20 +14,20 @@ public class Receptor : IReceptor { set => _name = value; } - public Receptor(Cluster cluster) { + public Receptor(ClusterPrefab cluster) { this.cluster = cluster; if (cluster != null) cluster.nuclei.Add(this); } - public Receptor(Cluster cluster, INucleus nucleus) { + public Receptor(ClusterPrefab cluster, INucleus nucleus) { this.cluster = cluster; if (cluster != null) cluster.nuclei.Add(this); this.AddReceiver(nucleus); } - public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { + public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) { if (cluster == null) return null; @@ -45,6 +45,15 @@ public class Receptor : IReceptor { return receptor; } + public virtual IReceptor CloneTo(ClusterPrefab parent) { + Receptor clone = new(parent); + + foreach (INucleus receiver in this.receivers) { + clone.AddReceiver(receiver); + } + + return clone; + } public virtual IReceptor Clone() { Receptor clone = new(this.cluster); diff --git a/Assets/NanoBrain/Synapse.cs b/Assets/NanoBrain/Synapse.cs index 40580c0..e7c8116 100644 --- a/Assets/NanoBrain/Synapse.cs +++ b/Assets/NanoBrain/Synapse.cs @@ -4,18 +4,19 @@ using UnityEngine; [Serializable] public class Synapse { // Support access to cluster of basic nucleus - public IReceptor nucleus => basicNucleus; + //public IReceptor nucleus => basicNucleus; + + + //[SerializeReference] + //public Cluster cluster; [SerializeReference] - private IReceptor basicNucleus; - - [SerializeReference] - public ClusterInstance cluster; + public IReceptor nucleus; public float weight; public Synapse(IReceptor nucleus, float weight = 1.0f) { - this.basicNucleus = nucleus; + this.nucleus = nucleus; this.weight = weight; } } \ No newline at end of file diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset index 9615d6d..f659ada 100644 --- a/Assets/NanoBrain/Velocity.asset +++ b/Assets/NanoBrain/Velocity.asset @@ -12,50 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: Velocity m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} - nuclei: - - rid: 2243601362379866169 + nuclei: [] references: version: 2 - RefIds: - - rid: 2243601362379866169 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601362379866170 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601362379866170 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601362379866169 - name: Output + RefIds: [] diff --git a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs index 66ef404..3a536df 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/BrainPickerWindow.cs @@ -5,11 +5,11 @@ using System.Linq; public class BrainPickerWindow : EditorWindow { private Vector2 scroll; - private Cluster[] items = new Cluster[0]; - private Action onPicked; + private ClusterPrefab[] items = new ClusterPrefab[0]; + private Action onPicked; private string search = ""; - public static void ShowPicker(Action onPicked, string title = "Select Cluster") { + public static void ShowPicker(Action onPicked, string title = "Select Cluster") { var w = CreateInstance(); w.titleContent = new GUIContent(title); w.minSize = new Vector2(360, 320); @@ -23,7 +23,7 @@ public class BrainPickerWindow : EditorWindow { private void RefreshList() { var guids = AssetDatabase.FindAssets("t:Cluster"); items = guids - .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) + .Select(g => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(g))) .Where(b => b != null) .OrderBy(b => b.name) .ToArray(); @@ -47,7 +47,7 @@ public class BrainPickerWindow : EditorWindow { continue; EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(Cluster)), GUILayout.Height(20)); + EditorGUILayout.LabelField(EditorGUIUtility.ObjectContent(it, typeof(ClusterPrefab)), GUILayout.Height(20)); if (GUILayout.Button("Select", GUILayout.Width(70))) { onPicked?.Invoke(it); Close(); diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index f44105d..94273dd 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -7,7 +7,7 @@ using UnityEngine.UIElements; using Unity.Mathematics; using static Unity.Mathematics.math; -[CustomEditor(typeof(Cluster))] +[CustomEditor(typeof(ClusterPrefab))] public class ClusterInspector : Editor { protected static VisualElement mainContainer; protected static VisualElement inspectorContainer; @@ -17,7 +17,7 @@ public class ClusterInspector : Editor { #region Start public override VisualElement CreateInspectorGUI() { - Cluster cluster = target as Cluster; + ClusterPrefab cluster = target as ClusterPrefab; serializedObject.Update(); @@ -72,7 +72,7 @@ public class ClusterInspector : Editor { } public class GraphView : VisualElement { - Cluster cluster; + ClusterPrefab cluster; SerializedObject serializedBrain; INucleus currentNucleus; GameObject gameObject; @@ -123,7 +123,7 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, ClusterPrefab brain, INucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; this.cluster = brain; if (Application.isPlaying == false) @@ -410,7 +410,7 @@ public class ClusterInspector : Editor { Handles.Label(labelPos, nucleus.name, style); } - if (nucleus is ClusterInstance cluster) { + if (nucleus is Cluster cluster) { Handles.color = Color.white; Handles.DrawWireDisc(position, Vector3.forward, size + 10); } @@ -529,7 +529,7 @@ public class ClusterInspector : Editor { if (synapse.nucleus != null) { EditorGUILayout.Space(); - EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); + //EditorGUI.BeginDisabledGroup(synapse.nucleus.isSleeping); if (Application.isPlaying) EditorGUILayout.FloatField(synapse.nucleus.name, length(synapse.nucleus.outputValue) * synapse.weight); else { @@ -543,7 +543,7 @@ public class ClusterInspector : Editor { EditorGUI.indentLevel++; synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight); EditorGUI.indentLevel--; - EditorGUI.EndDisabledGroup(); + //EditorGUI.EndDisabledGroup(); } } } @@ -563,7 +563,7 @@ public class ClusterInspector : Editor { if (GUILayout.Button("Delete this neuron")) DeleteNeuron(this.currentNucleus); - if (this.currentNucleus is ClusterInstance subCluster) { + if (this.currentNucleus is Cluster subCluster) { if (GUILayout.Button("Edit Cluster")) EditCluster(subCluster); } @@ -588,7 +588,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputNeuron(INucleus nucleus) { - Neuron newNeuroid = new(this.cluster.cluster, "New neuron"); + Neuron newNeuroid = new(this.cluster, "New neuron"); newNeuroid.AddReceiver(nucleus); this.currentNucleus = newNeuroid; BuildLayers(); @@ -610,7 +610,7 @@ public class ClusterInspector : Editor { } protected virtual void AddInputMemoryCell(INucleus nucleus) { - MemoryCell newMemory = new(this.cluster.cluster, "New memory cell"); + MemoryCell newMemory = new(this.cluster, "New memory cell"); newMemory.AddReceiver(nucleus); this.currentNucleus = newMemory; BuildLayers(); @@ -620,22 +620,23 @@ public class ClusterInspector : Editor { BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); } - private void OnClusterPicked(INucleus nucleus, Cluster subCluster) { - ClusterInstance clusterInstance = new(subCluster); - this.cluster.AddSubCluster(clusterInstance); - clusterInstance.AddReceiver(nucleus); + private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) { + Cluster subclusterInstance = new(this.cluster, subCluster); + //this.cluster.AddSubCluster(subclusterInstance); + //this.cluster.nuclei.Add(subclusterInstance); + subclusterInstance.AddReceiver(nucleus); } - private void EditCluster(ClusterInstance subCluster) { + private void EditCluster(Cluster subCluster) { //var currentActiveObject = Selection.activeObject; - Selection.activeObject = subCluster.asset; - EditorGUIUtility.PingObject(subCluster.asset); - var editor = Editor.CreateEditor(subCluster.asset); + Selection.activeObject = subCluster.prefab; + EditorGUIUtility.PingObject(subCluster.prefab); + var editor = Editor.CreateEditor(subCluster.prefab); //Selection.activeObject = currentActiveObject; } // Connect to another nucleus in the same cluster - protected virtual void ConnectNucleus(Cluster cluster, INucleus nucleus) { + protected virtual void ConnectNucleus(ClusterPrefab cluster, INucleus nucleus) { if (cluster == null) return; @@ -705,9 +706,9 @@ public class ClusterWrapper : ScriptableObject { //public string title; public Vector2 position; INucleus node; - Cluster graph; // needed to write back and mark dirty + ClusterPrefab graph; // needed to write back and mark dirty - public ClusterWrapper Init(INucleus node, Cluster graphAsset) { + public ClusterWrapper Init(INucleus node, ClusterPrefab graphAsset) { this.node = node; this.graph = graphAsset; //this.title = " A " + node.name; diff --git a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs index c9ad194..253993a 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/NanoBrainComponent_Editor.cs @@ -23,7 +23,7 @@ public class NanoBrainComponent_Editor : Editor { public override VisualElement CreateInspectorGUI() { //NanoBrainComponent component = target as NanoBrainComponent; - Cluster brain = Application.isPlaying ? component.brain : component.defaultBrain; + ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain; if (Application.isPlaying == false) serializedObject.Update(); diff --git a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs index 09fbfaa..56c9159 100644 --- a/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs +++ b/Assets/NanoBrain/VisualEditor/NanoBrainComponent.cs @@ -1,11 +1,11 @@ using UnityEngine; public class NanoBrainComponent : MonoBehaviour { - public Cluster defaultBrain; - private Cluster brainInstance; + public ClusterPrefab defaultBrain; + private ClusterPrefab brainInstance; public INucleus root => brainInstance.output; - public Cluster brain { + public ClusterPrefab brain { get { if (brainInstance == null && defaultBrain != null) { brainInstance = Instantiate(defaultBrain); @@ -23,7 +23,7 @@ public class NanoBrainComponent : MonoBehaviour { } } - public static void UpdateWeight(Cluster brain, string name, float weight) { + public static void UpdateWeight(ClusterPrefab brain, string name, float weight) { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { if (synapse.nucleus.name == name) { diff --git a/Assets/Scenes/Boids/New Cluster.asset b/Assets/Scenes/Boids/New Cluster.asset index cdf9f20..1db7fcd 100644 --- a/Assets/Scenes/Boids/New Cluster.asset +++ b/Assets/Scenes/Boids/New Cluster.asset @@ -12,50 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Name: New Cluster m_EditorClassIdentifier: Assembly-CSharp::Cluster - asset: {fileID: 0} - nuclei: - - rid: 2243601249170358341 + nuclei: [] references: version: 2 - RefIds: - - rid: 2243601249170358341 - type: {class: Neuron, ns: , asm: Assembly-CSharp} - data: - _name: Output - _synapses: [] - _receivers: [] - _array: - rid: 2243601249170358342 - _curvePreset: 0 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: 0 - outSlope: 1 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - - serializedVersion: 3 - time: 1000 - value: 1000 - inSlope: 1 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - curveMax: 1 - average: 0 - - rid: 2243601249170358342 - type: {class: NucleusArray, ns: , asm: Assembly-CSharp} - data: - _nuclei: - - rid: 2243601249170358341 - name: Output + RefIds: [] diff --git a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs index d8dbd3b..eaca9f7 100644 --- a/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs +++ b/Assets/Scenes/Boids/Scripts/Editor/SwarmControl_Editor.cs @@ -10,9 +10,9 @@ public class SwarmControl_Editor : Editor { if (EditorGUI.EndChangeCheck()) { SwarmControl swarmControl = (SwarmControl)target; - Cluster[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); + ClusterPrefab[] nanoBrains = FindObjectsByType(FindObjectsSortMode.None); - foreach (Cluster brain in nanoBrains) { + foreach (ClusterPrefab brain in nanoBrains) { NanoBrainComponent.UpdateWeight(brain, "Avoidance", swarmControl.avoidanceForce); NanoBrainComponent.UpdateWeight(brain, "Cohesion", swarmControl.cohesionForce); NanoBrainComponent.UpdateWeight(brain, "Separation", swarmControl.separationForce);