Simplifications

This commit is contained in:
Pascal Serrarens 2026-04-17 16:34:21 +02:00
parent bc0a79688d
commit 19f929606a
9 changed files with 421 additions and 360 deletions

View File

@ -174,23 +174,24 @@ namespace NanoBrain {
memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory);
}
if (this.currentNucleus is IReceptor receptor1) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count());
if (GUILayout.Button("Add")) {
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
receptor1.AddReceptorElement(this.prefab);
anythingChanged = true;
}
if (GUILayout.Button("Del")) {
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
receptor1.RemoveReceptorElement();
anythingChanged = true;
}
EditorGUILayout.EndHorizontal();
// if (this.currentNucleus is IReceptor receptor1) {
// EditorGUILayout.BeginHorizontal();
// EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count());
// if (GUILayout.Button("Add")) {
// Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
// receptor1.AddReceptorElement(this.prefab);
// anythingChanged = true;
// }
// if (GUILayout.Button("Del")) {
// Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
// receptor1.RemoveReceptorElement();
// anythingChanged = true;
// }
// EditorGUILayout.EndHorizontal();
}
else if (this.currentNucleus is Cluster cluster) {
// }
// else
if (this.currentNucleus is Cluster cluster) {
EditorGUILayout.BeginHorizontal();
if (cluster.siblingClusters != null && cluster.siblingClusters.Length > 1)
EditorGUILayout.IntField("Array size", cluster.siblingClusters.Count());
@ -211,7 +212,7 @@ namespace NanoBrain {
// Synapses
if (this.currentNucleus is not Receptor && this.currentNucleus is not ClusterReceptor) {
if (this.currentNucleus is not Receptor) { //} && this.currentNucleus is not ClusterReceptor) {
showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses");
if (showSynapses) {
if (this.currentNucleus is Neuron neuron2) {
@ -248,11 +249,11 @@ namespace NanoBrain {
continue;
}
else {
if (synapse.neuron.parent is IReceptor iReceptor) {
array = iReceptor.nucleiArray;
if (iReceptor is Cluster iCluster)
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
}
// if (synapse.neuron.parent is IReceptor iReceptor) {
// array = iReceptor.nucleiArray;
// if (iReceptor is Cluster iCluster)
// 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;
}
@ -299,14 +300,14 @@ namespace NanoBrain {
EditorGUI.indentLevel++;
float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight);
if (newWeight != synapse.weight) {
if (synapse.neuron.parent is IReceptor receptor) {
Nucleus[] receptorArray = receptor.nucleiArray;
foreach (Synapse s in this.currentNucleus.synapses) {
if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray)
s.weight = newWeight;
}
}
else
// if (synapse.neuron.parent is IReceptor receptor) {
// Nucleus[] receptorArray = receptor.nucleiArray;
// foreach (Synapse s in this.currentNucleus.synapses) {
// if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray)
// s.weight = newWeight;
// }
// }
// else
synapse.weight = newWeight;
anythingChanged = true;
}
@ -340,10 +341,10 @@ namespace NanoBrain {
neuron.curvePreset = newPreset;
EditorGUILayout.EndHorizontal();
}
if (neuron is Receptor receptor2) {
if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0)
receptor2.array = new NucleusArray(neuron);
}
// if (neuron is Receptor receptor2) {
// if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0)
// receptor2.array = new NucleusArray(neuron);
// }
}
EditorGUILayout.Space();
@ -377,22 +378,22 @@ namespace NanoBrain {
void OnSceneGUI(SceneView sceneView) {
if (this.gameObject != null) {
if (this.currentNucleus is IReceptor receptor) {
foreach (Nucleus nucleus in receptor.nucleiArray) {
if (nucleus is Neuron neuron) {
Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
Handles.color = Color.yellow;
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
}
}
}
else {
// if (this.currentNucleus is IReceptor receptor) {
// foreach (Nucleus nucleus in receptor.nucleiArray) {
// if (nucleus is Neuron neuron) {
// Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
// Handles.color = Color.yellow;
// Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
// }
// }
// }
// else {
if (this.currentNucleus is Neuron currentNeuron) {
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
Handles.color = Color.yellow;
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
}
}
// }
}
}
@ -452,15 +453,15 @@ namespace NanoBrain {
BuildLayers();
}
protected virtual void AddClusterReceptorInput(Nucleus nucleus) {
ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster");
}
private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name);
clusterInstance.defaultOutput.AddReceiver(nucleus);
this.currentNucleus = clusterInstance;
BuildLayers();
}
// protected virtual void AddClusterReceptorInput(Nucleus nucleus) {
// ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster");
// }
// private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
// ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name);
// clusterInstance.defaultOutput.AddReceiver(nucleus);
// this.currentNucleus = clusterInstance;
// BuildLayers();
// }
private void EditCluster(Cluster subCluster) {
// May be used with storedPrefab...
@ -502,9 +503,10 @@ namespace NanoBrain {
EditorGUILayout.EndHorizontal();
if (connecting) {
Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus);
if (nucleus is IReceptor receptor)
receptor.AddArrayReceiver(this.currentNucleus);
else if (nucleus is Neuron neuron)
// if (nucleus is IReceptor receptor)
// receptor.AddArrayReceiver(this.currentNucleus);
// else
if (nucleus is Neuron neuron)
neuron.AddReceiver(this.currentNucleus);
else if (nucleus is Cluster subCluster)
subCluster.defaultOutput.AddReceiver(this.currentNucleus);
@ -563,37 +565,37 @@ namespace NanoBrain {
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
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.neuron);
int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus);
foreach (Nucleus element in receptor.nucleiArray) {
if (element is not ClusterReceptor clusterReceptor)
continue;
// Get the same neuron as the synapse.nucleus in a different element
// of the ClusterReceptor array
Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx];
if (oldElementNucleus is not Neuron oldElementNeuron)
continue;
// Get the same neuron as newNucleus in a different element
// of the ClusterReceptor array
Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx];
if (newElementNucleus is not Neuron newElementNeuron)
continue;
// 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.neuron);
// int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus);
// foreach (Nucleus element in receptor.nucleiArray) {
// if (element is not ClusterReceptor clusterReceptor)
// continue;
// // Get the same neuron as the synapse.nucleus in a different element
// // of the ClusterReceptor array
// Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx];
// if (oldElementNucleus is not Neuron oldElementNeuron)
// continue;
// // Get the same neuron as newNucleus in a different element
// // of the ClusterReceptor array
// Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx];
// if (newElementNucleus is not Neuron newElementNeuron)
// continue;
oldElementNeuron.RemoveReceiver(this.currentNucleus);
newElementNeuron.AddReceiver(this.currentNucleus);
// Now find the synapse which pointed to the old Neuron
// Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron);
// synapseForUpdate.nucleus = newElementNeuron;
}
}
else {
// oldElementNeuron.RemoveReceiver(this.currentNucleus);
// newElementNeuron.AddReceiver(this.currentNucleus);
// // Now find the synapse which pointed to the old Neuron
// // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron);
// // synapseForUpdate.nucleus = newElementNeuron;
// }
// }
// else {
// it is a neuron in a subcluster
synapseNeuron.RemoveReceiver(this.currentNucleus);
newNucleus.AddReceiver(this.currentNucleus);
}
// }
}
else {
synapseNeuron.RemoveReceiver(this.currentNucleus);

View File

@ -186,67 +186,67 @@ namespace NanoBrain {
// Draw selected Nucleus
if (expandArray) {
if (this.currentNucleus is IReceptor receptor1) {
float maxValue = 0;
foreach (Nucleus nucleus in receptor1.nucleiArray) {
if (nucleus is Neuron neuron) {
float value = neuron.outputMagnitude;
if (value > maxValue)
maxValue = value;
}
}
// if (this.currentNucleus is IReceptor receptor1) {
// float maxValue = 0;
// foreach (Nucleus nucleus in receptor1.nucleiArray) {
// if (nucleus is Neuron neuron) {
// float value = neuron.outputMagnitude;
// if (value > maxValue)
// maxValue = value;
// }
// }
float spacing = 400f / receptor1.nucleiArray.Count();
float margin = 10 + spacing / 2;
float xMin = 150 - size;
float xMax = 150 + size;
float yMin = 10 + margin - size / 2;
float yMax = 400 - margin + size;
Vector3[] verts = new Vector3[4] {
new(xMin, yMin, 0),
new(xMax, yMin, 0),
new(xMax, yMax, 0),
new(xMin, yMax, 0)
};
Handles.color = Color.black;
Handles.DrawAAConvexPolygon(verts);
int row = 0;
foreach (Nucleus nucleus in receptor1.nucleiArray) {
Vector3 pos = new(150, margin + row * spacing, 0.0f);
Handles.color = Color.white;
// The selected nucleus highlight ring
Handles.DrawSolidDisc(pos, Vector3.forward, size + 2);
DrawNucleus(nucleus, pos, maxValue, size);
row++;
}
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.UpperCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
Vector3 labelPos = new(150, yMax + size + 5, 0);
string receptorName = receptor1.GetName();
int colonPos = receptorName.IndexOf(":");
if (colonPos > 0) {
string baseName = receptorName[..colonPos];
Handles.Label(labelPos, baseName, style);
}
else
Handles.Label(labelPos, receptorName, style);
}
else {
Handles.color = Color.white;
// The selected nucleus highlight ring
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
float maxValue = 1;
if (this.currentNucleus is Neuron neuron)
maxValue = neuron.outputMagnitude;
else if (this.currentNucleus is Cluster cluster)
maxValue = cluster.defaultOutput.outputMagnitude;
// float spacing = 400f / receptor1.nucleiArray.Count();
// float margin = 10 + spacing / 2;
// float xMin = 150 - size;
// float xMax = 150 + size;
// float yMin = 10 + margin - size / 2;
// float yMax = 400 - margin + size;
// Vector3[] verts = new Vector3[4] {
// new(xMin, yMin, 0),
// new(xMax, yMin, 0),
// new(xMax, yMax, 0),
// new(xMin, yMax, 0)
// };
// Handles.color = Color.black;
// Handles.DrawAAConvexPolygon(verts);
// int row = 0;
// foreach (Nucleus nucleus in receptor1.nucleiArray) {
// Vector3 pos = new(150, margin + row * spacing, 0.0f);
// Handles.color = Color.white;
// // The selected nucleus highlight ring
// Handles.DrawSolidDisc(pos, Vector3.forward, size + 2);
// DrawNucleus(nucleus, pos, maxValue, size);
// row++;
// }
// GUIStyle style = new(EditorStyles.label) {
// alignment = TextAnchor.UpperCenter,
// normal = { textColor = Color.white },
// fontStyle = FontStyle.Bold,
// };
// Vector3 labelPos = new(150, yMax + size + 5, 0);
// string receptorName = receptor1.GetName();
// int colonPos = receptorName.IndexOf(":");
// if (colonPos > 0) {
// string baseName = receptorName[..colonPos];
// Handles.Label(labelPos, baseName, style);
// }
// else
// Handles.Label(labelPos, receptorName, style);
// }
// else {
Handles.color = Color.white;
// The selected nucleus highlight ring
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
float maxValue = 1;
if (this.currentNucleus is Neuron neuron)
maxValue = neuron.outputMagnitude;
else if (this.currentNucleus is Cluster cluster)
maxValue = cluster.defaultOutput.outputMagnitude;
DrawNucleus(this.currentNucleus, position, maxValue, 20);
DrawNucleus(this.currentNucleus, position, maxValue, 20);
}
// }
}
else {
Handles.color = Color.white;
@ -290,11 +290,11 @@ namespace NanoBrain {
int row = 0;
List<Nucleus[]> drawnArrays = new();
foreach (Nucleus receiver in receivers) {
if (receiver is Receptor receptor) {
if (drawnArrays.Contains(receptor.nucleiArray))
continue;
drawnArrays.Add(receptor.nucleiArray);
}
// if (receiver is Receptor receptor) {
// if (drawnArrays.Contains(receptor.nucleiArray))
// continue;
// drawnArrays.Add(receptor.nucleiArray);
// }
Nucleus receiverNucleus = receiver;
if (receiverNucleus == null)
@ -321,26 +321,21 @@ namespace NanoBrain {
if (synapse.neuron == null)
continue;
if (synapse.neuron is Receptor receptor) {
if (drawnArrays.Contains(receptor.nucleiArray))
continue;
drawnArrays.Add(receptor.nucleiArray);
}
else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
continue;
drawnArrays.Add(clusterReceptor.nucleiArray);
}
else if (synapse.neuron.parent is Cluster cluster && cluster.siblingClusters != null) {
// if (synapse.neuron is Receptor receptor) {
// if (drawnArrays.Contains(receptor.nucleiArray))
// continue;
// drawnArrays.Add(receptor.nucleiArray);
// }
// else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
// if (drawnArrays.Contains(clusterReceptor.nucleiArray))
// continue;
// drawnArrays.Add(clusterReceptor.nucleiArray);
// }
if (synapse.neuron.parent is Cluster cluster && cluster.siblingClusters != null) {
if (drawnArrays.Contains(cluster.siblingClusters))
continue;
drawnArrays.Add(cluster.siblingClusters);
}
// else if (synapse.neuron.parent is Cluster cluster && cluster.clusterArray != null) {
// if (drawnArrays.Contains(cluster.clusterArray.clusters))
// continue;
// drawnArrays.Add(cluster.clusterArray.clusters);
// }
if (synapse.neuron is Neuron synapseNeuron) {
float value = synapseNeuron.outputMagnitude * synapse.weight;
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
@ -360,16 +355,16 @@ namespace NanoBrain {
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.neuron.parent is ClusterReceptor clusterReceptor) {
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
continue;
drawnArrays.Add(clusterReceptor.nucleiArray);
}
// if (synapse.neuron is Receptor neuron) {
// if (drawnArrays.Contains(neuron.nucleiArray))
// continue;
// drawnArrays.Add(neuron.nucleiArray);
// }
// else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
// if (drawnArrays.Contains(clusterReceptor.nucleiArray))
// continue;
// drawnArrays.Add(clusterReceptor.nucleiArray);
// }
Vector3 pos = new(250, margin + row * spacing, 0.0f);
Handles.color = Color.white;
Handles.DrawLine(parentPos, pos);
@ -384,11 +379,9 @@ namespace NanoBrain {
}
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) {
// the synapse nucleus is part of a subcluster
DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color);
//DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color);
DrawNucleus(synapse.neuron, 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.neuron, pos, maxValue, size, color);
}
@ -428,7 +421,29 @@ namespace NanoBrain {
fontStyle = FontStyle.Bold,
};
if (nucleus is IReceptor receptor1) {
// if (nucleus is IReceptor receptor1) {
// if (expandArray) {
// // Put array indices above elements
// style.alignment = TextAnchor.LowerCenter;
// Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc
// int colonPos1 = nucleus.name.IndexOf(":");
// if (colonPos1 > 0) {
// string extName = nucleus.name[(colonPos1 + 2)..];
// Handles.Label(labelPos1, extName, style);
// }
// }
// else {
// // draw the array size label
// if (color.grayscale > 0.5f)
// style.normal.textColor = Color.black;
// else
// style.normal.textColor = Color.white;
// Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style);
// style.normal.textColor = Color.white;
// }
// }
// else
if (nucleus.parent != null && nucleus.parent is Cluster parentCluster) {
if (expandArray) {
// Put array indices above elements
style.alignment = TextAnchor.LowerCenter;
@ -440,13 +455,15 @@ namespace NanoBrain {
}
}
else {
// draw the array size label
if (color.grayscale > 0.5f)
style.normal.textColor = Color.black;
else
if (parentCluster.siblingClusters != null && parentCluster.siblingClusters.Length > 1) {
// draw the array size label
if (color.grayscale > 0.5f)
style.normal.textColor = Color.black;
else
style.normal.textColor = Color.white;
Handles.Label(labelPosition, parentCluster.siblingClusters.Length.ToString(), style);
style.normal.textColor = Color.white;
Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style);
style.normal.textColor = Color.white;
}
}
}
else if (nucleus is Cluster cluster) {
@ -478,25 +495,46 @@ namespace NanoBrain {
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
style.alignment = TextAnchor.UpperCenter;
nucleus.name ??= "";
int colonPos = nucleus.name.IndexOf(":");
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
// if it is an array, we should not show the :0 of the first element
string baseName = nucleus.name[..colonPos];
Handles.Label(labelPos, baseName, style);
if (nucleus.parent != null && nucleus.parent is Cluster parentCluster1) {
parentCluster1.name ??= "";
string baseName = "";
if (parentCluster1 != currentNucleus.parent) {
int colonPos = parentCluster1.name.IndexOf(":");
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
baseName = parentCluster1.name[..colonPos] + ".";
else
baseName = parentCluster1.name + ".";
}
// if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2) {
// // if it is an array, we should not show the :0 of the first element
// //baseName = baseName[..colonPos];
// Handles.Label(labelPos, baseName + nucleus.name, style);
// }
// else
Handles.Label(labelPos, baseName + nucleus.name, style);
}
else {
nucleus.name ??= "";
int colonPos = nucleus.name.IndexOf(":");
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
// if it is an array, we should not show the :0 of the first element
string baseName = nucleus.name[..colonPos];
Handles.Label(labelPos, baseName, style);
}
else
Handles.Label(labelPos, nucleus.name, style);
}
else
Handles.Label(labelPos, nucleus.name, style);
}
// Draw Cluster ring
if (nucleus is Cluster) {
if (nucleus.parent != currentNucleus.parent || nucleus is Cluster) {
Handles.color = Color.white;
Handles.DrawWireDisc(position, Vector3.forward, size + 5);
}
// Tooltip
Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2);
int id = GUIUtility.GetControlID(FocusType.Passive);
Event e = Event.current;
EventType et = e.GetTypeForControl(id);
@ -507,7 +545,10 @@ namespace NanoBrain {
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
HandleClicked(nucleus);
if (nucleus.parent != null && nucleus.parent is Cluster parentCluster2)
HandleClicked(parentCluster2);
else
HandleClicked(nucleus);
}
}
}
@ -533,7 +574,7 @@ namespace NanoBrain {
private void HandleClicked(Nucleus nucleus) {
if (nucleus == this.currentNucleus) {
if (nucleus is Receptor || nucleus is ClusterReceptor)
if (nucleus is Receptor) // || nucleus is ClusterReceptor)
expandArray = !expandArray;
else
expandArray = false;
@ -547,22 +588,22 @@ namespace NanoBrain {
void OnSceneGUI(SceneView sceneView) {
if (this.gameObject != null) {
if (this.currentNucleus is IReceptor receptor) {
foreach (Nucleus nucleus in receptor.nucleiArray) {
if (nucleus is Neuron neuron) {
Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
Handles.color = Color.yellow;
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
}
}
}
else {
if (this.currentNucleus is Neuron currentNeuron) {
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
Handles.color = Color.yellow;
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
}
// if (this.currentNucleus is IReceptor receptor) {
// foreach (Nucleus nucleus in receptor.nucleiArray) {
// if (nucleus is Neuron neuron) {
// Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
// Handles.color = Color.yellow;
// Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
// }
// }
// }
// else {
if (this.currentNucleus is Neuron currentNeuron) {
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
Handles.color = Color.yellow;
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
}
// }
}
}

View File

@ -117,6 +117,7 @@ namespace NanoBrain {
}
}
/*
// Copy nucleus arrays for receptors
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
@ -152,6 +153,7 @@ namespace NanoBrain {
clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray;
}
}
*/
foreach (Nucleus nucleus in this.clusterNuclei) {
if (nucleus is Cluster clonedSubCluster)
@ -225,16 +227,19 @@ namespace NanoBrain {
clonedSynapse.weight = synapse.weight;
}
foreach (Neuron output in this.outputs) {
foreach (Nucleus receiver in output.receivers) {
int ix = GetNucleusIndex(this.clusterNuclei.ToArray(), output);
if (ix < 0)
continue;
foreach (Nucleus nucleus in this.clusterNuclei) {
if (nucleus is Neuron output) {
foreach (Nucleus receiver in output.receivers) {
int ix = GetNucleusIndex(this.clusterNuclei, output);
Debug.Log($"{output.name} -> {receiver.name}: {ix}");
if (ix < 0)
continue;
if (clone.clusterNuclei[ix] is not Neuron clonedOutput)
continue;
if (clone.clusterNuclei[ix] is not Neuron clonedOutput)
continue;
clonedOutput.AddReceiver(receiver);
clonedOutput.AddReceiver(receiver);
}
}
}
@ -313,43 +318,41 @@ namespace NanoBrain {
public void AddInstance(ClusterPrefab prefab) {
// if (this.siblingClusters.Length == 0) {
// Debug.LogError("Empty perceptoid array, cannot add");
// return;
// }
// Ensure siblingClusters exists
this.siblingClusters ??= new Cluster[1] { this };
// Prepare the new array
int newLength = this.siblingClusters.Length + 1;
Cluster[] newSiblings = new Cluster[newLength];
for (int i = 0; i < newSiblings.Length - 1; i++)
newSiblings[i] = this.siblingClusters[i];
Cluster newCluster = this.Clone(prefab) as Cluster;
string baseName = this.name;
int colonPos = baseName.IndexOf(":");
if (colonPos > 0)
baseName = baseName[..colonPos];
for (int i = 0; i < newSiblings.Length - 1; i++)
newSiblings[i] = this.siblingClusters[i];
// Cluster sourceCluster = this.siblingClusters[0];
Cluster newCluster = this.Clone(prefab) as Cluster;
newCluster.name = $"{baseName}: {newLength - 1}";
//newCluster.clusterArray = this;
newSiblings[newLength - 1] = newCluster;
this.siblingClusters = newSiblings;
newCluster.siblingClusters = newSiblings;
// All siblingClusters need to user this array!
foreach (Cluster sibling in this.siblingClusters)
sibling.siblingClusters = newSiblings;
}
public void RemoveInstance() {
int newLength = this.siblingClusters.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
if (this.siblingClusters == null || this.siblingClusters.Length <= 1)
return;
}
// Prepare the new array
int newLength = this.siblingClusters.Length - 1;
Cluster[] newClusters = new Cluster[newLength];
for (int i = 0; i < newLength; i++)
newClusters[i] = this.siblingClusters[i];
// Delete the last perception
//Cluster.Delete(nucleus);
Neuron.Delete(this.siblingClusters[^1]);
this.siblingClusters = newClusters;
}
@ -601,9 +604,11 @@ namespace NanoBrain {
if (startNucleus.trace)
Debug.Log($"Update from {startNucleus.name}");
foreach (Nucleus nucleus in computeOrder) {
nucleus.UpdateStateIsolated();
if (startNucleus.trace && nucleus is Neuron neuron)
Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {neuron.outputValue}");
if (nucleus is not Cluster) {
nucleus.UpdateStateIsolated();
if (startNucleus.trace && nucleus is Neuron neuron)
Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}]"); // = {neuron.outputValue}");
}
}
// continue in parent

View File

@ -1,3 +1,4 @@
/*
using System;
using System.Collections.Generic;
using UnityEngine;
@ -275,4 +276,5 @@ namespace NanoBrain {
}
}
}
*/

View File

@ -17,17 +17,17 @@ namespace NanoBrain {
/// The array of nuclei used to track multiple things sending stimuli
/// </summary>
/// The size of the array determines the maximum number of things which can be distinguished
public Nucleus[] nucleiArray { get; set; }
// public Nucleus[] nucleiArray { get; set; }
/// <summary>
/// Extends the nucleiArray with an additional element
/// </summary>
/// <param name="prefab">A prefab of the nucleus to add?</param>
public void AddReceptorElement(ClusterPrefab prefab);
// public void AddReceptorElement(ClusterPrefab prefab);
/// <summary>
/// Removes the last element from the nucleiArray
/// </summary>
public void RemoveReceptorElement();
// public void RemoveReceptorElement();
/// <summary>
/// Add a receiver for this receptor array
@ -35,7 +35,7 @@ namespace NanoBrain {
/// <param name="receiverToAdd">The receiving Nucleus</param>
/// <param name="weight">The initial weight to use for the synapses</param>
/// This function will add a synapse to the receiver for each element in the nucleiArray.
public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1);
// public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1);
/// <summary>
/// Process an external stimulus
@ -47,77 +47,78 @@ namespace NanoBrain {
}
public static class IReceptorHelpers {
/*
/// <summary>
/// Implementation for the NanoBrain::IReceptor::AddReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to extend its nucleiArray</param>
/// <param name="prefab">A prefab of the nucleus to add?</param>
public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) {
if (receptor.nucleiArray.Length == 0) {
Debug.LogError("Empty perceptoid array, cannot add");
}
int newLength = receptor.nucleiArray.Length + 1;
Nucleus[] newArray = new Nucleus[newLength];
/// <summary>
/// Implementation for the NanoBrain::IReceptor::AddReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to extend its nucleiArray</param>
/// <param name="prefab">A prefab of the nucleus to add?</param>
public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) {
if (receptor.nucleiArray.Length == 0) {
Debug.LogError("Empty perceptoid array, cannot add");
}
int newLength = receptor.nucleiArray.Length + 1;
Nucleus[] newArray = new Nucleus[newLength];
string baseName = receptor.GetName();
int colonPos = baseName.IndexOf(":");
if (colonPos > 0)
baseName = baseName[..colonPos];
string baseName = receptor.GetName();
int colonPos = baseName.IndexOf(":");
if (colonPos > 0)
baseName = baseName[..colonPos];
for (int i = 0; i < receptor.nucleiArray.Length; i++)
newArray[i] = receptor.nucleiArray[i];
if (receptor.nucleiArray[0] is Nucleus nucleus) {
newArray[newLength - 1] = nucleus.Clone(prefab);
newArray[newLength - 1].name = $"{baseName}: {newLength - 1}";
}
for (int i = 0; i < receptor.nucleiArray.Length; i++)
newArray[i] = receptor.nucleiArray[i];
if (receptor.nucleiArray[0] is Nucleus nucleus) {
newArray[newLength - 1] = nucleus.Clone(prefab);
newArray[newLength - 1].name = $"{baseName}: {newLength - 1}";
}
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
}
}
}
}
}
/// <summary>
/// Implementation for the NanoBrain::IReceptor::RemoteReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to shorten its nucleiArray</param>
public static void RemoveReceptorElement(IReceptor receptor) {
int newLength = receptor.nucleiArray.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
}
Nucleus[] newArray = new Nucleus[newLength];
for (int i = 0; i < newLength; i++)
newArray[i] = receptor.nucleiArray[i];
// Delete the last perception
if (receptor.nucleiArray[newLength] is Nucleus nucleus)
Neuron.Delete(nucleus);
/// <summary>
/// Implementation for the NanoBrain::IReceptor::RemoteReceptorElement which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor which needs to shorten its nucleiArray</param>
public static void RemoveReceptorElement(IReceptor receptor) {
int newLength = receptor.nucleiArray.Length - 1;
if (newLength == 0) {
Debug.LogWarning("Perceptoid array cannot be empty");
}
Nucleus[] newArray = new Nucleus[newLength];
for (int i = 0; i < newLength; i++)
newArray[i] = receptor.nucleiArray[i];
// Delete the last perception
if (receptor.nucleiArray[newLength] is Nucleus nucleus)
Neuron.Delete(nucleus);
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
}
}
foreach (Nucleus element in receptor.nucleiArray) {
if (element is IReceptor receptorElement) {
receptorElement.nucleiArray = newArray;
}
}
}
/// <summary>
/// Implementation for the NanoBreain::IRceptor::AddArrayReceiver which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor for which a receiving nuclues needs to be added</param>
/// <param name="receiverToAdd">The nucleus to receive input from the receptor</param>
/// <param name="weight">The initial weight for the synapses</param>
public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) {
foreach (Nucleus element in receptor.nucleiArray) {
if (element is Cluster cluster)
cluster.defaultOutput.AddReceiver(receiverToAdd, weight);
if (element is Neuron neuron)
neuron.AddReceiver(receiverToAdd, weight);
}
/// <summary>
/// Implementation for the NanoBreain::IRceptor::AddArrayReceiver which can be used for all implementations of IReceptor
/// </summary>
/// <param name="receptor">The IReceptor for which a receiving nuclues needs to be added</param>
/// <param name="receiverToAdd">The nucleus to receive input from the receptor</param>
/// <param name="weight">The initial weight for the synapses</param>
public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) {
foreach (Nucleus element in receptor.nucleiArray) {
if (element is Cluster cluster)
cluster.defaultOutput.AddReceiver(receiverToAdd, weight);
if (element is Neuron neuron)
neuron.AddReceiver(receiverToAdd, weight);
}
}
}
*/
}
}

View File

@ -171,7 +171,7 @@ namespace NanoBrain {
AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
}
return curve;
}
public static AnimationCurve Binary() {
return AnimationCurve.Linear(0, 0, 1, 1);
@ -270,9 +270,11 @@ namespace NanoBrain {
}
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.neuron == output);
foreach (Nucleus clusterNucleus in cluster.clusterNuclei) {
if (clusterNucleus is Neuron output) {
foreach (Nucleus receiver in output.receivers) {
receiver.synapses.RemoveAll(s => s.neuron == output);
}
}
}
}
@ -426,9 +428,9 @@ namespace NanoBrain {
return float3(value, value, value);
}
protected float3 ActivatorNormalized(float3 input) {
protected float3 ActivatorNormalized(float3 input) {
if (lengthsq(input) == 0)
return input;
return input;
float3 result = normalize(input);
return result;
}
@ -497,31 +499,31 @@ namespace NanoBrain {
}
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
if (this is IReceptor receptor) {
foreach (Nucleus element in receptor.nucleiArray) {
if (element is Neuron neuron) {
neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron);
}
}
}
else {
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
}
// if (this is IReceptor receptor) {
// foreach (Nucleus element in receptor.nucleiArray) {
// if (element is Neuron neuron) {
// neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
// receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron);
// }
// }
// }
// else {
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
// }
}
#endregion Receivers
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
if (this.parent is ClusterReceptor clusterReceptor)
clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
else
ProcessStimulusDirect(inputValue, thingId, thingName);
public override void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = null) {
// if (this.parent is ClusterReceptor clusterReceptor)
// clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
// else
ProcessStimulusDirect(inputValue); //, thingId, thingName);
}
public void ProcessStimulusDirect(Vector3 inputValue, int thingId = 0, string thingName = null) {
public void ProcessStimulusDirect(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) {
this.stale = 0;
this.bias = inputValue;
this.parent.UpdateFromNucleus(this);

View File

@ -138,7 +138,7 @@ public abstract class Nucleus {
/// <param name="inputValue">The value of the stimulus</param>
/// <param name="thingId">The id of the thing causing the stimulus</param>
/// <param name="thingName">The name of the thing causing the stimulus</param>
public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = "") {
public virtual void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = "") {
}
#endregion Update

View File

@ -1,3 +1,4 @@
/*
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
@ -194,4 +195,5 @@ namespace NanoBrain {
}
}
}
}
*/

View File

@ -10,16 +10,16 @@ namespace NanoBrain {
/// Basic IReceptor to receive external input
/// </summary>
[System.Serializable]
public class Receptor : Neuron, IReceptor {
public class Receptor : Neuron { //}, IReceptor {
/// <summary>
/// Create a new Receptor in a Cluster instance
/// </summary>
/// <param name="parent">The Cluster in which the Receptor is created</param>
/// <param name="name">The name of the new Receptor</param>
public Receptor(Cluster parent, string name) : base(parent, name) {
this.array = new NucleusArray(this);
if (this.name.IndexOf(":") < 0)
this.name += ": 0";
//this.array = new NucleusArray(this);
// if (this.name.IndexOf(":") < 0)
// this.name += ": 0";
}
/// <summary>
/// Create a new Receptor in a Cluster Prefab
@ -27,7 +27,7 @@ namespace NanoBrain {
/// <param name="prefab">The Cluster Prefab in which the Receptor is created</param>
/// <param name="name">The name of the new Receptor</param>
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) {
this.array = new NucleusArray(this);
//this.array = new NucleusArray(this);
}
public string GetName() {
@ -45,7 +45,7 @@ namespace NanoBrain {
/// \copydoc NanoBrain::Neuron::Clone
public override Nucleus Clone(ClusterPrefab prefab) {
Receptor clone = new(prefab, name) {
array = this._array
//array = this._array
};
CloneFields(clone);
// Adding receivers will also add synapses to the receivers
@ -55,28 +55,30 @@ namespace NanoBrain {
return clone;
}
[SerializeReference]
private NucleusArray _array;
public NucleusArray array {
set { _array = value; }
}
/*
[SerializeReference]
private NucleusArray _array;
public NucleusArray array {
set { _array = value; }
}
public Nucleus[] nucleiArray {
get { return _array.nuclei; }
set { _array.nuclei = value; }
}
public Nucleus[] nucleiArray {
get { return _array.nuclei; }
set { _array.nuclei = value; }
}
public void AddReceptorElement(ClusterPrefab prefab) {
IReceptorHelpers.AddReceptorElement(this, prefab);
}
public void AddReceptorElement(ClusterPrefab prefab) {
IReceptorHelpers.AddReceptorElement(this, prefab);
}
public void RemoveReceptorElement() {
IReceptorHelpers.RemoveReceptorElement(this);
}
public void RemoveReceptorElement() {
IReceptorHelpers.RemoveReceptorElement(this);
}
public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
}
public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
}
*/
public override void UpdateStateIsolated() {
this.outputValue = this.bias;
@ -104,10 +106,14 @@ namespace NanoBrain {
#endif
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
this._array ??= new NucleusArray(this.parent);
this._array.ProcessStimulus(thingId, inputValue, thingName);
public override void ProcessStimulus(Vector3 inputValue) { //}, int thingId = 0, string thingName = null) {
// this._array ??= new NucleusArray(this.parent);
// this._array.ProcessStimulus(thingId, inputValue, thingName);
this.stale = 0;
this.bias = inputValue;
this.parent.UpdateFromNucleus(this);
}
}
}