Cleanup
This commit is contained in:
parent
c8f0f0c9da
commit
75d9d1cd5c
@ -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() {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 837dfcffeb99804479a0887cbfc33372
|
||||
@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f64f5d72a422a7c8bb9ace598432aad
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f052292ad16bb53a3c07aa1694c705
|
||||
@ -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);
|
||||
|
||||
@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8cac60bd79854595a8571c042f77998
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfb9734aebc3ab85aacf87d26fb92e55
|
||||
Loading…
x
Reference in New Issue
Block a user