Further improve receptor / nucleusarray combination
This commit is contained in:
parent
9b948fdd07
commit
f295da9c55
@ -263,7 +263,7 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
// Draw selected Nucleus
|
// Draw selected Nucleus
|
||||||
if (expandArray) {
|
if (expandArray) {
|
||||||
if (this.currentNucleus is Receptor receptor) {
|
if (this.currentNucleus is ReceptorArray receptor) {
|
||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
foreach (Nucleus nucleus in receptor.instances) {
|
foreach (Nucleus nucleus in receptor.instances) {
|
||||||
float value = length(nucleus.outputValue);
|
float value = length(nucleus.outputValue);
|
||||||
@ -467,7 +467,7 @@ public class ClusterInspector : Editor {
|
|||||||
if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) {
|
if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) {
|
||||||
Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style);
|
Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style);
|
||||||
}
|
}
|
||||||
if (nucleus is Receptor receptor) {
|
if (nucleus is ReceptorArray receptor) {
|
||||||
Handles.Label(labelPosition, receptor.instances.Count().ToString(), style);
|
Handles.Label(labelPosition, receptor.instances.Count().ToString(), style);
|
||||||
}
|
}
|
||||||
// else if (nucleus is ReceptorInstance receptorI) {
|
// else if (nucleus is ReceptorInstance receptorI) {
|
||||||
@ -611,7 +611,7 @@ public class ClusterInspector : Editor {
|
|||||||
if (this.currentNucleus is MemoryCell memory) {
|
if (this.currentNucleus is MemoryCell memory) {
|
||||||
memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory);
|
memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory);
|
||||||
}
|
}
|
||||||
if (this.currentNucleus is Receptor receptor) {
|
if (this.currentNucleus is ReceptorArray receptor) {
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
EditorGUILayout.IntField("Receptor size", receptor.instances.Count());
|
EditorGUILayout.IntField("Receptor size", receptor.instances.Count());
|
||||||
if (GUILayout.Button("Add")) {
|
if (GUILayout.Button("Add")) {
|
||||||
@ -626,6 +626,22 @@ public class ClusterInspector : Editor {
|
|||||||
}
|
}
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
}
|
}
|
||||||
|
if (this.currentNucleus is Receptor receptor1) {
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count());
|
||||||
|
if (GUILayout.Button("Add")) {
|
||||||
|
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||||
|
receptor1.array.AddNucleus(this.prefab);
|
||||||
|
anythingChanged = true;
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Del")) {
|
||||||
|
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
||||||
|
receptor1.array.RemoveNucleus();
|
||||||
|
anythingChanged = true;
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Synapses
|
// Synapses
|
||||||
|
|
||||||
@ -707,19 +723,22 @@ public class ClusterInspector : Editor {
|
|||||||
}
|
}
|
||||||
if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0)
|
if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0)
|
||||||
neuron.array = new NucleusArray(neuron);
|
neuron.array = new NucleusArray(neuron);
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count());
|
// if (this.currentNucleus is Receptor receptor1) {
|
||||||
if (GUILayout.Button("Add")) {
|
// EditorGUILayout.BeginHorizontal();
|
||||||
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
// EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count());
|
||||||
neuron.array.AddNucleus(this.prefab);
|
// if (GUILayout.Button("Add")) {
|
||||||
anythingChanged = true;
|
// Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||||
}
|
// receptor1.array.AddNucleus(this.prefab);
|
||||||
if (GUILayout.Button("Del")) {
|
// anythingChanged = true;
|
||||||
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
// }
|
||||||
neuron.array.RemoveNucleus();
|
// if (GUILayout.Button("Del")) {
|
||||||
anythingChanged = true;
|
// Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
||||||
}
|
// receptor1.array.RemoveNucleus();
|
||||||
EditorGUILayout.EndHorizontal();
|
// anythingChanged = true;
|
||||||
|
// }
|
||||||
|
// EditorGUILayout.EndHorizontal();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
@ -753,7 +772,7 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
void OnSceneGUI(SceneView sceneView) {
|
void OnSceneGUI(SceneView sceneView) {
|
||||||
if (this.gameObject != null) {
|
if (this.gameObject != null) {
|
||||||
if (this.currentNucleus is Receptor receptor && expandArray) {
|
if (this.currentNucleus is ReceptorArray receptor && expandArray) {
|
||||||
foreach (Nucleus nucleus in receptor.instances) {
|
foreach (Nucleus nucleus in receptor.instances) {
|
||||||
Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue);
|
Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue);
|
||||||
Handles.color = Color.yellow;
|
Handles.color = Color.yellow;
|
||||||
@ -791,6 +810,9 @@ public class ClusterInspector : Editor {
|
|||||||
case Nucleus.Type.Receptor:
|
case Nucleus.Type.Receptor:
|
||||||
AddReceptorInput(nucleus);
|
AddReceptorInput(nucleus);
|
||||||
break;
|
break;
|
||||||
|
case Nucleus.Type.ReceptorArray:
|
||||||
|
AddReceptorArrayInput(nucleus);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -877,6 +899,13 @@ public class ClusterInspector : Editor {
|
|||||||
BuildLayers();
|
BuildLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void AddReceptorArrayInput(Nucleus nucleus) {
|
||||||
|
ReceptorArray newReceptor = new(this.prefab, "New Receptor");
|
||||||
|
newReceptor.AddReceiver(nucleus);
|
||||||
|
this.currentNucleus = newReceptor;
|
||||||
|
BuildLayers();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) {
|
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) {
|
||||||
Cluster subclusterInstance = new(prefab, this.prefab);
|
Cluster subclusterInstance = new(prefab, this.prefab);
|
||||||
subclusterInstance.AddReceiver(nucleus);
|
subclusterInstance.AddReceiver(nucleus);
|
||||||
|
|||||||
@ -14,8 +14,8 @@ public class Neuron : Nucleus {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.parent?.nuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
}
|
}
|
||||||
public Neuron(ClusterPrefab parent, string name) {
|
public Neuron(ClusterPrefab prefab, string name) {
|
||||||
this.cluster = parent;
|
this.cluster = prefab;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
if (this.cluster != null)
|
if (this.cluster != null)
|
||||||
this.cluster.nuclei.Add(this);
|
this.cluster.nuclei.Add(this);
|
||||||
|
|||||||
@ -41,7 +41,8 @@ public abstract class Nucleus {
|
|||||||
Selector,
|
Selector,
|
||||||
Cluster,
|
Cluster,
|
||||||
Pulsar,
|
Pulsar,
|
||||||
Receptor
|
Receptor,
|
||||||
|
ReceptorArray
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Synapses
|
#region Synapses
|
||||||
@ -111,6 +112,10 @@ public abstract class Nucleus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
|
this.array.ProcessStimulus(thingId, inputValue, thingName);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||||
this.array.ProcessStimulus(thingId, inputValue, thingName);
|
this.array.ProcessStimulus(thingId, inputValue, thingName);
|
||||||
}
|
}
|
||||||
|
|||||||
172
Receptor.cs
172
Receptor.cs
@ -1,159 +1,43 @@
|
|||||||
/*
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
|
||||||
public class Receptor : IReceptor {
|
[System.Serializable]
|
||||||
|
public class Receptor : Neuron {
|
||||||
|
public Receptor(Cluster parent, string name) : base(parent, name) { }
|
||||||
|
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { }
|
||||||
|
|
||||||
[SerializeField]
|
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||||
protected string _name;
|
Receptor clone = new(parent, name);
|
||||||
public virtual string name {
|
|
||||||
get => _name;
|
|
||||||
set => _name = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Receptor(Cluster parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
parent?.nuclei.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Receptor(Cluster parent, string name, string nucleusName) {
|
|
||||||
this.parent = parent ?? throw new ArgumentNullException(nameof(parent), "Parent cannot be null.");
|
|
||||||
|
|
||||||
this.name = name;
|
|
||||||
this.parent.nuclei.Add(this);
|
|
||||||
foreach (INucleus nucleus in parent.inputs) {
|
|
||||||
if (nucleus != null && nucleus.name == nucleusName) {
|
|
||||||
this.AddReceiver(nucleus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Cluster parent;
|
|
||||||
|
|
||||||
public virtual IReceptor ShallowCloneTo(Cluster parent) {
|
|
||||||
Receptor clone = new(parent);
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
public override Nucleus Clone(ClusterPrefab prefab) {
|
||||||
public virtual IReceptor Clone() {
|
Receptor clone = new(prefab, name);
|
||||||
Receptor clone = new(this.parent);
|
CloneFields(clone);
|
||||||
|
// Adding receivers will also add synapses to the receivers
|
||||||
foreach (INucleus receiver in this.receivers) {
|
foreach (Nucleus receiver in this.receivers)
|
||||||
clone.AddReceiver(receiver);
|
clone.AddReceiver(receiver);
|
||||||
}
|
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Receiver {
|
// [SerializeReference]
|
||||||
public INucleus nucleus;
|
// private NucleusArray _array;
|
||||||
public int thingId;
|
// public NucleusArray array {
|
||||||
public string thingName;
|
// get { return _array; }
|
||||||
public Receiver(INucleus nucleus, int thingId, string thingName) {
|
// set { _array = value; }
|
||||||
this.nucleus = nucleus;
|
// }
|
||||||
this.thingId = thingId;
|
|
||||||
this.thingName = thingName;
|
|
||||||
}
|
public override void UpdateStateIsolated() {
|
||||||
|
this.outputValue = this.bias;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeReference]
|
public override void UpdateNuclei() {
|
||||||
private List<INucleus> _receivers = new();
|
|
||||||
public List<INucleus> receivers {
|
|
||||||
get { return _receivers; }
|
|
||||||
set { _receivers = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int[] thingIds; // every receiver can handle a thing with this id
|
|
||||||
|
|
||||||
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
|
|
||||||
this._receivers.Add(receivingNucleus);
|
|
||||||
receivingNucleus.AddSynapse(this, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveReceiver(INucleus receiverNucleus) {
|
|
||||||
this._receivers.RemoveAll(receiver => receiver == receiverNucleus);
|
|
||||||
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int stale = 1000;
|
|
||||||
|
|
||||||
private bool _isSleeping = false;
|
|
||||||
public bool isSleeping => _isSleeping;
|
|
||||||
|
|
||||||
private float3 _outputValue;
|
|
||||||
public float3 outputValue {
|
|
||||||
get { return this._outputValue; }
|
|
||||||
set {
|
|
||||||
this.stale = 0;
|
|
||||||
this._isSleeping = false;
|
|
||||||
this._outputValue = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
|
|
||||||
this.outputValue = newLocalPositionVector;
|
|
||||||
if (this._receivers == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
thingIds ??= new int[this._receivers.Count];
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateNuclei() {
|
|
||||||
this.stale++;
|
this.stale++;
|
||||||
this._isSleeping = this.stale > 2;
|
if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) {
|
||||||
if (isSleeping)
|
this.bias = new float3(0, 0, 0);
|
||||||
this._outputValue = Vector3.zero;
|
this.parent.UpdateFromNucleus(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
}
|
||||||
@ -31,15 +31,15 @@ public class ReceptorInstance : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
public Receptor receptor;
|
public ReceptorArray receptor;
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
public override void UpdateStateIsolated() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Receptor : Nucleus {
|
public class ReceptorArray : Nucleus {
|
||||||
public Receptor(Cluster parent, string name) {
|
public ReceptorArray(Cluster parent, string name) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this._instances = new ReceptorInstance[1];
|
this._instances = new ReceptorInstance[1];
|
||||||
@ -48,7 +48,7 @@ public class Receptor : Nucleus {
|
|||||||
};
|
};
|
||||||
this.parent?.nuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
}
|
}
|
||||||
public Receptor(ClusterPrefab prefab, string name) {
|
public ReceptorArray(ClusterPrefab prefab, string name) {
|
||||||
this.cluster = prefab;
|
this.cluster = prefab;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this._instances = new ReceptorInstance[1];
|
this._instances = new ReceptorInstance[1];
|
||||||
@ -63,7 +63,7 @@ public class Receptor : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Nucleus ShallowCloneTo(Cluster parent) {
|
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||||
Receptor clone = new(parent, name) {
|
ReceptorArray clone = new(parent, name) {
|
||||||
_instances = new ReceptorInstance[this.instances.Length]
|
_instances = new ReceptorInstance[this.instances.Length]
|
||||||
};
|
};
|
||||||
for (int ix = 0; ix < this.instances.Length; ix++) {
|
for (int ix = 0; ix < this.instances.Length; ix++) {
|
||||||
@ -76,7 +76,7 @@ public class Receptor : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Nucleus Clone(ClusterPrefab prefab) {
|
public override Nucleus Clone(ClusterPrefab prefab) {
|
||||||
Receptor clone = new(prefab, this.name) {
|
ReceptorArray clone = new(prefab, this.name) {
|
||||||
_instances = new ReceptorInstance[this.instances.Length]
|
_instances = new ReceptorInstance[this.instances.Length]
|
||||||
};
|
};
|
||||||
for (int ix = 0; ix < this.instances.Length; ix++) {
|
for (int ix = 0; ix < this.instances.Length; ix++) {
|
||||||
@ -96,7 +96,7 @@ public class Receptor : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
private ReceptorInstance[] _instances;
|
private ReceptorInstance[] _instances = new ReceptorInstance[0];
|
||||||
public ReceptorInstance[] instances {
|
public ReceptorInstance[] instances {
|
||||||
get {
|
get {
|
||||||
return _instances;
|
return _instances;
|
||||||
@ -141,7 +141,7 @@ public class Receptor : Nucleus {
|
|||||||
public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||||
ProcessStimulus(inputValue, thingId, thingName);
|
ProcessStimulus(inputValue, thingId, thingName);
|
||||||
}
|
}
|
||||||
public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
CleanupReceivers();
|
CleanupReceivers();
|
||||||
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
|
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
|
||||||
//Debug.Log($" no receiver found for {thingId}");
|
//Debug.Log($" no receiver found for {thingId}");
|
||||||
@ -194,6 +194,7 @@ public class Receptor : Nucleus {
|
|||||||
float inputMagnitude = length(inputValue);
|
float inputMagnitude = length(inputValue);
|
||||||
Nucleus selectedReceiver = null;
|
Nucleus selectedReceiver = null;
|
||||||
float selectedMagnitude = 0;
|
float selectedMagnitude = 0;
|
||||||
|
this._instances ??= new ReceptorInstance[0];
|
||||||
foreach (Nucleus receiver in this._instances) {
|
foreach (Nucleus receiver in this._instances) {
|
||||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||||
// We found an unusued receiver
|
// We found an unusued receiver
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user