Disabled Receptor

This commit is contained in:
Pascal Serrarens 2026-02-05 16:55:12 +01:00
parent 0258ef1197
commit 0d268edd6d
9 changed files with 107 additions and 100 deletions

View File

@ -42,22 +42,22 @@ public class Cluster : INucleus {
} }
private void ClonePrefab() { private void ClonePrefab() {
IReceptor[] nuclei = this.prefab.nuclei.ToArray(); INucleus[] prefabNuclei = this.prefab.nuclei.ToArray();
// first clone the nuclei without their connections // first clone the nuclei without their connections
foreach (IReceptor nucleus in this.prefab.nuclei) foreach (INucleus nucleus in this.prefab.nuclei)
nucleus.ShallowCloneTo(this); nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray(); INucleus[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections // Now clone the connections
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
IReceptor receptor = nuclei[nucleusIx]; INucleus receptor = prefabNuclei[nucleusIx];
IReceptor clonedReceptor = clonedNuclei[nucleusIx]; INucleus clonedReceptor = clonedNuclei[nucleusIx];
if (clonedReceptor == null) if (clonedReceptor == null)
continue; continue;
// Copy the receivers, which will also create the synapses // Copy the receivers, which will also create the synapses
foreach (INucleus receiver in receptor.receivers) { foreach (INucleus receiver in receptor.receivers) {
int ix = GetNucleusIndex(nuclei, receiver); int ix = GetNucleusIndex(prefabNuclei, receiver);
if (ix < 0) if (ix < 0)
continue; continue;
@ -79,8 +79,8 @@ public class Cluster : INucleus {
} }
// Copy nucleus arrays // Copy nucleus arrays
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
IReceptor prefabReceptor = nuclei[nucleusIx]; IReceptor prefabReceptor = prefabNuclei[nucleusIx];
if (prefabReceptor is not INucleus prefabNucleus) if (prefabReceptor is not INucleus prefabNucleus)
continue; continue;
@ -93,7 +93,7 @@ public class Cluster : INucleus {
NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array");
int arrayIx = 0; int arrayIx = 0;
foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) { foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) {
int arrayNucleusIx = GetNucleusIndex(nuclei, prefabArrayNucleus); int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx];
clonedArray.nuclei[arrayIx] = clonedArrayNucleus; clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
arrayIx++; arrayIx++;
@ -102,7 +102,7 @@ public class Cluster : INucleus {
} }
else { else {
// The others will refer to the array created for the first nucleus in the array // The others will refer to the array created for the first nucleus in the array
int firstNucleusIx = GetNucleusIndex(nuclei, prefabNucleus.array.nuclei[0]); int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]);
INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus; INucleus clonedFirstNucleus = clonedNuclei[firstNucleusIx] as INucleus;
clonedNucleus.array = clonedFirstNucleus.array; clonedNucleus.array = clonedFirstNucleus.array;
} }
@ -110,26 +110,26 @@ public class Cluster : INucleus {
} }
// Sort the nuclei in a correct evaluation order // Sort the nuclei in a correct evaluation order
private List<IReceptor> TopologicalSort(List<IReceptor> nodes) { private List<IReceptor> TopologicalSort(List<INucleus> nodes) {
Dictionary<IReceptor, int> inDegree = new(); Dictionary<IReceptor, int> inDegree = new();
foreach (IReceptor node in nodes) foreach (IReceptor node in nodes)
inDegree[node] = 0; // Initialize in-degree to zero inDegree[node] = 0; // Initialize in-degree to zero
// Calculate in-degrees // Calculate in-degrees
foreach (IReceptor node in nodes) { foreach (INucleus node in nodes) {
foreach (INucleus receiver in node.receivers) foreach (INucleus receiver in node.receivers)
inDegree[receiver]++; inDegree[receiver]++;
} }
Queue<IReceptor> queue = new(); Queue<INucleus> queue = new();
foreach (IReceptor node in nodes) { foreach (INucleus node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node); queue.Enqueue(node);
} }
List<IReceptor> sortedOrder = new(); List<IReceptor> sortedOrder = new();
while (queue.Count > 0) { while (queue.Count > 0) {
IReceptor current = queue.Dequeue(); INucleus current = queue.Dequeue();
sortedOrder.Add(current); // Process the node sortedOrder.Add(current); // Process the node
foreach (INucleus receiver in current.receivers) { foreach (INucleus receiver in current.receivers) {
@ -185,7 +185,7 @@ public class Cluster : INucleus {
public Cluster parent { get; set; } public Cluster parent { get; set; }
[SerializeReference] [SerializeReference]
public List<IReceptor> nuclei = new(); public List<INucleus> nuclei = new();
// the nuclei sorted using topological sorting // the nuclei sorted using topological sorting
// to ensure that the cluster is computer in the right order // to ensure that the cluster is computer in the right order
public List<IReceptor> sortedNuclei; public List<IReceptor> sortedNuclei;
@ -235,13 +235,22 @@ public class Cluster : INucleus {
return false; return false;
} }
public Nucleus GetNucleus(string nucleusName) {
foreach (IReceptor receptor in this.nuclei) {
if (receptor is Nucleus nucleus)
if (nucleus.name == nucleusName)
return nucleus;
}
return null;
}
#region Synapses #region Synapses
[SerializeField] [SerializeField]
private List<Synapse> _synapses = new(); private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses; public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight); Synapse synapse = new(sendingNucleus, weight);
this._synapses.Add(synapse); this._synapses.Add(synapse);
return synapse; return synapse;
@ -361,7 +370,7 @@ public class Cluster : INucleus {
_outputValue = Vector3.zero; _outputValue = Vector3.zero;
//foreach (IReceptor nucleus in this.prefab.nuclei) //foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (IReceptor nucleus in this.nuclei) foreach (INucleus nucleus in this.nuclei)
nucleus.UpdateNuclei(); nucleus.UpdateNuclei();
} }

View File

@ -7,7 +7,7 @@ public class ClusterPrefab : ScriptableObject {
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
[SerializeReference] [SerializeReference]
public List<IReceptor> nuclei = new(); public List<INucleus> nuclei = new();
public virtual INucleus output => this.nuclei[0] as INucleus; public virtual INucleus output => this.nuclei[0] as INucleus;
@ -33,7 +33,7 @@ public class ClusterPrefab : ScriptableObject {
// This is an invariant and should be ensured before the nucleus is used // This is an invariant and should be ensured before the nucleus is used
// because output requires it. // because output requires it.
public void EnsureInitialization() { public void EnsureInitialization() {
nuclei ??= new List<IReceptor>(); nuclei ??= new List<INucleus>();
if (nuclei.Count == 0) if (nuclei.Count == 0)
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
} }
@ -74,7 +74,7 @@ public class ClusterPrefab : ScriptableObject {
} }
public virtual void UpdateNuclei() { public virtual void UpdateNuclei() {
foreach (IReceptor nucleus in this.nuclei) foreach (INucleus nucleus in this.nuclei)
nucleus.UpdateNuclei(); nucleus.UpdateNuclei();
} }
} }

View File

@ -210,7 +210,7 @@ public class ClusterInspector : Editor {
// Draw selected Nucleus // Draw selected Nucleus
if (expandArray) { if (expandArray) {
float maxValue = 0; float maxValue = 0;
foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { foreach (INucleus nucleus in this.currentNucleus.array.nuclei) {
float value = length(nucleus.outputValue); float value = length(nucleus.outputValue);
if (value > maxValue) if (value > maxValue)
maxValue = value; maxValue = value;
@ -231,7 +231,7 @@ public class ClusterInspector : Editor {
Handles.color = Color.black; Handles.color = Color.black;
Handles.DrawAAConvexPolygon(verts); Handles.DrawAAConvexPolygon(verts);
int row = 0; int row = 0;
foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { foreach (INucleus nucleus in this.currentNucleus.array.nuclei) {
Vector3 pos = new(150, margin + row * spacing, 0.0f); Vector3 pos = new(150, margin + row * spacing, 0.0f);
Handles.color = Color.white; Handles.color = Color.white;
// The selected nucleus highlight ring // The selected nucleus highlight ring
@ -344,7 +344,7 @@ public class ClusterInspector : Editor {
} }
} }
private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size) { private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size) {
Color color; Color color;
if (nucleus.isSleeping) if (nucleus.isSleeping)
color = Color.darkRed; color = Color.darkRed;
@ -359,7 +359,7 @@ public class ClusterInspector : Editor {
DrawNucleus(nucleus, position, maxValue, size, color); DrawNucleus(nucleus, position, maxValue, size, color);
} }
private void DrawNucleus(IReceptor nucleus, Vector3 position, float maxValue, float size, Color color) { private void DrawNucleus(INucleus nucleus, Vector3 position, float maxValue, float size, Color color) {
if (nucleus is MemoryCell memory) { if (nucleus is MemoryCell memory) {
Handles.color = Color.white; Handles.color = Color.white;
Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size); Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size);
@ -426,7 +426,7 @@ public class ClusterInspector : Editor {
} }
} }
private void HandleMouseHover(IReceptor nucleus, Rect rect) { private void HandleMouseHover(INucleus nucleus, Rect rect) {
GUIContent tooltip; GUIContent tooltip;
// if (nucleus is INucleus n) { // if (nucleus is INucleus n) {
// tooltip = new( // tooltip = new(
@ -692,7 +692,7 @@ public class ClusterInspector : Editor {
// Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()]; // Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()];
// n.AddReceiver(this.currentNucleus); // n.AddReceiver(this.currentNucleus);
// } // }
IReceptor receptor = cluster.nuclei[selectedIndex]; INucleus receptor = cluster.nuclei[selectedIndex];
receptor.AddReceiver(this.currentNucleus); receptor.AddReceiver(this.currentNucleus);
} }
} }

View File

@ -11,7 +11,7 @@ public interface INucleus : IReceptor {
// Senders // Senders
public List<Synapse> synapses { get; } public List<Synapse> synapses { get; }
public Synapse AddSynapse(IReceptor sender, float weight = 1.0f); public Synapse AddSynapse(INucleus sender, float weight = 1.0f);
public NucleusArray array { get; set; } public NucleusArray array { get; set; }
@ -25,9 +25,7 @@ public interface INucleus : IReceptor {
public void UpdateStateIsolated(float3 inputValue); public void UpdateStateIsolated(float3 inputValue);
#endregion dynamic state #endregion dynamic state
}
public interface IReceptor {
#region static #region static
public string name { get; set; } public string name { get; set; }
@ -54,3 +52,6 @@ public interface IReceptor {
public IReceptor Clone(); public IReceptor Clone();
} }
public interface IReceptor {
}

View File

@ -4,7 +4,7 @@ using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
public abstract class Nucleus : IReceptor { public abstract class Nucleus : INucleus {
[SerializeField] [SerializeField]
protected string _name; protected string _name;
public virtual string name { public virtual string name {
@ -42,7 +42,7 @@ public abstract class Nucleus : IReceptor {
private List<Synapse> _synapses = new(); private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses; public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { public Synapse AddSynapse(INucleus sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight); Synapse synapse = new(sendingNucleus, weight);
this.synapses.Add(synapse); this.synapses.Add(synapse);
return synapse; return synapse;

View File

@ -1,3 +1,4 @@
/*
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@ -155,3 +156,4 @@ public class Receptor : IReceptor {
this._outputValue = Vector3.zero; this._outputValue = Vector3.zero;
} }
} }
*/

View File

@ -1,3 +1,4 @@
/*
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@ -31,55 +32,56 @@ public class ReceptorArray {
//selectedReceiver.outputValue = newLocalPositionVector; //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; // int receiverIx = 0;
if (thingName != null) { // INucleus selectedReceiver = null;
string baseName = selectedReceiver.name; // int selectedReceiverIx = 0;
int colonPos = selectedReceiver.name.IndexOf(":"); // foreach (INucleus receiver in this.receivers) {
if (colonPos > 0) // if (thingIds[receiverIx] == thingId) {
baseName = selectedReceiver.name.Substring(0, colonPos); // // We found an existing receiver for this thing
selectedReceiver.name = baseName + ": " + thingName; // selectedReceiver = receiver;
} // selectedReceiverIx = receiverIx;
Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); // // Do not look any further
selectedReceiver.parent.UpdateStateIsolated(); // 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();
} }
} }
*/

View File

@ -5,17 +5,17 @@ public class SelectorBrain : NanoBrain {
public Vector3 input2; public Vector3 input2;
public Vector3 output; public Vector3 output;
public Receptor receptor1; public Nucleus receptor;
public Receptor receptor2; //public Nucleus receptor2;
protected void Awake() { protected void Awake() {
receptor1 = new Receptor(this.brain, "Receptor", "Selector"); receptor = this.brain.GetNucleus("Selector");
receptor2 = new Receptor(this.brain, "Receptor", "Selector"); //receptor2 = this.brain.GetNucleus("Selector");
} }
protected void Update() { protected void Update() {
receptor1.ProcessStimulus(0, input1); receptor.ProcessStimulus(0, input1);
receptor2.ProcessStimulus(1, input2); receptor.ProcessStimulus(1, input2);
output = this.brain.outputValue; output = this.brain.outputValue;
this.brain.UpdateNuclei(); this.brain.UpdateNuclei();

View File

@ -3,19 +3,12 @@ using UnityEngine;
[Serializable] [Serializable]
public class Synapse { public class Synapse {
// Support access to cluster of basic nucleus
//public IReceptor nucleus => basicNucleus;
//[SerializeReference]
//public Cluster cluster;
[SerializeReference] [SerializeReference]
public IReceptor nucleus; public INucleus nucleus;
public float weight; public float weight;
public Synapse(IReceptor nucleus, float weight = 1.0f) { public Synapse(INucleus nucleus, float weight = 1.0f) {
this.nucleus = nucleus; this.nucleus = nucleus;
this.weight = weight; this.weight = weight;
} }