This commit is contained in:
Pascal Serrarens 2026-04-20 09:39:36 +02:00
parent c8f0f0c9da
commit 75d9d1cd5c
12 changed files with 1 additions and 964 deletions

View File

@ -117,44 +117,6 @@ namespace NanoBrain {
}
}
/*
// Copy nucleus arrays for receptors
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
if (prefabNucleus is not IReceptor prefabReceptor)
continue;
if (prefabReceptor.nucleiArray == null || prefabReceptor.nucleiArray.Length == 0)
continue;
IReceptor clonedNucleus = clonedNuclei[nucleusIx] as IReceptor;
if (prefabReceptor == prefabReceptor.nucleiArray[0]) {
// We clone the array only for the first entry
NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length);
int arrayIx = 0;
foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) {
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
if (arrayNucleusIx >= 0) {
Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx];
clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
}
else {
Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones");
}
arrayIx++;
}
//clonedNucleus.array = clonedArray;
clonedNucleus.nucleiArray = clonedArray.nuclei;
}
else {
// The others will refer to the array created for the first nucleus in the array
int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabReceptor.nucleiArray[0]);
IReceptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as IReceptor;
clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray;
}
}
*/
foreach (Nucleus nucleus in this.clusterNuclei) {
if (nucleus is Cluster clonedSubCluster)
RestoreAllExternalReceivers(clonedSubCluster, this.prefab, this);
@ -381,13 +343,6 @@ namespace NanoBrain {
}
}
// Otherwise find the stalest cluster?
// Cluster stalestCluster = this.siblingClusters[0];
// for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
// if (this.siblingClusters[ix].defaultOutput.stale > stalestCluster.defaultOutput.stale)
// stalestCluster = this.siblingClusters[ix];
// }
// Otherwise find longest unused cluster
Cluster unusedCluster = this.siblingClusters[0];
for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
@ -575,11 +530,6 @@ namespace NanoBrain {
}
}
// [Obsolete("Use GetNucleus instead")]
// public IReceptor GetReceptor(string receptorName) {
// return GetNucleus(receptorName) as IReceptor;
// }
#region Receivers
public virtual List<Nucleus> CollectReceivers() {
@ -589,7 +539,6 @@ namespace NanoBrain {
// Only add receivers outside this cluster
if (receiver.clusterPrefab != this.prefab)
receivers.Add(receiver);
//receivers.AddRange(output.receivers);
}
}
return receivers;
@ -626,19 +575,6 @@ namespace NanoBrain {
public override void UpdateStateIsolated() {
throw new Exception("Cluster should not be updated!");
// float3 sum = this.bias;
// //Applying the weight factors
// foreach (Synapse synapse in this.synapses) {
// if (lengthsq(synapse.neuron.outputValue) > 0) {
// sum += synapse.weight * synapse.neuron.outputValue;
// }
// }
// foreach (Nucleus nucleus in this.sortedNuclei)
// nucleus.UpdateStateIsolated();
// UpdateNuclei();
}
public override void UpdateNuclei() {

View File

@ -1,145 +0,0 @@
/*
using System;
using System.Collections.Generic;
using UnityEngine;
namespace NanoBrain {
[Serializable]
public class ClusterArray : Nucleus {
public ClusterPrefab prefab;
[SerializeReference]
public Cluster[] clusters;
public Dictionary<int, Cluster> thingClusters = new();
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");
return;
}
int newLength = this.clusters.Length + 1;
Cluster[] newClusters = 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++)
newClusters[i] = this.clusters[i];
Cluster sourceCluster = this.clusters[0];
Cluster newCluster = sourceCluster.Clone(prefab) as Cluster;
newCluster.name = $"{baseName}: {newLength - 1}";
//newCluster.clusterArray = this;
newClusters[newLength - 1] = newCluster;
this.clusters = newClusters;
}
public void Remove() {
int newLength = this.clusters.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
return;
}
Cluster[] newClusters = new Cluster[newLength];
for (int i = 0; i < newLength; i++)
newClusters[i] = this.clusters[i];
// Delete the last perception
//Cluster.Delete(nucleus);
this.clusters = newClusters;
}
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;
}
public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
return cluster;
Cluster selectedCluster = SelectCluster();
thingClusters[thingId] = selectedCluster;
return selectedCluster;
}
private Cluster SelectCluster() {
// Find a sleeping cluster
foreach (Cluster cluster in clusters) {
if (cluster.defaultOutput.isSleeping) {
RemoveThingCluster(cluster);
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];
}
RemoveThingCluster(stalestCluster);
return stalestCluster;
}
private void RemoveThingCluster(Cluster cluster) {
List<int> keysToRemove = new();
foreach (KeyValuePair<int, Cluster> kvp in thingClusters) {
if (kvp.Value == cluster)
keysToRemove.Add(kvp.Key);
}
foreach (int thingId in keysToRemove)
thingClusters.Remove(thingId);
}
}
}
*/

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 837dfcffeb99804479a0887cbfc33372

View File

@ -1,280 +0,0 @@
/*
using System;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_MATHEMATICS
using Unity.Mathematics;
using static Unity.Mathematics.math;
#endif
using System.Linq;
namespace NanoBrain {
[Serializable]
public class ClusterReceptor : Cluster, IReceptor {
public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) {
this.name = name;
this.array = new NucleusArray(this);
if (this.name.IndexOf(":") < 0)
this.name += ": 0";
}
public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) {
this.name = name;
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
foreach (Neuron output in this.outputs) {
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() {
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;
}
[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);
if (inputIx < 0)
return;
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
selectedNeuron.ProcessStimulusDirect(inputValue);
}
#if UNITY_MATHEMATICS
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) {
// No existing nucleus for this thing
ClusterReceptor selectedReceiver = null;
float selectedMagnitude = 0;
foreach (ClusterReceptor receiver in this.nucleiArray.Cast<ClusterReceptor>()) {
if (thingReceivers.ContainsValue(receiver) == false) {
// We found an unusued receiver
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (receiver.defaultOutput.isSleeping) {
// A sleeping receiver is not active and can therefore always be used
thingReceivers.Add(thingId, receiver);
receiver.bias = float3(0, 0, 0);
return receiver;
}
else if (selectedReceiver == null) {
// 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;
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
}
}
}
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;
}
#else
private ClusterReceptor FindReceiver2(int thingId, Vector3 inputValue, Neuron input) {
// No existing nucleus for this thing
ClusterReceptor selectedReceiver = null;
float selectedMagnitude = 0;
foreach (ClusterReceptor receiver in this.nucleiArray.Cast<ClusterReceptor>()) {
if (thingReceivers.ContainsValue(receiver) == false) {
// We found an unusued receiver
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (receiver.defaultOutput.isSleeping) {
// A sleeping receiver is not active and can therefore always be used
thingReceivers.Add(thingId, receiver);
receiver.bias = new Vector3(0, 0, 0);
return receiver;
}
else if (selectedReceiver == null) {
// If we haven't found a receiver yet, just start by taking the first
selectedReceiver = receiver;
selectedMagnitude = selectedReceiver.defaultOutput.outputValue.magnitude;
}
// Look for the receiver with the lowest output magnitude
else {
float magnitude = receiver.defaultOutput.outputValue.magnitude;
if (receiver.defaultOutput.outputValue.magnitude < selectedMagnitude) {
selectedReceiver = receiver;
selectedMagnitude = selectedReceiver.defaultOutput.outputValue.magnitude;
}
}
}
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;
}
#endif
private void CleanupReceivers() {
// Remove a thing-receiver connection when the nucleus is inactive
List<int> receiversToRemove = new();
foreach (KeyValuePair<int, ClusterReceptor> item in thingReceivers) {
if (item.Value != null && item.Value.defaultOutput.isSleeping)
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];
}
}
}
}
*/

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 4f64f5d72a422a7c8bb9ace598432aad

View File

@ -1,126 +0,0 @@
/*
using UnityEngine;
namespace NanoBrain {
/// <summary>
/// A Receptor is a Nucleus which can receive input (called Stimulus) from outside the the cluster/brain
/// </summary>
/// It has the ability to distinguish stimuli from different things using an array of Nuclei
public interface IReceptor {
/// <summary>
/// Get the name of the receptor
/// </summary>
/// <returns>The name of the receptor</returns>
public string GetName();
/// <summary>
/// The array of nuclei used to track multiple things sending stimuli
/// </summary>
/// The size of the array determines the maximum number of things which can be distinguished
// public Nucleus[] nucleiArray { get; set; }
/// <summary>
/// Extends the nucleiArray with an additional element
/// </summary>
/// <param name="prefab">A prefab of the nucleus to add?</param>
// public void AddReceptorElement(ClusterPrefab prefab);
/// <summary>
/// Removes the last element from the nucleiArray
/// </summary>
// public void RemoveReceptorElement();
/// <summary>
/// Add a receiver for this receptor array
/// </summary>
/// <param name="receiverToAdd">The receiving Nucleus</param>
/// <param name="weight">The initial weight to use for the synapses</param>
/// This function will add a synapse to the receiver for each element in the nucleiArray.
// public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1);
/// <summary>
/// Process an external stimulus
/// </summary>
/// <param name="inputValue">The value of the stimulus</param>
/// <param name="thingId">The id of the thing causing the stimulus</param>
/// <param name="thingName">The name of the thing causing the stimulus</param>
public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null);
}
public static class IReceptorHelpers {
/// <summary>
/// Implementation for the NanoBrain::IReceptor::AddReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to extend its nucleiArray</param>
/// <param name="prefab">A prefab of the nucleus to add?</param>
public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) {
if (receptor.nucleiArray.Length == 0) {
Debug.LogError("Empty perceptoid array, cannot add");
}
int newLength = receptor.nucleiArray.Length + 1;
Nucleus[] newArray = new Nucleus[newLength];
string baseName = receptor.GetName();
int colonPos = baseName.IndexOf(":");
if (colonPos > 0)
baseName = baseName[..colonPos];
for (int i = 0; i < receptor.nucleiArray.Length; i++)
newArray[i] = receptor.nucleiArray[i];
if (receptor.nucleiArray[0] is Nucleus nucleus) {
newArray[newLength - 1] = nucleus.Clone(prefab);
newArray[newLength - 1].name = $"{baseName}: {newLength - 1}";
}
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
}
}
}
/// <summary>
/// Implementation for the NanoBrain::IReceptor::RemoteReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to shorten its nucleiArray</param>
public static void RemoveReceptorElement(IReceptor receptor) {
int newLength = receptor.nucleiArray.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
}
Nucleus[] newArray = new Nucleus[newLength];
for (int i = 0; i < newLength; i++)
newArray[i] = receptor.nucleiArray[i];
// Delete the last perception
if (receptor.nucleiArray[newLength] is Nucleus nucleus)
Neuron.Delete(nucleus);
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
}
}
}
/// <summary>
/// Implementation for the NanoBreain::IRceptor::AddArrayReceiver which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor for which a receiving nuclues needs to be added</param>
/// <param name="receiverToAdd">The nucleus to receive input from the receptor</param>
/// <param name="weight">The initial weight for the synapses</param>
public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) {
foreach (Nucleus element in receptor.nucleiArray) {
if (element is Cluster cluster)
cluster.defaultOutput.AddReceiver(receiverToAdd, weight);
if (element is Neuron neuron)
neuron.AddReceiver(receiverToAdd, weight);
}
}
}
}
*/

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 73f052292ad16bb53a3c07aa1694c705

View File

@ -521,32 +521,14 @@ namespace NanoBrain {
}
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
// if (this is IReceptor receptor) {
// foreach (Nucleus element in receptor.nucleiArray) {
// if (element is Neuron neuron) {
// neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
// receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron);
// }
// }
// }
// else {
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
// }
}
#endregion Receivers
public override void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = null) {
// if (this.parent is ClusterReceptor clusterReceptor)
// clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
// else
ProcessStimulusDirect(inputValue); //, thingId, thingName);
}
public void ProcessStimulusDirect(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) {
// this.stale = 0;
public override void ProcessStimulus(Vector3 inputValue) {;
this.lastUpdate = Time.time;
this.bias = inputValue;
this.parent.UpdateFromNucleus(this);

View File

@ -1,199 +0,0 @@
/*
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_MATHEMATICS
using Unity.Mathematics;
using static Unity.Mathematics.math;
#endif
namespace NanoBrain {
/// <summary>
/// Class to manage an array of nuclei for an IReceptor
/// </summary>
/// Would love to get rid of this class.
[System.Serializable]
public class NucleusArray {
/// <summary>
/// The nuclei in this array
/// </summary>
[SerializeReference]
private Nucleus[] _nuclei;
public Nucleus[] nuclei {
get {
return _nuclei;
}
set {
_nuclei = value;
}
}
/// <summary>
/// Create a new NucleusArray with the given nucleus
/// </summary>
/// <param name="nucleus">The Nucleus to put in the NucleusArray</param>
/// This results in an nucleus array of size 1
public NucleusArray(Nucleus nucleus) {
this._nuclei = new Nucleus[1];
this._nuclei[0] = nucleus;
}
/// <summary>
/// Create a new NucleusArray of the given size
/// </summary>
/// <param name="size">The size of the nucluesArray</param>
public NucleusArray(int size) {
this._nuclei = new Nucleus[size];
}
// public void AddNucleus(ClusterPrefab prefab) {
// if (this._nuclei.Length == 0) {
// Debug.LogError("Empty perceptoid array, cannot add");
// return;
// }
// int newLength = this._nuclei.Length + 1;
// Nucleus[] newArray = new Nucleus[newLength];
// for (int i = 0; i < this._nuclei.Length; i++)
// newArray[i] = this._nuclei[i];
// if (this._nuclei[0] is Nucleus nucleus) {
// newArray[newLength - 1] = nucleus.Clone(prefab);
// newArray[newLength - 1].name += $": {newLength - 1}";
// }
// this._nuclei = newArray;
// }
// public void RemoveNucleus() {
// int newLength = this._nuclei.Length - 1;
// if (newLength == 0) {
// Debug.LogWarning("Perceptoid array cannot be empty");
// return;
// }
// Nucleus[] newPerceptei = new Nucleus[newLength];
// for (int i = 0; i < newLength; i++)
// newPerceptei[i] = this._nuclei[i];
// // Delete the last perception
// if (this._nuclei[newLength] is Nucleus nucleus)
// Neuron.Delete(nucleus); //this._nuclei[newLength]);
// this._nuclei = newPerceptei;
// }
public Dictionary<int, Nucleus> thingReceivers = new();
#if UNITY_MATHEMATICS
private Nucleus FindReceiver(int thingId, float3 inputValue) {
float inputMagnitude = length(inputValue);
return FindReceiverMagnitude(thingId, inputMagnitude);
}
#else
private Nucleus FindReceiver(int thingId, Vector3 inputValue) {
float inputMagnitude = inputValue.magnitude;
return FindReceiverMagnitude(thingId, inputMagnitude);
}
#endif
private Nucleus FindReceiverMagnitude(int thingId, float inputMagnitude) {
Neuron selectedReceiver = null;
float selectedMagnitude = 0;
foreach (Nucleus nucleusReceiver in this._nuclei) {
if (nucleusReceiver is not Neuron receiver)
continue;
if (thingReceivers.ContainsValue(receiver) == false) {
// We found an unusued receiver
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (receiver.isSleeping) {
// A sleeping receiver is not active and can therefore always be used
thingReceivers.Add(thingId, receiver);
return receiver;
}
else if (selectedReceiver == null) {
// If we haven't found a receiver yet, just start by taking the first
selectedReceiver = receiver;
selectedMagnitude = selectedReceiver.outputMagnitude;
}
// Look for the receiver with the lowest magnitude
else {
float magnitude = receiver.outputMagnitude;
if (magnitude < inputMagnitude && receiver.outputMagnitude < selectedMagnitude) {
selectedReceiver = receiver;
selectedMagnitude = selectedReceiver.outputMagnitude;
}
}
}
if (selectedReceiver != null) {
// 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;
}
/// <summary>
/// Process an external stimulus
/// </summary>
/// <param name="inputValue">The value of the stimulus</param>
/// <param name="thingId">The id of the thing causing the stimulus</param>
/// <param name="thingName">The name of the thing causing the stimulus</param>
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
CleanupReceivers();
if (this._nuclei[0] is Neuron neuron)
inputValue = neuron.Activator(inputValue);
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
// No existing nucleus for this thing
selectedReceiver = FindReceiver(thingId, inputValue);
}
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;
}
if (selectedReceiver is Neuron selectedNucleus)
selectedNucleus.ProcessStimulusDirect(inputValue);
}
/// <summary>
/// Remove a thing-receiver connection when the nucleus is inactive
/// </summary>
private void CleanupReceivers() {
List<int> receiversToRemove = new();
foreach (KeyValuePair<int, Nucleus> item in thingReceivers) {
if (item.Value != null && item.Value is Neuron neuron && neuron.isSleeping)
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];
}
}
}
}
*/

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: f8cac60bd79854595a8571c042f77998

View File

@ -1,121 +0,0 @@
/*
using UnityEngine;
#if UNITY_MATHEMATICS
using Unity.Mathematics;
using static Unity.Mathematics.math;
#endif
namespace NanoBrain {
/// <summary>
/// Basic IReceptor to receive external input
/// </summary>
[System.Serializable]
public class Receptor : Neuron { //}, IReceptor {
/// <summary>
/// Create a new Receptor in a Cluster instance
/// </summary>
/// <param name="parent">The Cluster in which the Receptor is created</param>
/// <param name="name">The name of the new Receptor</param>
public Receptor(Cluster parent, string name) : base(parent, name) {
//this.array = new NucleusArray(this);
// if (this.name.IndexOf(":") < 0)
// this.name += ": 0";
}
/// <summary>
/// Create a new Receptor in a Cluster Prefab
/// </summary>
/// <param name="prefab">The Cluster Prefab in which the Receptor is created</param>
/// <param name="name">The name of the new Receptor</param>
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) {
//this.array = new NucleusArray(this);
}
public string GetName() {
return this.name;
}
/// \copydoc NanoBrain::Neuron::ShallowCloneTo
public override Nucleus ShallowCloneTo(Cluster parent) {
Receptor clone = new(parent, name) {
};
CloneFields(clone);
return clone;
}
/// \copydoc NanoBrain::Neuron::Clone
public override Nucleus Clone(ClusterPrefab prefab) {
Receptor clone = new(prefab, name) {
//array = this._array
};
CloneFields(clone);
// Adding receivers will also add synapses to the receivers
foreach (Nucleus receiver in this.receivers.ToArray())
clone.AddReceiver(receiver);
return clone;
}
[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 virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
}
public override void UpdateStateIsolated() {
this.outputValue = this.bias;
}
#if UNITY_MATHEMATICS
public override void UpdateNuclei() {
this.stale++;
if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) {
this.bias = new float3(0, 0, 0);
this.parent.UpdateFromNucleus(this);
}
}
#else
public override void UpdateNuclei() {
this.stale++;
if (this.stale > staleValueForSleep && this.bias.sqrMagnitude > 0) {
this.bias = new Vector3(0, 0, 0);
this.parent.UpdateFromNucleus(this);
}
}
#endif
public override void ProcessStimulus(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) {
// this._array ??= new NucleusArray(this.parent);
// this._array.ProcessStimulus(thingId, inputValue, thingName);
this.stale = 0;
this.bias = inputValue;
this.parent.UpdateFromNucleus(this);
}
}
}
*/

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: cfb9734aebc3ab85aacf87d26fb92e55