receptorarray is working
This commit is contained in:
parent
b73b28146c
commit
0258ef1197
40
Cluster.cs
40
Cluster.cs
@ -41,16 +41,6 @@ public class Cluster : INucleus {
|
||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||
}
|
||||
|
||||
// public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
|
||||
// this.prefab = realPrefab;
|
||||
// this.name = realPrefab.name;
|
||||
// this.cluster = parent;
|
||||
// if (this.cluster != null)
|
||||
// this.cluster.nuclei.Add(this);
|
||||
|
||||
// ClonePrefab();
|
||||
// }
|
||||
|
||||
private void ClonePrefab() {
|
||||
IReceptor[] nuclei = this.prefab.nuclei.ToArray();
|
||||
// first clone the nuclei without their connections
|
||||
@ -157,7 +147,8 @@ public class Cluster : INucleus {
|
||||
}
|
||||
|
||||
public virtual IReceptor Clone() {
|
||||
Neuron clone = new(this.cluster, this.name) {
|
||||
//Neuron clone = new(this.cluster, this.name) {
|
||||
Neuron clone = new(this.parent, this.name) {
|
||||
array = this.array,
|
||||
};
|
||||
|
||||
@ -232,6 +223,18 @@ public class Cluster : INucleus {
|
||||
set { _array = value; }
|
||||
}
|
||||
|
||||
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
|
||||
foreach (IReceptor receptor in this.nuclei) {
|
||||
if (receptor is Nucleus nucleus)
|
||||
if (nucleus.name == nucleusName) {
|
||||
foundNucleus = nucleus;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
foundNucleus = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Synapses
|
||||
|
||||
[SerializeField]
|
||||
@ -321,16 +324,23 @@ public class Cluster : INucleus {
|
||||
|
||||
//Applying the weight factors
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||
if (lengthsq(synapse.nucleus.outputValue) > 0) {
|
||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||
this.stale = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//this.inputs[0].UpdateState(sum);
|
||||
this.inputs[0].UpdateStateIsolated(sum);
|
||||
foreach (IReceptor receptor in this.sortedNuclei) {
|
||||
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
|
||||
nucleus.UpdateStateIsolated();
|
||||
if (receptor is INucleus nucleus && nucleus != this.inputs[0]) {
|
||||
//if (nucleus.isSleeping == false)
|
||||
nucleus.UpdateStateIsolated();
|
||||
}
|
||||
}
|
||||
this.outputValue = this.output.outputValue;
|
||||
|
||||
UpdateNuclei();
|
||||
}
|
||||
|
||||
// public virtual void UpdateResult(Vector3 result) {
|
||||
@ -347,7 +357,7 @@ public class Cluster : INucleus {
|
||||
|
||||
public void UpdateNuclei() {
|
||||
this.stale++;
|
||||
if (this.stale > 2)
|
||||
if (this.stale > 5)
|
||||
_outputValue = Vector3.zero;
|
||||
|
||||
//foreach (IReceptor nucleus in this.prefab.nuclei)
|
||||
|
||||
@ -428,17 +428,17 @@ public class ClusterInspector : Editor {
|
||||
|
||||
private void HandleMouseHover(IReceptor nucleus, Rect rect) {
|
||||
GUIContent tooltip;
|
||||
if (nucleus is INucleus n) {
|
||||
tooltip = new(
|
||||
$"{nucleus.name}" +
|
||||
$"\nsynapse count {n.synapses.Count}" +
|
||||
$"\nValue: {length(nucleus.outputValue)}");
|
||||
}
|
||||
else {
|
||||
// if (nucleus is INucleus n) {
|
||||
// tooltip = new(
|
||||
// $"{nucleus.name}" +
|
||||
// //$"\nsynapse count {n.synapses.Count}" +
|
||||
// $"\nValue: {length(nucleus.outputValue)}");
|
||||
// }
|
||||
// else {
|
||||
tooltip = new(
|
||||
$"{nucleus.name}" +
|
||||
$"\nValue: {length(nucleus.outputValue)}");
|
||||
}
|
||||
// }
|
||||
|
||||
Vector2 mousePosition = Event.current.mousePosition;
|
||||
|
||||
@ -616,6 +616,7 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
|
||||
protected virtual void AddInputNeuron(INucleus nucleus) {
|
||||
//Neuron newNeuroid = new(this.cluster, "New neuron");
|
||||
Neuron newNeuroid = new(this.cluster, "New neuron");
|
||||
newNeuroid.AddReceiver(nucleus);
|
||||
this.currentNucleus = newNeuroid;
|
||||
|
||||
25
Neuron.cs
25
Neuron.cs
@ -193,7 +193,8 @@ public class Neuron : Nucleus, INucleus {
|
||||
}
|
||||
|
||||
public override IReceptor Clone() {
|
||||
Neuron clone = new(this.cluster, this.name) {
|
||||
//Neuron clone = new(this.cluster, this.name) {
|
||||
Neuron clone = new(this.parent, this.name) {
|
||||
array = this.array,
|
||||
curve = this.curve,
|
||||
curvePreset = this.curvePreset,
|
||||
@ -299,8 +300,10 @@ public class Neuron : Nucleus, INucleus {
|
||||
// public virtual void UpdateStateIsolated() {
|
||||
// UpdateStateIsolated(new float3(0, 0, 0));
|
||||
// }
|
||||
public override void UpdateStateIsolated(float3 bias) {
|
||||
float3 sum = bias;
|
||||
|
||||
public float3 bias = float3(0, 0, 0);
|
||||
public override void UpdateStateIsolated(float3 bias_unused) {
|
||||
float3 sum = this.bias;
|
||||
int n = 0;
|
||||
|
||||
//Applying the weight factgors
|
||||
@ -308,8 +311,10 @@ public class Neuron : Nucleus, INucleus {
|
||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||
|
||||
// Perhaps synapses should be removed when the output value goes to 0....
|
||||
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
||||
if (lengthsq(synapse.nucleus.outputValue) != 0) {
|
||||
n++;
|
||||
this.stale = 0;
|
||||
}
|
||||
}
|
||||
if (this.average && n > 0)
|
||||
sum /= n;
|
||||
@ -337,7 +342,17 @@ public class Neuron : Nucleus, INucleus {
|
||||
result = normalize(sum) * activatedValue;
|
||||
break;
|
||||
}
|
||||
this.outputValue = result;
|
||||
if (this.stale > 5)
|
||||
this.outputValue = new float3(0,0,0);
|
||||
else
|
||||
this.outputValue = result;
|
||||
}
|
||||
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) {
|
||||
//this.outputValue = inputValue;
|
||||
this.stale = 0;
|
||||
Debug.Log($"{this.name} processed stimulus");
|
||||
this.bias = inputValue;
|
||||
}
|
||||
|
||||
// public virtual void UpdateResult(Vector3 result) {
|
||||
|
||||
13
Nucleus.cs
13
Nucleus.cs
@ -20,7 +20,8 @@ public abstract class Nucleus : IReceptor {
|
||||
public virtual float3 outputValue {
|
||||
get { return _outputValue; }
|
||||
set {
|
||||
this.stale = 0;
|
||||
//Debug.Log($"{this.name}: stale is reset, was: {this.stale}");
|
||||
//this.stale = 0;
|
||||
// this._isSleeping = false;
|
||||
_outputValue = value;
|
||||
}
|
||||
@ -28,7 +29,7 @@ public abstract class Nucleus : IReceptor {
|
||||
|
||||
public bool isSleeping => lengthsq(this.outputValue) == 0;
|
||||
[NonSerialized]
|
||||
private int stale = 1000;
|
||||
public int stale = 1000;
|
||||
|
||||
// Cannot clone an abstract nucleus...
|
||||
public virtual IReceptor ShallowCloneTo(Cluster parent) { return null; }
|
||||
@ -96,8 +97,14 @@ public abstract class Nucleus : IReceptor {
|
||||
|
||||
public void UpdateNuclei() {
|
||||
this.stale++;
|
||||
if (this.stale > 2)
|
||||
if (this.stale > 5) {
|
||||
//Debug.Log($"{this.name} goes to sleep, stale = {this.stale}");
|
||||
_outputValue = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||
this.array.ProcessStimulus(thingId, inputValue, thingName);
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
|
||||
@ -6,7 +6,6 @@ using UnityEngine;
|
||||
public class NucleusArray {
|
||||
[SerializeReference]
|
||||
private IReceptor[] _nuclei;
|
||||
//private ClusterPrefab[] _clusters;
|
||||
public IReceptor[] nuclei {
|
||||
get {
|
||||
return _nuclei;
|
||||
@ -18,13 +17,10 @@ public class NucleusArray {
|
||||
this.name = nucleus.name;
|
||||
this._nuclei = new INucleus[1];
|
||||
this._nuclei[0] = nucleus;
|
||||
//this._clusters = new ClusterPrefab[0];
|
||||
}
|
||||
public NucleusArray(ClusterPrefab cluster) {
|
||||
this.name = cluster.name;
|
||||
this._nuclei = new INucleus[0];
|
||||
// this._clusters = new ClusterPrefab[1];
|
||||
// this._clusters[0] = cluster;
|
||||
}
|
||||
public NucleusArray(int size, string name) {
|
||||
this.name = name;
|
||||
@ -64,5 +60,60 @@ public class NucleusArray {
|
||||
this._nuclei = newPerceptei;
|
||||
}
|
||||
|
||||
public Dictionary<int, INucleus> thingReceivers = new();
|
||||
|
||||
|
||||
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||
CleanupReceivers();
|
||||
if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) {
|
||||
Debug.Log($"No receiver found for {thingId}");
|
||||
foreach (IReceptor receptor in this.nuclei) {
|
||||
if (receptor is not INucleus receiver)
|
||||
continue;
|
||||
|
||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||
// receiver is not used yet
|
||||
Debug.Log($"{thingId} -> {receiver.name}");
|
||||
thingReceivers.Add(thingId, receiver);
|
||||
selectedReceiver = receiver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.ProcessStimulus(inputValue);
|
||||
selectedReceiver.parent.UpdateStateIsolated();
|
||||
}
|
||||
|
||||
private void CleanupReceivers() {
|
||||
// Remove a thing-receiver connection when the nucleus is inactive
|
||||
List<int> receiversToRemove = new();
|
||||
foreach (KeyValuePair<int, INucleus> item in thingReceivers) {
|
||||
if (item.Value.isSleeping) {
|
||||
Nucleus n = item.Value as Nucleus;
|
||||
Debug.Log($"{item.Value.name} is sleeping, stale = {n.stale}");
|
||||
receiversToRemove.Add(item.Key);
|
||||
}
|
||||
}
|
||||
foreach (int thingId in receiversToRemove) {
|
||||
INucleus selectedReceiver = thingReceivers[thingId];
|
||||
|
||||
thingReceivers.Remove(thingId);
|
||||
Debug.Log($"Cleanup receiver for {thingId}");
|
||||
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
selectedReceiver.name = selectedReceiver.name[..colonPos];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Receptor.cs
17
Receptor.cs
@ -6,7 +6,6 @@ using static Unity.Mathematics.math;
|
||||
|
||||
public class Receptor : IReceptor {
|
||||
|
||||
|
||||
[SerializeField]
|
||||
protected string _name;
|
||||
public virtual string name {
|
||||
@ -16,13 +15,7 @@ public class Receptor : IReceptor {
|
||||
|
||||
public Receptor(Cluster parent) {
|
||||
this.parent = parent;
|
||||
if (parent != null)
|
||||
parent.nuclei.Add(this);
|
||||
}
|
||||
public Receptor(ClusterPrefab cluster) {
|
||||
this.cluster = cluster;
|
||||
if (cluster != null)
|
||||
cluster.nuclei.Add(this);
|
||||
parent?.nuclei.Add(this);
|
||||
}
|
||||
|
||||
public Receptor(Cluster parent, string name, string nucleusName) {
|
||||
@ -37,8 +30,7 @@ public class Receptor : IReceptor {
|
||||
}
|
||||
}
|
||||
|
||||
private ClusterPrefab cluster;
|
||||
private Cluster parent;
|
||||
private readonly Cluster parent;
|
||||
|
||||
public virtual IReceptor ShallowCloneTo(Cluster parent) {
|
||||
Receptor clone = new(parent);
|
||||
@ -46,7 +38,7 @@ public class Receptor : IReceptor {
|
||||
}
|
||||
|
||||
public virtual IReceptor Clone() {
|
||||
Receptor clone = new(this.cluster);
|
||||
Receptor clone = new(this.parent);
|
||||
|
||||
foreach (INucleus receiver in this.receivers) {
|
||||
clone.AddReceiver(receiver);
|
||||
@ -90,9 +82,6 @@ public class Receptor : IReceptor {
|
||||
private bool _isSleeping = false;
|
||||
public bool isSleeping => _isSleeping;
|
||||
|
||||
// public float distanceResolution = 0.1f;
|
||||
// public float directionResolution = 5;
|
||||
|
||||
private float3 _outputValue;
|
||||
public float3 outputValue {
|
||||
get { return this._outputValue; }
|
||||
|
||||
85
ReceptorArray.cs
Normal file
85
ReceptorArray.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ReceptorArray {
|
||||
public string name;
|
||||
|
||||
public Cluster parent { get; set; }
|
||||
|
||||
public NucleusArray nuclei;
|
||||
public int size => nuclei.nuclei.Length;
|
||||
|
||||
public Dictionary<int, INucleus> thingReceivers = new();
|
||||
|
||||
public ReceptorArray(Cluster parent, NucleusArray nuclei) {
|
||||
this.parent = parent;
|
||||
this.nuclei = nuclei;
|
||||
}
|
||||
|
||||
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
|
||||
if (!thingReceivers.TryGetValue(thingId, out INucleus selectedReceiver)) {
|
||||
foreach (IReceptor receptor in this.nuclei.nuclei) {
|
||||
if (receptor is not INucleus receiver)
|
||||
continue;
|
||||
if (thingReceivers.ContainsValue(receiver))
|
||||
continue;
|
||||
// receiver is not used yet
|
||||
thingReceivers.Add(thingId, receiver);
|
||||
selectedReceiver = receiver;
|
||||
}
|
||||
}
|
||||
//selectedReceiver.outputValue = newLocalPositionVector;
|
||||
|
||||
|
||||
/*
|
||||
int receiverIx = 0;
|
||||
INucleus selectedReceiver = null;
|
||||
int selectedReceiverIx = 0;
|
||||
foreach (INucleus receiver in this.receivers) {
|
||||
if (thingIds[receiverIx] == thingId) {
|
||||
// We found an existing receiver for this thing
|
||||
selectedReceiver = receiver;
|
||||
selectedReceiverIx = receiverIx;
|
||||
// Do not look any further
|
||||
break;
|
||||
}
|
||||
else if (receiver.isSleeping) {
|
||||
// A sleeping receiver is not active and can therefore always be used
|
||||
selectedReceiver = receiver;
|
||||
selectedReceiverIx = receiverIx;
|
||||
// Look further because we may find an existing receiver for this thing
|
||||
}
|
||||
else if (selectedReceiver == null) {
|
||||
// If we haven't found a receiver yet, just start by taking the first
|
||||
selectedReceiver = receiver;
|
||||
selectedReceiverIx = receiverIx;
|
||||
}
|
||||
else if (selectedReceiver.isSleeping == false) {
|
||||
// If no existing or sleeping receiver is found, we look for
|
||||
// the receiver with the furthest/least interesting stimulus
|
||||
if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) {
|
||||
// Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" +
|
||||
// $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} ");
|
||||
selectedReceiver = receiver;
|
||||
selectedReceiverIx = receiverIx;
|
||||
}
|
||||
}
|
||||
receiverIx++;
|
||||
}
|
||||
if (selectedReceiverIx >= thingIds.Length)
|
||||
return;
|
||||
|
||||
thingIds[selectedReceiverIx] = thingId;
|
||||
if (thingName != null) {
|
||||
string baseName = selectedReceiver.name;
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
baseName = selectedReceiver.name.Substring(0, colonPos);
|
||||
selectedReceiver.name = baseName + ": " + thingName;
|
||||
}
|
||||
Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}");
|
||||
selectedReceiver.parent.UpdateStateIsolated();
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
2
ReceptorArray.cs.meta
Normal file
2
ReceptorArray.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e915c8563642f23891b20522b3589cf
|
||||
Loading…
x
Reference in New Issue
Block a user