Merge commit 'dd326823a8256f3ddb808e071d98c4aede72e410'
This commit is contained in:
commit
ec2a6b7ae9
@ -64,30 +64,22 @@ namespace NanoBrain {
|
|||||||
public class GraphEditor : GraphView {
|
public class GraphEditor : GraphView {
|
||||||
|
|
||||||
protected ClusterPrefab prefab;
|
protected ClusterPrefab prefab;
|
||||||
|
protected Nucleus currentPrefabNucleus;
|
||||||
|
|
||||||
|
protected override Nucleus currentNucleus {
|
||||||
|
get => base.currentNucleus;
|
||||||
|
set {
|
||||||
|
base.currentNucleus = value;
|
||||||
|
this.currentPrefabNucleus = value != null ? this.prefab.GetNucleus(value.name) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public GraphEditor(ClusterPrefab prefab) : base(prefab.output.parent) {
|
public GraphEditor(ClusterPrefab prefab) : base(prefab.output.parent) {
|
||||||
this.prefab = prefab;
|
this.prefab = prefab;
|
||||||
|
|
||||||
// In a Prefab editor, no instance exists but we need it for the ClusterViewer.
|
// In a Prefab editor, no instance exists but we need it for the ClusterViewer.
|
||||||
// So we create a temporary instance
|
// So we create a temporary instance
|
||||||
Cluster cluster = new(prefab);
|
this.currentCluster = new(prefab);
|
||||||
this.currentCluster = cluster;
|
|
||||||
|
|
||||||
Button addButton = new(() => OnAddClusterOutput()) {
|
|
||||||
text = "Add"
|
|
||||||
};
|
|
||||||
topMenuContainer?.Add(addButton);
|
|
||||||
|
|
||||||
Add(topMenuContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnAddClusterOutput() {
|
|
||||||
Nucleus newOutput = new Neuron(this.prefab, "New Output");
|
|
||||||
this.prefab.RefreshOutputs();
|
|
||||||
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
|
||||||
// outputsPopup.value = newOutput.name;
|
|
||||||
|
|
||||||
this.currentNucleus = newOutput;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
||||||
@ -151,69 +143,76 @@ namespace NanoBrain {
|
|||||||
if (serializedObject == null || serializedObject.targetObject == null)
|
if (serializedObject == null || serializedObject.targetObject == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.currentNucleus == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
|
|
||||||
GUIStyle headerStyle = new(EditorStyles.boldLabel) {
|
|
||||||
alignment = TextAnchor.MiddleLeft,
|
|
||||||
margin = new RectOffset(10, 0, 4, 4)
|
|
||||||
};
|
|
||||||
GUIStyle boldTextFieldStyle = new(EditorStyles.textField) {
|
GUIStyle boldTextFieldStyle = new(EditorStyles.textField) {
|
||||||
fontStyle = FontStyle.Bold
|
fontStyle = FontStyle.Bold
|
||||||
};
|
};
|
||||||
|
|
||||||
// Nucleus type
|
if (this.currentNucleus == null) {
|
||||||
string nucleusType = this.currentNucleus.GetType().Name;
|
OutputsInspector(ref anythingChanged);
|
||||||
GUILayout.Label(nucleusType, headerStyle);
|
return;
|
||||||
|
|
||||||
// Nucleus name
|
|
||||||
if (this.currentNucleus.parent is Cluster parentCluster) {
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
if (GUILayout.Button(this.currentNucleus.parent.name))
|
|
||||||
OnClusterClick(parentCluster);
|
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
|
||||||
EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
|
||||||
EditorGUI.EndDisabledGroup();
|
|
||||||
if (GUILayout.Button("Reimport"))
|
|
||||||
ReimportCluster(parentCluster);
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
GUIStyle headerStyle = new(EditorStyles.boldLabel) {
|
||||||
if (newName != this.currentNucleus.name) {
|
alignment = TextAnchor.MiddleLeft,
|
||||||
this.currentNucleus.name = newName;
|
margin = new RectOffset(10, 0, 4, 4)
|
||||||
this.prefab.RefreshOutputs();
|
};
|
||||||
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
// Nucleus type
|
||||||
anythingChanged = true;
|
string nucleusType = this.currentNucleus.GetType().Name;
|
||||||
}
|
GUILayout.Label(nucleusType, headerStyle);
|
||||||
}
|
|
||||||
|
|
||||||
// Current output value
|
// Nucleus name
|
||||||
if (Application.isPlaying) {
|
Cluster cluster = this.currentPrefabNucleus as Cluster;
|
||||||
if (currentNucleus is Neuron currentNeuron1) {
|
if (cluster != null) {
|
||||||
GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString());
|
EditorGUILayout.BeginHorizontal();
|
||||||
EditorGUILayout.FloatField(nameLabel, currentNeuron1.outputMagnitude);
|
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) {
|
||||||
|
Nucleus prefabNucleus = this.prefab.GetNucleus(this.currentNucleus.name);
|
||||||
|
prefabNucleus.name = newName;
|
||||||
|
// This changes it in the temporary cluster instance
|
||||||
|
this.currentNucleus.name = newName;
|
||||||
|
this.prefab.RefreshOutputs();
|
||||||
|
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
|
anythingChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current output value
|
||||||
|
if (Application.isPlaying) {
|
||||||
|
if (currentNucleus is Neuron currentNeuron1) {
|
||||||
|
GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString());
|
||||||
|
EditorGUILayout.FloatField(nameLabel, currentNeuron1.outputMagnitude);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
EditorGUILayout.LabelField(" ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EditorGUILayout.LabelField(" ");
|
EditorGUILayout.LabelField(" ");
|
||||||
|
|
||||||
|
// Memory cell
|
||||||
|
if (this.currentNucleus is MemoryCell memory)
|
||||||
|
MemoryCellInspector(memory, ref anythingChanged);
|
||||||
|
// Cluster
|
||||||
|
else if (cluster != null)
|
||||||
|
ClusterInspector(cluster, ref anythingChanged);
|
||||||
|
// Other
|
||||||
|
else
|
||||||
|
NucleusInspector(this.currentNucleus, ref anythingChanged);
|
||||||
|
|
||||||
|
if (GUILayout.Button("Delete"))
|
||||||
|
DeleteNucleus(this.currentNucleus);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
EditorGUILayout.LabelField(" ");
|
|
||||||
|
|
||||||
// Memory cell
|
|
||||||
if (this.currentNucleus is MemoryCell memory)
|
|
||||||
MemoryCellInspector(memory, ref anythingChanged);
|
|
||||||
// Cluster
|
|
||||||
else if (this.currentNucleus is Cluster cluster)
|
|
||||||
ClusterInspector(cluster, ref anythingChanged);
|
|
||||||
// Other
|
|
||||||
else
|
|
||||||
NucleusInspector(this.currentNucleus, ref anythingChanged);
|
|
||||||
|
|
||||||
if (GUILayout.Button("Delete"))
|
|
||||||
DeleteNucleus(this.currentNucleus);
|
|
||||||
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
if (anythingChanged) {
|
if (anythingChanged) {
|
||||||
@ -222,6 +221,24 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void OutputsInspector(ref bool anythingChanged) {
|
||||||
|
GUIStyle headerStyle = new(EditorStyles.boldLabel) {
|
||||||
|
alignment = TextAnchor.MiddleLeft,
|
||||||
|
margin = new RectOffset(10, 0, 4, 4)
|
||||||
|
};
|
||||||
|
GUILayout.Label("Outputs", headerStyle);
|
||||||
|
|
||||||
|
bool connecting = GUILayout.Button("Add Output Neuron");
|
||||||
|
if (connecting) {
|
||||||
|
Nucleus newOutput = new Neuron(this.prefab, "New Output");
|
||||||
|
// Regenerate the temporary clsuter instance
|
||||||
|
// See also the constructor
|
||||||
|
this.currentCluster = new(this.prefab);
|
||||||
|
this.currentNucleus = newOutput;
|
||||||
|
this.selectedOutput = this.currentNucleus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void MemoryCellInspector(MemoryCell memoryCell, ref bool anythingChanged) {
|
protected void MemoryCellInspector(MemoryCell memoryCell, ref bool anythingChanged) {
|
||||||
memoryCell.staticMemory = EditorGUILayout.Toggle("Static Memory", memoryCell.staticMemory);
|
memoryCell.staticMemory = EditorGUILayout.Toggle("Static Memory", memoryCell.staticMemory);
|
||||||
NucleusInspector(memoryCell, ref anythingChanged);
|
NucleusInspector(memoryCell, ref anythingChanged);
|
||||||
@ -241,7 +258,6 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
if (GUILayout.Button("Add")) {
|
if (GUILayout.Button("Add")) {
|
||||||
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||||
//cluster.AddInstance(this.prefab);
|
|
||||||
cluster.AddInstance();
|
cluster.AddInstance();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
@ -284,14 +300,17 @@ namespace NanoBrain {
|
|||||||
EditorGUIUtility.labelWidth = 100;
|
EditorGUIUtility.labelWidth = 100;
|
||||||
|
|
||||||
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias);
|
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias);
|
||||||
anythingChanged |= newBias != this.currentNucleus.bias;
|
if (newBias != this.currentPrefabNucleus.bias) {
|
||||||
this.currentNucleus.bias = newBias;
|
anythingChanged |= newBias != this.currentNucleus.bias;
|
||||||
|
this.currentPrefabNucleus.bias = newBias;
|
||||||
|
this.currentNucleus.bias = newBias;
|
||||||
|
}
|
||||||
EditorGUIUtility.labelWidth = previousLabelWidth;
|
EditorGUIUtility.labelWidth = previousLabelWidth;
|
||||||
|
|
||||||
Nucleus[] array = null;
|
Nucleus[] array = null;
|
||||||
int elementIx = -1;
|
int elementIx = -1;
|
||||||
if (this.currentNucleus.synapses.Count > 0) {
|
if (this.currentPrefabNucleus.synapses.Count > 0) {
|
||||||
Synapse[] synapses = this.currentNucleus.synapses.ToArray();
|
Synapse[] synapses = this.currentPrefabNucleus.synapses.ToArray();
|
||||||
foreach (Synapse synapse in synapses) {
|
foreach (Synapse synapse in synapses) {
|
||||||
if (synapse.neuron == null)
|
if (synapse.neuron == null)
|
||||||
continue;
|
continue;
|
||||||
@ -330,24 +349,20 @@ namespace NanoBrain {
|
|||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
if (synapse.neuron.clusterPrefab != this.currentNucleus.clusterPrefab) {
|
if (synapse.neuron.clusterPrefab != this.currentNucleus.clusterPrefab) {
|
||||||
// If it is a 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.clusterPrefab != null) {
|
if (synapse.neuron.clusterPrefab != null) {
|
||||||
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.clusterPrefab.name}.")).x;
|
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.clusterPrefab.name}.")).x;
|
||||||
GUILayout.Label($"{synapse.neuron.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
GUILayout.Label($"{synapse.neuron.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
||||||
}
|
}
|
||||||
//string[] options = synapse.neuron.parent.clusterNuclei.Select(n => n.name).ToArray();
|
|
||||||
string[] options = synapse.neuron.clusterPrefab.nuclei.Select(n => n.name).ToArray();
|
string[] options = synapse.neuron.clusterPrefab.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 && synapse.neuron.clusterPrefab.nuclei[newIndex] is Neuron newNeuron)
|
|
||||||
// ChangeSynapse(synapse, newNeuron);
|
|
||||||
if (newIndex != selectedIndex) {
|
if (newIndex != selectedIndex) {
|
||||||
// It shall be ensured that the parent.clusterNuclei and
|
// Nucleus selectedNucleus = synapse.neuron.parent.clusterNuclei[newIndex];
|
||||||
// clusterPrefab.nuclei contain the same neurons in the same order....
|
// Neuron newNeuron = selectedNucleus as Neuron;
|
||||||
Nucleus selectedNucleus = synapse.neuron.parent.clusterNuclei[newIndex];
|
Neuron newNeuron = synapse.neuron.clusterPrefab.nuclei[newIndex] as Neuron;
|
||||||
Neuron newNeuron = selectedNucleus as Neuron;
|
|
||||||
ChangeSynapse(synapse, newNeuron);
|
ChangeSynapse(synapse, newNeuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,14 +382,6 @@ namespace NanoBrain {
|
|||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
||||||
if (newWeight != 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
|
|
||||||
synapse.weight = newWeight;
|
synapse.weight = newWeight;
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
@ -430,15 +437,6 @@ namespace NanoBrain {
|
|||||||
case Nucleus.Type.Cluster:
|
case Nucleus.Type.Cluster:
|
||||||
AddClusterInput(nucleus);
|
AddClusterInput(nucleus);
|
||||||
break;
|
break;
|
||||||
// case Nucleus.Type.Receptor:
|
|
||||||
// AddReceptorInput(nucleus);
|
|
||||||
// break;
|
|
||||||
// case Nucleus.Type.ClusterReceptor:
|
|
||||||
// AddClusterReceptorInput(nucleus);
|
|
||||||
// break;
|
|
||||||
// case Nucleus.Type.ClusterArray:
|
|
||||||
// AddClusterArrayInput(nucleus);
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -535,17 +533,15 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.prefab.nuclei.Remove(nucleus);
|
this.currentCluster.DeleteNucleus(nucleus);//clusterNuclei.Remove(nucleus);
|
||||||
|
|
||||||
// if (outputsPopup.value == nucleus.name) {
|
// this.prefab.nuclei.Remove(nucleus);
|
||||||
// this.prefab.RefreshOutputs();
|
// Neuron.Delete(nucleus);
|
||||||
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
this.prefab.RefreshOutputs();
|
||||||
// outputsPopup.index = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Neuron.Delete(nucleus);
|
|
||||||
|
|
||||||
this.currentNucleus = this.prefab.output;
|
this.currentNucleus = this.prefab.output;
|
||||||
|
this.selectedOutput = this.currentNucleus;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nucleus.Type selectedType = Nucleus.Type.None;
|
Nucleus.Type selectedType = Nucleus.Type.None;
|
||||||
@ -570,7 +566,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
||||||
Neuron synapseNeuron = synapse.neuron as Neuron;
|
Neuron synapseNeuron = synapse.neuron;
|
||||||
if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
|
if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
|
||||||
// if (synapse.neuron.parent is ClusterReceptor receptor) {
|
// if (synapse.neuron.parent is ClusterReceptor receptor) {
|
||||||
// // the new nucleus is part of a (cluster) receptor,
|
// // the new nucleus is part of a (cluster) receptor,
|
||||||
@ -600,8 +596,8 @@ namespace NanoBrain {
|
|||||||
// }
|
// }
|
||||||
// else {
|
// else {
|
||||||
// it is a neuron in a subcluster
|
// it is a neuron in a subcluster
|
||||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
synapseNeuron.RemoveReceiver(this.currentPrefabNucleus);
|
||||||
newNucleus.AddReceiver(this.currentNucleus);
|
newNucleus.AddReceiver(this.currentPrefabNucleus);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@ -15,8 +15,15 @@ namespace NanoBrain {
|
|||||||
//protected readonly ClusterPrefab prefab;
|
//protected readonly ClusterPrefab prefab;
|
||||||
protected Cluster currentCluster;
|
protected Cluster currentCluster;
|
||||||
protected SerializedObject serializedBrain;
|
protected SerializedObject serializedBrain;
|
||||||
protected Nucleus currentNucleus;
|
protected Nucleus _currentNucleus;
|
||||||
|
protected virtual Nucleus currentNucleus {
|
||||||
|
get => _currentNucleus;
|
||||||
|
set => _currentNucleus = value;
|
||||||
|
}
|
||||||
|
//protected Nucleus currentNucleus;
|
||||||
protected Nucleus selectedOutput;
|
protected Nucleus selectedOutput;
|
||||||
|
// Only used when selecting a synapse to a multi-cluster
|
||||||
|
protected Nucleus selectedSynapseNeuron;
|
||||||
|
|
||||||
protected GameObject gameObject;
|
protected GameObject gameObject;
|
||||||
private bool expandArray = false;
|
private bool expandArray = false;
|
||||||
@ -324,7 +331,7 @@ namespace NanoBrain {
|
|||||||
if (nucleus is Neuron neuron)
|
if (nucleus is Neuron neuron)
|
||||||
receivers = neuron.receivers;
|
receivers = neuron.receivers;
|
||||||
else if (nucleus is Cluster cluster)
|
else if (nucleus is Cluster cluster)
|
||||||
receivers = cluster.CollectReceivers();
|
receivers = cluster.CollectReceivers(true);
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -354,7 +361,6 @@ namespace NanoBrain {
|
|||||||
float margin = 10 + spacing / 2;
|
float margin = 10 + spacing / 2;
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
List<Nucleus[]> drawnArrays = new();
|
|
||||||
foreach (Nucleus receiver in receivers) {
|
foreach (Nucleus receiver in receivers) {
|
||||||
Nucleus receiverNucleus = receiver;
|
Nucleus receiverNucleus = receiver;
|
||||||
if (receiverNucleus == null)
|
if (receiverNucleus == null)
|
||||||
@ -380,6 +386,10 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
protected void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||||
|
if (this.selectedSynapseNeuron != null) {
|
||||||
|
DrawClusterSynapses(this.selectedSynapseNeuron, parentPos, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (nucleus == null)
|
if (nucleus == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -387,15 +397,19 @@ namespace NanoBrain {
|
|||||||
// 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;
|
||||||
int neuronCount = 0;
|
int neuronCount = 0;
|
||||||
List<Neuron> drawnNeurons = new();
|
List<string> drawnNeuronNames = new();
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
if (synapse.neuron == null)
|
if (synapse.neuron == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Count multiple synapses to the same neuron only once
|
// Count multiple synapses to the same neuron only once
|
||||||
if (drawnNeurons.Contains(synapse.neuron))
|
string neuronName = synapse.neuron.name;
|
||||||
|
if (synapse.neuron.parent != null)
|
||||||
|
neuronName = synapse.neuron.parent.baseName + "." + neuronName;
|
||||||
|
|
||||||
|
if (drawnNeuronNames.Contains(neuronName))
|
||||||
continue;
|
continue;
|
||||||
drawnNeurons.Add(synapse.neuron);
|
drawnNeuronNames.Add(neuronName);
|
||||||
|
|
||||||
float value = synapse.neuron.outputMagnitude * synapse.weight;
|
float value = synapse.neuron.outputMagnitude * synapse.weight;
|
||||||
if (value > maxValue)
|
if (value > maxValue)
|
||||||
@ -409,15 +423,20 @@ namespace NanoBrain {
|
|||||||
float margin = 10 + spacing / 2;
|
float margin = 10 + spacing / 2;
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
drawnNeurons = new();
|
//List<Neuron> drawnNeurons = new();
|
||||||
|
drawnNeuronNames = new();
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
if (synapse.neuron is null)
|
if (synapse.neuron is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Draw multiple synapses to the same neuron only once
|
// Draw multiple synapses to the same neuron only once
|
||||||
if (drawnNeurons.Contains(synapse.neuron))
|
string neuronName = synapse.neuron.name;
|
||||||
|
if (synapse.neuron.parent != null)
|
||||||
|
neuronName = synapse.neuron.parent.baseName + "." + neuronName;
|
||||||
|
|
||||||
|
if (drawnNeuronNames.Contains(neuronName))
|
||||||
continue;
|
continue;
|
||||||
drawnNeurons.Add(synapse.neuron);
|
drawnNeuronNames.Add(neuronName);
|
||||||
|
|
||||||
Vector3 pos = new(250, margin + row * spacing, 0.0f);
|
Vector3 pos = new(250, margin + row * spacing, 0.0f);
|
||||||
DrawEdge(parentPos, pos);
|
DrawEdge(parentPos, pos);
|
||||||
@ -435,6 +454,50 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void DrawClusterSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||||
|
if (nucleus == null || nucleus.parent == null || nucleus.parent.siblingClusters == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Hack to disable showing labels
|
||||||
|
expandArray = true;
|
||||||
|
|
||||||
|
float maxValue = 0;
|
||||||
|
foreach (Cluster sibling in nucleus.parent.siblingClusters) {
|
||||||
|
Neuron siblingNeuron = sibling.GetNucleus(nucleus.name) as Neuron;
|
||||||
|
float value = siblingNeuron.outputMagnitude; // no need to add weight as they are all the same
|
||||||
|
if (value > maxValue)
|
||||||
|
maxValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the spacing of the nuclei in the layer
|
||||||
|
float spacing = 400f / nucleus.parent.instanceCount;
|
||||||
|
float margin = 10 + spacing / 2;
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
foreach (Cluster sibling in nucleus.parent.siblingClusters) {
|
||||||
|
Neuron siblingNeuron = sibling.GetNucleus(nucleus.name) as Neuron;
|
||||||
|
Vector3 position = new(250, margin + row * spacing, 0.0f);
|
||||||
|
DrawEdge(parentPos, position);
|
||||||
|
Color color = Color.black;
|
||||||
|
if (Application.isPlaying) {
|
||||||
|
if (maxValue == 0 || !float.IsFinite(maxValue))
|
||||||
|
maxValue = 1;
|
||||||
|
float brightness = siblingNeuron.outputMagnitude / maxValue;
|
||||||
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
|
} DrawNucleus(siblingNeuron, position, size, color);
|
||||||
|
GUIStyle style = new(EditorStyles.label) {
|
||||||
|
alignment = TextAnchor.UpperCenter,
|
||||||
|
normal = { textColor = Color.white },
|
||||||
|
fontStyle = FontStyle.Bold,
|
||||||
|
};
|
||||||
|
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||||
|
string name = $"{sibling.baseName}.{nucleus.name}";
|
||||||
|
Handles.Label(labelPos, name, style);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
expandArray = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected void DrawOutputs(Vector2 parentPos, float size) {
|
protected void DrawOutputs(Vector2 parentPos, float size) {
|
||||||
// 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
|
||||||
@ -534,7 +597,7 @@ namespace NanoBrain {
|
|||||||
else if (nucleus is Cluster cluster)
|
else if (nucleus is Cluster cluster)
|
||||||
DrawCluster(cluster, position, color, size);
|
DrawCluster(cluster, position, color, size);
|
||||||
|
|
||||||
if (expandArray == false || nucleus != currentNucleus) {
|
if (expandArray == false) {// || nucleus != currentNucleus) {
|
||||||
// put name below nucleus
|
// put name below nucleus
|
||||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||||
style.alignment = TextAnchor.UpperCenter;
|
style.alignment = TextAnchor.UpperCenter;
|
||||||
@ -728,24 +791,33 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
protected void OnNeuronClick(Nucleus nucleus) {
|
protected void OnNeuronClick(Nucleus nucleus) {
|
||||||
if (nucleus == this.currentNucleus) {
|
if (nucleus == this.currentNucleus) {
|
||||||
if (Application.isPlaying) {
|
this.selectedSynapseNeuron = null;
|
||||||
if (nucleus is Cluster)
|
// if (Application.isPlaying) {
|
||||||
expandArray = !expandArray;
|
// if (nucleus is Cluster)
|
||||||
else
|
// expandArray = !expandArray;
|
||||||
expandArray = false;
|
// else
|
||||||
}
|
// expandArray = false;
|
||||||
else {
|
// }
|
||||||
if (nucleus is Cluster cluster)
|
// else {
|
||||||
OnClusterClick(cluster);
|
if (nucleus is Cluster cluster)
|
||||||
}
|
OnClusterClick(cluster);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else if (nucleus.parent != null && this.currentNucleus != null && nucleus.parent != this.currentNucleus.parent) {
|
else if (nucleus.parent != null && this.currentNucleus != null && nucleus.parent != this.currentNucleus.parent) {
|
||||||
// We go to a different cluster
|
// We go to a different cluster
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
this.currentNucleus = nucleus;
|
if (this.selectedSynapseNeuron == null && nucleus.parent.instanceCount > 1) {
|
||||||
if (this.currentNucleus is Neuron neuron && neuron.receivers.Count == 0)
|
this.selectedSynapseNeuron = nucleus;
|
||||||
this.selectedOutput = this.currentNucleus;
|
expandArray = false;
|
||||||
expandArray = false;
|
}
|
||||||
|
else {
|
||||||
|
this.currentNucleus = nucleus;
|
||||||
|
if (this.currentNucleus is Neuron neuron && neuron.receivers.Count == 0)
|
||||||
|
this.selectedOutput = this.currentNucleus;
|
||||||
|
this.selectedSynapseNeuron = null;
|
||||||
|
expandArray = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// select the cluster, not the neuron in the cluster
|
// select the cluster, not the neuron in the cluster
|
||||||
|
|||||||
@ -32,9 +32,11 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This should not be serialized
|
// This should not be serialized
|
||||||
[SerializeReference]
|
//[SerializeReference]
|
||||||
|
[NonSerialized]
|
||||||
public Cluster[] siblingClusters;
|
public Cluster[] siblingClusters;
|
||||||
// This serialization should be enough
|
// This serialization should be enough
|
||||||
|
[SerializeField]
|
||||||
public int instanceCount = 1;
|
public int instanceCount = 1;
|
||||||
public Dictionary<int, Cluster> thingClusters = new();
|
public Dictionary<int, Cluster> thingClusters = new();
|
||||||
|
|
||||||
@ -93,6 +95,8 @@ namespace NanoBrain {
|
|||||||
nucleus.ShallowCloneTo(this);
|
nucleus.ShallowCloneTo(this);
|
||||||
}
|
}
|
||||||
Nucleus[] clonedNuclei = this.clusterNuclei.ToArray();
|
Nucleus[] clonedNuclei = this.clusterNuclei.ToArray();
|
||||||
|
// foreach (Nucleus n in clonedNuclei)
|
||||||
|
// n.name += "(c)";
|
||||||
|
|
||||||
// Now clone the connections
|
// Now clone the connections
|
||||||
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
|
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
|
||||||
@ -106,19 +110,15 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
||||||
Neuron synapseNeuron = prefabSynapse.neuron;
|
Neuron synapseNeuron = prefabSynapse.neuron;
|
||||||
if (synapseNeuron.parent is not null && synapseNeuron.clusterPrefab != this.clusterPrefab) {
|
if (synapseNeuron.clusterPrefab != null && synapseNeuron.clusterPrefab != this.prefab) {
|
||||||
// Neuron is in another cluster, find the cloned cluster first
|
// Neuron is in another cluster, find the cloned cluster first
|
||||||
Cluster prefabCluster = synapseNeuron.parent;
|
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
||||||
int clusterIx = GetNucleusIndex(prefabNuclei, prefabCluster);
|
Cluster clonedCluster = this.clusterNuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
||||||
if (clusterIx < 0)
|
if (clonedCluster == null)
|
||||||
// Could not find the cluster in the prefab
|
|
||||||
continue;
|
|
||||||
if (clonedNuclei[clusterIx] is not Cluster clonedCluster)
|
|
||||||
// Could not find the cloned cluster
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Now find the neuron in that cloned cluster
|
// Now find the neuron in that cloned cluster
|
||||||
int neuronIx = GetNucleusIndex(prefabCluster.prefab.nuclei, prefabSynapse.neuron);
|
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;
|
||||||
@ -127,6 +127,7 @@ namespace NanoBrain {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
||||||
|
//Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int ix = GetNucleusIndex(prefabNuclei, prefabSynapse.neuron);
|
int ix = GetNucleusIndex(prefabNuclei, prefabSynapse.neuron);
|
||||||
@ -137,6 +138,7 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
// Copy the receivers which will also create the synapse
|
// Copy the receivers which will also create the synapse
|
||||||
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
||||||
|
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,99 +164,157 @@ namespace NanoBrain {
|
|||||||
// clonedNeuron.AddReceiver(clonedReceiver, weight);
|
// clonedNeuron.AddReceiver(clonedReceiver, weight);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// Copy the siblings for clusters
|
|
||||||
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
|
|
||||||
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
|
|
||||||
if (prefabNucleus is not Cluster prefabCluster)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (prefabCluster.siblingClusters == null || prefabCluster.siblingClusters.Length == 0)
|
if (Application.isPlaying) {
|
||||||
continue;
|
// Only create cluster siblings at runtime
|
||||||
|
foreach (Nucleus clonedNucleus in clonedNuclei) {
|
||||||
|
if (clonedNucleus is not Cluster clonedCluster)
|
||||||
|
continue;
|
||||||
|
|
||||||
Cluster clonedNucleus = clonedNuclei[nucleusIx] as Cluster;
|
List<Cluster> siblings = new() {
|
||||||
if (prefabCluster == prefabCluster.siblingClusters[0]) {
|
clonedCluster
|
||||||
// We clone the array only for the first entry
|
};
|
||||||
//NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length);
|
for (int instanceIx = 1; instanceIx < clonedCluster.instanceCount; instanceIx++) {
|
||||||
Cluster[] clonedArray = new Cluster[prefabCluster.siblingClusters.Length];
|
// Create another sibling
|
||||||
int arrayIx = 0;
|
Debug.Log($"create {clonedCluster.prefab.name} sibling");
|
||||||
foreach (Cluster prefabArrayNucleus in prefabCluster.siblingClusters) {
|
Cluster sibling = new(clonedCluster.prefab, this) {
|
||||||
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
name = $"{clonedCluster.baseName}: {instanceIx}",
|
||||||
if (arrayNucleusIx >= 0) {
|
clusterPrefab = this.clusterPrefab,
|
||||||
Cluster clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Cluster;
|
instanceCount = this.instanceCount,
|
||||||
clonedArray[arrayIx] = clonedArrayNucleus;
|
};
|
||||||
}
|
siblings.Add(sibling);
|
||||||
else {
|
CopyAllExternalReceivers(clonedCluster, sibling, clonedCluster.prefab, this);
|
||||||
Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones");
|
}
|
||||||
}
|
Cluster[] siblingClusters = siblings.ToArray();
|
||||||
arrayIx++;
|
foreach (Cluster sibling in siblings)
|
||||||
}
|
sibling.siblingClusters = siblingClusters;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Collect the subclusters
|
|
||||||
List<Cluster> subClusters = new();
|
|
||||||
foreach (Nucleus nucleus in prefabNuclei) {
|
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
|
||||||
Nucleus synapseNucleus = synapse.neuron;
|
|
||||||
Cluster subCluster = synapseNucleus.parent;
|
|
||||||
if (subCluster is null ||
|
|
||||||
synapseNucleus.clusterPrefab == this.clusterPrefab) {
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// if (synapseNucleus is not Cluster subCluster)
|
|
||||||
// continue;
|
|
||||||
if (subClusters.Contains(subCluster))
|
|
||||||
continue;
|
|
||||||
subClusters.Add(subCluster);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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)
|
|
||||||
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 == 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);
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Collect the subclusters
|
||||||
|
List<Cluster> subClusters = new();
|
||||||
|
foreach (Nucleus nucleus in prefabNuclei) {
|
||||||
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
|
Nucleus synapseNucleus = synapse.neuron;
|
||||||
|
Cluster subCluster = synapseNucleus.parent;
|
||||||
|
if (subCluster is null ||
|
||||||
|
synapseNucleus.clusterPrefab == this.clusterPrefab) {
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// if (synapseNucleus is not Cluster subCluster)
|
||||||
|
// continue;
|
||||||
|
if (subClusters.Contains(subCluster))
|
||||||
|
continue;
|
||||||
|
subClusters.Add(subCluster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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)
|
||||||
|
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 == 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.clusterPrefab != null && synapseNeuron.clusterPrefab != this.prefab) {
|
||||||
|
// Neuron is in another cluster, find the cloned cluster first
|
||||||
|
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
||||||
|
Cluster clonedCluster = this.clusterNuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
||||||
|
if (clonedCluster == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Now find the neuron in that cloned cluster
|
||||||
|
int neuronIx = GetNucleusIndex(prefabCluster.nuclei, prefabSynapse.neuron.name);
|
||||||
|
if (neuronIx < 0)
|
||||||
|
// Could not find the neuron in the prefab cluster
|
||||||
|
continue;
|
||||||
|
if (clonedCluster.clusterNuclei[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.clusterNuclei.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>
|
||||||
@ -347,33 +407,29 @@ namespace NanoBrain {
|
|||||||
Cluster clone = new(this.prefab, parent) {
|
Cluster clone = new(this.prefab, parent) {
|
||||||
name = this.name,
|
name = this.name,
|
||||||
clusterPrefab = this.clusterPrefab,
|
clusterPrefab = this.clusterPrefab,
|
||||||
|
instanceCount = this.instanceCount,
|
||||||
};
|
};
|
||||||
// Somehow siblingClusters should be cloned too. Believe I do this in ClonePrefab right now.
|
// Somehow siblingClusters should be cloned too. Believe I do this in ClonePrefab right now.
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RestoreAllExternalReceivers(Cluster clonedCluster, ClusterPrefab prefabParent, Cluster clonedParent) {
|
private static void CopyAllExternalReceivers(Cluster sourceCluster, Cluster sibling, ClusterPrefab prefabParent, Cluster clonedParent) {
|
||||||
int clonedClusterIx = GetNucleusIndex(clonedParent.clusterNuclei, clonedCluster);
|
|
||||||
if (prefabParent.nuclei[clonedClusterIx] is not Cluster sourceCluster)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) {
|
for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) {
|
||||||
Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx];
|
Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx];
|
||||||
if (sourceNucleus is not Neuron sourceNeuron)
|
if (sourceNucleus is not Neuron sourceNeuron)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (clonedCluster.clusterNuclei[nucleusIx] is not Neuron clonedNeuron)
|
if (sibling.clusterNuclei[nucleusIx] is not Neuron clonedNeuron)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// copy the receivers (and thus synapses) from the source to the clone
|
// copy the receivers (and thus synapses) from the source to the sibling
|
||||||
foreach (Nucleus receiver in sourceNeuron.receivers) {
|
foreach (Nucleus receiver in sourceNeuron.receivers) {
|
||||||
int ix = GetNucleusIndex(prefabParent.nuclei, receiver);
|
int ix = GetNucleusIndex(clonedParent.clusterNuclei, receiver);
|
||||||
if (ix < 0 || ix >= clonedParent.clusterNuclei.Count)
|
if (ix < 0 || ix >= clonedParent.clusterNuclei.Count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Nucleus clonedReceiver = clonedParent.clusterNuclei[ix];
|
|
||||||
|
|
||||||
// Find the synapse for the weight
|
// Find the synapse for the weight
|
||||||
float weight = 1;
|
float weight = 1;
|
||||||
foreach (Synapse synapse in receiver.synapses) {
|
foreach (Synapse synapse in receiver.synapses) {
|
||||||
@ -384,10 +440,11 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clonedNeuron.AddReceiver(clonedReceiver, weight);
|
clonedNeuron.AddReceiver(receiver, weight);
|
||||||
// Debug.Log($"external: {clonedReceiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}");
|
Debug.Log($"external: {receiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) {
|
protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) {
|
||||||
@ -402,13 +459,25 @@ namespace NanoBrain {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (Nucleus nucleiElement in nuclei) {
|
foreach (Nucleus nucleiElement in nuclei) {
|
||||||
//for (int i = 0; i < nuclei.Length; i++) {
|
//for (int i = 0; i < nuclei.Length; i++) {
|
||||||
if (nucleus == nucleiElement)
|
if (nucleiElement == nucleus)
|
||||||
return i;
|
return i;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetNucleusIndex(List<Nucleus> nuclei, string nucleusName) {
|
||||||
|
int i = 0;
|
||||||
|
foreach (Nucleus nucleiElement in nuclei) {
|
||||||
|
//for (int i = 0; i < nuclei.Length; i++) {
|
||||||
|
if (nucleiElement.name == nucleusName)
|
||||||
|
return i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
|
|
||||||
#region Cluster Array
|
#region Cluster Array
|
||||||
@ -470,6 +539,7 @@ namespace NanoBrain {
|
|||||||
return cluster;
|
return cluster;
|
||||||
|
|
||||||
Cluster selectedCluster = SelectCluster();
|
Cluster selectedCluster = SelectCluster();
|
||||||
|
selectedCluster.name = baseName + ": " + thingName;
|
||||||
thingClusters[thingId] = selectedCluster;
|
thingClusters[thingId] = selectedCluster;
|
||||||
return selectedCluster;
|
return selectedCluster;
|
||||||
}
|
}
|
||||||
@ -528,10 +598,6 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
#endregion ClusterArray
|
#endregion ClusterArray
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//public Dictionary<string, Nucleus> nucleiDict = new();
|
|
||||||
|
|
||||||
public List<Nucleus> _inputs = null;
|
public List<Nucleus> _inputs = null;
|
||||||
public virtual List<Nucleus> inputs {
|
public virtual List<Nucleus> inputs {
|
||||||
get {
|
get {
|
||||||
@ -550,22 +616,33 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
||||||
private void ComputeOrders() {
|
private void ComputeOrders() {
|
||||||
foreach (Nucleus input in this._inputs)
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
computeOrders[input] = TopologicalSort2(input);
|
// if (nucleus is Cluster cluster) {
|
||||||
|
// List<Synapse> synapses = this.CollectSynapsesTo(cluster);
|
||||||
|
// foreach (Synapse synapse in synapses) {
|
||||||
|
// computeOrders[synapse.neuron] = TopologicalSort2(synapse.neuron);
|
||||||
|
// Debug.Log($"{this.baseName}: Order for {cluster.baseName}.{synapse.neuron.name}");
|
||||||
|
// }
|
||||||
|
// // List<Nucleus> receivers = cluster.CollectReceivers();
|
||||||
|
// // foreach (Nucleus receiver in receivers)
|
||||||
|
// // computeOrders[receiver] = TopologicalSort2(receiver);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
computeOrders[nucleus] = TopologicalSort2(nucleus);
|
||||||
|
Debug.Log($"{this.baseName} Order for {nucleus.name}");
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
||||||
Dictionary<Nucleus, int> inDegree = new();
|
Dictionary<Nucleus, int> inDegree = new();
|
||||||
HashSet<Nucleus> visited = new();
|
//HashSet<Nucleus> visited = new();
|
||||||
|
|
||||||
// Initialize in-degrees and mark all nodes as unvisited
|
|
||||||
foreach (Nucleus node in this.clusterNuclei)
|
|
||||||
inDegree[node] = 0;
|
|
||||||
|
|
||||||
// Calculate in-degrees for all nodes reachable from the start node
|
// Calculate in-degrees for all nodes reachable from the start node
|
||||||
Queue<Nucleus> queue = new Queue<Nucleus>();
|
Queue<Nucleus> queue = new();
|
||||||
queue.Enqueue(startNode);
|
queue.Enqueue(startNode);
|
||||||
visited.Add(startNode);
|
//visited.Add(startNode);
|
||||||
|
inDegree[startNode] = 0;
|
||||||
|
|
||||||
while (queue.Count > 0) {
|
while (queue.Count > 0) {
|
||||||
Nucleus current = queue.Dequeue();
|
Nucleus current = queue.Dequeue();
|
||||||
@ -575,25 +652,24 @@ namespace NanoBrain {
|
|||||||
else if (current is Cluster cluster)
|
else if (current is Cluster cluster)
|
||||||
receivers = cluster.CollectReceivers();
|
receivers = cluster.CollectReceivers();
|
||||||
|
|
||||||
// if (current is Neuron neuron) {
|
|
||||||
foreach (Nucleus receiver in receivers) {
|
foreach (Nucleus receiver in receivers) {
|
||||||
if (!visited.Contains(receiver)) {
|
if (!inDegree.ContainsKey(receiver)) {
|
||||||
visited.Add(receiver);
|
//visited.Add(receiver);
|
||||||
|
inDegree[receiver] = 0;
|
||||||
queue.Enqueue(receiver);
|
queue.Enqueue(receiver);
|
||||||
}
|
}
|
||||||
inDegree[receiver]++;
|
inDegree[receiver]++;
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform topological sort on all reachable nodes
|
// Perform topological sort on all reachable nodes
|
||||||
queue.Clear();
|
queue.Clear();
|
||||||
foreach (Nucleus node in visited) {
|
foreach (Nucleus node in inDegree.Keys) {
|
||||||
if (inDegree[node] == 0)
|
if (inDegree[node] == 0)
|
||||||
queue.Enqueue(node);
|
queue.Enqueue(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Nucleus> sortedOrder = new List<Nucleus>();
|
List<Nucleus> sortedOrder = new();
|
||||||
while (queue.Count > 0) {
|
while (queue.Count > 0) {
|
||||||
Nucleus current = queue.Dequeue();
|
Nucleus current = queue.Dequeue();
|
||||||
sortedOrder.Add(current); // Process the node
|
sortedOrder.Add(current); // Process the node
|
||||||
@ -604,21 +680,18 @@ namespace NanoBrain {
|
|||||||
else if (current is Cluster cluster)
|
else if (current is Cluster cluster)
|
||||||
receivers = cluster.CollectReceivers();
|
receivers = cluster.CollectReceivers();
|
||||||
|
|
||||||
//if (current is Neuron neuron) {
|
|
||||||
|
|
||||||
foreach (Nucleus receiver in receivers) {
|
foreach (Nucleus receiver in receivers) {
|
||||||
if (visited.Contains(receiver)) {
|
if (inDegree.ContainsKey(receiver)) {
|
||||||
inDegree[receiver]--;
|
inDegree[receiver]--;
|
||||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||||
queue.Enqueue(receiver);
|
queue.Enqueue(receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for cycles in the graph
|
// Check for cycles in the graph
|
||||||
if (sortedOrder.Count != visited.Count)
|
// if (sortedOrder.Count != visited.Count)
|
||||||
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
// throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||||
|
|
||||||
return sortedOrder;
|
return sortedOrder;
|
||||||
}
|
}
|
||||||
@ -643,6 +716,9 @@ namespace NanoBrain {
|
|||||||
return this._outputs;
|
return this._outputs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void RefreshOutputs() {
|
||||||
|
this._outputs = null;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
|
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
|
||||||
foreach (Nucleus receptor in this.clusterNuclei) {
|
foreach (Nucleus receptor in this.clusterNuclei) {
|
||||||
@ -685,18 +761,39 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DeleteNucleus(Nucleus nucleus) {
|
||||||
|
if (this.clusterNuclei.Contains(nucleus) == false) {
|
||||||
|
// Try to find the nucleus by name
|
||||||
|
if (TryGetNucleus(nucleus.name, out nucleus) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Neuron.Delete(nucleus);
|
||||||
|
int nucleusIx = this.clusterNuclei.IndexOf(nucleus);
|
||||||
|
this.clusterNuclei.Remove(nucleus);
|
||||||
|
this.prefab.nuclei.RemoveAt(nucleusIx);
|
||||||
|
RefreshOutputs();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#region Receivers
|
#region Receivers
|
||||||
|
|
||||||
public virtual List<Nucleus> CollectReceivers() {
|
public virtual List<Nucleus> CollectReceivers(bool removeDuplicates = false) {
|
||||||
List<Nucleus> receivers = new();
|
List<Nucleus> receivers = new();
|
||||||
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Debug.Log($"output {this.name} {outputNucleus.name}");
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
|
// Debug.Log($"output {receiver.name}");
|
||||||
// Only add receivers outside this cluster
|
// Only add receivers outside this cluster
|
||||||
if (receiver.clusterPrefab != this.prefab)
|
if (receiver.clusterPrefab != this.prefab) {
|
||||||
receivers.Add(receiver);
|
if (removeDuplicates == false || receivers.Contains(receiver) == false)
|
||||||
|
// Debug.Log($" YES");
|
||||||
|
receivers.Add(receiver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return receivers;
|
return receivers;
|
||||||
@ -717,6 +814,19 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
return connections;
|
return connections;
|
||||||
}
|
}
|
||||||
|
public List<Synapse> CollectSynapsesTo(Cluster otherCluster) {
|
||||||
|
List<Synapse> collectedSynapses = new();
|
||||||
|
|
||||||
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
|
if (nucleus is not Neuron neuron)
|
||||||
|
continue;
|
||||||
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
|
if (synapse.neuron.parent == otherCluster)
|
||||||
|
collectedSynapses.Add(synapse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collectedSynapses;
|
||||||
|
}
|
||||||
|
|
||||||
public void MoveReceivers(Cluster newCluster) {
|
public void MoveReceivers(Cluster newCluster) {
|
||||||
Debug.Log($"Move receivers for {this.name} to {newCluster.name}");
|
Debug.Log($"Move receivers for {this.name} to {newCluster.name}");
|
||||||
@ -752,23 +862,31 @@ namespace NanoBrain {
|
|||||||
// no bias+synapse input state calculation for now...
|
// no bias+synapse input state calculation for now...
|
||||||
|
|
||||||
if (this.computeOrders.ContainsKey(startNucleus) == false) {
|
if (this.computeOrders.ContainsKey(startNucleus) == false) {
|
||||||
//Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}");
|
Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
||||||
if (startNucleus.trace)
|
//if (startNucleus.trace)
|
||||||
Debug.Log($"Update from {startNucleus.name}");
|
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)
|
//if (startNucleus.trace && nucleus is Neuron neuron)
|
||||||
Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}]"); // = {neuron.outputValue}");
|
Debug.Log($" {nucleus.name}");
|
||||||
|
if (nucleus is Neuron neuron) {
|
||||||
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
|
if (receiver.parent != this) {
|
||||||
|
Debug.Log($" External: {receiver.parent.name}.{receiver.name}");
|
||||||
|
receiver.parent.UpdateFromNucleus(receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue in parent
|
// continue in parent
|
||||||
this.parent?.UpdateFromNucleus(this);
|
//this.parent?.UpdateFromNucleus(this);
|
||||||
|
|
||||||
UpdateNuclei();
|
UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,8 +33,10 @@ namespace NanoBrain {
|
|||||||
public Neuron(ClusterPrefab prefab, string name) {
|
public Neuron(ClusterPrefab prefab, string name) {
|
||||||
this.clusterPrefab = prefab;
|
this.clusterPrefab = prefab;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
if (this.clusterPrefab != null)
|
if (this.clusterPrefab != null) {
|
||||||
this.clusterPrefab.nuclei.Add(this);
|
this.clusterPrefab.nuclei.Add(this);
|
||||||
|
this.clusterPrefab.RefreshOutputs();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Debug.LogError("No prefab when adding neuron to prefab");
|
Debug.LogError("No prefab when adding neuron to prefab");
|
||||||
}
|
}
|
||||||
@ -264,15 +266,19 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void Delete(Nucleus nucleus) {
|
public static void Delete(Nucleus nucleus) {
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
if (nucleus == null)
|
||||||
if (synapse.neuron is Neuron synapse_nucleus) {
|
return;
|
||||||
if (synapse_nucleus.receivers.Count > 1) {
|
if (nucleus.synapses != null) {
|
||||||
// there is another nucleus feeding into this input nucleus
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
synapse_nucleus.receivers.RemoveAll(r => r == nucleus);
|
if (synapse.neuron is Neuron synapse_nucleus) {
|
||||||
}
|
if (synapse_nucleus.receivers.Count > 1) {
|
||||||
else {
|
// there is another nucleus feeding into this input nucleus
|
||||||
// No other links, delete it.
|
synapse_nucleus.receivers.RemoveAll(r => r == nucleus);
|
||||||
Neuron.Delete(synapse_nucleus);
|
}
|
||||||
|
else {
|
||||||
|
// No other links, delete it.
|
||||||
|
Neuron.Delete(synapse_nucleus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,6 +526,8 @@ namespace NanoBrain {
|
|||||||
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||||
this._receivers.Add(receiverToAdd);
|
this._receivers.Add(receiverToAdd);
|
||||||
receiverToAdd.AddSynapse(this, weight);
|
receiverToAdd.AddSynapse(this, weight);
|
||||||
|
//Debug.Log($"Add synapse {this.clusterPrefab.name}.{this.name} -> {receiverToAdd.name} --- [{this.receivers.Count}]");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
|
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
|
||||||
|
|||||||
@ -29,11 +29,7 @@ namespace NanoBrain {
|
|||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool isSleeping {
|
public bool isSleeping => this.neuron.isSleeping;
|
||||||
get {
|
|
||||||
return this.neuron.isSleeping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user