Compare commits
No commits in common. "da370bb7013ecf8dbf5635adc4969ad72b6103f4" and "7ef8e42e091cd5a46bf77dfbf9b1a3b3a4422752" have entirely different histories.
da370bb701
...
7ef8e42e09
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 9197e2d322d23b5798ab4aef729815b0
|
guid: 9197e2d322d23b5798ab4aef729815b0
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f05072314d39990639a2dbf99f322664
|
guid: f05072314d39990639a2dbf99f322664
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -64,24 +64,22 @@ 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.cluster.defaultOutput.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
|
||||||
//this.currentCluster = new(prefab);
|
this.currentCluster = new(prefab);
|
||||||
this.currentCluster = prefab.cluster;
|
|
||||||
this.currentCluster.Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
public void SetGraph(GameObject gameObject, VisualElement inspectorContainer) {
|
||||||
@ -89,7 +87,7 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
if (Application.isPlaying == false)
|
if (Application.isPlaying == false)
|
||||||
this.serializedBrain = new SerializedObject(this.prefab);
|
this.serializedBrain = new SerializedObject(this.prefab);
|
||||||
this.selectedOutput = this.currentCluster.defaultOutput;
|
this.selectedOutput = this.currentCluster.outputs[0];
|
||||||
this.currentNucleus = this.selectedOutput;
|
this.currentNucleus = this.selectedOutput;
|
||||||
//this.currentCluster = this.currentNucleus.parent;
|
//this.currentCluster = this.currentNucleus.parent;
|
||||||
Rebuild(inspectorContainer);
|
Rebuild(inspectorContainer);
|
||||||
@ -122,7 +120,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.cluster.nuclei) {
|
foreach (Nucleus nucleus in this.prefab.nuclei) {
|
||||||
nucleus.Initialize();
|
nucleus.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,11 +163,30 @@ namespace NanoBrain {
|
|||||||
GUILayout.Label(nucleusType, headerStyle);
|
GUILayout.Label(nucleusType, headerStyle);
|
||||||
|
|
||||||
// Nucleus name
|
// Nucleus name
|
||||||
|
Cluster cluster = this.currentPrefabNucleus as Cluster;
|
||||||
|
if (cluster != null) {
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
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);
|
string newName = EditorGUILayout.TextField(this.currentNucleus.name, boldTextFieldStyle);
|
||||||
if (newName != this.currentNucleus.name) {
|
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.currentNucleus.name = newName;
|
||||||
|
this.prefab.RefreshOutputs();
|
||||||
|
// outputsPopup.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Current output value
|
// Current output value
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
@ -187,7 +204,7 @@ namespace NanoBrain {
|
|||||||
if (this.currentNucleus is MemoryCell memory)
|
if (this.currentNucleus is MemoryCell memory)
|
||||||
MemoryCellInspector(memory, ref anythingChanged);
|
MemoryCellInspector(memory, ref anythingChanged);
|
||||||
// Cluster
|
// Cluster
|
||||||
else if (this.currentNucleus is Cluster cluster)
|
else if (cluster != null)
|
||||||
ClusterInspector(cluster, ref anythingChanged);
|
ClusterInspector(cluster, ref anythingChanged);
|
||||||
// Other
|
// Other
|
||||||
else
|
else
|
||||||
@ -213,8 +230,10 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
bool connecting = GUILayout.Button("Add Output Neuron");
|
bool connecting = GUILayout.Button("Add Output Neuron");
|
||||||
if (connecting) {
|
if (connecting) {
|
||||||
Nucleus newOutput = new Neuron(this.currentCluster, "New Output");
|
Nucleus newOutput = new Neuron(this.prefab, "New Output");
|
||||||
this.currentCluster.Refresh();
|
// Regenerate the temporary clsuter instance
|
||||||
|
// See also the constructor
|
||||||
|
this.currentCluster = new(this.prefab);
|
||||||
this.currentNucleus = newOutput;
|
this.currentNucleus = newOutput;
|
||||||
this.selectedOutput = this.currentNucleus;
|
this.selectedOutput = this.currentNucleus;
|
||||||
}
|
}
|
||||||
@ -262,9 +281,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) {
|
||||||
@ -274,30 +293,31 @@ 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", neuron2.bias);
|
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias);
|
||||||
if (newBias != neuron2.bias) {
|
if (newBias != this.currentPrefabNucleus.bias) {
|
||||||
anythingChanged |= newBias != neuron2.bias;
|
anythingChanged |= newBias != this.currentNucleus.bias;
|
||||||
neuron2.bias = newBias;
|
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 is Neuron currentNeuron && currentNeuron.synapses.Count > 0) {
|
if (this.currentPrefabNucleus.synapses.Count > 0) {
|
||||||
Synapse[] synapses = currentNeuron.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;
|
||||||
|
|
||||||
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.nuclei, synapse.neuron);
|
int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
||||||
if (thisElementIx == elementIx)
|
if (thisElementIx == elementIx)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
@ -312,7 +332,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.nuclei, synapse.neuron);
|
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,19 +348,21 @@ namespace NanoBrain {
|
|||||||
else {
|
else {
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
if (synapse.neuron.parent != this.currentNucleus.parent) {
|
if (synapse.neuron.clusterPrefab != this.currentNucleus.clusterPrefab) {
|
||||||
// If it is a different cluster
|
// If it is a different cluster
|
||||||
GUIStyle labelStyle = new(GUI.skin.label);
|
GUIStyle labelStyle = new(GUI.skin.label);
|
||||||
float labelWidth = 200;
|
float labelWidth = 200;
|
||||||
if (synapse.neuron.parent != null) {
|
if (synapse.neuron.clusterPrefab != null) {
|
||||||
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.name}.")).x;
|
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.clusterPrefab.name}.")).x;
|
||||||
GUILayout.Label($"{synapse.neuron.parent.name}", GUILayout.Width(labelWidth));
|
GUILayout.Label($"{synapse.neuron.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
||||||
}
|
}
|
||||||
string[] options = synapse.neuron.parent.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) {
|
if (newIndex != selectedIndex) {
|
||||||
Neuron newNeuron = synapse.neuron.parent.nuclei[newIndex] as Neuron;
|
// Nucleus selectedNucleus = synapse.neuron.parent.clusterNuclei[newIndex];
|
||||||
|
// Neuron newNeuron = selectedNucleus as Neuron;
|
||||||
|
Neuron newNeuron = synapse.neuron.clusterPrefab.nuclei[newIndex] as Neuron;
|
||||||
ChangeSynapse(synapse, newNeuron);
|
ChangeSynapse(synapse, newNeuron);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,12 +370,13 @@ 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) {
|
if (disconnecting && synapse.neuron is Neuron synapseNeuron) {
|
||||||
synapse.neuron.RemoveReceiver(this.currentNucleus);
|
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||||
this.currentCluster.Refresh();
|
this.prefab.GarbageCollection();
|
||||||
anythingChanged = true;
|
anythingChanged = true;
|
||||||
}
|
}
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUI.indentLevel++;
|
EditorGUI.indentLevel++;
|
||||||
@ -420,14 +443,13 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddNeuronInput(Nucleus nucleus) {
|
protected virtual void AddNeuronInput(Nucleus nucleus) {
|
||||||
Neuron newNeuron = new(this.currentCluster, "New Neuron");
|
Neuron newNeuroid = new(this.prefab, "New neuron");
|
||||||
//Neuron newNeuroid = new(this.prefab.cluster, "New neuron");
|
newNeuroid.AddReceiver(nucleus);
|
||||||
newNeuron.AddReceiver(nucleus);
|
this.currentNucleus = newNeuroid;
|
||||||
this.currentNucleus = newNeuron;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddMemoryCellInput(Nucleus nucleus) {
|
protected virtual void AddMemoryCellInput(Nucleus nucleus) {
|
||||||
MemoryCell newMemory = new(this.prefab.cluster, "New memory cell");
|
MemoryCell newMemory = new(this.prefab, "New memory cell");
|
||||||
newMemory.AddReceiver(nucleus);
|
newMemory.AddReceiver(nucleus);
|
||||||
this.currentNucleus = newMemory;
|
this.currentNucleus = newMemory;
|
||||||
}
|
}
|
||||||
@ -436,7 +458,7 @@ namespace NanoBrain {
|
|||||||
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
||||||
}
|
}
|
||||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
||||||
Cluster subclusterInstance = new(selectedPrefab, this.currentCluster);
|
Cluster subclusterInstance = new(selectedPrefab, this.prefab);
|
||||||
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,12 +493,11 @@ namespace NanoBrain {
|
|||||||
if (cluster == null)
|
if (cluster == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Neuron currentNeuron = this.currentNucleus as Neuron;
|
IEnumerable<Nucleus> synapseNuclei = this.currentNucleus.synapses
|
||||||
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.cluster.nuclei
|
IEnumerable<Nucleus> nuclei = cluster.nuclei
|
||||||
.Except(synapseNuclei);
|
.Except(synapseNuclei);
|
||||||
IEnumerable<string> nucleiNames = nuclei
|
IEnumerable<string> nucleiNames = nuclei
|
||||||
.Select(n => {
|
.Select(n => {
|
||||||
@ -492,14 +513,11 @@ 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) {
|
if (nucleus is Cluster subCluster)
|
||||||
subCluster.AddArrayReceiver(this.currentNucleus);
|
subCluster.AddArrayReceiver(this.currentNucleus);
|
||||||
}
|
else if (nucleus is Neuron neuron)
|
||||||
else if (nucleus is Neuron neuron) {
|
|
||||||
neuron.AddReceiver(this.currentNucleus);
|
neuron.AddReceiver(this.currentNucleus);
|
||||||
}
|
}
|
||||||
this.currentCluster.Refresh();
|
|
||||||
}
|
|
||||||
return connecting;
|
return connecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,10 +537,10 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
// this.prefab.nuclei.Remove(nucleus);
|
// this.prefab.nuclei.Remove(nucleus);
|
||||||
// Neuron.Delete(nucleus);
|
// Neuron.Delete(nucleus);
|
||||||
this.prefab.cluster.RefreshOutputs();
|
this.prefab.RefreshOutputs();
|
||||||
|
|
||||||
|
|
||||||
this.currentNucleus = this.prefab.cluster.defaultOutput;
|
this.currentNucleus = this.prefab.output;
|
||||||
this.selectedOutput = this.currentNucleus;
|
this.selectedOutput = this.currentNucleus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,6 +558,11 @@ namespace NanoBrain {
|
|||||||
AddInput(selectedType, this.currentNucleus);
|
AddInput(selectedType, this.currentNucleus);
|
||||||
}
|
}
|
||||||
return connecting;
|
return connecting;
|
||||||
|
// if (selectedType == Nucleus.Type.None)
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// AddInput(selectedType, this.currentNucleus);
|
||||||
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
||||||
@ -573,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 {
|
||||||
@ -583,6 +606,19 @@ 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
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1fc1fb7db9f7ad54a87d31313e7f457d
|
guid: 1fc1fb7db9f7ad54a87d31313e7f457d
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -106,8 +106,6 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public void SetGraph(GameObject gameObject) {
|
public void SetGraph(GameObject gameObject) {
|
||||||
this.gameObject = gameObject;
|
this.gameObject = gameObject;
|
||||||
if (this.currentCluster == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Application.isPlaying == false)
|
if (Application.isPlaying == false)
|
||||||
this.serializedBrain = new SerializedObject(this.currentCluster.prefab);
|
this.serializedBrain = new SerializedObject(this.currentCluster.prefab);
|
||||||
@ -130,7 +128,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void OnIMGUI() {
|
public void OnIMGUI() {
|
||||||
if (Application.isPlaying == false && serializedBrain != null)
|
if (Application.isPlaying == false)
|
||||||
serializedBrain.Update();
|
serializedBrain.Update();
|
||||||
|
|
||||||
Handles.BeginGUI();
|
Handles.BeginGUI();
|
||||||
@ -213,8 +211,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void DescendGraph(Dag.Node receiver, ref int ix, Dag dag) {
|
private void DescendGraph(Dag.Node receiver, ref int ix, Dag dag) {
|
||||||
Neuron receiverNeuron = receiver.nucleus as Neuron;
|
foreach (Synapse synapse in receiver.nucleus.synapses) {
|
||||||
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;
|
||||||
@ -387,9 +384,6 @@ 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;
|
||||||
@ -402,7 +396,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 neuron.synapses) {
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
if (synapse.neuron == null)
|
if (synapse.neuron == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -429,7 +423,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 neuron.synapses) {
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
if (synapse.neuron is null)
|
if (synapse.neuron is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -488,15 +482,14 @@ namespace NanoBrain {
|
|||||||
maxValue = 1;
|
maxValue = 1;
|
||||||
float brightness = siblingNeuron.outputMagnitude / maxValue;
|
float brightness = siblingNeuron.outputMagnitude / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
}
|
} DrawNucleus(siblingNeuron, position, size, color);
|
||||||
DrawNucleus(siblingNeuron, position, size, color);
|
|
||||||
GUIStyle style = new(EditorStyles.label) {
|
GUIStyle style = new(EditorStyles.label) {
|
||||||
alignment = TextAnchor.UpperCenter,
|
alignment = TextAnchor.UpperCenter,
|
||||||
normal = { textColor = Color.white },
|
normal = { textColor = Color.white },
|
||||||
fontStyle = FontStyle.Bold,
|
fontStyle = FontStyle.Bold,
|
||||||
};
|
};
|
||||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||||
string name = $"{sibling.baseName}\n{nucleus.name}";
|
string name = $"{sibling.baseName}.{nucleus.name}";
|
||||||
Handles.Label(labelPos, name, style);
|
Handles.Label(labelPos, name, style);
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
@ -504,9 +497,6 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void DrawOutputs(Vector2 parentPos, float size) {
|
protected void DrawOutputs(Vector2 parentPos, float size) {
|
||||||
if (this.currentCluster == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Determine the maximum value in this layer
|
// Determine the maximum value in this layer
|
||||||
// This is used to 'scale' the output value colors of the nuclei
|
// This is used to 'scale' the output value colors of the nuclei
|
||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
@ -613,12 +603,18 @@ namespace NanoBrain {
|
|||||||
if (nucleus.parent != null && currentNucleus != null && nucleus.parent != currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
|
if (nucleus.parent != null && currentNucleus != null && nucleus.parent != currentNucleus.parent && nucleus.parent is Cluster parentCluster1) {
|
||||||
// This neuron is part of another cluster
|
// This neuron is part of another cluster
|
||||||
parentCluster1.name ??= "";
|
parentCluster1.name ??= "";
|
||||||
|
string baseName = "";
|
||||||
int colonPos = parentCluster1.name.IndexOf(":");
|
int colonPos = parentCluster1.name.IndexOf(":");
|
||||||
string baseName;
|
|
||||||
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
|
if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2)
|
||||||
baseName = parentCluster1.name[..colonPos] + "\n";
|
baseName = parentCluster1.name[..colonPos] + ".";
|
||||||
else
|
else
|
||||||
baseName = parentCluster1.name + "\n";
|
baseName = parentCluster1.name + ".";
|
||||||
|
// if (colonPos > 0 && colonPos < parentCluster1.name.Length - 2) {
|
||||||
|
// // if it is an array, we should not show the :0 of the first element
|
||||||
|
// //baseName = baseName[..colonPos];
|
||||||
|
// Handles.Label(labelPos, baseName + nucleus.name, style);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
Handles.Label(labelPos, baseName + nucleus.name, style);
|
Handles.Label(labelPos, baseName + nucleus.name, style);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -853,34 +849,22 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
void OnSceneGUI(SceneView sceneView) {
|
void OnSceneGUI(SceneView sceneView) {
|
||||||
if (this.gameObject != null) {
|
if (this.gameObject != null) {
|
||||||
|
// if (this.currentNucleus is IReceptor receptor) {
|
||||||
Handles.color = Color.yellow;
|
// foreach (Nucleus nucleus in receptor.nucleiArray) {
|
||||||
if (this.selectedSynapseNeuron != null) {
|
// if (nucleus is Neuron neuron) {
|
||||||
foreach (Cluster sibling in this.selectedSynapseNeuron.parent.siblingClusters) {
|
// Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
|
||||||
Neuron siblingNeuron = sibling.GetNucleus(this.selectedSynapseNeuron.name) as Neuron;
|
// Handles.color = Color.yellow;
|
||||||
Vector3 worldVector = this.gameObject.transform.TransformVector(siblingNeuron.outputValue);
|
// Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
|
||||||
}
|
|
||||||
// if (this.currentNucleus is Cluster cluster) {
|
|
||||||
// foreach (Cluster sibling in cluster.siblingClusters) {
|
|
||||||
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// // if (this.currentNucleus is IReceptor receptor) {
|
// }
|
||||||
// // foreach (Nucleus nucleus in receptor.nucleiArray) {
|
// else {
|
||||||
// // if (nucleus is Neuron neuron) {
|
|
||||||
// // Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
|
|
||||||
// // Handles.color = Color.yellow;
|
|
||||||
// // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this.currentNucleus is Neuron currentNeuron) {
|
if (this.currentNucleus is Neuron currentNeuron) {
|
||||||
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
|
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
|
||||||
|
Handles.color = Color.yellow;
|
||||||
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4fe58945c76d153edacc220597474ad2
|
guid: 4fe58945c76d153edacc220597474ad2
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: c7539a20f7894542ca347730cd8417b1
|
guid: c7539a20f7894542ca347730cd8417b1
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace NanoBrain {
|
|
||||||
[CustomPropertyDrawer(typeof(Neuron))]
|
|
||||||
class Neuron_Drawer : PropertyDrawer {
|
|
||||||
public static void Insepctor(SerializedObject serializedObject, string propertyName ) {
|
|
||||||
EditorGUILayout.PropertyField(serializedObject.FindProperty(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
|
||||||
// Draw foldout + properties
|
|
||||||
label = EditorGUI.BeginProperty(position, label, property);
|
|
||||||
|
|
||||||
// Begin indent block
|
|
||||||
int indent = EditorGUI.indentLevel;
|
|
||||||
EditorGUI.indentLevel = 0;
|
|
||||||
|
|
||||||
object instance = GetTargetObjectOfProperty(property);
|
|
||||||
|
|
||||||
float lineHeight = EditorGUIUtility.singleLineHeight;
|
|
||||||
Rect r = new(position.x, position.y, position.width, lineHeight);
|
|
||||||
if (instance != null) {
|
|
||||||
FieldInfo field = typeof(Neuron).GetField("_outputValue", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
if (field != null) {
|
|
||||||
float3 val = (float3)field.GetValue(instance);
|
|
||||||
EditorGUI.Vector3Field(r, $"Neuron: {label}", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorGUI.indentLevel = indent;
|
|
||||||
EditorGUI.EndProperty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
|
||||||
// height for 1 line
|
|
||||||
return (EditorGUIUtility.singleLineHeight * 1) + (EditorGUIUtility.standardVerticalSpacing * 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object GetTargetObjectOfProperty(SerializedProperty prop) {
|
|
||||||
var path = prop.propertyPath.Replace(".Array.data[", "[");
|
|
||||||
object obj = prop.serializedObject.targetObject;
|
|
||||||
var elements = path.Split('.');
|
|
||||||
foreach (var element in elements) {
|
|
||||||
if (element.Contains("[")) {
|
|
||||||
var elementName = element.Substring(0, element.IndexOf("["));
|
|
||||||
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
|
|
||||||
obj = GetValue_Imp(obj, elementName, index);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obj = GetValue_Imp(obj, element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static object GetValue_Imp(object source, string name) {
|
|
||||||
if (source == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
Type t = source.GetType();
|
|
||||||
FieldInfo f = t.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
if (f != null)
|
|
||||||
return f.GetValue(source);
|
|
||||||
PropertyInfo p = t.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
return p?.GetValue(source, null);
|
|
||||||
}
|
|
||||||
static object GetValue_Imp(object source, string name, int index) {
|
|
||||||
if (GetValue_Imp(source, name) is not IEnumerable enumerable)
|
|
||||||
return null;
|
|
||||||
IEnumerator en = enumerable.GetEnumerator();
|
|
||||||
for (int i = 0; i <= index; i++) {
|
|
||||||
if (!en.MoveNext())
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return en.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: aa0e340763ca6299e93d514b271ae38d
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#if !UNITY_5_6_OR_NEWER
|
//#if !UNITY_5_6_OR_NEWER
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@ -268,4 +268,4 @@ namespace LinearAlgebra.Test {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
//#endif
|
||||||
@ -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) {
|
||||||
Neuron root = brain.defaultOutput;
|
Nucleus 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) {
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 92f34a5e4027a1dc39efd8ce63cf6aba
|
guid: 92f34a5e4027a1dc39efd8ce63cf6aba
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ namespace NanoBrain {
|
|||||||
public Dictionary<int, Cluster> thingClusters = new();
|
public Dictionary<int, Cluster> thingClusters = new();
|
||||||
|
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
public List<Nucleus> nuclei = new();
|
public List<Nucleus> clusterNuclei = 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?.nuclei.Add(this);
|
this.parent?.clusterNuclei.Add(this);
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
_ = this.inputs;
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -72,15 +72,14 @@ namespace NanoBrain {
|
|||||||
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
|
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
|
||||||
this.prefab = prefab;
|
this.prefab = prefab;
|
||||||
this.name = prefab.name;
|
this.name = prefab.name;
|
||||||
if (parent != null)
|
this.clusterPrefab = parent;
|
||||||
this.parent = parent.cluster;
|
|
||||||
|
|
||||||
// if (this.parent.prefab != null)
|
if (this.clusterPrefab != null)
|
||||||
// this.parent.prefab.cluster.nuclei.Add(this);
|
this.clusterPrefab.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
_ = this.inputs;
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -89,13 +88,15 @@ 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.cluster.nuclei.ToArray();
|
Nucleus[] prefabNuclei = this.prefab.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.nuclei.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++) {
|
||||||
@ -109,10 +110,10 @@ 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.prefab != null && synapseNeuron.parent.prefab != 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
|
||||||
Cluster prefabCluster = synapseNeuron.parent;
|
ClusterPrefab prefabCluster = synapseNeuron.clusterPrefab;
|
||||||
Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
Cluster clonedCluster = this.clusterNuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
||||||
if (clonedCluster == null)
|
if (clonedCluster == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ namespace NanoBrain {
|
|||||||
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.nuclei[neuronIx] is not Neuron clonedSender)
|
if (clonedCluster.clusterNuclei[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;
|
||||||
|
|
||||||
@ -140,6 +141,28 @@ namespace NanoBrain {
|
|||||||
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
// Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Copy the receivers, which will also create the synapses
|
||||||
|
// foreach (Nucleus receiver in prefabNeuron.receivers.ToArray()) {
|
||||||
|
// int ix = GetNucleusIndex(prefabNuclei, receiver);
|
||||||
|
// if (ix < 0)
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
// if (clonedNuclei[ix] is not Nucleus clonedReceiver)
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
// // Find the synapse for the weight
|
||||||
|
// float weight = 1;
|
||||||
|
// foreach (Synapse synapse in receiver.synapses) {
|
||||||
|
// // Find the weight for this synapse
|
||||||
|
// if (synapse.neuron == prefabNucleus) {
|
||||||
|
// weight = synapse.weight;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// clonedNeuron.AddReceiver(clonedReceiver, weight);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
@ -156,7 +179,7 @@ namespace NanoBrain {
|
|||||||
Debug.Log($"create {clonedCluster.prefab.name} sibling");
|
Debug.Log($"create {clonedCluster.prefab.name} sibling");
|
||||||
Cluster sibling = new(clonedCluster.prefab, this) {
|
Cluster sibling = new(clonedCluster.prefab, this) {
|
||||||
name = $"{clonedCluster.baseName}: {instanceIx}",
|
name = $"{clonedCluster.baseName}: {instanceIx}",
|
||||||
parent = this.parent,
|
clusterPrefab = this.clusterPrefab,
|
||||||
instanceCount = this.instanceCount,
|
instanceCount = this.instanceCount,
|
||||||
};
|
};
|
||||||
siblings.Add(sibling);
|
siblings.Add(sibling);
|
||||||
@ -166,46 +189,133 @@ namespace NanoBrain {
|
|||||||
foreach (Cluster sibling in siblings)
|
foreach (Cluster sibling in siblings)
|
||||||
sibling.siblingClusters = siblingClusters;
|
sibling.siblingClusters = siblingClusters;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for (int nucleusIx = 0; nucleusIx < clonedNuclei.Length; nucleusIx++) {
|
||||||
|
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
|
||||||
|
if (prefabNucleus is not Cluster prefabCluster)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Ensure that all neurons are computed to initialize bias
|
if (prefabCluster.instanceCount <= 1)
|
||||||
foreach (Nucleus clonedNucleus in clonedNuclei) {
|
continue;
|
||||||
if (clonedNucleus is not Cluster)
|
|
||||||
clonedNucleus.UpdateStateIsolated();
|
Cluster clonedNucleus = clonedNuclei[nucleusIx] as Cluster;
|
||||||
|
if (prefabCluster == prefabCluster.siblingClusters[0]) {
|
||||||
|
// We clone the array only for the first entry
|
||||||
|
//NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length);
|
||||||
|
Cluster[] clonedArray = new Cluster[prefabCluster.siblingClusters.Length];
|
||||||
|
int arrayIx = 0;
|
||||||
|
foreach (Cluster prefabArrayNucleus in prefabCluster.siblingClusters) {
|
||||||
|
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
||||||
|
if (arrayNucleusIx >= 0) {
|
||||||
|
Cluster clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Cluster;
|
||||||
|
clonedArray[arrayIx] = clonedArrayNucleus;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones");
|
||||||
|
}
|
||||||
|
arrayIx++;
|
||||||
|
}
|
||||||
|
clonedNucleus.siblingClusters = clonedArray;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The others will refer to the array created for the first nucleus in the array
|
||||||
|
int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabCluster.siblingClusters[0]);
|
||||||
|
Cluster clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Cluster;
|
||||||
|
clonedNucleus.siblingClusters = clonedFirstNucleus.siblingClusters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void CloneSynapses(Neuron prefabNeuron, Neuron clonedNeuron) {
|
/*
|
||||||
// foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
// Collect the subclusters
|
||||||
// Neuron synapseNeuron = prefabSynapse.neuron;
|
List<Cluster> subClusters = new();
|
||||||
// if (synapseNeuron.parent.prefab != null && synapseNeuron.parent.prefab != this.prefab) {
|
foreach (Nucleus nucleus in prefabNuclei) {
|
||||||
// // Neuron is in another cluster, find the cloned cluster first
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
// ClusterPrefab prefabCluster = synapseNeuron.parent.prefab;
|
Nucleus synapseNucleus = synapse.neuron;
|
||||||
// Cluster clonedCluster = this.nuclei.Find(n => n.name == prefabCluster.name) as Cluster;
|
Cluster subCluster = synapseNucleus.parent;
|
||||||
// if (clonedCluster == null)
|
if (subCluster is null ||
|
||||||
// continue;
|
synapseNucleus.clusterPrefab == this.clusterPrefab) {
|
||||||
|
|
||||||
// // Now find the neuron in that cloned cluster
|
continue;
|
||||||
// int neuronIx = GetNucleusIndex(prefabCluster.cluster.nuclei, prefabSynapse.neuron.name);
|
}
|
||||||
// if (neuronIx < 0)
|
// if (synapseNucleus is not Cluster subCluster)
|
||||||
// // Could not find the neuron in the prefab cluster
|
|
||||||
// continue;
|
|
||||||
// if (clonedCluster.nuclei[neuronIx] is not Neuron clonedSender)
|
|
||||||
// // Could not find the neuron in the cloned cluster
|
|
||||||
// continue;
|
// 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;
|
||||||
|
|
||||||
// clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
if (clonedNuclei[receiverIx] is not Nucleus clonedReceiver)
|
||||||
// //Debug.Log($"Add synapse {clonedCluster.name}.{clonedSender.name} -> {clonedNeuron.name} [{clonedSender.receivers.Count}]");
|
continue;
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// Neuron clonedSender = this.nuclei.Find(n => n.name == prefabSynapse.neuron.name) as Neuron;
|
|
||||||
// // Copy the receivers which will also create the synapse
|
|
||||||
// clonedSender.AddReceiver(clonedNeuron, prefabSynapse.weight);
|
|
||||||
// // Debug.Log($"Add synapse {clonedSender.name} -> {clonedNeuron.name}");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// Find the synapse for the weight
|
||||||
|
float weight = 1;
|
||||||
|
foreach (Synapse synapse in receiver.synapses) {
|
||||||
|
// Find the weight for this synapse
|
||||||
|
if (synapse.neuron == sender) {
|
||||||
|
weight = synapse.weight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clusterInstance.GetNucleus(sender.name) is not Neuron clonedSender)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
clonedSender.AddReceiver(clonedReceiver, weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
|
// if (nucleus is Cluster clonedSubCluster)
|
||||||
|
// RestoreAllExternalReceivers(clonedSubCluster, this.prefab, this);
|
||||||
// }
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloneSynapses(Neuron prefabNeuron, Neuron clonedNeuron) {
|
||||||
|
foreach (Synapse prefabSynapse in prefabNeuron.synapses) {
|
||||||
|
Neuron synapseNeuron = prefabSynapse.neuron;
|
||||||
|
if (synapseNeuron.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>
|
||||||
/// Sort the nuclei in a correct evaluation order
|
/// Sort the nuclei in a correct evaluation order
|
||||||
@ -268,20 +378,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.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
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.nuclei, output);
|
int ix = GetNucleusIndex(this.clusterNuclei, 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.nuclei[ix] is not Neuron clonedOutput)
|
if (clone.clusterNuclei[ix] is not Neuron clonedOutput)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
clonedOutput.AddReceiver(receiver);
|
clonedOutput.AddReceiver(receiver);
|
||||||
@ -296,7 +406,7 @@ namespace NanoBrain {
|
|||||||
// Clusters should not be cloned, but instantiated from the prefab....
|
// Clusters should not be cloned, but instantiated from the prefab....
|
||||||
Cluster clone = new(this.prefab, parent) {
|
Cluster clone = new(this.prefab, parent) {
|
||||||
name = this.name,
|
name = this.name,
|
||||||
parent = this.parent,
|
clusterPrefab = this.clusterPrefab,
|
||||||
instanceCount = this.instanceCount,
|
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.
|
||||||
@ -306,26 +416,23 @@ 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.nuclei.Count; nucleusIx++) {
|
for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) {
|
||||||
Nucleus sourceNucleus = sourceCluster.nuclei[nucleusIx];
|
Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx];
|
||||||
if (sourceNucleus is not Neuron sourceNeuron)
|
if (sourceNucleus is not Neuron sourceNeuron)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sibling.nuclei[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 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) {
|
||||||
if (receiver is not Neuron receiverNeuron)
|
int ix = GetNucleusIndex(clonedParent.clusterNuclei, receiver);
|
||||||
continue;
|
if (ix < 0 || ix >= clonedParent.clusterNuclei.Count)
|
||||||
|
|
||||||
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 receiverNeuron.synapses) {
|
foreach (Synapse synapse in receiver.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;
|
||||||
@ -423,43 +530,42 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public virtual Cluster GetThingCluster() {
|
public virtual Cluster GetThingCluster() {
|
||||||
// Cluster selectedCluster = SelectCluster();
|
Cluster selectedCluster = SelectCluster();
|
||||||
// return selectedCluster;
|
return selectedCluster;
|
||||||
// }
|
}
|
||||||
// public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
|
public virtual Cluster GetThingCluster(int thingId, string thingName = null) {
|
||||||
// if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
||||||
// return cluster;
|
return cluster;
|
||||||
|
|
||||||
// Cluster selectedCluster = SelectCluster();
|
Cluster selectedCluster = SelectCluster();
|
||||||
// selectedCluster.name = baseName + ": " + thingName;
|
selectedCluster.name = baseName + ": " + thingName;
|
||||||
// thingClusters[thingId] = selectedCluster;
|
thingClusters[thingId] = selectedCluster;
|
||||||
// return selectedCluster;
|
return selectedCluster;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// private Cluster SelectCluster() {
|
private Cluster SelectCluster() {
|
||||||
// if (this.siblingClusters == null)
|
if (this.siblingClusters == null)
|
||||||
// return this;
|
return this;
|
||||||
|
|
||||||
// // Find a sleeping cluster
|
// Find a sleeping cluster
|
||||||
// // foreach (Cluster cluster in this.siblingClusters) {
|
foreach (Cluster cluster in this.siblingClusters) {
|
||||||
// // if (cluster.defaultOutput.isSleeping) {
|
if (cluster.defaultOutput.isSleeping) {
|
||||||
// // RemoveThingCluster(cluster);
|
RemoveThingCluster(cluster);
|
||||||
// // return cluster;
|
return cluster;
|
||||||
// // }
|
}
|
||||||
// // }
|
}
|
||||||
|
|
||||||
// // Find longest unused cluster
|
// Otherwise find longest unused cluster
|
||||||
// // Note this uses the default output...
|
Cluster unusedCluster = this.siblingClusters[0];
|
||||||
// Cluster unusedCluster = this.siblingClusters[0];
|
for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
||||||
// for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
||||||
// if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
unusedCluster = this.siblingClusters[ix];
|
||||||
// unusedCluster = this.siblingClusters[ix];
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// RemoveThingCluster(unusedCluster);
|
RemoveThingCluster(unusedCluster);
|
||||||
// return unusedCluster;
|
return unusedCluster;
|
||||||
// }
|
}
|
||||||
|
|
||||||
private void RemoveThingCluster(Cluster cluster) {
|
private void RemoveThingCluster(Cluster cluster) {
|
||||||
List<int> keysToRemove = new();
|
List<int> keysToRemove = new();
|
||||||
@ -497,33 +603,35 @@ namespace NanoBrain {
|
|||||||
get {
|
get {
|
||||||
if (this._inputs == null) {
|
if (this._inputs == null) {
|
||||||
this._inputs = new();
|
this._inputs = new();
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
if (nucleus is not Neuron neuron)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// inputs have no synapses
|
// inputs have no synapses
|
||||||
if (neuron.synapses.Count == 0)
|
if (nucleus.synapses.Count == 0)
|
||||||
this._inputs.Add(nucleus);
|
this._inputs.Add(nucleus);
|
||||||
}
|
}
|
||||||
RefreshComputeOrders();
|
ComputeOrders();
|
||||||
}
|
}
|
||||||
return this._inputs;
|
return this._inputs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<Nucleus, List<Nucleus>> _computeOrders;
|
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
||||||
public Dictionary<Nucleus, List<Nucleus>> computeOrders {
|
private void ComputeOrders() {
|
||||||
get {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
if (_computeOrders == null || _computeOrders.Count == 0) {
|
// if (nucleus is Cluster cluster) {
|
||||||
_computeOrders = new();
|
// List<Synapse> synapses = this.CollectSynapsesTo(cluster);
|
||||||
foreach (Nucleus nucleus in this.nuclei)
|
// foreach (Synapse synapse in synapses) {
|
||||||
_computeOrders[nucleus] = TopologicalSort2(nucleus);
|
// 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}");
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
return _computeOrders;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void RefreshComputeOrders() {
|
|
||||||
this._computeOrders = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
||||||
@ -590,17 +698,17 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus;
|
public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus;
|
||||||
get {
|
get {
|
||||||
if (this.nuclei.Count > 0)
|
if (this.clusterNuclei.Count > 0)
|
||||||
return this.nuclei[0] as Neuron;
|
return this.clusterNuclei[0] as Neuron;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected List<Neuron> _outputs = null;
|
protected List<Neuron> _outputs = null;
|
||||||
public List<Neuron> outputs {
|
public List<Neuron> outputs {
|
||||||
get {
|
get {
|
||||||
if (this._outputs == null || this._outputs.Count == 0) {
|
if (this._outputs == null) {
|
||||||
this._outputs = new();
|
this._outputs = new();
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -613,7 +721,7 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
|
public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) {
|
||||||
foreach (Nucleus receptor in this.nuclei) {
|
foreach (Nucleus receptor in this.clusterNuclei) {
|
||||||
if (receptor is Nucleus nucleus)
|
if (receptor is Nucleus nucleus)
|
||||||
if (nucleus.name == nucleusName) {
|
if (nucleus.name == nucleusName) {
|
||||||
foundNucleus = nucleus;
|
foundNucleus = nucleus;
|
||||||
@ -629,7 +737,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.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
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)..];
|
||||||
@ -641,9 +749,9 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string nucleusName0 = nucleusName + ": 0";
|
string nucleusName0 = nucleusName + ": 0";
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
if (nucleus is Cluster) {
|
if (nucleus is Cluster) { //IReceptor receptor) {
|
||||||
if (nucleus.name == nucleusName || nucleus.name == nucleusName0)
|
if (nucleus.name == nucleusName | nucleus.name == nucleusName0)
|
||||||
return nucleus;
|
return nucleus;
|
||||||
}
|
}
|
||||||
else if (nucleus.name == nucleusName)
|
else if (nucleus.name == nucleusName)
|
||||||
@ -653,70 +761,17 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Neuron GetNeuron(string neuronName) {
|
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
|
||||||
if (nucleus is Neuron neuron && neuron.name == neuronName)
|
|
||||||
return neuron;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Neuron GetNeuron(int thingId, string neuronName, string thingName = null) {
|
|
||||||
if (this.siblingClusters == null || this.siblingClusters.Length <= 1)
|
|
||||||
return this.GetNeuron(neuronName);
|
|
||||||
|
|
||||||
// See if we are already using a cluster for thingId
|
|
||||||
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
|
|
||||||
return cluster.GetNeuron(neuronName);
|
|
||||||
|
|
||||||
// Find the cluster with the lowest value neuron
|
|
||||||
Neuron lowestNeuron = null;
|
|
||||||
foreach (Cluster sibling in this.siblingClusters) {
|
|
||||||
Neuron neuron = sibling.GetNeuron(neuronName);
|
|
||||||
if (lowestNeuron == null || neuron.outputMagnitude < lowestNeuron.outputMagnitude)
|
|
||||||
lowestNeuron = neuron;
|
|
||||||
}
|
|
||||||
Cluster selectedCluster = lowestNeuron.parent;
|
|
||||||
RemoveThingCluster(selectedCluster);
|
|
||||||
selectedCluster.name = baseName + ": " + thingName;
|
|
||||||
thingClusters[thingId] = selectedCluster;
|
|
||||||
return lowestNeuron;
|
|
||||||
/*
|
|
||||||
// Find a sleeping cluster
|
|
||||||
// foreach (Cluster cluster in this.siblingClusters) {
|
|
||||||
// if (cluster.defaultOutput.isSleeping) {
|
|
||||||
// RemoveThingCluster(cluster);
|
|
||||||
// return cluster;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Find longest unused cluster
|
|
||||||
// Note this uses the default output...
|
|
||||||
Cluster unusedCluster = this.siblingClusters[0];
|
|
||||||
for (int ix = 1; ix < this.siblingClusters.Length; ix++) {
|
|
||||||
if (this.siblingClusters[ix].defaultOutput.lastUpdate < unusedCluster.defaultOutput.lastUpdate)
|
|
||||||
unusedCluster = this.siblingClusters[ix];
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveThingCluster(unusedCluster);
|
|
||||||
//return unusedCluster;
|
|
||||||
|
|
||||||
Cluster cluster = GetThingCluster(thingId, thingName);
|
|
||||||
Neuron neuron = cluster?.GetNeuron(neuronName);
|
|
||||||
return neuron;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
public bool DeleteNucleus(Nucleus nucleus) {
|
public bool DeleteNucleus(Nucleus nucleus) {
|
||||||
if (this.nuclei.Contains(nucleus) == false) {
|
if (this.clusterNuclei.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.nuclei.IndexOf(nucleus);
|
int nucleusIx = this.clusterNuclei.IndexOf(nucleus);
|
||||||
this.nuclei.Remove(nucleus);
|
this.clusterNuclei.Remove(nucleus);
|
||||||
//this.prefab.cluster.nuclei.RemoveAt(nucleusIx);
|
this.prefab.nuclei.RemoveAt(nucleusIx);
|
||||||
RefreshOutputs();
|
RefreshOutputs();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -726,7 +781,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.nuclei) {
|
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -734,7 +789,7 @@ namespace NanoBrain {
|
|||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
// Debug.Log($"output {receiver.name}");
|
// Debug.Log($"output {receiver.name}");
|
||||||
// Only add receivers outside this cluster
|
// Only add receivers outside this cluster
|
||||||
if (receiver.parent.prefab != this.prefab) {
|
if (receiver.clusterPrefab != this.prefab) {
|
||||||
if (removeDuplicates == false || receivers.Contains(receiver) == false)
|
if (removeDuplicates == false || receivers.Contains(receiver) == false)
|
||||||
// Debug.Log($" YES");
|
// Debug.Log($" YES");
|
||||||
receivers.Add(receiver);
|
receivers.Add(receiver);
|
||||||
@ -747,13 +802,13 @@ 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.nuclei) {
|
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
// Only add receivers outside this cluster
|
// Only add receivers outside this cluster
|
||||||
if (receiver.parent.prefab != this.prefab)
|
if (receiver.clusterPrefab != this.prefab)
|
||||||
connections.Add((output, receiver));
|
connections.Add((output, receiver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -762,10 +817,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.nuclei) {
|
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||||
if (nucleus is not Neuron neuron)
|
if (nucleus is not Neuron neuron)
|
||||||
continue;
|
continue;
|
||||||
foreach (Synapse synapse in neuron.synapses) {
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
if (synapse.neuron.parent == otherCluster)
|
if (synapse.neuron.parent == otherCluster)
|
||||||
collectedSynapses.Add(synapse);
|
collectedSynapses.Add(synapse);
|
||||||
}
|
}
|
||||||
@ -775,7 +830,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.nuclei) {
|
foreach (Nucleus outputNucleus in this.clusterNuclei) {
|
||||||
if (outputNucleus is not Neuron output)
|
if (outputNucleus is not Neuron output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -787,13 +842,11 @@ namespace NanoBrain {
|
|||||||
Debug.Log($"Check {this.name}.{output.name} receivers");
|
Debug.Log($"Check {this.name}.{output.name} receivers");
|
||||||
Nucleus[] receivers = output.receivers.ToArray();
|
Nucleus[] receivers = output.receivers.ToArray();
|
||||||
foreach (Nucleus receiver in receivers) {
|
foreach (Nucleus receiver in receivers) {
|
||||||
if (receiver.parent.prefab != this.prefab) {
|
if (receiver.clusterPrefab != this.prefab) {
|
||||||
// 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}");
|
||||||
if (receiver is not Neuron receiverNeuron)
|
Synapse synapse = receiver.GetSynapse(output);
|
||||||
continue;
|
|
||||||
Synapse synapse = receiverNeuron.GetSynapse(output);
|
|
||||||
newOutput.AddReceiver(receiver, synapse.weight);
|
newOutput.AddReceiver(receiver, synapse.weight);
|
||||||
output.RemoveReceiver(receiver);
|
output.RemoveReceiver(receiver);
|
||||||
}
|
}
|
||||||
@ -814,45 +867,41 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
||||||
|
//if (startNucleus.trace)
|
||||||
|
Debug.Log($"Update from {startNucleus.name}");
|
||||||
foreach (Nucleus nucleus in computeOrder) {
|
foreach (Nucleus nucleus in computeOrder) {
|
||||||
if (nucleus is not Cluster) {
|
if (nucleus is not Cluster) {
|
||||||
nucleus.UpdateStateIsolated();
|
nucleus.UpdateStateIsolated();
|
||||||
|
//if (startNucleus.trace && nucleus is Neuron neuron)
|
||||||
|
Debug.Log($" {nucleus.name}");
|
||||||
if (nucleus is Neuron neuron) {
|
if (nucleus is Neuron neuron) {
|
||||||
foreach (Nucleus receiver in neuron.receivers) {
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
if (receiver.parent != this) {
|
if (receiver.parent != this) {
|
||||||
//Debug.Log($" External: {receiver.parent.name}.{receiver.name}");
|
Debug.Log($" External: {receiver.parent.name}.{receiver.name}");
|
||||||
receiver.parent.UpdateFromNucleus(receiver);
|
receiver.parent.UpdateFromNucleus(receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//UpdateNuclei();
|
|
||||||
|
// continue in parent
|
||||||
|
//this.parent?.UpdateFromNucleus(this);
|
||||||
|
|
||||||
|
UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
public override void UpdateStateIsolated() {
|
||||||
throw new Exception("Cluster should not be updated!");
|
throw new Exception("Cluster should not be updated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't think this does anything anymore...
|
public override void UpdateNuclei() {
|
||||||
// public override void UpdateNuclei() {
|
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||||
// foreach (Nucleus nucleus in this.nuclei)
|
nucleus.UpdateNuclei();
|
||||||
// nucleus.UpdateNuclei();
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
#endregion Update
|
#endregion Update
|
||||||
|
|
||||||
public void Refresh() {
|
|
||||||
// This should not be needed, but somehow somewhere the parent is changed...
|
|
||||||
foreach (Nucleus nucleus in this.nuclei) {
|
|
||||||
// if (nucleus is not Neuron neuron)
|
|
||||||
// continue;
|
|
||||||
nucleus.parent = this;
|
|
||||||
}
|
|
||||||
RefreshOutputs();
|
|
||||||
RefreshComputeOrders();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f13cdc4a175a9f379a00317ae68d8bea
|
guid: f13cdc4a175a9f379a00317ae68d8bea
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ namespace NanoBrain {
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class MemoryCell : Neuron {
|
public class MemoryCell : Neuron {
|
||||||
|
|
||||||
// public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { }
|
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { }
|
||||||
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
|
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
|
||||||
|
|
||||||
public bool staticMemory = false;
|
public bool staticMemory = false;
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 29633aa3fe5cd9dcc8d886051f45d4d8
|
guid: 29633aa3fe5cd9dcc8d886051f45d4d8
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -23,91 +23,26 @@ 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?.nuclei.Add(this);
|
this.parent?.clusterNuclei.Add(this);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new Neuron in a Cluster Prefab
|
/// Create a new Neuron in a Cluster Prefab
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="prefab">The Cluster Preafb in which the new Neuron should be created</param>
|
/// <param name="prefab">The Cluster Preafb in which the new Neuron should be created</param>
|
||||||
/// <param name="name">The name of the new Neuron</param>
|
/// <param name="name">The name of the new Neuron</param>
|
||||||
// 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.cluster.nuclei.Add(this);
|
this.clusterPrefab.nuclei.Add(this);
|
||||||
// this.clusterPrefab.cluster.RefreshOutputs();
|
this.clusterPrefab.RefreshOutputs();
|
||||||
// }
|
}
|
||||||
// else
|
else
|
||||||
// Debug.LogError("No prefab when adding neuron to prefab");
|
Debug.LogError("No prefab when adding neuron to prefab");
|
||||||
// }
|
}
|
||||||
|
|
||||||
#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.lastUpdate = Time.time;
|
|
||||||
this.parent?.UpdateFromNucleus(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of combinators
|
/// The type of combinators
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -117,6 +52,8 @@ namespace NanoBrain {
|
|||||||
Sum,
|
Sum,
|
||||||
/// Multiply the weighted values
|
/// Multiply the weighted values
|
||||||
Product,
|
Product,
|
||||||
|
/// Take the maximum of all the weighted values
|
||||||
|
Max,
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of combinator used for this Neuron
|
/// The type of combinator used for this Neuron
|
||||||
@ -274,11 +211,16 @@ namespace NanoBrain {
|
|||||||
public float outputSqrMagnitude => _outputValue.sqrMagnitude;
|
public float outputSqrMagnitude => _outputValue.sqrMagnitude;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
public bool isFiring => this.outputMagnitude > 0.5f;
|
public bool isFiring {
|
||||||
|
get {
|
||||||
|
SleepCheck();
|
||||||
|
return this.outputMagnitude > 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
public Action WhenFiring;
|
public Action WhenFiring;
|
||||||
|
|
||||||
public bool persistOutput = false;
|
|
||||||
public virtual bool isSleeping => !persistOutput && (Time.time - this.lastUpdate > this.timeToSleep);
|
public virtual bool isSleeping => Time.time - this.lastUpdate > this.timeToSleep; //this.outputMagnitude == 0;
|
||||||
public void SleepCheck() {
|
public void SleepCheck() {
|
||||||
if (this.isSleeping) {
|
if (this.isSleeping) {
|
||||||
#if UNITY_MATHEMATICS
|
#if UNITY_MATHEMATICS
|
||||||
@ -289,27 +231,20 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
[NonSerialized]
|
||||||
/// Toggle for printing debugging trace data
|
|
||||||
/// </summary>
|
|
||||||
//public bool trace = false;
|
|
||||||
|
|
||||||
//[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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \copydoc NanoBrain::Nucleus::Clone
|
/// \copydoc NanoBrain::Nucleus::Clone
|
||||||
public override Nucleus Clone(ClusterPrefab prefab) {
|
public override Nucleus Clone(ClusterPrefab prefab) {
|
||||||
Neuron clone = new(prefab.cluster, this.name);
|
Neuron clone = new(prefab, this.name);
|
||||||
CloneFields(clone);
|
CloneFields(clone);
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||||
@ -322,8 +257,8 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CloneFields(Neuron clone) {
|
protected virtual void CloneFields(Neuron clone) {
|
||||||
|
clone.clusterPrefab = this.clusterPrefab;
|
||||||
clone.bias = this.bias;
|
clone.bias = this.bias;
|
||||||
clone.persistOutput = this.persistOutput;
|
|
||||||
clone.combinator = this.combinator;
|
clone.combinator = this.combinator;
|
||||||
clone.curve = this.curve;
|
clone.curve = this.curve;
|
||||||
clone.curvePreset = this.curvePreset;
|
clone.curvePreset = this.curvePreset;
|
||||||
@ -333,8 +268,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 is Neuron neuron) {
|
if (nucleus.synapses != null) {
|
||||||
foreach (Synapse synapse in neuron.synapses) {
|
foreach (Synapse synapse in nucleus.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
|
||||||
@ -346,43 +281,45 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (nucleus is Neuron neuron) {
|
||||||
foreach (Nucleus receiver in neuron.receivers) {
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
if (receiver is not Neuron receiverNeuron)
|
if (receiver != null && receiver.synapses != null)
|
||||||
continue;
|
receiver.synapses.RemoveAll(s => s.neuron == nucleus);
|
||||||
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.nuclei) {
|
foreach (Nucleus clusterNucleus in cluster.clusterNuclei) {
|
||||||
if (clusterNucleus is Neuron output) {
|
if (clusterNucleus is Neuron output) {
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
if (receiver is not Neuron receiverNeuron)
|
receiver.synapses.RemoveAll(s => s.neuron == output);
|
||||||
continue;
|
|
||||||
receiverNeuron.synapses.RemoveAll(s => s.neuron == output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (nucleus.parent.prefab != null) {
|
if (nucleus.clusterPrefab != null) {
|
||||||
nucleus.parent.prefab.cluster.nuclei.RemoveAll(n => n == nucleus);
|
nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus);
|
||||||
nucleus.parent.prefab.cluster.RefreshOutputs();
|
nucleus.clusterPrefab.RefreshOutputs();
|
||||||
nucleus.parent.prefab.GarbageCollection();
|
nucleus.clusterPrefab.GarbageCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
public override void UpdateStateIsolated() {
|
||||||
|
CheckSleepingSynapses();
|
||||||
var result = Combinator();
|
var result = Combinator();
|
||||||
this.outputValue = ApplyActivator(result);
|
this.outputValue = Activator(result);
|
||||||
this.lastUpdate = Time.time;
|
this.lastUpdate = Time.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void CheckSleepingSynapses() {
|
protected void CheckSleepingSynapses() {
|
||||||
foreach (Synapse synapse in this.synapses)
|
foreach (Synapse synapse in this.synapses) {
|
||||||
synapse.neuron.SleepCheck();
|
if (synapse.isSleeping) {
|
||||||
|
synapse.neuron.outputValue = Vector3.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Combinator
|
#region Combinator
|
||||||
@ -392,27 +329,42 @@ namespace NanoBrain {
|
|||||||
protected Func<float3> Combinator => combinator switch {
|
protected Func<float3> Combinator => combinator switch {
|
||||||
CombinatorType.Sum => CombinatorSum,
|
CombinatorType.Sum => CombinatorSum,
|
||||||
CombinatorType.Product => CombinatorProduct,
|
CombinatorType.Product => CombinatorProduct,
|
||||||
|
CombinatorType.Max => CombinatorMax,
|
||||||
_ => CombinatorSum
|
_ => CombinatorSum
|
||||||
};
|
};
|
||||||
|
|
||||||
public float3 CombinatorSum() {
|
public float3 CombinatorSum() {
|
||||||
float3 sum = this.bias;
|
float3 sum = this.bias;
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses)
|
||||||
synapse.neuron.SleepCheck();
|
|
||||||
sum += synapse.weight * synapse.neuron.outputValue;
|
sum += synapse.weight * synapse.neuron.outputValue;
|
||||||
}
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float3 CombinatorProduct() {
|
public float3 CombinatorProduct() {
|
||||||
float3 product = this.bias;
|
float3 product = this.bias;
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
synapse.neuron.SleepCheck();
|
|
||||||
product *= synapse.weight * synapse.neuron.outputValue;
|
product *= synapse.weight * synapse.neuron.outputValue;
|
||||||
}
|
}
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float3 CombinatorMax() {
|
||||||
|
float3 max = this.bias;
|
||||||
|
float maxLength = length(max);
|
||||||
|
|
||||||
|
//Applying the weight factors
|
||||||
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
float3 input = synapse.weight * synapse.neuron.outputValue;
|
||||||
|
|
||||||
|
float inputLength = length(input);
|
||||||
|
if (inputLength > maxLength) {
|
||||||
|
max = input;
|
||||||
|
maxLength = inputLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
protected Func<Vector3> Combinator => combinator switch {
|
protected Func<Vector3> Combinator => combinator switch {
|
||||||
@ -461,20 +413,6 @@ namespace NanoBrain {
|
|||||||
|
|
||||||
#if UNITY_MATHEMATICS
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
// This does not allocate memory and seems faster than the solution below
|
|
||||||
float3 ApplyActivator(float3 x) {
|
|
||||||
switch (curvePreset) {
|
|
||||||
case ActivationType.Linear: return ActivatorLinear(x);
|
|
||||||
case ActivationType.Sqrt: return ActivatorSqrt(x);
|
|
||||||
case ActivationType.Power: return ActivatorPower(x);
|
|
||||||
case ActivationType.Reciprocal: return ActivatorReciprocal(x);
|
|
||||||
case ActivationType.Tanh: return ActivatorTanh(x);
|
|
||||||
case ActivationType.Binary: return ActivatorBinary(x);
|
|
||||||
case ActivationType.Normalized: return ActivatorNormalized(x);
|
|
||||||
default: return ActivatorCustom(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Func<float3, float3> Activator => this.curvePreset switch {
|
public Func<float3, float3> Activator => this.curvePreset switch {
|
||||||
ActivationType.Linear => ActivatorLinear,
|
ActivationType.Linear => ActivatorLinear,
|
||||||
ActivationType.Sqrt => ActivatorSqrt,
|
ActivationType.Sqrt => ActivatorSqrt,
|
||||||
@ -586,40 +524,25 @@ namespace NanoBrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||||
if (receiverToAdd is not Neuron receiverNeuron)
|
this._receivers.Add(receiverToAdd);
|
||||||
return;
|
receiverToAdd.AddSynapse(this, weight);
|
||||||
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) {
|
||||||
if (receiverToRemove is not Neuron receiverNeuron)
|
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
||||||
return;
|
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
|
||||||
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);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion Receivers
|
#endregion Receivers
|
||||||
|
|
||||||
/// <summary>
|
public override void ProcessStimulus(Vector3 inputValue) {
|
||||||
/// Process an external stimulus
|
;
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputValue">The value of the stimulus</param>
|
|
||||||
/// <param name="thingId">The id of the thing causing the stimulus</param>
|
|
||||||
/// <param name="thingName">The name of the thing causing the stimulus</param>
|
|
||||||
public virtual void ProcessStimulus(Vector3 inputValue) {
|
|
||||||
this.lastUpdate = Time.time;
|
this.lastUpdate = Time.time;
|
||||||
this.bias = inputValue;
|
this.bias = inputValue;
|
||||||
this.parent?.UpdateFromNucleus(this);
|
this.parent.UpdateFromNucleus(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 750748f3f0e7d472fbf88ab02987074c
|
guid: 750748f3f0e7d472fbf88ab02987074c
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -17,15 +17,11 @@ 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>
|
||||||
// [SerializeReference]
|
[SerializeReference]
|
||||||
// public ClusterPrefab clusterPrefab;
|
public ClusterPrefab clusterPrefab;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cluster instance in which the nucleus is located
|
/// The cluster instance in which the nucleus is located
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -35,7 +31,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
|
||||||
@ -65,60 +61,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>
|
||||||
|
/// 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>
|
|
||||||
// /// 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);
|
||||||
|
}
|
||||||
|
|
||||||
// /// <summary>
|
#endregion Synapses
|
||||||
// /// 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
|
|
||||||
|
|
||||||
#region Update
|
#region Update
|
||||||
|
|
||||||
@ -133,14 +129,23 @@ 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>
|
||||||
|
/// Process an external stimulus
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputValue">The value of the stimulus</param>
|
||||||
|
/// <param name="thingId">The id of the thing causing the stimulus</param>
|
||||||
|
/// <param name="thingName">The name of the thing causing the stimulus</param>
|
||||||
|
public virtual void ProcessStimulus(Vector3 inputValue) { //, int thingId = 0, string thingName = "") {
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Update
|
#endregion Update
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4310eea6ab77628b085387a226c1c386
|
guid: 4310eea6ab77628b085387a226c1c386
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -1,11 +1,2 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 334a58eafccd60cbdb32f719e9e861c6
|
guid: 334a58eafccd60cbdb32f719e9e861c6
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|||||||
@ -8,9 +8,6 @@ namespace NanoBrain {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
[CreateAssetMenu(menuName = "Passer/Cluster")]
|
||||||
public class ClusterPrefab : ScriptableObject {
|
public class ClusterPrefab : ScriptableObject {
|
||||||
|
|
||||||
public Cluster cluster;
|
|
||||||
/*
|
|
||||||
/// The nuclei in this cluster
|
/// The nuclei in this cluster
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
// This list should not include any clusters...
|
// This list should not include any clusters...
|
||||||
@ -63,91 +60,82 @@ namespace NanoBrain {
|
|||||||
this._outputs.Add(nucleus);
|
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) {
|
||||||
return cluster.GetNucleus(nucleusName);
|
foreach (Nucleus nucleus in this.nuclei) {
|
||||||
// foreach (Nucleus nucleus in this.nuclei) {
|
if (nucleus.name == nucleusName)
|
||||||
// if (nucleus.name == nucleusName)
|
return nucleus;
|
||||||
// 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() {
|
||||||
this.cluster.prefab = this;
|
nuclei ??= new List<Nucleus>();
|
||||||
this.cluster.name = this.name;
|
if (nuclei.Count == 0)
|
||||||
this.cluster.nuclei ??= new List<Nucleus>();
|
new Neuron(this, "Output"); // Every cluster should have at least 1 neuron
|
||||||
if (this.cluster.nuclei.Count <= 0)
|
|
||||||
new Neuron(this.cluster, "Output"); // Every cluster should have at least 1 neuron
|
|
||||||
this.cluster.instanceCount = 1;
|
|
||||||
// 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) {
|
||||||
// if (nucleus is null)
|
if (nucleus is null)
|
||||||
// return;
|
return;
|
||||||
|
|
||||||
// if (nucleus.parent != null && nucleus.parent.prefab != this)
|
if (nucleus.parent != null && nucleus.parent.prefab != this)
|
||||||
// visitedNuclei.Add(nucleus.parent);
|
visitedNuclei.Add(nucleus.parent);
|
||||||
// else
|
else
|
||||||
// visitedNuclei.Add(nucleus);
|
visitedNuclei.Add(nucleus);
|
||||||
// if (nucleus is Neuron neuron) {
|
if (nucleus.synapses != null) {
|
||||||
// if (neuron.synapses != null) {
|
HashSet<Synapse> visitedSynapses = new();
|
||||||
// HashSet<Synapse> visitedSynapses = new();
|
foreach (Synapse synapse in nucleus.synapses) {
|
||||||
// foreach (Synapse synapse in neuron.synapses) {
|
if (synapse != null && synapse.neuron != null) {
|
||||||
// if (synapse != null && synapse.neuron != null) {
|
visitedSynapses.Add(synapse);
|
||||||
// visitedSynapses.Add(synapse);
|
if (synapse.neuron is Nucleus synapse_nucleus)
|
||||||
// if (synapse.neuron is Nucleus synapse_nucleus)
|
MarkNuclei(visitedNuclei, synapse_nucleus);
|
||||||
// MarkNuclei(visitedNuclei, synapse_nucleus);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
||||||
// neuron.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
}
|
||||||
// }
|
if (nucleus is Neuron neuron && neuron.receivers != null) {
|
||||||
// if (neuron.receivers != null) {
|
HashSet<Nucleus> visitedReceivers = new();
|
||||||
// HashSet<Nucleus> visitedReceivers = new();
|
foreach (Nucleus receiver in neuron.receivers) {
|
||||||
// foreach (Nucleus receiver in neuron.receivers) {
|
if (receiver != null && receiver != null) {
|
||||||
// if (receiver != null && receiver != null) {
|
visitedReceivers.Add(receiver);
|
||||||
// visitedReceivers.Add(receiver);
|
visitedNuclei.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;
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user