Cleanup and fix connect neuron
This commit is contained in:
parent
ec2a6b7ae9
commit
79376c30ea
@ -64,22 +64,23 @@ namespace NanoBrain {
|
|||||||
public class GraphEditor : GraphView {
|
public class GraphEditor : GraphView {
|
||||||
|
|
||||||
protected ClusterPrefab prefab;
|
protected ClusterPrefab prefab;
|
||||||
protected Nucleus currentPrefabNucleus;
|
//protected Nucleus currentPrefabNucleus;
|
||||||
|
|
||||||
protected override Nucleus currentNucleus {
|
protected override Nucleus currentNucleus {
|
||||||
get => base.currentNucleus;
|
get => base.currentNucleus;
|
||||||
set {
|
set {
|
||||||
base.currentNucleus = value;
|
base.currentNucleus = value;
|
||||||
this.currentPrefabNucleus = value != null ? this.prefab.GetNucleus(value.name) : null;
|
// this.currentPrefabNucleus = value != null ? this.prefab.GetNucleus(value.name) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphEditor(ClusterPrefab prefab) : base(prefab.output.parent) {
|
public GraphEditor(ClusterPrefab prefab) : base(prefab.cluster.defaultOutput.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
|
||||||
this.currentCluster = new(prefab);
|
//this.currentCluster = new(prefab);
|
||||||
|
this.currentCluster = prefab.cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
||||||
@ -120,7 +121,7 @@ namespace NanoBrain {
|
|||||||
// create a SerializedObject wrapper so Unity inspector controls work (and Undo)
|
// create a SerializedObject wrapper so Unity inspector controls work (and Undo)
|
||||||
SerializedObject so = new(prefabAsset);
|
SerializedObject so = new(prefabAsset);
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.prefab.nuclei) {
|
foreach (Nucleus nucleus in this.prefab.cluster.nuclei) {
|
||||||
nucleus.Initialize();
|
nucleus.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +164,8 @@ namespace NanoBrain {
|
|||||||
GUILayout.Label(nucleusType, headerStyle);
|
GUILayout.Label(nucleusType, headerStyle);
|
||||||
|
|
||||||
// Nucleus name
|
// Nucleus name
|
||||||
Cluster cluster = this.currentPrefabNucleus as Cluster;
|
//Cluster cluster = this.currentPrefabNucleus as Cluster;
|
||||||
|
Cluster cluster = this.currentNucleus as Cluster;
|
||||||
if (cluster != null) {
|
if (cluster != null) {
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
if (GUILayout.Button(this.currentNucleus.parent.name))
|
if (GUILayout.Button(this.currentNucleus.parent.name))
|
||||||
@ -182,7 +184,7 @@ namespace NanoBrain {
|
|||||||
prefabNucleus.name = newName;
|
prefabNucleus.name = newName;
|
||||||
// This changes it in the temporary cluster instance
|
// This changes it in the temporary cluster instance
|
||||||
this.currentNucleus.name = newName;
|
this.currentNucleus.name = newName;
|
||||||
this.prefab.RefreshOutputs();
|
this.prefab.cluster.RefreshOutputs();
|
||||||
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
@ -281,9 +283,9 @@ 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);
|
||||||
|
currentNeuron.trace = trace;
|
||||||
}
|
}
|
||||||
trace = EditorGUILayout.Toggle("Trace", trace);
|
|
||||||
this.currentNucleus.trace = trace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SynapsesInspector(ref bool anythingChanged) {
|
protected void SynapsesInspector(ref bool anythingChanged) {
|
||||||
@ -293,31 +295,32 @@ namespace NanoBrain {
|
|||||||
Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator);
|
Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator);
|
||||||
anythingChanged |= newCombinator != neuron2.combinator;
|
anythingChanged |= newCombinator != neuron2.combinator;
|
||||||
neuron2.combinator = newCombinator;
|
neuron2.combinator = newCombinator;
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUIUtility.wideMode = true;
|
EditorGUIUtility.wideMode = true;
|
||||||
float previousLabelWidth = EditorGUIUtility.labelWidth;
|
float previousLabelWidth = EditorGUIUtility.labelWidth;
|
||||||
EditorGUIUtility.labelWidth = 100;
|
EditorGUIUtility.labelWidth = 100;
|
||||||
|
|
||||||
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias);
|
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", neuron2.bias);
|
||||||
if (newBias != this.currentPrefabNucleus.bias) {
|
if (newBias != neuron2.bias) {
|
||||||
anythingChanged |= newBias != this.currentNucleus.bias;
|
anythingChanged |= newBias != neuron2.bias;
|
||||||
this.currentPrefabNucleus.bias = newBias;
|
neuron2.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.currentPrefabNucleus.synapses.Count > 0) {
|
//if (this.currentPrefabNucleus is Neuron prefabNeuron && prefabNeuron.synapses.Count > 0) {
|
||||||
Synapse[] synapses = this.currentPrefabNucleus.synapses.ToArray();
|
// Synapse[] synapses = prefabNeuron.synapses.ToArray();
|
||||||
|
if (this.currentNucleus is Neuron currentNeuron && currentNeuron.synapses.Count > 0) {
|
||||||
|
Synapse[] synapses = currentNeuron.synapses.ToArray();
|
||||||
foreach (Synapse synapse in synapses) {
|
foreach (Synapse synapse in synapses) {
|
||||||
if (synapse.neuron == null)
|
if (synapse.neuron == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
if (synapse.neuron.parent is Cluster iCluster && elementIx > 0) {
|
if (synapse.neuron.parent is Cluster iCluster && elementIx > 0) {
|
||||||
int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
int thisElementIx = Cluster.GetNucleusIndex(iCluster.nuclei, synapse.neuron);
|
||||||
if (thisElementIx == elementIx)
|
if (thisElementIx == elementIx)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
@ -332,7 +335,7 @@ namespace NanoBrain {
|
|||||||
if (synapse.neuron.parent is Cluster iReceptor) {
|
if (synapse.neuron.parent is Cluster iReceptor) {
|
||||||
array = iReceptor.siblingClusters;
|
array = iReceptor.siblingClusters;
|
||||||
if (iReceptor is Cluster iCluster)
|
if (iReceptor is Cluster iCluster)
|
||||||
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
elementIx = Cluster.GetNucleusIndex(iCluster.nuclei, synapse.neuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,13 +359,13 @@ namespace NanoBrain {
|
|||||||
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.clusterPrefab.nuclei.Select(n => n.name).ToArray();
|
string[] options = synapse.neuron.clusterPrefab.cluster.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) {
|
||||||
// Nucleus selectedNucleus = synapse.neuron.parent.clusterNuclei[newIndex];
|
// Nucleus selectedNucleus = synapse.neuron.parent.clusterNuclei[newIndex];
|
||||||
// Neuron newNeuron = selectedNucleus as Neuron;
|
// Neuron newNeuron = selectedNucleus as Neuron;
|
||||||
Neuron newNeuron = synapse.neuron.clusterPrefab.nuclei[newIndex] as Neuron;
|
Neuron newNeuron = synapse.neuron.clusterPrefab.cluster.nuclei[newIndex] as Neuron;
|
||||||
ChangeSynapse(synapse, newNeuron);
|
ChangeSynapse(synapse, newNeuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -370,13 +373,12 @@ namespace NanoBrain {
|
|||||||
GUILayout.Label(synapse.neuron.name);
|
GUILayout.Label(synapse.neuron.name);
|
||||||
|
|
||||||
bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80));
|
bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80));
|
||||||
if (disconnecting && synapse.neuron is Neuron synapseNeuron) {
|
if (disconnecting) {
|
||||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
synapse.neuron.RemoveReceiver(this.currentNucleus);
|
||||||
this.prefab.GarbageCollection();
|
this.prefab.GarbageCollection();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
@ -493,11 +495,12 @@ namespace NanoBrain {
|
|||||||
if (cluster == null)
|
if (cluster == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
IEnumerable<Nucleus> synapseNuclei = this.currentNucleus.synapses
|
Neuron currentNeuron = this.currentNucleus as Neuron;
|
||||||
|
IEnumerable<Nucleus> synapseNuclei = currentNeuron.synapses
|
||||||
.Where(synapse => synapse.neuron != null)
|
.Where(synapse => synapse.neuron != null)
|
||||||
.Select(synapse => synapse.neuron);
|
.Select(synapse => synapse.neuron);
|
||||||
|
|
||||||
IEnumerable<Nucleus> nuclei = cluster.nuclei
|
IEnumerable<Nucleus> nuclei = cluster.cluster.nuclei
|
||||||
.Except(synapseNuclei);
|
.Except(synapseNuclei);
|
||||||
IEnumerable<string> nucleiNames = nuclei
|
IEnumerable<string> nucleiNames = nuclei
|
||||||
.Select(n => {
|
.Select(n => {
|
||||||
@ -513,14 +516,36 @@ namespace NanoBrain {
|
|||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
if (connecting) {
|
if (connecting) {
|
||||||
Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus);
|
Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus);
|
||||||
if (nucleus is Cluster subCluster)
|
// Nucleus prefabNucleus = this.prefab.cluster.nuclei.ElementAt(selectedConnectNucleus);
|
||||||
|
if (nucleus is Cluster subCluster) {
|
||||||
subCluster.AddArrayReceiver(this.currentNucleus);
|
subCluster.AddArrayReceiver(this.currentNucleus);
|
||||||
else if (nucleus is Neuron neuron)
|
// Cluster prefabSubCluster = prefabNucleus as Cluster;
|
||||||
|
}
|
||||||
|
else if (nucleus is Neuron neuron) {
|
||||||
neuron.AddReceiver(this.currentNucleus);
|
neuron.AddReceiver(this.currentNucleus);
|
||||||
|
// if (prefabNucleus is Neuron prefabNeuron)
|
||||||
|
// prefabNeuron.AddReceiver(this.currentPrefabNucleus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return connecting;
|
return connecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void DisconnectNucleus(Neuron nucleus) {
|
||||||
|
if (this.currentNucleus.clusterPrefab == null)
|
||||||
|
return;
|
||||||
|
Neuron currentNeuron = this.currentNucleus as Neuron;
|
||||||
|
string[] names = currentNeuron.synapses.Select(synapse => synapse.neuron.name).ToArray();
|
||||||
|
int selectedIndex = -1;
|
||||||
|
selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names);
|
||||||
|
if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.cluster.nuclei.Count) {
|
||||||
|
Synapse synapse = currentNeuron.synapses[selectedIndex];
|
||||||
|
synapse.neuron.RemoveReceiver(this.currentNucleus);
|
||||||
|
|
||||||
|
// synapse = currentNeuron.synapses[selectedIndex];
|
||||||
|
// synapse.neuron.RemoveReceiver(this.currentPrefabNucleus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void DeleteNucleus(Nucleus nucleus) {
|
protected virtual void DeleteNucleus(Nucleus nucleus) {
|
||||||
if (nucleus == null)
|
if (nucleus == null)
|
||||||
return;
|
return;
|
||||||
@ -537,10 +562,10 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
// this.prefab.nuclei.Remove(nucleus);
|
// this.prefab.nuclei.Remove(nucleus);
|
||||||
// Neuron.Delete(nucleus);
|
// Neuron.Delete(nucleus);
|
||||||
this.prefab.RefreshOutputs();
|
this.prefab.cluster.RefreshOutputs();
|
||||||
|
|
||||||
|
|
||||||
this.currentNucleus = this.prefab.output;
|
this.currentNucleus = this.prefab.cluster.defaultOutput;
|
||||||
this.selectedOutput = this.currentNucleus;
|
this.selectedOutput = this.currentNucleus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,8 +621,8 @@ namespace NanoBrain {
|
|||||||
// }
|
// }
|
||||||
// else {
|
// else {
|
||||||
// it is a neuron in a subcluster
|
// it is a neuron in a subcluster
|
||||||
synapseNeuron.RemoveReceiver(this.currentPrefabNucleus);
|
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||||
newNucleus.AddReceiver(this.currentPrefabNucleus);
|
newNucleus.AddReceiver(this.currentNucleus);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -606,19 +631,6 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void DisconnectNucleus(Neuron nucleus) {
|
|
||||||
if (this.currentNucleus.clusterPrefab == null)
|
|
||||||
return;
|
|
||||||
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.neuron.name).ToArray();
|
|
||||||
int selectedIndex = -1;
|
|
||||||
selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names);
|
|
||||||
if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) {
|
|
||||||
Synapse synapse = this.currentNucleus.synapses[selectedIndex];
|
|
||||||
Neuron synapseNeuron = synapse.neuron as Neuron;
|
|
||||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Synapses
|
#endregion Synapses
|
||||||
|
|
||||||
#endregion Inspector
|
#endregion Inspector
|
||||||
|
|||||||
@ -213,7 +213,8 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void DescendGraph(Dag.Node receiver, ref int ix, Dag dag) {
|
private void DescendGraph(Dag.Node receiver, ref int ix, Dag dag) {
|
||||||
foreach (Synapse synapse in receiver.nucleus.synapses) {
|
Neuron receiverNeuron = receiver.nucleus as Neuron;
|
||||||
|
foreach (Synapse synapse in receiverNeuron.synapses) {
|
||||||
Nucleus nucleus = synapse.neuron;
|
Nucleus nucleus = synapse.neuron;
|
||||||
if (nucleus.parent != null && nucleus.parent != currentNucleus.parent) {
|
if (nucleus.parent != null && nucleus.parent != currentNucleus.parent) {
|
||||||
nucleus = nucleus.parent;
|
nucleus = nucleus.parent;
|
||||||
@ -386,6 +387,9 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
protected void DrawSynapses(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||||
|
if (nucleus is not Neuron neuron)
|
||||||
|
return;
|
||||||
|
|
||||||
if (this.selectedSynapseNeuron != null) {
|
if (this.selectedSynapseNeuron != null) {
|
||||||
DrawClusterSynapses(this.selectedSynapseNeuron, parentPos, size);
|
DrawClusterSynapses(this.selectedSynapseNeuron, parentPos, size);
|
||||||
return;
|
return;
|
||||||
@ -398,7 +402,7 @@ namespace NanoBrain {
|
|||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
int neuronCount = 0;
|
int neuronCount = 0;
|
||||||
List<string> drawnNeuronNames = new();
|
List<string> drawnNeuronNames = new();
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in neuron.synapses) {
|
||||||
if (synapse.neuron == null)
|
if (synapse.neuron == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -425,7 +429,7 @@ namespace NanoBrain {
|
|||||||
int row = 0;
|
int row = 0;
|
||||||
//List<Neuron> drawnNeurons = new();
|
//List<Neuron> drawnNeurons = new();
|
||||||
drawnNeuronNames = new();
|
drawnNeuronNames = new();
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in neuron.synapses) {
|
||||||
if (synapse.neuron is null)
|
if (synapse.neuron is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@ namespace NanoBrain {
|
|||||||
/// <param name="name">The name of the Neuron for which the weights are updated</param>
|
/// <param name="name">The name of the Neuron for which the weights are updated</param>
|
||||||
/// <param name="weight">The new Synapse weight</param>
|
/// <param name="weight">The new Synapse weight</param>
|
||||||
public static void UpdateWeight(Cluster brain, string name, float weight) {
|
public static void UpdateWeight(Cluster brain, string name, float weight) {
|
||||||
Nucleus root = brain.defaultOutput;
|
Neuron root = brain.defaultOutput;
|
||||||
foreach (Synapse synapse in root.synapses) {
|
foreach (Synapse synapse in root.synapses) {
|
||||||
if (synapse.neuron.name == name) {
|
if (synapse.neuron.name == name) {
|
||||||
if (synapse.weight != weight) {
|
if (synapse.weight != weight) {
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace NanoBrain {
|
|||||||
public Dictionary<int, Cluster> thingClusters = new();
|
public Dictionary<int, Cluster> thingClusters = new();
|
||||||
|
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
public List<Nucleus> clusterNuclei = new();
|
public List<Nucleus> nuclei = new();
|
||||||
// the nuclei sorted using topological sorting
|
// the nuclei sorted using topological sorting
|
||||||
// to ensure that the cluster is computer in the right order
|
// to ensure that the cluster is computer in the right order
|
||||||
public List<Nucleus> sortedNuclei;
|
public List<Nucleus> sortedNuclei;
|
||||||
@ -58,10 +58,10 @@ namespace NanoBrain {
|
|||||||
this.name = prefab.name;
|
this.name = prefab.name;
|
||||||
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.parent?.clusterNuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
_ = this.inputs;
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -75,11 +75,11 @@ namespace NanoBrain {
|
|||||||
this.clusterPrefab = parent;
|
this.clusterPrefab = parent;
|
||||||
|
|
||||||
if (this.clusterPrefab != null)
|
if (this.clusterPrefab != null)
|
||||||
this.clusterPrefab.nuclei.Add(this);
|
this.clusterPrefab.cluster.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
_ = this.inputs;
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -88,15 +88,13 @@ namespace NanoBrain {
|
|||||||
/// Strange that this does not take any parameters or return values.
|
/// Strange that this does not take any parameters or return values.
|
||||||
/// Where which the clone be found???
|
/// Where which the clone be found???
|
||||||
private void ClonePrefab() {
|
private void ClonePrefab() {
|
||||||
Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray();
|
Nucleus[] prefabNuclei = this.prefab.cluster.nuclei.ToArray();
|
||||||
|
|
||||||
// first clone the nuclei without their connections
|
// first clone the nuclei without their connections
|
||||||
foreach (Nucleus nucleus in prefabNuclei) {
|
foreach (Nucleus nucleus in prefabNuclei) {
|
||||||
nucleus.ShallowCloneTo(this);
|
nucleus.ShallowCloneTo(this);
|
||||||
}
|
}
|
||||||
Nucleus[] clonedNuclei = this.clusterNuclei.ToArray();
|
Nucleus[] clonedNuclei = this.nuclei.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++) {
|
||||||
@ -113,16 +111,16 @@ namespace NanoBrain {
|
|||||||
if (synapseNeuron.clusterPrefab != null && synapseNeuron.clusterPrefab != this.prefab) {
|
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
|
||||||
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
||||||
Cluster clonedCluster = this.clusterNuclei.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.nuclei, prefabSynapse.neuron.name);
|
int neuronIx = GetNucleusIndex(prefabCluster.cluster.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;
|
||||||
if (clonedCluster.clusterNuclei[neuronIx] is not Neuron clonedSender)
|
if (clonedCluster.nuclei[neuronIx] is not Neuron clonedSender)
|
||||||
// Could not find the neuron in the cloned cluster
|
// Could not find the neuron in the cloned cluster
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -291,16 +289,16 @@ namespace NanoBrain {
|
|||||||
if (synapseNeuron.clusterPrefab != null && synapseNeuron.clusterPrefab != this.prefab) {
|
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
|
||||||
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
||||||
Cluster clonedCluster = this.clusterNuclei.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.nuclei, prefabSynapse.neuron.name);
|
int neuronIx = GetNucleusIndex(prefabCluster.cluster.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;
|
||||||
if (clonedCluster.clusterNuclei[neuronIx] is not Neuron clonedSender)
|
if (clonedCluster.nuclei[neuronIx] is not Neuron clonedSender)
|
||||||
// Could not find the neuron in the cloned cluster
|
// Could not find the neuron in the cloned cluster
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -308,7 +306,7 @@ namespace NanoBrain {
|
|||||||
//Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
//Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Neuron clonedSender = this.clusterNuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron;
|
Neuron clonedSender = this.nuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron;
|
||||||
// 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}");
|
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
||||||
@ -378,20 +376,20 @@ namespace NanoBrain {
|
|||||||
public override Nucleus Clone(ClusterPrefab parent) {
|
public override Nucleus Clone(ClusterPrefab parent) {
|
||||||
Cluster clone = new(this.prefab, parent);
|
Cluster clone = new(this.prefab, parent);
|
||||||
|
|
||||||
foreach (Synapse synapse in this.synapses) {
|
// foreach (Synapse synapse in this.synapses) {
|
||||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
// Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||||
clonedSynapse.weight = synapse.weight;
|
// clonedSynapse.weight = synapse.weight;
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is Neuron output) {
|
if (nucleus is Neuron output) {
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
int ix = GetNucleusIndex(this.clusterNuclei, output);
|
int ix = GetNucleusIndex(this.nuclei, output);
|
||||||
Debug.Log($"{output.name} -> {receiver.name}: {ix}");
|
Debug.Log($"{output.name} -> {receiver.name}: {ix}");
|
||||||
if (ix < 0)
|
if (ix < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (clone.clusterNuclei[ix] is not Neuron clonedOutput)
|
if (clone.nuclei[ix] is not Neuron clonedOutput)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
clonedOutput.AddReceiver(receiver);
|
clonedOutput.AddReceiver(receiver);
|
||||||
@ -416,23 +414,26 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
private static void CopyAllExternalReceivers(Cluster sourceCluster, Cluster sibling, ClusterPrefab prefabParent, Cluster clonedParent) {
|
private static void CopyAllExternalReceivers(Cluster sourceCluster, Cluster sibling, ClusterPrefab prefabParent, Cluster clonedParent) {
|
||||||
|
|
||||||
for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) {
|
for (int nucleusIx = 0; nucleusIx < sourceCluster.nuclei.Count; nucleusIx++) {
|
||||||
Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx];
|
Nucleus sourceNucleus = sourceCluster.nuclei[nucleusIx];
|
||||||
if (sourceNucleus is not Neuron sourceNeuron)
|
if (sourceNucleus is not Neuron sourceNeuron)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sibling.clusterNuclei[nucleusIx] is not Neuron clonedNeuron)
|
if (sibling.nuclei[nucleusIx] is not Neuron clonedNeuron)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// copy the receivers (and thus synapses) from the source to the sibling
|
// 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(clonedParent.clusterNuclei, receiver);
|
if (receiver is not Neuron receiverNeuron)
|
||||||
if (ix < 0 || ix >= clonedParent.clusterNuclei.Count)
|
continue;
|
||||||
|
|
||||||
|
int ix = GetNucleusIndex(clonedParent.nuclei, receiver);
|
||||||
|
if (ix < 0 || ix >= clonedParent.nuclei.Count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 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 receiverNeuron.synapses) {
|
||||||
// Find the weight for this synapse
|
// Find the weight for this synapse
|
||||||
if (synapse.neuron == sourceNucleus) {
|
if (synapse.neuron == sourceNucleus) {
|
||||||
weight = synapse.weight;
|
weight = synapse.weight;
|
||||||
@ -603,9 +604,12 @@ namespace NanoBrain {
|
|||||||
get {
|
get {
|
||||||
if (this._inputs == null) {
|
if (this._inputs == null) {
|
||||||
this._inputs = new();
|
this._inputs = new();
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
|
if (nucleus is not Neuron neuron)
|
||||||
|
continue;
|
||||||
|
|
||||||
// inputs have no synapses
|
// inputs have no synapses
|
||||||
if (nucleus.synapses.Count == 0)
|
if (neuron.synapses.Count == 0)
|
||||||
this._inputs.Add(nucleus);
|
this._inputs.Add(nucleus);
|
||||||
}
|
}
|
||||||
ComputeOrders();
|
ComputeOrders();
|
||||||
@ -616,7 +620,7 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
||||||
private void ComputeOrders() {
|
private void ComputeOrders() {
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
// if (nucleus is Cluster cluster) {
|
// if (nucleus is Cluster cluster) {
|
||||||
// List<Synapse> synapses = this.CollectSynapsesTo(cluster);
|
// List<Synapse> synapses = this.CollectSynapsesTo(cluster);
|
||||||
// foreach (Synapse synapse in synapses) {
|
// foreach (Synapse synapse in synapses) {
|
||||||
@ -628,8 +632,8 @@ namespace NanoBrain {
|
|||||||
// // computeOrders[receiver] = TopologicalSort2(receiver);
|
// // computeOrders[receiver] = TopologicalSort2(receiver);
|
||||||
// }
|
// }
|
||||||
// else {
|
// else {
|
||||||
computeOrders[nucleus] = TopologicalSort2(nucleus);
|
computeOrders[nucleus] = TopologicalSort2(nucleus);
|
||||||
Debug.Log($"{this.baseName} Order for {nucleus.name}");
|
//Debug.Log($"{this.baseName} Order for {nucleus.name}");
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,8 +702,8 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus;
|
public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus;
|
||||||
get {
|
get {
|
||||||
if (this.clusterNuclei.Count > 0)
|
if (this.nuclei.Count > 0)
|
||||||
return this.clusterNuclei[0] as Neuron;
|
return this.nuclei[0] as Neuron;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,7 +712,7 @@ namespace NanoBrain {
|
|||||||
get {
|
get {
|
||||||
if (this._outputs == null) {
|
if (this._outputs == null) {
|
||||||
this._outputs = new();
|
this._outputs = new();
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
||||||
this._outputs.Add(neuron);
|
this._outputs.Add(neuron);
|
||||||
}
|
}
|
||||||
@ -721,7 +725,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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.nuclei) {
|
||||||
if (receptor is Nucleus nucleus)
|
if (receptor is Nucleus nucleus)
|
||||||
if (nucleus.name == nucleusName) {
|
if (nucleus.name == nucleusName) {
|
||||||
foundNucleus = nucleus;
|
foundNucleus = nucleus;
|
||||||
@ -737,7 +741,7 @@ namespace NanoBrain {
|
|||||||
if (dotPosition >= 0) {
|
if (dotPosition >= 0) {
|
||||||
string clusterName = nucleusName[..dotPosition];
|
string clusterName = nucleusName[..dotPosition];
|
||||||
string clusterName0 = clusterName + ": 0";
|
string clusterName0 = clusterName + ": 0";
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is Cluster cluster) {
|
if (nucleus is Cluster cluster) {
|
||||||
if (cluster.name == clusterName || cluster.name == clusterName0) {
|
if (cluster.name == clusterName || cluster.name == clusterName0) {
|
||||||
string subNucleusName = nucleusName[(dotPosition + 1)..];
|
string subNucleusName = nucleusName[(dotPosition + 1)..];
|
||||||
@ -749,7 +753,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string nucleusName0 = nucleusName + ": 0";
|
string nucleusName0 = nucleusName + ": 0";
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is Cluster) { //IReceptor receptor) {
|
if (nucleus is Cluster) { //IReceptor receptor) {
|
||||||
if (nucleus.name == nucleusName | nucleus.name == nucleusName0)
|
if (nucleus.name == nucleusName | nucleus.name == nucleusName0)
|
||||||
return nucleus;
|
return nucleus;
|
||||||
@ -762,16 +766,16 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool DeleteNucleus(Nucleus nucleus) {
|
public bool DeleteNucleus(Nucleus nucleus) {
|
||||||
if (this.clusterNuclei.Contains(nucleus) == false) {
|
if (this.nuclei.Contains(nucleus) == false) {
|
||||||
// Try to find the nucleus by name
|
// Try to find the nucleus by name
|
||||||
if (TryGetNucleus(nucleus.name, out nucleus) == false)
|
if (TryGetNucleus(nucleus.name, out nucleus) == false)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Neuron.Delete(nucleus);
|
Neuron.Delete(nucleus);
|
||||||
int nucleusIx = this.clusterNuclei.IndexOf(nucleus);
|
int nucleusIx = this.nuclei.IndexOf(nucleus);
|
||||||
this.clusterNuclei.Remove(nucleus);
|
this.nuclei.Remove(nucleus);
|
||||||
this.prefab.nuclei.RemoveAt(nucleusIx);
|
this.prefab.cluster.nuclei.RemoveAt(nucleusIx);
|
||||||
RefreshOutputs();
|
RefreshOutputs();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -781,7 +785,7 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public virtual List<Nucleus> CollectReceivers(bool removeDuplicates = false) {
|
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.nuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -802,7 +806,7 @@ namespace NanoBrain {
|
|||||||
public List<(Neuron, Nucleus)> CollectConnections() {
|
public List<(Neuron, Nucleus)> CollectConnections() {
|
||||||
List<(Neuron, Nucleus)> connections = new();
|
List<(Neuron, Nucleus)> connections = new();
|
||||||
|
|
||||||
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
foreach (Nucleus outputNucleus in this.nuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -817,10 +821,10 @@ namespace NanoBrain {
|
|||||||
public List<Synapse> CollectSynapsesTo(Cluster otherCluster) {
|
public List<Synapse> CollectSynapsesTo(Cluster otherCluster) {
|
||||||
List<Synapse> collectedSynapses = new();
|
List<Synapse> collectedSynapses = new();
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (nucleus is not Neuron neuron)
|
if (nucleus is not Neuron neuron)
|
||||||
continue;
|
continue;
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in neuron.synapses) {
|
||||||
if (synapse.neuron.parent == otherCluster)
|
if (synapse.neuron.parent == otherCluster)
|
||||||
collectedSynapses.Add(synapse);
|
collectedSynapses.Add(synapse);
|
||||||
}
|
}
|
||||||
@ -830,7 +834,7 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
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}");
|
||||||
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
foreach (Nucleus outputNucleus in this.nuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -846,7 +850,9 @@ namespace NanoBrain {
|
|||||||
// Replace synapse with new synapse
|
// Replace synapse with new synapse
|
||||||
// to the new cluster
|
// to the new cluster
|
||||||
Debug.Log($"move {receiver.name} from {this.name}.{output.name} to {newCluster.name}.{newOutput.name}");
|
Debug.Log($"move {receiver.name} from {this.name}.{output.name} to {newCluster.name}.{newOutput.name}");
|
||||||
Synapse synapse = receiver.GetSynapse(output);
|
if (receiver is not Neuron receiverNeuron)
|
||||||
|
continue;
|
||||||
|
Synapse synapse = receiverNeuron.GetSynapse(output);
|
||||||
newOutput.AddReceiver(receiver, synapse.weight);
|
newOutput.AddReceiver(receiver, synapse.weight);
|
||||||
output.RemoveReceiver(receiver);
|
output.RemoveReceiver(receiver);
|
||||||
}
|
}
|
||||||
@ -896,7 +902,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateNuclei() {
|
public override void UpdateNuclei() {
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
foreach (Nucleus nucleus in this.nuclei)
|
||||||
nucleus.UpdateNuclei();
|
nucleus.UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ namespace NanoBrain {
|
|||||||
public Neuron(Cluster parent, string name) {
|
public Neuron(Cluster parent, string name) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.parent?.clusterNuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new Neuron in a Cluster Prefab
|
/// Create a new Neuron in a Cluster Prefab
|
||||||
@ -34,8 +34,8 @@ namespace NanoBrain {
|
|||||||
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.cluster.nuclei.Add(this);
|
||||||
this.clusterPrefab.RefreshOutputs();
|
this.clusterPrefab.cluster.RefreshOutputs();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Debug.LogError("No prefab when adding neuron to prefab");
|
Debug.LogError("No prefab when adding neuron to prefab");
|
||||||
@ -43,6 +43,71 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
#region Serialization
|
#region Serialization
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The bias
|
||||||
|
/// </summary>
|
||||||
|
/// The bias which a value which is always added to the combined value of the neuron
|
||||||
|
/// It does not have a synapse and therefore no weight of source nucleus
|
||||||
|
public Vector3 bias = Vector3.zero;
|
||||||
|
|
||||||
|
|
||||||
|
#region Synapses
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private List<Synapse> _synapses = new();
|
||||||
|
/// <summary>
|
||||||
|
/// The synapses of the nucleus
|
||||||
|
/// </summary>
|
||||||
|
public List<Synapse> synapses => _synapses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a new synapse to this nuclues
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sendingNucleus">The nucleus from which the signals may originate</param>
|
||||||
|
/// <param name="weight">The weight applied to the input. Default value = 1</param>
|
||||||
|
/// <returns>The created Synapse</returns>
|
||||||
|
/// This will add a new input to this nucleus with the given weight.
|
||||||
|
public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1) {
|
||||||
|
Synapse synapse = new(sendingNucleus, weight);
|
||||||
|
this.synapses.Add(synapse);
|
||||||
|
return synapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public Synapse AddSynapse(ClusterPrefab clusterPrefab, string neuronName, float weight = 1) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find a synapse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender of the input to the Synapse</param>
|
||||||
|
/// <returns>The found Synapse or null when the sender has no synapse to this nucleus.</returns>
|
||||||
|
public Synapse GetSynapse(Nucleus sender) {
|
||||||
|
foreach (Synapse synapse in this.synapses)
|
||||||
|
if (synapse.neuron == sender)
|
||||||
|
return synapse;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a synapse from a Nucleus
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sendingNucleus">Remote the synapse connecting to this Nucleus</param>
|
||||||
|
public void RemoveSynapse(Nucleus sendingNucleus) {
|
||||||
|
this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Synapses
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the bias, recalculate the output and update all Nuclei receiving from this Nucleus
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputValue"></param>
|
||||||
|
public virtual void SetBias(Vector3 inputValue) {
|
||||||
|
this.bias = inputValue;
|
||||||
|
this.parent.UpdateFromNucleus(this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of combinators
|
/// The type of combinators
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -231,13 +296,20 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle for printing debugging trace data
|
||||||
|
/// </summary>
|
||||||
|
public bool trace = false;
|
||||||
|
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public float lastUpdate = 0;
|
public float lastUpdate = 0;
|
||||||
public readonly float timeToSleep = 1f;
|
public readonly float timeToSleep = 1f;
|
||||||
|
|
||||||
/// \copydoc NanoBrain::Nucleus::ShallowCloneTo
|
/// \copydoc NanoBrain::Nucleus::ShallowCloneTo
|
||||||
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
||||||
Neuron clone = new(newParent, this.name);
|
Neuron clone = new(newParent, this.name) {
|
||||||
|
// prefabNucleus = this
|
||||||
|
};
|
||||||
CloneFields(clone);
|
CloneFields(clone);
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
@ -268,8 +340,8 @@ namespace NanoBrain {
|
|||||||
public static void Delete(Nucleus nucleus) {
|
public static void Delete(Nucleus nucleus) {
|
||||||
if (nucleus == null)
|
if (nucleus == null)
|
||||||
return;
|
return;
|
||||||
if (nucleus.synapses != null) {
|
if (nucleus is Neuron neuron) {
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
foreach (Synapse synapse in neuron.synapses) {
|
||||||
if (synapse.neuron is Neuron synapse_nucleus) {
|
if (synapse.neuron is Neuron synapse_nucleus) {
|
||||||
if (synapse_nucleus.receivers.Count > 1) {
|
if (synapse_nucleus.receivers.Count > 1) {
|
||||||
// there is another nucleus feeding into this input nucleus
|
// there is another nucleus feeding into this input nucleus
|
||||||
@ -281,19 +353,21 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (nucleus is Neuron neuron) {
|
|
||||||
foreach (Nucleus receiver in neuron.receivers) {
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
if (receiver != null && receiver.synapses != null)
|
if (receiver is not Neuron receiverNeuron)
|
||||||
receiver.synapses.RemoveAll(s => s.neuron == nucleus);
|
continue;
|
||||||
|
if (receiver != null && receiverNeuron.synapses != null)
|
||||||
|
receiverNeuron.synapses.RemoveAll(s => s.neuron == nucleus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nucleus is Cluster cluster) {
|
else if (nucleus is Cluster cluster) {
|
||||||
// remove all receivers for this cluster
|
// remove all receivers for this cluster
|
||||||
foreach (Nucleus clusterNucleus in cluster.clusterNuclei) {
|
foreach (Nucleus clusterNucleus in cluster.nuclei) {
|
||||||
if (clusterNucleus is Neuron output) {
|
if (clusterNucleus is Neuron output) {
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
receiver.synapses.RemoveAll(s => s.neuron == output);
|
if (receiver is not Neuron receiverNeuron)
|
||||||
|
continue;
|
||||||
|
receiverNeuron.synapses.RemoveAll(s => s.neuron == output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,8 +375,8 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
|
|
||||||
if (nucleus.clusterPrefab != null) {
|
if (nucleus.clusterPrefab != null) {
|
||||||
nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus);
|
nucleus.clusterPrefab.cluster.nuclei.RemoveAll(n => n == nucleus);
|
||||||
nucleus.clusterPrefab.RefreshOutputs();
|
nucleus.clusterPrefab.cluster.RefreshOutputs();
|
||||||
nucleus.clusterPrefab.GarbageCollection();
|
nucleus.clusterPrefab.GarbageCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,15 +598,25 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||||
this._receivers.Add(receiverToAdd);
|
if (receiverToAdd is not Neuron receiverNeuron)
|
||||||
receiverToAdd.AddSynapse(this, weight);
|
return;
|
||||||
|
this._receivers.Add(receiverNeuron);
|
||||||
|
receiverNeuron.AddSynapse(this, weight);
|
||||||
//Debug.Log($"Add synapse {this.clusterPrefab.name}.{this.name} -> {receiverToAdd.name} --- [{this.receivers.Count}]");
|
//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) {
|
||||||
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
if (receiverToRemove is not Neuron receiverNeuron)
|
||||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
|
return;
|
||||||
|
this._receivers.RemoveAll(receiver => receiver == receiverNeuron);
|
||||||
|
receiverNeuron.synapses.RemoveAll(synapse => synapse.neuron == this);
|
||||||
|
|
||||||
|
// Nucleus prefabReceiver = receiverToRemove.prefabNucleus;
|
||||||
|
// if (this.prefabNucleus is Neuron prefabNeuron && prefabReceiver != null) {
|
||||||
|
// prefabNeuron.receivers.RemoveAll(receiver => receiver == prefabReceiver);
|
||||||
|
// prefabReceiver.synapses.RemoveAll(synapse => synapse.neuron == prefabNeuron);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,9 @@ public abstract class Nucleus {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string name;
|
public string name;
|
||||||
|
|
||||||
|
// [NonSerialized]
|
||||||
|
// public Nucleus prefabNucleus;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cluster prefab in which the nucleus is located
|
/// The cluster prefab in which the nucleus is located
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -31,7 +34,7 @@ public abstract class Nucleus {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Toggle for printing debugging trace data
|
/// Toggle for printing debugging trace data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool trace = false;
|
//public bool trace = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Function to make a partial clone of this nucleus
|
/// Function to make a partial clone of this nucleus
|
||||||
@ -61,60 +64,60 @@ public abstract class Nucleus {
|
|||||||
|
|
||||||
public virtual void Initialize() {}
|
public virtual void Initialize() {}
|
||||||
|
|
||||||
#region Synapses
|
// #region Synapses
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// The bias of the nucleus
|
// /// The bias of the nucleus
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// The bias which a value which is always added to the combined value of the nucleus
|
// /// The bias which a value which is always added to the combined value of the nucleus
|
||||||
/// It does not have a synapse and therefore no weight of source nucleus
|
// /// It does not have a synapse and therefore no weight of source nucleus
|
||||||
public Vector3 bias = Vector3.zero;
|
// //public Vector3 bias = Vector3.zero;
|
||||||
|
|
||||||
[SerializeField]
|
// [SerializeField]
|
||||||
private List<Synapse> _synapses = new();
|
// private List<Synapse> _synapses = new();
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// The synapses of the nucleus
|
// /// The synapses of the nucleus
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public List<Synapse> synapses => _synapses;
|
// public List<Synapse> synapses => _synapses;
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Add a new synapse to this nuclues
|
// /// Add a new synapse to this nuclues
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="sendingNucleus">The nucleus from which the signals may originate</param>
|
// /// <param name="sendingNucleus">The nucleus from which the signals may originate</param>
|
||||||
/// <param name="weight">The weight applied to the input. Default value = 1</param>
|
// /// <param name="weight">The weight applied to the input. Default value = 1</param>
|
||||||
/// <returns>The created Synapse</returns>
|
// /// <returns>The created Synapse</returns>
|
||||||
/// This will add a new input to this nucleus with the given weight.
|
// /// This will add a new input to this nucleus with the given weight.
|
||||||
public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1) {
|
// public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1) {
|
||||||
Synapse synapse = new(sendingNucleus, weight);
|
// Synapse synapse = new(sendingNucleus, weight);
|
||||||
this.synapses.Add(synapse);
|
// this.synapses.Add(synapse);
|
||||||
return synapse;
|
// return synapse;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// public Synapse AddSynapse(ClusterPrefab clusterPrefab, string neuronName, float weight = 1) {
|
// // public Synapse AddSynapse(ClusterPrefab clusterPrefab, string neuronName, float weight = 1) {
|
||||||
|
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Find a synapse
|
// /// Find a synapse
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="sender">The sender of the input to the Synapse</param>
|
// /// <param name="sender">The sender of the input to the Synapse</param>
|
||||||
/// <returns>The found Synapse or null when the sender has no synapse to this nucleus.</returns>
|
// /// <returns>The found Synapse or null when the sender has no synapse to this nucleus.</returns>
|
||||||
public Synapse GetSynapse(Nucleus sender) {
|
// public Synapse GetSynapse(Nucleus sender) {
|
||||||
foreach (Synapse synapse in this.synapses)
|
// foreach (Synapse synapse in this.synapses)
|
||||||
if (synapse.neuron == sender)
|
// if (synapse.neuron == sender)
|
||||||
return synapse;
|
// return synapse;
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Remove a synapse from a Nucleus
|
// /// Remove a synapse from a Nucleus
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="sendingNucleus">Remote the synapse connecting to this Nucleus</param>
|
// /// <param name="sendingNucleus">Remote the synapse connecting to this Nucleus</param>
|
||||||
public void RemoveSynapse(Nucleus sendingNucleus) {
|
// public void RemoveSynapse(Nucleus sendingNucleus) {
|
||||||
this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus);
|
// this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus);
|
||||||
}
|
// }
|
||||||
|
|
||||||
#endregion Synapses
|
// #endregion Synapses
|
||||||
|
|
||||||
#region Update
|
#region Update
|
||||||
|
|
||||||
@ -129,14 +132,14 @@ public abstract class Nucleus {
|
|||||||
public virtual void UpdateNuclei() {
|
public virtual void UpdateNuclei() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Set the bias, recalculate the output and update all Nuclei receiving from this Nucleus
|
// /// Set the bias, recalculate the output and update all Nuclei receiving from this Nucleus
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="inputValue"></param>
|
// /// <param name="inputValue"></param>
|
||||||
public virtual void SetBias(Vector3 inputValue) {
|
// public virtual void SetBias(Vector3 inputValue) {
|
||||||
this.bias = inputValue;
|
// this.bias = inputValue;
|
||||||
this.parent.UpdateFromNucleus(this);
|
// this.parent.UpdateFromNucleus(this);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process an external stimulus
|
/// Process an external stimulus
|
||||||
|
|||||||
@ -8,87 +8,94 @@ namespace NanoBrain {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
||||||
public class ClusterPrefab : ScriptableObject {
|
public class ClusterPrefab : ScriptableObject {
|
||||||
/// The nuclei in this cluster
|
|
||||||
[SerializeReference]
|
|
||||||
// This list should not include any clusters...
|
|
||||||
public List<Nucleus> nuclei = new();
|
|
||||||
|
|
||||||
/// <summary>
|
public Cluster cluster;
|
||||||
/// The output of this cluster
|
/*
|
||||||
/// </summary>
|
/// The nuclei in this cluster
|
||||||
/// <deprecated>This only returens the first(default) nucleus. Use outputs[0] instead</deprecated>
|
[SerializeReference]
|
||||||
public virtual Nucleus output => this.nuclei[0] as Nucleus;
|
// This list should not include any clusters...
|
||||||
|
public List<Nucleus> nuclei = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The nuclei in this cluster which are meant for receiving signals from outside the cluster
|
/// The output of this cluster
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remark>This is currently the nuclei which do not have any incoming synapse</remark>
|
/// <deprecated>This only returens the first(default) nucleus. Use outputs[0] instead</deprecated>
|
||||||
public List<Nucleus> _inputs = null;
|
public virtual Nucleus output => this.nuclei[0] as Nucleus;
|
||||||
public virtual List<Nucleus> inputs {
|
|
||||||
get {
|
/// <summary>
|
||||||
if (this._inputs == null) {
|
/// The nuclei in this cluster which are meant for receiving signals from outside the cluster
|
||||||
this._inputs = new();
|
/// </summary>
|
||||||
foreach (Nucleus receptor in this.nuclei) {
|
/// <remark>This is currently the nuclei which do not have any incoming synapse</remark>
|
||||||
if (receptor is Nucleus nucleus) {
|
public List<Nucleus> _inputs = null;
|
||||||
// inputs have no incoming synapses yet.
|
public virtual List<Nucleus> inputs {
|
||||||
if (nucleus.synapses.Count == 0)
|
get {
|
||||||
this._inputs.Add(nucleus);
|
if (this._inputs == null) {
|
||||||
|
this._inputs = new();
|
||||||
|
foreach (Nucleus receptor in this.nuclei) {
|
||||||
|
if (receptor is Nucleus nucleus) {
|
||||||
|
// inputs have no incoming synapses yet.
|
||||||
|
if (nucleus.synapses.Count == 0)
|
||||||
|
this._inputs.Add(nucleus);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return this._inputs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this._inputs;
|
/// <summary>
|
||||||
}
|
/// The nuclei in this cluster which are meant for sending signals onward
|
||||||
}
|
/// </summary>
|
||||||
/// <summary>
|
private List<Nucleus> _outputs = null;
|
||||||
/// The nuclei in this cluster which are meant for sending signals onward
|
public List<Nucleus> outputs {
|
||||||
/// </summary>
|
get {
|
||||||
private List<Nucleus> _outputs = null;
|
if (this._outputs == null)
|
||||||
public List<Nucleus> outputs {
|
RefreshOutputs();
|
||||||
get {
|
return this._outputs;
|
||||||
if (this._outputs == null)
|
}
|
||||||
RefreshOutputs();
|
}
|
||||||
return this._outputs;
|
/// <summary>
|
||||||
}
|
/// Redetermine the outpus in the cluster
|
||||||
}
|
/// </summary>
|
||||||
/// <summary>
|
public void RefreshOutputs() {
|
||||||
/// Redetermine the outpus in the cluster
|
this._outputs = new();
|
||||||
/// </summary>
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
public void RefreshOutputs() {
|
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
||||||
this._outputs = new();
|
this._outputs.Add(nucleus);
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
}
|
||||||
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
}
|
||||||
this._outputs.Add(nucleus);
|
*/
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve a nucleus in this cluster
|
/// Retrieve a nucleus in this cluster
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nucleusName">The name of the nucleus</param>
|
/// <param name="nucleusName">The name of the nucleus</param>
|
||||||
/// <returns>The Nucleus with the given name or null if no such Nucleus could be found</returns>
|
/// <returns>The Nucleus with the given name or null if no such Nucleus could be found</returns>
|
||||||
public Nucleus GetNucleus(string nucleusName) {
|
public Nucleus GetNucleus(string nucleusName) {
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
return cluster.GetNucleus(nucleusName);
|
||||||
if (nucleus.name == nucleusName)
|
// foreach (Nucleus nucleus in this.nuclei) {
|
||||||
return nucleus;
|
// if (nucleus.name == nucleusName)
|
||||||
}
|
// return nucleus;
|
||||||
return null;
|
// }
|
||||||
|
// return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this function to ensure that there is at least one nucleus
|
// Call this function to ensure that there is at least one nucleus
|
||||||
// This is an invariant and should be ensured before the nucleus is used
|
// This is an invariant and should be ensured before the nucleus is used
|
||||||
// because output requires it.
|
// because output requires it.
|
||||||
public void EnsureInitialization() {
|
public void EnsureInitialization() {
|
||||||
nuclei ??= new List<Nucleus>();
|
this.cluster.nuclei ??= new List<Nucleus>();
|
||||||
if (nuclei.Count == 0)
|
if (this.cluster.nuclei.Count <= 0)
|
||||||
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
||||||
|
// nuclei ??= new List<Nucleus>();
|
||||||
|
// if (nuclei.Count == 0)
|
||||||
|
// new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GarbageCollection() {
|
public void GarbageCollection() {
|
||||||
HashSet<Nucleus> visitedNuclei = new();
|
// HashSet<Nucleus> visitedNuclei = new();
|
||||||
foreach (Nucleus output in this.outputs)
|
// foreach (Nucleus output in this.outputs)
|
||||||
MarkNuclei(visitedNuclei, output);
|
// MarkNuclei(visitedNuclei, output);
|
||||||
//Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
// //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
||||||
this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
|
// this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkNuclei(HashSet<Nucleus> visitedNuclei, Nucleus nucleus) {
|
public void MarkNuclei(HashSet<Nucleus> visitedNuclei, Nucleus nucleus) {
|
||||||
@ -99,43 +106,45 @@ namespace NanoBrain {
|
|||||||
visitedNuclei.Add(nucleus.parent);
|
visitedNuclei.Add(nucleus.parent);
|
||||||
else
|
else
|
||||||
visitedNuclei.Add(nucleus);
|
visitedNuclei.Add(nucleus);
|
||||||
if (nucleus.synapses != null) {
|
if (nucleus is Neuron neuron) {
|
||||||
HashSet<Synapse> visitedSynapses = new();
|
if (neuron.synapses != null) {
|
||||||
foreach (Synapse synapse in nucleus.synapses) {
|
HashSet<Synapse> visitedSynapses = new();
|
||||||
if (synapse != null && synapse.neuron != null) {
|
foreach (Synapse synapse in neuron.synapses) {
|
||||||
visitedSynapses.Add(synapse);
|
if (synapse != null && synapse.neuron != null) {
|
||||||
if (synapse.neuron is Nucleus synapse_nucleus)
|
visitedSynapses.Add(synapse);
|
||||||
MarkNuclei(visitedNuclei, synapse_nucleus);
|
if (synapse.neuron is Nucleus synapse_nucleus)
|
||||||
|
MarkNuclei(visitedNuclei, synapse_nucleus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
neuron.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
||||||
}
|
}
|
||||||
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
if (neuron.receivers != null) {
|
||||||
}
|
HashSet<Nucleus> visitedReceivers = new();
|
||||||
if (nucleus is Neuron neuron && neuron.receivers != null) {
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
HashSet<Nucleus> visitedReceivers = new();
|
if (receiver != null && receiver != null) {
|
||||||
foreach (Nucleus receiver in neuron.receivers) {
|
visitedReceivers.Add(receiver);
|
||||||
if (receiver != null && receiver != null) {
|
visitedNuclei.Add(receiver);
|
||||||
visitedReceivers.Add(receiver);
|
}
|
||||||
visitedNuclei.Add(receiver);
|
|
||||||
}
|
}
|
||||||
|
neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
||||||
}
|
}
|
||||||
neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateNuclei() {
|
// public virtual void UpdateNuclei() {
|
||||||
foreach (Nucleus nucleus in this.nuclei)
|
// foreach (Nucleus nucleus in this.nuclei)
|
||||||
nucleus.UpdateNuclei();
|
// nucleus.UpdateNuclei();
|
||||||
}
|
// }
|
||||||
|
|
||||||
public int GetNucleusIndex(Nucleus receiver) {
|
// public int GetNucleusIndex(Nucleus receiver) {
|
||||||
int ix = 0;
|
// int ix = 0;
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
// foreach (Nucleus nucleus in this.nuclei) {
|
||||||
if (receiver == nucleus)
|
// if (receiver == nucleus)
|
||||||
return ix;
|
// return ix;
|
||||||
ix++;
|
// ix++;
|
||||||
}
|
// }
|
||||||
return -1;
|
// return -1;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,11 +43,11 @@ namespace CreatureControl {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// It is used by the brain to do things periodically
|
/// It is used by the brain to do things periodically
|
||||||
/// like placing pheromones
|
/// like placing pheromones
|
||||||
public Nucleus beat;
|
public Neuron beat;
|
||||||
|
|
||||||
public Nucleus pheromoneSteering;
|
public Neuron pheromoneSteering;
|
||||||
public Nucleus hitLeft;
|
public Neuron hitLeft;
|
||||||
public Nucleus hitRight;
|
public Neuron hitRight;
|
||||||
public Neuron foodReceptor;
|
public Neuron foodReceptor;
|
||||||
public Neuron homeReceptor;
|
public Neuron homeReceptor;
|
||||||
|
|
||||||
@ -60,6 +60,22 @@ namespace CreatureControl {
|
|||||||
base.Awake();
|
base.Awake();
|
||||||
|
|
||||||
this.nanoBrain = GetComponentInChildren<Brain>();
|
this.nanoBrain = GetComponentInChildren<Brain>();
|
||||||
|
|
||||||
|
Cluster brain = this.nanoBrain.brain;
|
||||||
|
if (brain != null) {
|
||||||
|
//--- brain inputs
|
||||||
|
|
||||||
|
this.beat = brain.GetNucleus("Beat") as Neuron;
|
||||||
|
this.hitLeft = brain.GetNucleus("Hit Left") as Neuron;
|
||||||
|
this.hitRight = brain.GetNucleus("Hit Right") as Neuron;
|
||||||
|
this.foodReceptor = brain.GetNucleus("Food Receptor") as Neuron;
|
||||||
|
this.homeReceptor = brain.GetNucleus("Home Receptor") as Neuron;
|
||||||
|
this.pheromoneSteering = brain.GetNucleus("Pheromone Steering") as Neuron;
|
||||||
|
|
||||||
|
//--- brain outputs
|
||||||
|
this.targetDirection = brain.GetNucleus("Output") as Neuron;
|
||||||
|
this.hasFood = brain.GetNucleus("Having Food") as Neuron;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
@ -71,17 +87,6 @@ namespace CreatureControl {
|
|||||||
|
|
||||||
Cluster brain = this.nanoBrain.brain;
|
Cluster brain = this.nanoBrain.brain;
|
||||||
if (brain != null) {
|
if (brain != null) {
|
||||||
//--- brain inputs
|
|
||||||
|
|
||||||
this.beat = brain.GetNucleus("Beat");
|
|
||||||
this.hitLeft = brain.GetNucleus("Hit Left");
|
|
||||||
this.hitRight = brain.GetNucleus("Hit Right");
|
|
||||||
this.foodReceptor = brain.GetNucleus("Food Receptor") as Neuron;
|
|
||||||
this.homeReceptor = brain.GetNucleus("Home Receptor") as Neuron;
|
|
||||||
this.pheromoneSteering = brain.GetNucleus("Pheromone Steering");
|
|
||||||
|
|
||||||
//--- brain outputs
|
|
||||||
this.targetDirection = brain.defaultOutput;
|
|
||||||
|
|
||||||
// Try to find the Home Pheromones Neuron
|
// Try to find the Home Pheromones Neuron
|
||||||
if (brain.GetNucleus("Home Pheromones") is Neuron homePheromones)
|
if (brain.GetNucleus("Home Pheromones") is Neuron homePheromones)
|
||||||
@ -92,7 +97,6 @@ namespace CreatureControl {
|
|||||||
// and call PlaceFoodPheromone when it is firing
|
// and call PlaceFoodPheromone when it is firing
|
||||||
foodPheromones.WhenFiring += PlaceFoodPheromone;
|
foodPheromones.WhenFiring += PlaceFoodPheromone;
|
||||||
|
|
||||||
this.hasFood = brain.GetNucleus("Having Food") as Neuron;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the callbacks for the antenna colliders
|
// Initialize the callbacks for the antenna colliders
|
||||||
|
|||||||
@ -1,233 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!114 &11400000
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
|
|
||||||
m_Name: Foraging
|
|
||||||
m_EditorClassIdentifier:
|
|
||||||
nuclei:
|
|
||||||
- rid: 2642584373999960064
|
|
||||||
- rid: 2642584373999960065
|
|
||||||
references:
|
|
||||||
version: 2
|
|
||||||
RefIds:
|
|
||||||
- rid: -2
|
|
||||||
type: {class: , ns: , asm: }
|
|
||||||
- rid: 2642584373999960064
|
|
||||||
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Output
|
|
||||||
clusterPrefab: {fileID: 11400000}
|
|
||||||
parent:
|
|
||||||
rid: -2
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses: []
|
|
||||||
combinator: 0
|
|
||||||
_curvePreset: 0
|
|
||||||
curve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve: []
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
curveMax: 1
|
|
||||||
_receivers: []
|
|
||||||
- rid: 2642584373999960065
|
|
||||||
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Collision Steering
|
|
||||||
clusterPrefab: {fileID: 11400000}
|
|
||||||
parent:
|
|
||||||
rid: -2
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses: []
|
|
||||||
combinator: 0
|
|
||||||
_curvePreset: 0
|
|
||||||
curve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 1
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1000
|
|
||||||
value: 1000
|
|
||||||
inSlope: 1
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
curveMax: 1
|
|
||||||
_receivers:
|
|
||||||
- rid: 2642584373999960066
|
|
||||||
- rid: 2642584373999960068
|
|
||||||
- rid: 2642584373999960066
|
|
||||||
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Output
|
|
||||||
clusterPrefab: {fileID: 11400000}
|
|
||||||
parent:
|
|
||||||
rid: 2642584373999960067
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses:
|
|
||||||
- neuron:
|
|
||||||
rid: 2642584373999960065
|
|
||||||
weight: 1
|
|
||||||
combinator: 0
|
|
||||||
_curvePreset: 0
|
|
||||||
curve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 1
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1000
|
|
||||||
value: 1000
|
|
||||||
inSlope: 1
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
curveMax: 1
|
|
||||||
_receivers: []
|
|
||||||
- rid: 2642584373999960067
|
|
||||||
type: {class: Cluster, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Foraging
|
|
||||||
clusterPrefab: {fileID: 0}
|
|
||||||
parent:
|
|
||||||
rid: -2
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses: []
|
|
||||||
prefab: {fileID: 11400000}
|
|
||||||
siblingClusters: []
|
|
||||||
instanceCount: 1
|
|
||||||
clusterNuclei:
|
|
||||||
- rid: 2642584373999960066
|
|
||||||
- rid: 2642584373999960068
|
|
||||||
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Output
|
|
||||||
clusterPrefab: {fileID: 11400000}
|
|
||||||
parent:
|
|
||||||
rid: 2642584373999960069
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses:
|
|
||||||
- neuron:
|
|
||||||
rid: 2642584373999960065
|
|
||||||
weight: 1
|
|
||||||
combinator: 0
|
|
||||||
_curvePreset: 0
|
|
||||||
curve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 1
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1000
|
|
||||||
value: 1000
|
|
||||||
inSlope: 1
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
curveMax: 1
|
|
||||||
_receivers: []
|
|
||||||
- rid: 2642584373999960069
|
|
||||||
type: {class: Cluster, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Foraging
|
|
||||||
clusterPrefab: {fileID: 0}
|
|
||||||
parent:
|
|
||||||
rid: -2
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses: []
|
|
||||||
prefab: {fileID: 11400000}
|
|
||||||
siblingClusters: []
|
|
||||||
instanceCount: 1
|
|
||||||
clusterNuclei:
|
|
||||||
- rid: 2642584373999960068
|
|
||||||
- rid: 2642584373999960070
|
|
||||||
- rid: 2642584373999960070
|
|
||||||
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
|
||||||
data:
|
|
||||||
name: Collision Steering
|
|
||||||
clusterPrefab: {fileID: 11400000}
|
|
||||||
parent:
|
|
||||||
rid: 2642584373999960069
|
|
||||||
trace: 0
|
|
||||||
bias: {x: 0, y: 0, z: 0}
|
|
||||||
_synapses: []
|
|
||||||
combinator: 0
|
|
||||||
_curvePreset: 0
|
|
||||||
curve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 1
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1000
|
|
||||||
value: 1000
|
|
||||||
inSlope: 1
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0
|
|
||||||
outWeight: 0
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
curveMax: 1
|
|
||||||
_receivers: []
|
|
||||||
109
Samples/Brain/New Cluster Prefab.asset
Normal file
109
Samples/Brain/New Cluster Prefab.asset
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
|
||||||
|
m_Name: New Cluster Prefab
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
cluster:
|
||||||
|
name:
|
||||||
|
clusterPrefab: {fileID: 0}
|
||||||
|
parent:
|
||||||
|
rid: -2
|
||||||
|
prefab: {fileID: 0}
|
||||||
|
instanceCount: 0
|
||||||
|
nuclei:
|
||||||
|
- rid: 4201949831649034293
|
||||||
|
- rid: 4201949831649034294
|
||||||
|
references:
|
||||||
|
version: 2
|
||||||
|
RefIds:
|
||||||
|
- rid: -2
|
||||||
|
type: {class: , ns: , asm: }
|
||||||
|
- rid: 4201949831649034293
|
||||||
|
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
||||||
|
data:
|
||||||
|
name: Output
|
||||||
|
clusterPrefab: {fileID: 11400000}
|
||||||
|
parent:
|
||||||
|
rid: -2
|
||||||
|
bias: {x: 0, y: 0, z: 0}
|
||||||
|
_synapses:
|
||||||
|
- neuron:
|
||||||
|
rid: 4201949831649034294
|
||||||
|
weight: 1
|
||||||
|
combinator: 0
|
||||||
|
_curvePreset: 0
|
||||||
|
curve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 1
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 1000
|
||||||
|
value: 1000
|
||||||
|
inSlope: 1
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
curveMax: 1
|
||||||
|
trace: 0
|
||||||
|
_receivers: []
|
||||||
|
- rid: 4201949831649034294
|
||||||
|
type: {class: Neuron, ns: NanoBrain, asm: Assembly-CSharp}
|
||||||
|
data:
|
||||||
|
name: New neuron
|
||||||
|
clusterPrefab: {fileID: 11400000}
|
||||||
|
parent:
|
||||||
|
rid: -2
|
||||||
|
bias: {x: 0, y: 0, z: 0}
|
||||||
|
_synapses: []
|
||||||
|
combinator: 0
|
||||||
|
_curvePreset: 0
|
||||||
|
curve:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Curve:
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 0
|
||||||
|
value: 0
|
||||||
|
inSlope: 0
|
||||||
|
outSlope: 1
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
time: 1000
|
||||||
|
value: 1000
|
||||||
|
inSlope: 1
|
||||||
|
outSlope: 0
|
||||||
|
tangentMode: 0
|
||||||
|
weightedMode: 0
|
||||||
|
inWeight: 0
|
||||||
|
outWeight: 0
|
||||||
|
m_PreInfinity: 2
|
||||||
|
m_PostInfinity: 2
|
||||||
|
m_RotationOrder: 4
|
||||||
|
curveMax: 1
|
||||||
|
trace: 0
|
||||||
|
_receivers:
|
||||||
|
- rid: 4201949831649034293
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 81292defec7ff5278a48a5d154659d00
|
guid: c8e4b0990eb7dbbc4bee34addd9cd2b8
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
Loading…
x
Reference in New Issue
Block a user