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() {
IReceptor[] nuclei = this.prefab.nuclei.ToArray();
INucleus[] prefabNuclei = this.prefab.nuclei.ToArray();
// first clone the nuclei without their connections
foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (INucleus nucleus in this.prefab.nuclei)
nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray();
INucleus[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) {
IReceptor receptor = nuclei[nucleusIx];
IReceptor clonedReceptor = clonedNuclei[nucleusIx];
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
INucleus receptor = prefabNuclei[nucleusIx];
INucleus clonedReceptor = clonedNuclei[nucleusIx];
if (clonedReceptor == null)
continue;
// Copy the receivers, which will also create the synapses
foreach (INucleus receiver in receptor.receivers) {
int ix = GetNucleusIndex(nuclei, receiver);
int ix = GetNucleusIndex(prefabNuclei, receiver);
if (ix < 0)
continue;
@ -79,8 +79,8 @@ public class Cluster : INucleus {
}
// Copy nucleus arrays
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) {
IReceptor prefabReceptor = nuclei[nucleusIx];
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
IReceptor prefabReceptor = prefabNuclei[nucleusIx];
if (prefabReceptor is not INucleus prefabNucleus)
continue;
@ -93,7 +93,7 @@ public class Cluster : INucleus {
NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array");
int arrayIx = 0;
foreach (IReceptor prefabArrayNucleus in prefabNucleus.array.nuclei) {
int arrayNucleusIx = GetNucleusIndex(nuclei, prefabArrayNucleus);
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
IReceptor clonedArrayNucleus = clonedNuclei[arrayNucleusIx];
clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
arrayIx++;
@ -102,7 +102,7 @@ public class Cluster : INucleus {
}
else {
// 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;
clonedNucleus.array = clonedFirstNucleus.array;
}
@ -110,26 +110,26 @@ public class Cluster : INucleus {
}
// 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();
foreach (IReceptor node in nodes)
inDegree[node] = 0; // Initialize in-degree to zero
// Calculate in-degrees
foreach (IReceptor node in nodes) {
foreach (INucleus node in nodes) {
foreach (INucleus receiver in node.receivers)
inDegree[receiver]++;
}
Queue<IReceptor> queue = new();
foreach (IReceptor node in nodes) {
Queue<INucleus> queue = new();
foreach (INucleus node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node);
}
List<IReceptor> sortedOrder = new();
while (queue.Count > 0) {
IReceptor current = queue.Dequeue();
INucleus current = queue.Dequeue();
sortedOrder.Add(current); // Process the node
foreach (INucleus receiver in current.receivers) {
@ -185,7 +185,7 @@ public class Cluster : INucleus {
public Cluster parent { get; set; }
[SerializeReference]
public List<IReceptor> nuclei = new();
public List<INucleus> nuclei = new();
// the nuclei sorted using topological sorting
// to ensure that the cluster is computer in the right order
public List<IReceptor> sortedNuclei;
@ -235,13 +235,22 @@ public class Cluster : INucleus {
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
[SerializeField]
private List<Synapse> _synapses = new();
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);
this._synapses.Add(synapse);
return synapse;
@ -335,7 +344,7 @@ public class Cluster : INucleus {
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0]) {
//if (nucleus.isSleeping == false)
nucleus.UpdateStateIsolated();
nucleus.UpdateStateIsolated();
}
}
this.outputValue = this.output.outputValue;
@ -357,11 +366,11 @@ public class Cluster : INucleus {
public void UpdateNuclei() {
this.stale++;
if (this.stale > 5)
if (this.stale > 5)
_outputValue = Vector3.zero;
//foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (IReceptor nucleus in this.nuclei)
foreach (INucleus nucleus in this.nuclei)
nucleus.UpdateNuclei();
}

View File

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

View File

@ -210,7 +210,7 @@ public class ClusterInspector : Editor {
// Draw selected Nucleus
if (expandArray) {
float maxValue = 0;
foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) {
foreach (INucleus nucleus in this.currentNucleus.array.nuclei) {
float value = length(nucleus.outputValue);
if (value > maxValue)
maxValue = value;
@ -231,7 +231,7 @@ public class ClusterInspector : Editor {
Handles.color = Color.black;
Handles.DrawAAConvexPolygon(verts);
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);
Handles.color = Color.white;
// 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;
if (nucleus.isSleeping)
color = Color.darkRed;
@ -359,7 +359,7 @@ public class ClusterInspector : Editor {
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) {
Handles.color = Color.white;
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;
// if (nucleus is INucleus n) {
// tooltip = new(
@ -692,7 +692,7 @@ public class ClusterInspector : Editor {
// Nucleus n = this.currentNucleus.brain.nuclei[selectedIndex - perceptei.Count()];
// n.AddReceiver(this.currentNucleus);
// }
IReceptor receptor = cluster.nuclei[selectedIndex];
INucleus receptor = cluster.nuclei[selectedIndex];
receptor.AddReceiver(this.currentNucleus);
}
}

View File

@ -11,7 +11,7 @@ public interface INucleus : IReceptor {
// Senders
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; }
@ -25,9 +25,7 @@ public interface INucleus : IReceptor {
public void UpdateStateIsolated(float3 inputValue);
#endregion dynamic state
}
public interface IReceptor {
#region static
public string name { get; set; }
@ -54,3 +52,6 @@ public interface IReceptor {
public IReceptor Clone();
}
public interface IReceptor {
}

View File

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

View File

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

View File

@ -1,3 +1,4 @@
/*
using System.Collections.Generic;
using UnityEngine;
@ -31,55 +32,56 @@ public class ReceptorArray {
//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;
// 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();
*/
// 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 output;
public Receptor receptor1;
public Receptor receptor2;
public Nucleus receptor;
//public Nucleus receptor2;
protected void Awake() {
receptor1 = new Receptor(this.brain, "Receptor", "Selector");
receptor2 = new Receptor(this.brain, "Receptor", "Selector");
receptor = this.brain.GetNucleus("Selector");
//receptor2 = this.brain.GetNucleus("Selector");
}
protected void Update() {
receptor1.ProcessStimulus(0, input1);
receptor2.ProcessStimulus(1, input2);
receptor.ProcessStimulus(0, input1);
receptor.ProcessStimulus(1, input2);
output = this.brain.outputValue;
this.brain.UpdateNuclei();

View File

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