synapses connect to neurons

This commit is contained in:
Pascal Serrarens 2026-03-05 17:04:17 +01:00
parent ccb7a41577
commit 28ef70c773
8 changed files with 86 additions and 87 deletions

View File

@ -75,7 +75,7 @@ public class Cluster : Nucleus {
float weight = 1;
foreach (Synapse synapse in receiver.synapses) {
// Find the weight for this synapse
if (synapse.nucleus == prefabNucleus) {
if (synapse.neuron == prefabNucleus) {
weight = synapse.weight;
break;
}
@ -184,7 +184,7 @@ public class Cluster : Nucleus {
Cluster clone = new(this.prefab, parent);
foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
clonedSynapse.weight = synapse.weight;
}
@ -238,7 +238,7 @@ public class Cluster : Nucleus {
float weight = 1;
foreach (Synapse synapse in receiver.synapses) {
// Find the weight for this synapse
if (synapse.nucleus == sourceNucleus) {
if (synapse.neuron == sourceNucleus) {
weight = synapse.weight;
break;
}
@ -434,10 +434,10 @@ public class Cluster : Nucleus {
}
}
[Obsolete("Use GetNucleus instead")]
public IReceptor GetReceptor(string receptorName) {
return GetNucleus(receptorName) as IReceptor;
}
// [Obsolete("Use GetNucleus instead")]
// public IReceptor GetReceptor(string receptorName) {
// return GetNucleus(receptorName) as IReceptor;
// }
#region Receivers
@ -482,21 +482,20 @@ public class Cluster : Nucleus {
}
public override void UpdateStateIsolated() {
float3 sum = this.bias;
throw new Exception("Cluster should not be updated!");
// float3 sum = this.bias;
//Applying the weight factors
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus is Neuron neuron) {
if (lengthsq(neuron.outputValue) > 0) {
sum += synapse.weight * neuron.outputValue;
}
}
}
// //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();
// foreach (Nucleus nucleus in this.sortedNuclei)
// nucleus.UpdateStateIsolated();
UpdateNuclei();
// UpdateNuclei();
}
public override void UpdateNuclei() {

View File

@ -79,9 +79,9 @@ public class ClusterPrefab : ScriptableObject {
if (nucleus.synapses != null) {
HashSet<Synapse> visitedSynapses = new();
foreach (Synapse synapse in nucleus.synapses) {
if (synapse != null && synapse.nucleus != null) {
if (synapse != null && synapse.neuron != null) {
visitedSynapses.Add(synapse);
if (synapse.nucleus is Nucleus synapse_nucleus)
if (synapse.neuron is Nucleus synapse_nucleus)
MarkNuclei(visitedNuclei, synapse_nucleus);
}
}

View File

@ -37,7 +37,7 @@ public class ClusterReceptor : Cluster, IReceptor {
};
foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
clonedSynapse.weight = synapse.weight;
}

View File

@ -215,7 +215,7 @@ public class ClusterInspector : Editor {
if (selectedNucleus.synapses != null) {
foreach (Synapse synapse in selectedNucleus.synapses) {
Nucleus input = synapse.nucleus;
Nucleus input = synapse.neuron;
AddToLayer(currentLayer, input);
// Debug.Log($"layer {layerIx} nucleus {input.name}");
}
@ -391,17 +391,20 @@ public class ClusterInspector : Editor {
int neuronCount = 0;
List<Nucleus[]> drawnArrays = new();
foreach (Synapse synapse in nucleus.synapses) {
if (synapse.nucleus is Receptor receptor) {
if (synapse.neuron == null)
continue;
if (synapse.neuron is Receptor receptor) {
if (drawnArrays.Contains(receptor.nucleiArray))
continue;
drawnArrays.Add(receptor.nucleiArray);
}
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
continue;
drawnArrays.Add(clusterReceptor.nucleiArray);
}
if (synapse.nucleus is Neuron synapseNeuron) {
if (synapse.neuron is Neuron synapseNeuron) {
float value = length(synapseNeuron.outputValue) * synapse.weight;
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
if (value > maxValue)
@ -417,12 +420,15 @@ public class ClusterInspector : Editor {
int row = 0;
drawnArrays = new();
foreach (Synapse synapse in nucleus.synapses) {
if (synapse.nucleus is Receptor neuron) {
if (synapse.neuron is null)
continue;
if (synapse.neuron is Receptor neuron) {
if (drawnArrays.Contains(neuron.nucleiArray))
continue;
drawnArrays.Add(neuron.nucleiArray);
}
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
continue;
drawnArrays.Add(clusterReceptor.nucleiArray);
@ -435,19 +441,19 @@ public class ClusterInspector : Editor {
if (maxValue == 0 || !float.IsFinite(maxValue))
maxValue = 1;
float brightness = 0;
if (synapse.nucleus is Neuron synapseNeuron)
if (synapse.neuron is Neuron synapseNeuron)
brightness = length(synapseNeuron.outputValue * synapse.weight) / maxValue;
color = new Color(brightness, brightness, brightness, 1f);
}
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) {
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) {
// the synapse nucleus is part of a subcluster
DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color);
DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color);
}
// else if (synapse.nucleus.cluster != null && synapse.nucleus.cluster != this.currentNucleus.cluster) {
// DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color);
// }
else {
DrawNucleus(synapse.nucleus, pos, maxValue, size, color);
DrawNucleus(synapse.neuron, pos, maxValue, size, color);
}
row++;
}
@ -685,12 +691,12 @@ public class ClusterInspector : Editor {
if (this.currentNucleus.synapses.Count > 0) {
Synapse[] synapses = this.currentNucleus.synapses.ToArray();
foreach (Synapse synapse in synapses) {
if (synapse.nucleus == null)
if (synapse.neuron == null)
continue;
if (array != null) {
if (synapse.nucleus.parent is Cluster iCluster && elementIx > 0) {
int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus);
if (synapse.neuron.parent is Cluster iCluster && elementIx > 0) {
int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
if (thisElementIx == elementIx)
continue;
else
@ -698,14 +704,14 @@ public class ClusterInspector : Editor {
}
// if (array.Contains(synapse.nucleus))
// continue;
else if (array.Contains(synapse.nucleus.parent))
else if (array.Contains(synapse.neuron.parent))
continue;
}
else {
if (synapse.nucleus.parent is IReceptor iReceptor) {
if (synapse.neuron.parent is IReceptor iReceptor) {
array = iReceptor.nucleiArray;
if (iReceptor is Cluster iCluster)
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.nucleus);
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
}
// else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1)
// array = receptor2.nucleiArray;
@ -714,34 +720,34 @@ public class ClusterInspector : Editor {
EditorGUILayout.Space();
if (Application.isPlaying) {
if (synapse.nucleus is Neuron synapseNeuron) {
if (synapse.neuron is Neuron synapseNeuron) {
Vector3 value = synapseNeuron.outputValue * synapse.weight;
GUIContent synapseValueLabel = new(synapse.nucleus.name, synapseNeuron.outputValue.ToString());
GUIContent synapseValueLabel = new(synapse.neuron.name, synapseNeuron.outputValue.ToString());
EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue));
}
}
else {
EditorGUILayout.BeginHorizontal();
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) {
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus) {
// If it is a cluster
GUIStyle labelStyle = new(GUI.skin.label);
float labelWidth = 200;
if (synapse.nucleus.clusterPrefab != null) {
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.parent.baseName}.")).x;
GUILayout.Label($"{synapse.nucleus.parent.baseName}", GUILayout.Width(labelWidth));
if (synapse.neuron.clusterPrefab != null) {
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.baseName}.")).x;
GUILayout.Label($"{synapse.neuron.parent.baseName}", GUILayout.Width(labelWidth));
}
string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray();
int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name);
string[] options = synapse.neuron.parent.clusterNuclei.Select(n => n.name).ToArray();
int selectedIndex = System.Array.IndexOf(options, synapse.neuron.name);
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron)
if (newIndex != selectedIndex && synapse.neuron.parent.clusterNuclei[newIndex] is Neuron newNeuron)
ChangeSynapse(synapse, newNeuron);
}
else
GUILayout.Label(synapse.nucleus.name);
GUILayout.Label(synapse.neuron.name);
bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80));
if (disconnecting && synapse.nucleus is Neuron synapseNeuron) {
if (disconnecting && synapse.neuron is Neuron synapseNeuron) {
synapseNeuron.RemoveReceiver(this.currentNucleus);
this.prefab.GarbageCollection();
anythingChanged = true;
@ -753,10 +759,10 @@ public class ClusterInspector : Editor {
EditorGUI.indentLevel++;
float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight);
if (newWeight != synapse.weight) {
if (synapse.nucleus.parent is IReceptor receptor) {
if (synapse.neuron.parent is IReceptor receptor) {
Nucleus[] receptorArray = receptor.nucleiArray;
foreach (Synapse s in this.currentNucleus.synapses) {
if (s.nucleus.parent is IReceptor r && r.nucleiArray == receptorArray)
if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray)
s.weight = newWeight;
}
}
@ -949,8 +955,8 @@ public class ClusterInspector : Editor {
return false;
IEnumerable<Nucleus> synapseNuclei = this.currentNucleus.synapses
.Where(synapse => synapse.nucleus != null)
.Select(synapse => synapse.nucleus);
.Where(synapse => synapse.neuron != null)
.Select(synapse => synapse.neuron);
IEnumerable<Nucleus> nuclei = cluster.nuclei
.Except(synapseNuclei);
@ -1027,12 +1033,12 @@ public class ClusterInspector : Editor {
}
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
Neuron synapseNeuron = synapse.nucleus as Neuron;
if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
if (synapse.nucleus.parent is ClusterReceptor receptor) {
Neuron synapseNeuron = synapse.neuron as Neuron;
if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
if (synapse.neuron.parent is ClusterReceptor receptor) {
// the new nucleus is part of a (cluster) receptor,
// so we have to change all synapses to this nucleus array elements
int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus);
int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.neuron);
int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus);
foreach (Nucleus element in receptor.nucleiArray) {
if (element is not ClusterReceptor clusterReceptor)
@ -1070,12 +1076,12 @@ public class ClusterInspector : Editor {
protected virtual void DisconnectNucleus(Neuron nucleus) {
if (this.currentNucleus.clusterPrefab == null)
return;
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray();
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.neuron.name).ToArray();
int selectedIndex = -1;
selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names);
if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) {
Synapse synapse = this.currentNucleus.synapses[selectedIndex];
Neuron synapseNeuron = synapse.nucleus as Neuron;
Neuron synapseNeuron = synapse.neuron as Neuron;
synapseNeuron.RemoveReceiver(this.currentNucleus);
}
}

View File

@ -20,7 +20,7 @@ public class NanoBrain : MonoBehaviour {
public static void UpdateWeight(Cluster brain, string name, float weight) {
Nucleus root = brain.defaultOutput;
foreach (Synapse synapse in root.synapses) {
if (synapse.nucleus.name == name) {
if (synapse.neuron.name == name) {
if (synapse.weight != weight) {
synapse.weight = weight;
// Debug.Log($"Updated weight for {name}");

View File

@ -144,7 +144,7 @@ public class Neuron : Nucleus {
Neuron clone = new(prefab, this.name);
CloneFields(clone);
foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
clonedSynapse.weight = synapse.weight;
}
foreach (Nucleus receiver in this.receivers) {
@ -164,7 +164,7 @@ public class Neuron : Nucleus {
public static void Delete(Nucleus nucleus) {
foreach (Synapse synapse in nucleus.synapses) {
if (synapse.nucleus is Neuron synapse_nucleus) {
if (synapse.neuron is Neuron synapse_nucleus) {
if (synapse_nucleus.receivers.Count > 1) {
// there is another nucleus feeding into this input nucleus
synapse_nucleus.receivers.RemoveAll(r => r == nucleus);
@ -178,14 +178,14 @@ public class Neuron : Nucleus {
if (nucleus is Neuron neuron) {
foreach (Nucleus receiver in neuron.receivers) {
if (receiver != null && receiver.synapses != null)
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
receiver.synapses.RemoveAll(s => s.neuron == nucleus);
}
}
else if (nucleus is Cluster cluster) {
// remove all receivers for this cluster
foreach (Neuron output in cluster.outputs) {
foreach (Nucleus receiver in output.receivers) {
receiver.synapses.RemoveAll(s => s.nucleus == output);
receiver.synapses.RemoveAll(s => s.neuron == output);
}
}
}
@ -214,18 +214,15 @@ public class Neuron : Nucleus {
public float3 CombinatorSum() {
float3 sum = this.bias;
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus is Neuron neuron)
sum += synapse.weight * neuron.outputValue;
}
foreach (Synapse synapse in this.synapses)
sum += synapse.weight * synapse.neuron.outputValue;
return sum;
}
public float3 CombinatorProduct() {
float3 product = this.bias;
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus is Neuron neuron)
product *= synapse.weight * neuron.outputValue;
product *= synapse.weight * synapse.neuron.outputValue;
}
return product;
}
@ -236,14 +233,12 @@ public class Neuron : Nucleus {
//Applying the weight factors
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus is Neuron neuron) {
float3 input = synapse.weight * neuron.outputValue;
float3 input = synapse.weight * synapse.neuron.outputValue;
float inputLength = length(input);
if (inputLength > maxLength) {
max = input;
maxLength = inputLength;
}
float inputLength = length(input);
if (inputLength > maxLength) {
max = input;
maxLength = inputLength;
}
}
return max;
@ -311,13 +306,13 @@ public class Neuron : Nucleus {
foreach (Nucleus element in receptor.nucleiArray) {
if (element is Neuron neuron) {
neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron);
}
}
}
else {
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
}
}
@ -325,9 +320,8 @@ public class Neuron : Nucleus {
#endregion Receivers
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
if (this.parent is ClusterReceptor clusterReceptor) {
if (this.parent is ClusterReceptor clusterReceptor)
clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
}
else
ProcessStimulusDirect(inputValue, thingId, thingName);
}

View File

@ -33,7 +33,7 @@ public abstract class Nucleus {
private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) {
public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight);
this.synapses.Add(synapse);
return synapse;
@ -41,13 +41,13 @@ public abstract class Nucleus {
public Synapse GetSynapse(Nucleus sender) {
foreach (Synapse synapse in this.synapses)
if (synapse.nucleus == sender)
if (synapse.neuron == sender)
return synapse;
return null;
}
public void RemoveSynapse(Nucleus sendingNucleus) {
this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus);
this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus);
}
#endregion Synapses

View File

@ -4,12 +4,12 @@ using UnityEngine;
[Serializable]
public class Synapse {
[SerializeReference]
public Nucleus nucleus;
public Neuron neuron;
public float weight;
public Synapse(Nucleus nucleus, float weight = 1.0f) {
this.nucleus = nucleus;
public Synapse(Neuron nucleus, float weight = 1.0f) {
this.neuron = nucleus;
this.weight = weight;
}
}