Multi smell works
This commit is contained in:
parent
33ea14bb72
commit
32b58852d4
@ -165,25 +165,10 @@ namespace NanoBrain {
|
|||||||
GUILayout.Label(nucleusType, headerStyle);
|
GUILayout.Label(nucleusType, headerStyle);
|
||||||
|
|
||||||
// Nucleus name
|
// Nucleus name
|
||||||
//Cluster cluster = this.currentPrefabNucleus as Cluster;
|
string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
||||||
Cluster cluster = this.currentNucleus as Cluster;
|
if (newName != this.currentNucleus.name) {
|
||||||
if (cluster != null) {
|
this.currentNucleus.name = newName;
|
||||||
EditorGUILayout.BeginHorizontal();
|
anythingChanged = true;
|
||||||
if (GUILayout.Button(this.currentNucleus.parent.name))
|
|
||||||
OnClusterClick(cluster);
|
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
|
||||||
EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
|
||||||
EditorGUI.EndDisabledGroup();
|
|
||||||
if (GUILayout.Button("Reimport"))
|
|
||||||
ReimportCluster(cluster);
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
|
||||||
if (newName != this.currentNucleus.name) {
|
|
||||||
this.currentNucleus.name = newName;
|
|
||||||
anythingChanged = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current output value
|
// Current output value
|
||||||
@ -202,7 +187,7 @@ namespace NanoBrain {
|
|||||||
if (this.currentNucleus is MemoryCell memory)
|
if (this.currentNucleus is MemoryCell memory)
|
||||||
MemoryCellInspector(memory, ref anythingChanged);
|
MemoryCellInspector(memory, ref anythingChanged);
|
||||||
// Cluster
|
// Cluster
|
||||||
else if (cluster != null)
|
else if (this.currentNucleus is Cluster cluster)
|
||||||
ClusterInspector(cluster, ref anythingChanged);
|
ClusterInspector(cluster, ref anythingChanged);
|
||||||
// Other
|
// Other
|
||||||
else
|
else
|
||||||
@ -277,8 +262,8 @@ namespace NanoBrain {
|
|||||||
if (breakOnWake && this.currentNucleus is Neuron currentNeuron) {
|
if (breakOnWake && this.currentNucleus is Neuron currentNeuron) {
|
||||||
if (currentNeuron.isSleeping == false)
|
if (currentNeuron.isSleeping == false)
|
||||||
Debug.Break();
|
Debug.Break();
|
||||||
trace = EditorGUILayout.Toggle("Trace", trace);
|
// trace = EditorGUILayout.Toggle("Trace", trace);
|
||||||
currentNeuron.trace = trace;
|
// currentNeuron.trace = trace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +289,6 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
Nucleus[] array = null;
|
Nucleus[] array = null;
|
||||||
int elementIx = -1;
|
int elementIx = -1;
|
||||||
//if (this.currentPrefabNucleus is Neuron prefabNeuron && prefabNeuron.synapses.Count > 0) {
|
|
||||||
// Synapse[] synapses = prefabNeuron.synapses.ToArray();
|
|
||||||
if (this.currentNucleus is Neuron currentNeuron && currentNeuron.synapses.Count > 0) {
|
if (this.currentNucleus is Neuron currentNeuron && currentNeuron.synapses.Count > 0) {
|
||||||
Synapse[] synapses = currentNeuron.synapses.ToArray();
|
Synapse[] synapses = currentNeuron.synapses.ToArray();
|
||||||
foreach (Synapse synapse in synapses) {
|
foreach (Synapse synapse in synapses) {
|
||||||
@ -345,19 +328,19 @@ namespace NanoBrain {
|
|||||||
else {
|
else {
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
if (synapse.neuron.parent.prefab != this.currentNucleus.parent.prefab) {
|
if (synapse.neuron.parent != this.currentNucleus.parent) {
|
||||||
// If it is a different cluster
|
// If it is a different cluster
|
||||||
GUIStyle labelStyle = new(GUI.skin.label);
|
GUIStyle labelStyle = new(GUI.skin.label);
|
||||||
float labelWidth = 200;
|
float labelWidth = 200;
|
||||||
if (synapse.neuron.parent.prefab != null) {
|
if (synapse.neuron.parent != null) {
|
||||||
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.prefab.name}.")).x;
|
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.name}.")).x;
|
||||||
GUILayout.Label($"{synapse.neuron.parent.prefab.name}", GUILayout.Width(labelWidth));
|
GUILayout.Label($"{synapse.neuron.parent.name}", GUILayout.Width(labelWidth));
|
||||||
}
|
}
|
||||||
string[] options = synapse.neuron.parent.prefab.cluster.nuclei.Select(n => n.name).ToArray();
|
string[] options = synapse.neuron.parent.nuclei.Select(n => n.name).ToArray();
|
||||||
int selectedIndex = System.Array.IndexOf(options, synapse.neuron.name);
|
int selectedIndex = System.Array.IndexOf(options, synapse.neuron.name);
|
||||||
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
|
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
|
||||||
if (newIndex != selectedIndex) {
|
if (newIndex != selectedIndex) {
|
||||||
Neuron newNeuron = synapse.neuron.parent.prefab.cluster.nuclei[newIndex] as Neuron;
|
Neuron newNeuron = synapse.neuron.parent.nuclei[newIndex] as Neuron;
|
||||||
ChangeSynapse(synapse, newNeuron);
|
ChangeSynapse(synapse, newNeuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,7 +420,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddNeuronInput(Nucleus nucleus) {
|
protected virtual void AddNeuronInput(Nucleus nucleus) {
|
||||||
Neuron newNeuron = new (this.currentCluster, "New Neuron");
|
Neuron newNeuron = new(this.currentCluster, "New Neuron");
|
||||||
//Neuron newNeuroid = new(this.prefab.cluster, "New neuron");
|
//Neuron newNeuroid = new(this.prefab.cluster, "New neuron");
|
||||||
newNeuron.AddReceiver(nucleus);
|
newNeuron.AddReceiver(nucleus);
|
||||||
this.currentNucleus = newNeuron;
|
this.currentNucleus = newNeuron;
|
||||||
@ -453,7 +436,7 @@ namespace NanoBrain {
|
|||||||
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
||||||
}
|
}
|
||||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
||||||
Cluster subclusterInstance = new(selectedPrefab, this.prefab);
|
Cluster subclusterInstance = new(selectedPrefab, this.currentCluster);
|
||||||
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,11 +540,6 @@ namespace NanoBrain {
|
|||||||
AddInput(selectedType, this.currentNucleus);
|
AddInput(selectedType, this.currentNucleus);
|
||||||
}
|
}
|
||||||
return connecting;
|
return connecting;
|
||||||
// if (selectedType == Nucleus.Type.None)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
// AddInput(selectedType, this.currentNucleus);
|
|
||||||
// return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
||||||
|
|||||||
@ -108,7 +108,7 @@ namespace NanoBrain {
|
|||||||
this.gameObject = gameObject;
|
this.gameObject = gameObject;
|
||||||
if (this.currentCluster == null)
|
if (this.currentCluster == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Application.isPlaying == false)
|
if (Application.isPlaying == false)
|
||||||
this.serializedBrain = new SerializedObject(this.currentCluster.prefab);
|
this.serializedBrain = new SerializedObject(this.currentCluster.prefab);
|
||||||
this.selectedOutput = this.currentCluster.outputs[0];
|
this.selectedOutput = this.currentCluster.outputs[0];
|
||||||
@ -488,14 +488,15 @@ namespace NanoBrain {
|
|||||||
maxValue = 1;
|
maxValue = 1;
|
||||||
float brightness = siblingNeuron.outputMagnitude / maxValue;
|
float brightness = siblingNeuron.outputMagnitude / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
} DrawNucleus(siblingNeuron, position, size, color);
|
}
|
||||||
|
DrawNucleus(siblingNeuron, position, size, color);
|
||||||
GUIStyle style = new(EditorStyles.label) {
|
GUIStyle style = new(EditorStyles.label) {
|
||||||
alignment = TextAnchor.UpperCenter,
|
alignment = TextAnchor.UpperCenter,
|
||||||
normal = { textColor = Color.white },
|
normal = { textColor = Color.white },
|
||||||
fontStyle = FontStyle.Bold,
|
fontStyle = FontStyle.Bold,
|
||||||
};
|
};
|
||||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||||
string name = $"{sibling.baseName}.{nucleus.name}";
|
string name = $"{sibling.baseName}\n{nucleus.name}";
|
||||||
Handles.Label(labelPos, name, style);
|
Handles.Label(labelPos, name, style);
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
@ -505,7 +506,7 @@ namespace NanoBrain {
|
|||||||
protected void DrawOutputs(Vector2 parentPos, float size) {
|
protected void DrawOutputs(Vector2 parentPos, float size) {
|
||||||
if (this.currentCluster == null)
|
if (this.currentCluster == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Determine the maximum value in this layer
|
// Determine the maximum value in this layer
|
||||||
// This is used to 'scale' the output value colors of the nuclei
|
// This is used to 'scale' the output value colors of the nuclei
|
||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
@ -612,18 +613,12 @@ namespace NanoBrain {
|
|||||||
if (nucleus.parent != null && currentNucleus != null && nucleus.parent != currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
|
if (nucleus.parent != null && currentNucleus != null && nucleus.parent != currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
|
||||||
// This neuron is part of another cluster
|
// This neuron is part of another cluster
|
||||||
parentCluster1.name ??= "";
|
parentCluster1.name ??= "";
|
||||||
string baseName = "";
|
|
||||||
int colonPos = parentCluster1.name.IndexOf(":");
|
int colonPos = parentCluster1.name.IndexOf(":");
|
||||||
|
string baseName;
|
||||||
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
|
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
|
||||||
baseName = parentCluster1.name[..colonPos] + ".";
|
baseName = parentCluster1.name[..colonPos] + "\n";
|
||||||
else
|
else
|
||||||
baseName = parentCluster1.name + ".";
|
baseName = parentCluster1.name + "\n";
|
||||||
// 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);
|
Handles.Label(labelPos, baseName + nucleus.name, style);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -858,22 +853,34 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
void OnSceneGUI(SceneView sceneView) {
|
void OnSceneGUI(SceneView sceneView) {
|
||||||
if (this.gameObject != null) {
|
if (this.gameObject != null) {
|
||||||
// if (this.currentNucleus is IReceptor receptor) {
|
|
||||||
// foreach (Nucleus nucleus in receptor.nucleiArray) {
|
Handles.color = Color.yellow;
|
||||||
// if (nucleus is Neuron neuron) {
|
if (this.selectedSynapseNeuron != null) {
|
||||||
// Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
|
foreach (Cluster sibling in this.selectedSynapseNeuron.parent.siblingClusters) {
|
||||||
// Handles.color = Color.yellow;
|
Neuron siblingNeuron = sibling.GetNucleus(this.selectedSynapseNeuron.name) as Neuron;
|
||||||
// Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
Vector3 worldVector = this.gameObject.transform.TransformVector(siblingNeuron.outputValue);
|
||||||
// }
|
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
// }
|
}
|
||||||
// }
|
// if (this.currentNucleus is Cluster cluster) {
|
||||||
// else {
|
// foreach (Cluster sibling in cluster.siblingClusters) {
|
||||||
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.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -111,13 +111,13 @@ namespace NanoBrain {
|
|||||||
Neuron synapseNeuron = prefabSynapse.neuron;
|
Neuron synapseNeuron = prefabSynapse.neuron;
|
||||||
if (synapseNeuron.parent.prefab != null && synapseNeuron.parent.prefab != this.prefab) {
|
if (synapseNeuron.parent.prefab != null && synapseNeuron.parent.prefab != this.prefab) {
|
||||||
// Neuron is in another cluster, find the cloned cluster first
|
// Neuron is in another cluster, find the cloned cluster first
|
||||||
ClusterPrefab prefabCluster = synapseNeuron.parent.prefab;
|
Cluster prefabCluster = synapseNeuron.parent;
|
||||||
Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
||||||
if (clonedCluster == null)
|
if (clonedCluster == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Now find the neuron in that cloned cluster
|
// Now find the neuron in that cloned cluster
|
||||||
int neuronIx = GetNucleusIndex(prefabCluster.cluster.nuclei, prefabSynapse.neuron.name);
|
int neuronIx = GetNucleusIndex(prefabCluster.nuclei, prefabSynapse.neuron.name);
|
||||||
if (neuronIx < 0)
|
if (neuronIx < 0)
|
||||||
// Could not find the neuron in the prefab cluster
|
// Could not find the neuron in the prefab cluster
|
||||||
continue;
|
continue;
|
||||||
@ -140,28 +140,6 @@ namespace NanoBrain {
|
|||||||
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Copy the receivers, which will also create the synapses
|
|
||||||
// foreach (Nucleus receiver in prefabNeuron.receivers.ToArray()) {
|
|
||||||
// int ix = GetNucleusIndex(prefabNuclei, receiver);
|
|
||||||
// if (ix < 0)
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// if (clonedNuclei[ix] is not Nucleus clonedReceiver)
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// // Find the synapse for the weight
|
|
||||||
// float weight = 1;
|
|
||||||
// foreach (Synapse synapse in receiver.synapses) {
|
|
||||||
// // Find the weight for this synapse
|
|
||||||
// if (synapse.neuron == prefabNucleus) {
|
|
||||||
// weight = synapse.weight;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// clonedNeuron.AddReceiver(clonedReceiver, weight);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
@ -191,135 +169,43 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
// Ensure that all neurons are computed to initialize bias
|
// Ensure that all neurons are computed to initialize bias
|
||||||
foreach (Nucleus clonedNucleus in clonedNuclei) {
|
foreach (Nucleus clonedNucleus in clonedNuclei) {
|
||||||
clonedNucleus.UpdateStateIsolated();
|
if (clonedNucleus is not Cluster)
|
||||||
|
clonedNucleus.UpdateStateIsolated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
for (int nucleusIx = 0; nucleusIx < clonedNuclei.Length; nucleusIx++) {
|
|
||||||
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
|
|
||||||
if (prefabNucleus is not Cluster prefabCluster)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (prefabCluster.instanceCount <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Cluster clonedNucleus = clonedNuclei[nucleusIx] as Cluster;
|
|
||||||
if (prefabCluster == prefabCluster.siblingClusters[0]) {
|
|
||||||
// We clone the array only for the first entry
|
|
||||||
//NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length);
|
|
||||||
Cluster[] clonedArray = new Cluster[prefabCluster.siblingClusters.Length];
|
|
||||||
int arrayIx = 0;
|
|
||||||
foreach (Cluster prefabArrayNucleus in prefabCluster.siblingClusters) {
|
|
||||||
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
|
||||||
if (arrayNucleusIx >= 0) {
|
|
||||||
Cluster clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Cluster;
|
|
||||||
clonedArray[arrayIx] = clonedArrayNucleus;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones");
|
|
||||||
}
|
|
||||||
arrayIx++;
|
|
||||||
}
|
|
||||||
clonedNucleus.siblingClusters = clonedArray;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// The others will refer to the array created for the first nucleus in the array
|
|
||||||
int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabCluster.siblingClusters[0]);
|
|
||||||
Cluster clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Cluster;
|
|
||||||
clonedNucleus.siblingClusters = clonedFirstNucleus.siblingClusters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// private void CloneSynapses(Neuron prefabNeuron, Neuron clonedNeuron) {
|
||||||
// Collect the subclusters
|
// foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
||||||
List<Cluster> subClusters = new();
|
// Neuron synapseNeuron = prefabSynapse.neuron;
|
||||||
foreach (Nucleus nucleus in prefabNuclei) {
|
// if (synapseNeuron.parent.prefab != null && synapseNeuron.parent.prefab != this.prefab) {
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
// // Neuron is in another cluster, find the cloned cluster first
|
||||||
Nucleus synapseNucleus = synapse.neuron;
|
// ClusterPrefab prefabCluster = synapseNeuron.parent.prefab;
|
||||||
Cluster subCluster = synapseNucleus.parent;
|
// Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
||||||
if (subCluster is null ||
|
// if (clonedCluster == null)
|
||||||
synapseNucleus.clusterPrefab == this.clusterPrefab) {
|
// continue;
|
||||||
|
|
||||||
continue;
|
// // Now find the neuron in that cloned cluster
|
||||||
}
|
// int neuronIx = GetNucleusIndex(prefabCluster.cluster.nuclei, prefabSynapse.neuron.name);
|
||||||
// if (synapseNucleus is not Cluster subCluster)
|
// if (neuronIx < 0)
|
||||||
// continue;
|
// // Could not find the neuron in the prefab cluster
|
||||||
if (subClusters.Contains(subCluster))
|
// continue;
|
||||||
continue;
|
// if (clonedCluster.nuclei[neuronIx] is not Neuron clonedSender)
|
||||||
subClusters.Add(subCluster);
|
// // Could not find the neuron in the cloned cluster
|
||||||
}
|
// continue;
|
||||||
}
|
|
||||||
// Create the subcluster instances
|
|
||||||
foreach (Cluster subCluster in subClusters) {
|
|
||||||
for (int ix = 0; ix < subCluster.instanceCount; ix++) {
|
|
||||||
// create the new instance
|
|
||||||
Cluster clusterInstance = new(subCluster.prefab);
|
|
||||||
// connect it
|
|
||||||
foreach ((Neuron sender, Nucleus receiver) in subCluster.CollectConnections()) {
|
|
||||||
int receiverIx = GetNucleusIndex(prefabNuclei, receiver);
|
|
||||||
if (receiverIx < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (clonedNuclei[receiverIx] is not Nucleus clonedReceiver)
|
// clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
||||||
continue;
|
// //Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Neuron clonedSender = this.nuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron;
|
||||||
|
// // Copy the receivers which will also create the synapse
|
||||||
|
// clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
||||||
|
// // Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Find the synapse for the weight
|
// }
|
||||||
float weight = 1;
|
|
||||||
foreach (Synapse synapse in receiver.synapses) {
|
|
||||||
// Find the weight for this synapse
|
|
||||||
if (synapse.neuron == sender) {
|
|
||||||
weight = synapse.weight;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clusterInstance.GetNucleus(sender.name) is not Neuron clonedSender)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
clonedSender.AddReceiver(clonedReceiver, weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// foreach (Nucleus nucleus in this.clusterNuclei) {
|
|
||||||
// if (nucleus is Cluster clonedSubCluster)
|
|
||||||
// RestoreAllExternalReceivers(clonedSubCluster, this.prefab, this);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloneSynapses(Neuron prefabNeuron, Neuron clonedNeuron) {
|
|
||||||
foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
|
||||||
Neuron synapseNeuron = prefabSynapse.neuron;
|
|
||||||
if (synapseNeuron.parent.prefab != null && synapseNeuron.parent.prefab != this.prefab) {
|
|
||||||
// Neuron is in another cluster, find the cloned cluster first
|
|
||||||
ClusterPrefab prefabCluster = synapseNeuron.parent.prefab;
|
|
||||||
Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
|
||||||
if (clonedCluster == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Now find the neuron in that cloned cluster
|
|
||||||
int neuronIx = GetNucleusIndex(prefabCluster.cluster.nuclei, prefabSynapse.neuron.name);
|
|
||||||
if (neuronIx < 0)
|
|
||||||
// Could not find the neuron in the prefab cluster
|
|
||||||
continue;
|
|
||||||
if (clonedCluster.nuclei[neuronIx] is not Neuron clonedSender)
|
|
||||||
// Could not find the neuron in the cloned cluster
|
|
||||||
continue;
|
|
||||||
|
|
||||||
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
|
||||||
//Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Neuron clonedSender = this.nuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron;
|
|
||||||
// Copy the receivers which will also create the synapse
|
|
||||||
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
|
||||||
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sort the nuclei in a correct evaluation order
|
/// Sort the nuclei in a correct evaluation order
|
||||||
@ -537,43 +423,43 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Cluster GetThingCluster() {
|
// public virtual Cluster GetThingCluster() {
|
||||||
Cluster selectedCluster = SelectCluster();
|
// Cluster selectedCluster = SelectCluster();
|
||||||
return selectedCluster;
|
// return selectedCluster;
|
||||||
}
|
// }
|
||||||
public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
|
// public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
|
||||||
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
// if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
||||||
return cluster;
|
// return cluster;
|
||||||
|
|
||||||
Cluster selectedCluster = SelectCluster();
|
// Cluster selectedCluster = SelectCluster();
|
||||||
selectedCluster.name = baseName + ": " + thingName;
|
// selectedCluster.name = baseName + ": " + thingName;
|
||||||
thingClusters[thingId] = selectedCluster;
|
// thingClusters[thingId] = selectedCluster;
|
||||||
return selectedCluster;
|
// return selectedCluster;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private Cluster SelectCluster() {
|
// private Cluster SelectCluster() {
|
||||||
if (this.siblingClusters == null)
|
// if (this.siblingClusters == null)
|
||||||
return this;
|
// return this;
|
||||||
|
|
||||||
// Find a sleeping cluster
|
// // Find a sleeping cluster
|
||||||
// foreach (Cluster cluster in this.siblingClusters) {
|
// // foreach (Cluster cluster in this.siblingClusters) {
|
||||||
// if (cluster.defaultOutput.isSleeping) {
|
// // if (cluster.defaultOutput.isSleeping) {
|
||||||
// RemoveThingCluster(cluster);
|
// // RemoveThingCluster(cluster);
|
||||||
// return cluster;
|
// // return cluster;
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
// Find longest unused cluster
|
// // Find longest unused cluster
|
||||||
// Note this uses the default output...
|
// // Note this uses the default output...
|
||||||
Cluster unusedCluster = this.siblingClusters[0];
|
// Cluster unusedCluster = this.siblingClusters[0];
|
||||||
for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
// for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
||||||
if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
// if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
||||||
unusedCluster = this.siblingClusters[ix];
|
// unusedCluster = this.siblingClusters[ix];
|
||||||
}
|
// }
|
||||||
|
|
||||||
RemoveThingCluster(unusedCluster);
|
// RemoveThingCluster(unusedCluster);
|
||||||
return unusedCluster;
|
// return unusedCluster;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void RemoveThingCluster(Cluster cluster) {
|
private void RemoveThingCluster(Cluster cluster) {
|
||||||
List<int> keysToRemove = new();
|
List<int> keysToRemove = new();
|
||||||
@ -756,8 +642,8 @@ namespace NanoBrain {
|
|||||||
else {
|
else {
|
||||||
string nucleusName0 = nucleusName + ": 0";
|
string nucleusName0 = nucleusName + ": 0";
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is Cluster) { //IReceptor receptor) {
|
if (nucleus is Cluster) {
|
||||||
if (nucleus.name == nucleusName | nucleus.name == nucleusName0)
|
if (nucleus.name == nucleusName || nucleus.name == nucleusName0)
|
||||||
return nucleus;
|
return nucleus;
|
||||||
}
|
}
|
||||||
else if (nucleus.name == nucleusName)
|
else if (nucleus.name == nucleusName)
|
||||||
@ -775,6 +661,51 @@ namespace NanoBrain {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Neuron GetNeuron(int thingId, string neuronName, string thingName = null) {
|
||||||
|
if (this.siblingClusters == null || this.siblingClusters.Length <= 1)
|
||||||
|
return this.GetNeuron(neuronName);
|
||||||
|
|
||||||
|
// See if we are already using a cluster for thingId
|
||||||
|
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
||||||
|
return cluster.GetNeuron(neuronName);
|
||||||
|
|
||||||
|
// Find the cluster with the lowest value neuron
|
||||||
|
Neuron lowestNeuron = null;
|
||||||
|
foreach (Cluster sibling in this.siblingClusters) {
|
||||||
|
Neuron neuron = sibling.GetNeuron(neuronName);
|
||||||
|
if (lowestNeuron == null || neuron.outputMagnitude < lowestNeuron.outputMagnitude)
|
||||||
|
lowestNeuron = neuron;
|
||||||
|
}
|
||||||
|
Cluster selectedCluster = lowestNeuron.parent;
|
||||||
|
RemoveThingCluster(selectedCluster);
|
||||||
|
selectedCluster.name = baseName + ": " + thingName;
|
||||||
|
thingClusters[thingId] = selectedCluster;
|
||||||
|
return lowestNeuron;
|
||||||
|
/*
|
||||||
|
// Find a sleeping cluster
|
||||||
|
// foreach (Cluster cluster in this.siblingClusters) {
|
||||||
|
// if (cluster.defaultOutput.isSleeping) {
|
||||||
|
// RemoveThingCluster(cluster);
|
||||||
|
// return cluster;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Find longest unused cluster
|
||||||
|
// Note this uses the default output...
|
||||||
|
Cluster unusedCluster = this.siblingClusters[0];
|
||||||
|
for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
||||||
|
if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
||||||
|
unusedCluster = this.siblingClusters[ix];
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveThingCluster(unusedCluster);
|
||||||
|
//return unusedCluster;
|
||||||
|
|
||||||
|
Cluster cluster = GetThingCluster(thingId, thingName);
|
||||||
|
Neuron neuron = cluster?.GetNeuron(neuronName);
|
||||||
|
return neuron;
|
||||||
|
*/
|
||||||
|
}
|
||||||
public bool DeleteNucleus(Nucleus nucleus) {
|
public bool DeleteNucleus(Nucleus nucleus) {
|
||||||
if (this.nuclei.Contains(nucleus) == false) {
|
if (this.nuclei.Contains(nucleus) == false) {
|
||||||
// Try to find the nucleus by name
|
// Try to find the nucleus by name
|
||||||
@ -883,27 +814,19 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
||||||
//if (startNucleus.trace)
|
|
||||||
// Debug.Log($"Update from {startNucleus.name}");
|
|
||||||
foreach (Nucleus nucleus in computeOrder) {
|
foreach (Nucleus nucleus in computeOrder) {
|
||||||
if (nucleus is not Cluster) {
|
if (nucleus is not Cluster) {
|
||||||
nucleus.UpdateStateIsolated();
|
nucleus.UpdateStateIsolated();
|
||||||
//if (startNucleus.trace && nucleus is Neuron neuron)
|
|
||||||
// Debug.Log($" {nucleus.name}");
|
|
||||||
if (nucleus is Neuron neuron) {
|
if (nucleus is Neuron neuron) {
|
||||||
foreach (Nucleus receiver in neuron.receivers) {
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
if (receiver.parent != this) {
|
if (receiver.parent != this) {
|
||||||
Debug.Log($" External: {receiver.parent.name}.{receiver.name}");
|
//Debug.Log($" External: {receiver.parent.name}.{receiver.name}");
|
||||||
receiver.parent.UpdateFromNucleus(receiver);
|
receiver.parent.UpdateFromNucleus(receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue in parent
|
|
||||||
//this.parent?.UpdateFromNucleus(this);
|
|
||||||
|
|
||||||
UpdateNuclei();
|
UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,6 +834,7 @@ namespace NanoBrain {
|
|||||||
throw new Exception("Cluster should not be updated!");
|
throw new Exception("Cluster should not be updated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't think this does anything anymore...
|
||||||
public override void UpdateNuclei() {
|
public override void UpdateNuclei() {
|
||||||
foreach (Nucleus nucleus in this.nuclei)
|
foreach (Nucleus nucleus in this.nuclei)
|
||||||
nucleus.UpdateNuclei();
|
nucleus.UpdateNuclei();
|
||||||
@ -921,9 +845,9 @@ namespace NanoBrain {
|
|||||||
public void Refresh() {
|
public void Refresh() {
|
||||||
// This should not be needed, but somehow somewhere the parent is changed...
|
// This should not be needed, but somehow somewhere the parent is changed...
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is not Neuron neuron)
|
// if (nucleus is not Neuron neuron)
|
||||||
continue;
|
// continue;
|
||||||
neuron.parent = this;
|
nucleus.parent = this;
|
||||||
}
|
}
|
||||||
RefreshOutputs();
|
RefreshOutputs();
|
||||||
RefreshComputeOrders();
|
RefreshComputeOrders();
|
||||||
|
|||||||
@ -276,16 +276,11 @@ namespace NanoBrain {
|
|||||||
public float outputSqrMagnitude => _outputValue.sqrMagnitude;
|
public float outputSqrMagnitude => _outputValue.sqrMagnitude;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
public bool isFiring {
|
public bool isFiring => this.outputMagnitude > 0.5f;
|
||||||
get {
|
|
||||||
//SleepCheck();
|
|
||||||
return this.outputMagnitude > 0.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Action WhenFiring;
|
public Action WhenFiring;
|
||||||
|
|
||||||
public bool persistOutput = false;
|
public bool persistOutput = false;
|
||||||
public virtual bool isSleeping => persistOutput ? false : (Time.time - this.lastUpdate > this.timeToSleep);
|
public virtual bool isSleeping => !persistOutput && (Time.time - this.lastUpdate > this.timeToSleep);
|
||||||
public void SleepCheck() {
|
public void SleepCheck() {
|
||||||
if (this.isSleeping) {
|
if (this.isSleeping) {
|
||||||
#if UNITY_MATHEMATICS
|
#if UNITY_MATHEMATICS
|
||||||
@ -299,9 +294,9 @@ namespace NanoBrain {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Toggle for printing debugging trace data
|
/// Toggle for printing debugging trace data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool trace = false;
|
//public bool trace = false;
|
||||||
|
|
||||||
[NonSerialized]
|
//[NonSerialized]
|
||||||
public float lastUpdate = 0;
|
public float lastUpdate = 0;
|
||||||
public readonly float timeToSleep = 1f;
|
public readonly float timeToSleep = 1f;
|
||||||
|
|
||||||
@ -624,7 +619,13 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
#endregion Receivers
|
#endregion Receivers
|
||||||
|
|
||||||
public override void ProcessStimulus(Vector3 inputValue) {
|
/// <summary>
|
||||||
|
/// Process an external stimulus
|
||||||
|
/// </summary>
|
||||||
|
/// <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) {
|
||||||
this.lastUpdate = Time.time;
|
this.lastUpdate = Time.time;
|
||||||
this.bias = inputValue;
|
this.bias = inputValue;
|
||||||
this.parent?.UpdateFromNucleus(this);
|
this.parent?.UpdateFromNucleus(this);
|
||||||
|
|||||||
@ -142,15 +142,6 @@ public abstract class Nucleus {
|
|||||||
// this.parent.UpdateFromNucleus(this);
|
// this.parent.UpdateFromNucleus(this);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process an external stimulus
|
|
||||||
/// </summary>
|
|
||||||
/// <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 = "") {
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Update
|
#endregion Update
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user