Added ClusterArray
This commit is contained in:
parent
0023920ffa
commit
1fc75a8143
@ -188,6 +188,20 @@ namespace NanoBrain {
|
|||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
} else if (this.currentNucleus is Cluster cluster && cluster.clusterArray != null) {
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.IntField("Array size", cluster.clusterArray.clusters.Count());
|
||||||
|
if (GUILayout.Button("Add")) {
|
||||||
|
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||||
|
cluster.clusterArray.Add(this.prefab);
|
||||||
|
anythingChanged = true;
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Del")) {
|
||||||
|
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
||||||
|
cluster.clusterArray.Remove();
|
||||||
|
anythingChanged = true;
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synapses
|
// Synapses
|
||||||
@ -387,24 +401,18 @@ namespace NanoBrain {
|
|||||||
case Nucleus.Type.MemoryCell:
|
case Nucleus.Type.MemoryCell:
|
||||||
AddMemoryCellInput(nucleus);
|
AddMemoryCellInput(nucleus);
|
||||||
break;
|
break;
|
||||||
// case Nucleus.Type.Selector:
|
|
||||||
// AddSelectorInput(nucleus);
|
|
||||||
// break;
|
|
||||||
case Nucleus.Type.Cluster:
|
case Nucleus.Type.Cluster:
|
||||||
AddClusterInput(nucleus);
|
AddClusterInput(nucleus);
|
||||||
break;
|
break;
|
||||||
// case Nucleus.Type.Pulsar:
|
|
||||||
// AddPulsarInput(nucleus);
|
|
||||||
// break;
|
|
||||||
case Nucleus.Type.Receptor:
|
case Nucleus.Type.Receptor:
|
||||||
AddReceptorInput(nucleus);
|
AddReceptorInput(nucleus);
|
||||||
break;
|
break;
|
||||||
// case Nucleus.Type.ReceptorArray:
|
|
||||||
// AddReceptorArrayInput(nucleus);
|
|
||||||
// break;
|
|
||||||
case Nucleus.Type.ClusterReceptor:
|
case Nucleus.Type.ClusterReceptor:
|
||||||
AddClusterReceptorInput(nucleus);
|
AddClusterReceptorInput(nucleus);
|
||||||
break;
|
break;
|
||||||
|
case Nucleus.Type.ClusterArray:
|
||||||
|
AddClusterArrayInput(nucleus);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -456,6 +464,13 @@ namespace NanoBrain {
|
|||||||
var editor = Editor.CreateEditor(subCluster.prefab);
|
var editor = Editor.CreateEditor(subCluster.prefab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void AddClusterArrayInput(Nucleus nucleus) {
|
||||||
|
ClusterPickerWindow.ShowPicker(prefab => OnPickedClusterArray(nucleus, prefab), "Select Cluster");
|
||||||
|
}
|
||||||
|
private void OnPickedClusterArray(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
||||||
|
_ = new ClusterArray(selectedPrefab, this.prefab, 1, nucleus);
|
||||||
|
}
|
||||||
|
|
||||||
int selectedConnectNucleus = -1;
|
int selectedConnectNucleus = -1;
|
||||||
// Connect to another nucleus in the same cluster
|
// Connect to another nucleus in the same cluster
|
||||||
protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) {
|
protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) {
|
||||||
|
|||||||
@ -439,12 +439,34 @@ namespace NanoBrain {
|
|||||||
style.normal.textColor = Color.white;
|
style.normal.textColor = Color.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (nucleus is Cluster cluster && cluster.clusterArray != null) {
|
||||||
|
if (expandArray) {
|
||||||
|
// Put array indices above elements
|
||||||
|
style.alignment = TextAnchor.LowerCenter;
|
||||||
|
Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc
|
||||||
|
int colonPos1 = nucleus.name.IndexOf(":");
|
||||||
|
if (colonPos1 > 0) {
|
||||||
|
string extName = nucleus.name[(colonPos1 + 2)..];
|
||||||
|
Handles.Label(labelPos1, extName, style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// draw the array size label
|
||||||
|
if (color.grayscale > 0.5f)
|
||||||
|
style.normal.textColor = Color.black;
|
||||||
|
else
|
||||||
|
style.normal.textColor = Color.white;
|
||||||
|
Handles.Label(labelPosition, cluster.clusterArray.clusters.Length.ToString(), style);
|
||||||
|
style.normal.textColor = Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expandArray == false || nucleus is not IReceptor) {
|
if (expandArray == false || nucleus is not IReceptor) {
|
||||||
// put name below nucleus
|
// put name below nucleus
|
||||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||||
style.alignment = TextAnchor.UpperCenter;
|
style.alignment = TextAnchor.UpperCenter;
|
||||||
|
|
||||||
|
nucleus.name ??= "";
|
||||||
int colonPos = nucleus.name.IndexOf(":");
|
int colonPos = nucleus.name.IndexOf(":");
|
||||||
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
|
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
|
||||||
// if it is an array, we should not show the :0 of the first element
|
// if it is an array, we should not show the :0 of the first element
|
||||||
|
|||||||
@ -28,6 +28,9 @@ public class Cluster : Nucleus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SerializeReference]
|
||||||
|
public ClusterArray clusterArray;
|
||||||
|
|
||||||
#region Init
|
#region Init
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
109
Runtime/Scripts/Core/ClusterArray.cs
Normal file
109
Runtime/Scripts/Core/ClusterArray.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NanoBrain {
|
||||||
|
|
||||||
|
public class ClusterArray : Nucleus {
|
||||||
|
|
||||||
|
public ClusterPrefab prefab;
|
||||||
|
public Cluster[] clusters;
|
||||||
|
|
||||||
|
public ClusterArray(ClusterPrefab prefab, Cluster parent, int size, Nucleus receiver = null) {
|
||||||
|
this.prefab = prefab;
|
||||||
|
this.name = prefab.name;
|
||||||
|
this.clusters = new Cluster[size];
|
||||||
|
for (int ix = 0; ix < size; ix++) {
|
||||||
|
Cluster cluster = new(prefab, parent);
|
||||||
|
cluster.defaultOutput.AddReceiver(receiver);
|
||||||
|
cluster.clusterArray = this;
|
||||||
|
this.clusters[ix] = cluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClusterArray(ClusterPrefab prefab, ClusterPrefab parent, int size, Nucleus receiver = null) {
|
||||||
|
this.prefab = prefab;
|
||||||
|
this.name = prefab.name;
|
||||||
|
this.clusters = new Cluster[size];
|
||||||
|
for (int ix = 0; ix < size; ix++) {
|
||||||
|
Cluster cluster = new(prefab, parent);
|
||||||
|
cluster.defaultOutput.AddReceiver(receiver);
|
||||||
|
cluster.clusterArray = this;
|
||||||
|
this.clusters[ix] = cluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||||
|
ClusterArray clone = new(this.prefab, parent, this.clusters.Length) {
|
||||||
|
clusterPrefab = this.clusterPrefab,
|
||||||
|
};
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Nucleus Clone(ClusterPrefab parent) {
|
||||||
|
ClusterArray clone = new(this.prefab, parent, this.clusters.Length) {
|
||||||
|
};
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ClusterPrefab prefab) {
|
||||||
|
if (this.clusters.Length == 0) {
|
||||||
|
Debug.LogError("Empty perceptoid array, cannot add");
|
||||||
|
}
|
||||||
|
int newLength = this.clusters.Length + 1;
|
||||||
|
Cluster[] newArray = new Cluster[newLength];
|
||||||
|
|
||||||
|
string baseName = this.name;
|
||||||
|
int colonPos = baseName.IndexOf(":");
|
||||||
|
if (colonPos > 0)
|
||||||
|
baseName = baseName[..colonPos];
|
||||||
|
|
||||||
|
for (int i = 0; i < this.clusters.Length; i++)
|
||||||
|
newArray[i] = this.clusters[i];
|
||||||
|
Cluster cluster = this.clusters[0];
|
||||||
|
newArray[newLength - 1] = cluster.Clone(prefab) as Cluster;
|
||||||
|
newArray[newLength - 1].name = $"{baseName}: {newLength - 1}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove() {
|
||||||
|
int newLength = this.clusters.Length - 1;
|
||||||
|
if (newLength == 0) {
|
||||||
|
Debug.LogWarning("Perceptoid array cannot be empty");
|
||||||
|
}
|
||||||
|
Cluster[] newArray = new Cluster[newLength];
|
||||||
|
for (int i = 0; i < newLength; i++)
|
||||||
|
newArray[i] = this.clusters[i];
|
||||||
|
// Delete the last perception
|
||||||
|
//Cluster.Delete(nucleus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateStateIsolated() {
|
||||||
|
// Clusters don't do anything,
|
||||||
|
// The nuclei in them do the work
|
||||||
|
// and should be called directly, not from the cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Cluster GetThingCluster() {
|
||||||
|
Cluster selectedCluster = SelectCluster();
|
||||||
|
return selectedCluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cluster SelectCluster() {
|
||||||
|
// Find a sleeping cluster
|
||||||
|
foreach (Cluster cluster in clusters) {
|
||||||
|
if (cluster.defaultOutput.isSleeping)
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise find the stalest cluster?
|
||||||
|
Cluster stalestCluster = clusters[0];
|
||||||
|
for (int ix = 1; ix < clusters.Length; ix++) {
|
||||||
|
if (clusters[ix].defaultOutput.stale > stalestCluster.defaultOutput.stale)
|
||||||
|
stalestCluster = clusters[ix];
|
||||||
|
}
|
||||||
|
|
||||||
|
return stalestCluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
Runtime/Scripts/Core/ClusterArray.cs.meta
Normal file
2
Runtime/Scripts/Core/ClusterArray.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 837dfcffeb99804479a0887cbfc33372
|
||||||
@ -9,194 +9,194 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace NanoBrain {
|
namespace NanoBrain {
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ClusterReceptor : Cluster, IReceptor {
|
public class ClusterReceptor : Cluster, IReceptor {
|
||||||
public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) {
|
public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.array = new NucleusArray(this);
|
this.array = new NucleusArray(this);
|
||||||
if (this.name.IndexOf(":") < 0)
|
if (this.name.IndexOf(":") < 0)
|
||||||
this.name += ": 0";
|
this.name += ": 0";
|
||||||
|
|
||||||
}
|
}
|
||||||
public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) {
|
public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.array = new NucleusArray(this);
|
this.array = new NucleusArray(this);
|
||||||
}
|
|
||||||
|
|
||||||
public string GetName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Nucleus ShallowCloneTo(Cluster parent) {
|
|
||||||
ClusterReceptor clone = new(this.prefab, parent, this.name) {
|
|
||||||
clusterPrefab = this.clusterPrefab,
|
|
||||||
};
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Nucleus Clone(ClusterPrefab parent) {
|
|
||||||
ClusterReceptor clone = new(prefab, parent, this.name) {
|
|
||||||
array = this._array
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (Synapse synapse in this.synapses) {
|
|
||||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
|
||||||
clonedSynapse.weight = synapse.weight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._outputs = null; // Make sure the output are regenerated
|
public string GetName() {
|
||||||
foreach (Neuron output in this.outputs) {
|
return this.name;
|
||||||
int ix = GetNucleusIndex(this.clusterNuclei, output);
|
|
||||||
if (ix < 0 || clone.clusterNuclei[ix] is not Neuron clonedOutput)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (Nucleus receiver in output.receivers)
|
|
||||||
clonedOutput.AddReceiver(receiver);
|
|
||||||
}
|
}
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override List<Nucleus> CollectReceivers() {
|
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||||
List<Nucleus> receivers = new();
|
ClusterReceptor clone = new(this.prefab, parent, this.name) {
|
||||||
foreach (Nucleus element in this.nucleiArray) {
|
clusterPrefab = this.clusterPrefab,
|
||||||
if (element is not Cluster clusterElement)
|
};
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) {
|
return clone;
|
||||||
if (outputNucleus is not Neuron output)
|
}
|
||||||
|
|
||||||
|
public override Nucleus Clone(ClusterPrefab parent) {
|
||||||
|
ClusterReceptor clone = new(prefab, parent, this.name) {
|
||||||
|
array = this._array
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||||
|
clonedSynapse.weight = synapse.weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._outputs = null; // Make sure the output are regenerated
|
||||||
|
foreach (Neuron output in this.outputs) {
|
||||||
|
int ix = GetNucleusIndex(this.clusterNuclei, output);
|
||||||
|
if (ix < 0 || clone.clusterNuclei[ix] is not Neuron clonedOutput)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// this should be clusterElement.outputs,
|
foreach (Nucleus receiver in output.receivers)
|
||||||
// but outputs is not updated when correctly and may contain old data...
|
clonedOutput.AddReceiver(receiver);
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
}
|
||||||
// Only add receivers outside clusterElement cluster
|
return clone;
|
||||||
if (receiver.clusterPrefab != clusterElement.prefab &&
|
}
|
||||||
receivers.Contains(receiver) == false)
|
|
||||||
receivers.Add(receiver);
|
public override List<Nucleus> CollectReceivers() {
|
||||||
|
List<Nucleus> receivers = new();
|
||||||
|
foreach (Nucleus element in this.nucleiArray) {
|
||||||
|
if (element is not Cluster clusterElement)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) {
|
||||||
|
if (outputNucleus is not Neuron output)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// this should be clusterElement.outputs,
|
||||||
|
// but outputs is not updated when correctly and may contain old data...
|
||||||
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
|
// Only add receivers outside clusterElement cluster
|
||||||
|
if (receiver.clusterPrefab != clusterElement.prefab &&
|
||||||
|
receivers.Contains(receiver) == false)
|
||||||
|
receivers.Add(receiver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return receivers;
|
||||||
return receivers;
|
|
||||||
}
|
|
||||||
|
|
||||||
[SerializeReference]
|
|
||||||
private NucleusArray _array;
|
|
||||||
public NucleusArray array {
|
|
||||||
set { _array = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Nucleus[] nucleiArray {
|
|
||||||
get { return _array.nuclei; }
|
|
||||||
set { _array.nuclei = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddReceptorElement(ClusterPrefab prefab) {
|
|
||||||
IReceptorHelpers.AddReceptorElement(this, prefab);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveReceptorElement() {
|
|
||||||
IReceptorHelpers.RemoveReceptorElement(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
|
|
||||||
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
|
||||||
// Clusters don't do anything,
|
|
||||||
// The nuclei in them do the work
|
|
||||||
// and should be called directly, not from the cluster
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateNuclei() {
|
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
|
||||||
nucleus.UpdateNuclei();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
|
||||||
Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<int, ClusterReceptor> thingReceivers = new();
|
|
||||||
|
|
||||||
public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) {
|
|
||||||
CleanupReceivers();
|
|
||||||
|
|
||||||
if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver))
|
|
||||||
selectedReceiver = FindReceiver2(thingId, inputValue, input);
|
|
||||||
if (selectedReceiver == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (thingName != null) {
|
|
||||||
string baseName = selectedReceiver.name;
|
|
||||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
|
||||||
if (colonPos > 0)
|
|
||||||
baseName = selectedReceiver.name[..colonPos];
|
|
||||||
selectedReceiver.name = baseName + ": " + thingName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
[SerializeReference]
|
||||||
if (inputIx < 0)
|
private NucleusArray _array;
|
||||||
return;
|
public NucleusArray array {
|
||||||
|
set { _array = value; }
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
public Nucleus[] nucleiArray {
|
||||||
selectedNeuron.ProcessStimulusDirect(inputValue);
|
get { return _array.nuclei; }
|
||||||
}
|
set { _array.nuclei = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddReceptorElement(ClusterPrefab prefab) {
|
||||||
|
IReceptorHelpers.AddReceptorElement(this, prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveReceptorElement() {
|
||||||
|
IReceptorHelpers.RemoveReceptorElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||||
|
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateStateIsolated() {
|
||||||
|
// Clusters don't do anything,
|
||||||
|
// The nuclei in them do the work
|
||||||
|
// and should be called directly, not from the cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateNuclei() {
|
||||||
|
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||||
|
nucleus.UpdateNuclei();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
|
Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<int, ClusterReceptor> thingReceivers = new();
|
||||||
|
|
||||||
|
public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
|
CleanupReceivers();
|
||||||
|
|
||||||
|
if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver))
|
||||||
|
selectedReceiver = FindReceiver2(thingId, inputValue, input);
|
||||||
|
if (selectedReceiver == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (thingName != null) {
|
||||||
|
string baseName = selectedReceiver.name;
|
||||||
|
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||||
|
if (colonPos > 0)
|
||||||
|
baseName = selectedReceiver.name[..colonPos];
|
||||||
|
selectedReceiver.name = baseName + ": " + thingName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
||||||
|
if (inputIx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
||||||
|
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
#if UNITY_MATHEMATICS
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) {
|
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) {
|
||||||
// No existing nucleus for this thing
|
// No existing nucleus for this thing
|
||||||
ClusterReceptor selectedReceiver = null;
|
ClusterReceptor selectedReceiver = null;
|
||||||
float selectedMagnitude = 0;
|
float selectedMagnitude = 0;
|
||||||
foreach (ClusterReceptor receiver in this.nucleiArray.Cast<ClusterReceptor>()) {
|
foreach (ClusterReceptor receiver in this.nucleiArray.Cast<ClusterReceptor>()) {
|
||||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||||
// We found an unusued receiver
|
// We found an unusued receiver
|
||||||
thingReceivers.Add(thingId, receiver);
|
thingReceivers.Add(thingId, receiver);
|
||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
else if (receiver.defaultOutput.isSleeping) {
|
else if (receiver.defaultOutput.isSleeping) {
|
||||||
// A sleeping receiver is not active and can therefore always be used
|
// A sleeping receiver is not active and can therefore always be used
|
||||||
thingReceivers.Add(thingId, receiver);
|
thingReceivers.Add(thingId, receiver);
|
||||||
receiver.bias = float3(0, 0, 0);
|
receiver.bias = float3(0, 0, 0);
|
||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
else if (selectedReceiver == null) {
|
else if (selectedReceiver == null) {
|
||||||
// If we haven't found a receiver yet, just start by taking the first
|
// If we haven't found a receiver yet, just start by taking the first
|
||||||
selectedReceiver = receiver;
|
|
||||||
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
|
||||||
}
|
|
||||||
// Look for the receiver with the lowest output magnitude
|
|
||||||
else {
|
|
||||||
float magnitude = length(receiver.defaultOutput.outputValue);
|
|
||||||
|
|
||||||
if (length(receiver.defaultOutput.outputValue) < selectedMagnitude) {
|
|
||||||
selectedReceiver = receiver;
|
selectedReceiver = receiver;
|
||||||
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
||||||
}
|
}
|
||||||
}
|
// Look for the receiver with the lowest output magnitude
|
||||||
}
|
else {
|
||||||
if (selectedReceiver != null) {
|
float magnitude = length(receiver.defaultOutput.outputValue);
|
||||||
// To re-initialize the cluster (esp. memory cells)
|
|
||||||
// we update the cluster neuron twice.
|
|
||||||
// Bit of a hack.....
|
|
||||||
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
|
||||||
if (inputIx >= 0) {
|
|
||||||
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
|
||||||
selectedNeuron.ProcessStimulusDirect(inputValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the receiver
|
if (length(receiver.defaultOutput.outputValue) < selectedMagnitude) {
|
||||||
// Find the thingId current associated with the receiver
|
selectedReceiver = receiver;
|
||||||
int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key;
|
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
||||||
if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove))
|
}
|
||||||
thingReceivers.Remove(keyToRemove);
|
}
|
||||||
// And add the new association
|
}
|
||||||
thingReceivers.Add(thingId, selectedReceiver);
|
if (selectedReceiver != null) {
|
||||||
|
// To re-initialize the cluster (esp. memory cells)
|
||||||
|
// we update the cluster neuron twice.
|
||||||
|
// Bit of a hack.....
|
||||||
|
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
||||||
|
if (inputIx >= 0) {
|
||||||
|
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
||||||
|
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the receiver
|
||||||
|
// Find the thingId current associated with the receiver
|
||||||
|
int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key;
|
||||||
|
if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove))
|
||||||
|
thingReceivers.Remove(keyToRemove);
|
||||||
|
// And add the new association
|
||||||
|
thingReceivers.Add(thingId, selectedReceiver);
|
||||||
|
}
|
||||||
|
return selectedReceiver;
|
||||||
}
|
}
|
||||||
return selectedReceiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -254,24 +254,25 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private void CleanupReceivers() {
|
private void CleanupReceivers() {
|
||||||
// Remove a thing-receiver connection when the nucleus is inactive
|
// Remove a thing-receiver connection when the nucleus is inactive
|
||||||
List<int> receiversToRemove = new();
|
List<int> receiversToRemove = new();
|
||||||
foreach (KeyValuePair<int, ClusterReceptor> item in thingReceivers) {
|
foreach (KeyValuePair<int, ClusterReceptor> item in thingReceivers) {
|
||||||
if (item.Value != null && item.Value.defaultOutput.isSleeping)
|
if (item.Value != null && item.Value.defaultOutput.isSleeping)
|
||||||
receiversToRemove.Add(item.Key);
|
receiversToRemove.Add(item.Key);
|
||||||
|
}
|
||||||
|
foreach (int thingId in receiversToRemove) {
|
||||||
|
Nucleus selectedReceiver = thingReceivers[thingId];
|
||||||
|
|
||||||
|
thingReceivers.Remove(thingId);
|
||||||
|
|
||||||
|
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||||
|
if (colonPos > 0)
|
||||||
|
selectedReceiver.name = selectedReceiver.name[..colonPos];
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach (int thingId in receiversToRemove) {
|
|
||||||
Nucleus selectedReceiver = thingReceivers[thingId];
|
|
||||||
|
|
||||||
thingReceivers.Remove(thingId);
|
|
||||||
|
|
||||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
|
||||||
if (colonPos > 0)
|
|
||||||
selectedReceiver.name = selectedReceiver.name[..colonPos];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -56,6 +56,7 @@ public abstract class Nucleus {
|
|||||||
Cluster,
|
Cluster,
|
||||||
Receptor,
|
Receptor,
|
||||||
ClusterReceptor,
|
ClusterReceptor,
|
||||||
|
ClusterArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Synapses
|
#region Synapses
|
||||||
|
|||||||
@ -29,7 +29,7 @@ namespace NanoBrain {
|
|||||||
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) {
|
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) {
|
||||||
this.array = new NucleusArray(this);
|
this.array = new NucleusArray(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetName() {
|
public string GetName() {
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
@ -108,6 +108,6 @@ namespace NanoBrain {
|
|||||||
this._array ??= new NucleusArray(this.parent);
|
this._array ??= new NucleusArray(this.parent);
|
||||||
this._array.ProcessStimulus(thingId, inputValue, thingName);
|
this._array.ProcessStimulus(thingId, inputValue, thingName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user