cluster no longer have receivers
This commit is contained in:
parent
a394f582cf
commit
36e73081f9
156
Cluster.cs
156
Cluster.cs
@ -15,11 +15,11 @@ public class Cluster : Nucleus {
|
||||
this.name = prefab.name;
|
||||
|
||||
this.parent = parent;
|
||||
this.parent?.nuclei.Add(this);
|
||||
this.parent?.clusterNuclei.Add(this);
|
||||
|
||||
ClonePrefab();
|
||||
_ = this.inputs;
|
||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
||||
}
|
||||
|
||||
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
|
||||
@ -32,7 +32,7 @@ public class Cluster : Nucleus {
|
||||
|
||||
ClonePrefab();
|
||||
_ = this.inputs;
|
||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||
this.sortedNuclei = TopologicalSort(this.clusterNuclei);
|
||||
}
|
||||
|
||||
private void ClonePrefab() {
|
||||
@ -40,7 +40,7 @@ public class Cluster : Nucleus {
|
||||
// first clone the nuclei without their connections
|
||||
foreach (Nucleus nucleus in this.prefab.nuclei)
|
||||
nucleus.ShallowCloneTo(this);
|
||||
Nucleus[] clonedNuclei = this.nuclei.ToArray();
|
||||
Nucleus[] clonedNuclei = this.clusterNuclei.ToArray();
|
||||
|
||||
// Now clone the connections
|
||||
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
|
||||
@ -50,26 +50,27 @@ public class Cluster : Nucleus {
|
||||
continue;
|
||||
|
||||
// Copy the receivers, which will also create the synapses
|
||||
foreach (Nucleus receiver in prefabNucleus.receivers) {
|
||||
int ix = GetNucleusIndex(prefabNuclei, receiver);
|
||||
if (ix < 0)
|
||||
continue;
|
||||
// Clusters do not have receivers...
|
||||
// foreach (Nucleus receiver in prefabNucleus.receivers) {
|
||||
// int ix = GetNucleusIndex(prefabNuclei, receiver);
|
||||
// if (ix < 0)
|
||||
// continue;
|
||||
|
||||
if (clonedNuclei[ix] is not Nucleus clonedReceiver)
|
||||
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.nucleus == prefabNucleus) {
|
||||
weight = synapse.weight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// // Find the synapse for the weight
|
||||
// float weight = 1;
|
||||
// foreach (Synapse synapse in receiver.synapses) {
|
||||
// // Find the weight for this synapse
|
||||
// if (synapse.nucleus == prefabNucleus) {
|
||||
// weight = synapse.weight;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
clonedReceptor.AddReceiver(clonedReceiver, weight);
|
||||
}
|
||||
// clonedReceptor.AddReceiver(clonedReceiver, weight);
|
||||
// }
|
||||
}
|
||||
|
||||
// Copy nucleus arrays
|
||||
@ -116,8 +117,10 @@ public class Cluster : Nucleus {
|
||||
|
||||
// Calculate in-degrees
|
||||
foreach (Nucleus node in nodes) {
|
||||
foreach (Nucleus receiver in node.receivers)
|
||||
inDegree[receiver]++;
|
||||
if (node is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers)
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
}
|
||||
|
||||
Queue<Nucleus> queue = new();
|
||||
@ -132,10 +135,12 @@ public class Cluster : Nucleus {
|
||||
Nucleus current = queue.Dequeue();
|
||||
sortedOrder.Add(current); // Process the node
|
||||
|
||||
foreach (Nucleus receiver in current.receivers) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,9 +158,9 @@ public class Cluster : Nucleus {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
foreach (Nucleus receiver in this.receivers) {
|
||||
clone.AddReceiver(receiver);
|
||||
}
|
||||
// foreach (Nucleus receiver in this.receivers) {
|
||||
// clone.AddReceiver(receiver);
|
||||
// }
|
||||
return clone;
|
||||
}
|
||||
|
||||
@ -181,7 +186,7 @@ public class Cluster : Nucleus {
|
||||
|
||||
|
||||
[SerializeReference]
|
||||
public List<Nucleus> nuclei = new();
|
||||
public List<Nucleus> clusterNuclei = new();
|
||||
// the nuclei sorted using topological sorting
|
||||
// to ensure that the cluster is computer in the right order
|
||||
public List<Nucleus> sortedNuclei;
|
||||
@ -192,7 +197,7 @@ public class Cluster : Nucleus {
|
||||
get {
|
||||
if (this._inputs == null) {
|
||||
this._inputs = new();
|
||||
foreach (Nucleus nucleus in this.nuclei) {
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
// inputs have no synapses
|
||||
if (nucleus.synapses.Count == 0)
|
||||
this._inputs.Add(nucleus);
|
||||
@ -215,7 +220,7 @@ public class Cluster : Nucleus {
|
||||
HashSet<Nucleus> visited = new HashSet<Nucleus>();
|
||||
|
||||
// Initialize in-degrees and mark all nodes as unvisited
|
||||
foreach (Nucleus node in this.nuclei) {
|
||||
foreach (Nucleus node in this.clusterNuclei) {
|
||||
inDegree[node] = 0;
|
||||
}
|
||||
|
||||
@ -226,12 +231,14 @@ public class Cluster : Nucleus {
|
||||
|
||||
while (queue.Count > 0) {
|
||||
Nucleus current = queue.Dequeue();
|
||||
foreach (Nucleus receiver in current.receivers) {
|
||||
if (!visited.Contains(receiver)) {
|
||||
visited.Add(receiver);
|
||||
queue.Enqueue(receiver);
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (!visited.Contains(receiver)) {
|
||||
visited.Add(receiver);
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,11 +255,13 @@ public class Cluster : Nucleus {
|
||||
Nucleus current = queue.Dequeue();
|
||||
sortedOrder.Add(current); // Process the node
|
||||
|
||||
foreach (Nucleus receiver in current.receivers) {
|
||||
if (visited.Contains(receiver)) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (visited.Contains(receiver)) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,13 +275,15 @@ public class Cluster : Nucleus {
|
||||
|
||||
private List<Nucleus> TopologicalSort3(Nucleus startNode) {
|
||||
Dictionary<Nucleus, int> inDegree = new();
|
||||
foreach (Nucleus node in this.nuclei)
|
||||
foreach (Nucleus node in this.clusterNuclei)
|
||||
inDegree[node] = 0; // Initialize in-degree to zero
|
||||
|
||||
// Calculate in-degrees
|
||||
foreach (Nucleus node in this.nuclei) {
|
||||
foreach (Nucleus receiver in node.receivers)
|
||||
inDegree[receiver]++;
|
||||
foreach (Nucleus node in this.clusterNuclei) {
|
||||
if (node is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers)
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
}
|
||||
|
||||
Queue<Nucleus> queue = new();
|
||||
@ -283,10 +294,12 @@ public class Cluster : Nucleus {
|
||||
Nucleus current = queue.Dequeue();
|
||||
sortedOrder.Add(current); // Process the node
|
||||
|
||||
foreach (Nucleus receiver in current.receivers) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,22 +311,21 @@ public class Cluster : Nucleus {
|
||||
return sortedOrder;
|
||||
}
|
||||
|
||||
public virtual Nucleus output {//=> this.nuclei[0] as Nucleus;
|
||||
public virtual Neuron defaultOutput {//=> this.nuclei[0] as Nucleus;
|
||||
get {
|
||||
if (this.nuclei.Count > 0)
|
||||
return this.nuclei[0];
|
||||
if (this.clusterNuclei.Count > 0)
|
||||
return this.clusterNuclei[0] as Neuron;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public List<Nucleus> _outputs = null;
|
||||
public List<Nucleus> outputs {
|
||||
private List<Neuron> _outputs = null;
|
||||
public List<Neuron> outputs {
|
||||
get {
|
||||
if (this._outputs == null) {
|
||||
this._outputs = new();
|
||||
foreach (Nucleus nucleus in this.nuclei) {
|
||||
// outputs have not receivers
|
||||
if (nucleus.receivers.Count == 0)
|
||||
this._outputs.Add(nucleus);
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is Neuron neuron) // && neuron.receivers.Count == 0)
|
||||
this._outputs.Add(neuron);
|
||||
}
|
||||
}
|
||||
return this._outputs;
|
||||
@ -321,7 +333,7 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
|
||||
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 (nucleus.name == nucleusName) {
|
||||
foundNucleus = nucleus;
|
||||
@ -333,7 +345,7 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
|
||||
public Nucleus GetNucleus(string nucleusName) {
|
||||
foreach (Nucleus nucleus in this.nuclei) {
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus.name == nucleusName)
|
||||
return nucleus;
|
||||
}
|
||||
@ -341,7 +353,7 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
|
||||
public Receptor GetReceptor(string receptorName) {
|
||||
foreach (Nucleus nucleus in this.nuclei) {
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is Receptor receptor)
|
||||
if (receptor.name == receptorName)
|
||||
return receptor;
|
||||
@ -349,6 +361,18 @@ public class Cluster : Nucleus {
|
||||
return null;
|
||||
}
|
||||
|
||||
#region Receivers
|
||||
|
||||
public virtual List<Nucleus> CollectReceivers() {
|
||||
List<Nucleus> receivers = new();
|
||||
foreach (Neuron output in this.outputs) {
|
||||
receivers.AddRange(output.receivers);
|
||||
}
|
||||
return receivers;
|
||||
}
|
||||
|
||||
#endregion Receivers
|
||||
|
||||
#region Update
|
||||
|
||||
public void UpdateFromNucleus(Nucleus startNucleus) {
|
||||
@ -363,7 +387,7 @@ public class Cluster : Nucleus {
|
||||
Debug.Log($" {nucleus.name} = {nucleus.outputValue}");
|
||||
}
|
||||
|
||||
this.outputValue = this.output.outputValue;
|
||||
this.outputValue = this.defaultOutput.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
@ -383,14 +407,14 @@ public class Cluster : Nucleus {
|
||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
nucleus.UpdateStateIsolated();
|
||||
|
||||
this.outputValue = this.output.outputValue;
|
||||
this.outputValue = this.defaultOutput.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
}
|
||||
|
||||
public override void UpdateNuclei() {
|
||||
foreach (Nucleus nucleus in this.nuclei)
|
||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||
nucleus.UpdateNuclei();
|
||||
}
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ public class ClusterPrefab : ScriptableObject {
|
||||
public void RefreshOutputs() {
|
||||
this._outputs = new();
|
||||
foreach (Nucleus nucleus in this.nuclei) {
|
||||
if (nucleus.receivers.Count == 0)
|
||||
if (nucleus is Neuron neuron && neuron.receivers.Count == 0)
|
||||
this._outputs.Add(nucleus);
|
||||
}
|
||||
}
|
||||
@ -85,15 +85,15 @@ public class ClusterPrefab : ScriptableObject {
|
||||
}
|
||||
nucleus.synapses.RemoveAll(synapse => visitedSynapses.Contains(synapse) == false);
|
||||
}
|
||||
if (nucleus.receivers != null) {
|
||||
if (nucleus is Neuron neuron && neuron.receivers != null) {
|
||||
HashSet<Nucleus> visitedReceivers = new();
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (receiver != null && receiver != null) {
|
||||
visitedReceivers.Add(receiver);
|
||||
visitedNuclei.Add(receiver);
|
||||
}
|
||||
}
|
||||
nucleus.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
||||
neuron.receivers.RemoveAll(receiver => visitedReceivers.Contains(receiver) == false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[Serializable]
|
||||
public class ClusterReceptor : Cluster {
|
||||
public class ClusterReceptor : Cluster, IReceptor {
|
||||
public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) {
|
||||
this.name = name;
|
||||
this.array ??= new NucleusArray(this);
|
||||
@ -32,9 +32,9 @@ public class ClusterReceptor : Cluster {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
foreach (Nucleus receiver in this.receivers) {
|
||||
clone.AddReceiver(receiver);
|
||||
}
|
||||
// foreach (Nucleus receiver in this.receivers) {
|
||||
// clone.AddReceiver(receiver);
|
||||
// }
|
||||
return clone;
|
||||
}
|
||||
|
||||
@ -48,21 +48,22 @@ public class ClusterReceptor : Cluster {
|
||||
#region Receivers
|
||||
|
||||
private List<Nucleus> _clusterReceivers = null;
|
||||
public override List<Nucleus> receivers {
|
||||
get {
|
||||
if (_clusterReceivers == null || _clusterReceivers.Count == 0) {
|
||||
_clusterReceivers = new();
|
||||
foreach (Nucleus output in this.nuclei) {
|
||||
_clusterReceivers.AddRange(output.receivers);
|
||||
}
|
||||
}
|
||||
return _clusterReceivers;
|
||||
}
|
||||
}
|
||||
public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) {
|
||||
this.output.receivers.Add(receivingNucleus);
|
||||
receivingNucleus.AddSynapse(this.output, weight);
|
||||
}
|
||||
// public override List<Nucleus> receivers {
|
||||
// get {
|
||||
// if (_clusterReceivers == null || _clusterReceivers.Count == 0) {
|
||||
// _clusterReceivers = new();
|
||||
// foreach (Nucleus output in this.clusterNuclei) {
|
||||
// _clusterReceivers.AddRange(output.receivers);
|
||||
// }
|
||||
// }
|
||||
// return _clusterReceivers;
|
||||
// }
|
||||
// }
|
||||
// public override void AddReceiver(Nucleus receivingNucleus, float weight = 1) {
|
||||
// string nucleusName = this.
|
||||
// this.output.receivers.Add(receivingNucleus);
|
||||
// receivingNucleus.AddSynapse(this.output, weight);
|
||||
// }
|
||||
|
||||
#endregion Receivers
|
||||
|
||||
@ -72,7 +73,7 @@ public class ClusterReceptor : Cluster {
|
||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
nucleus.UpdateStateIsolated();
|
||||
|
||||
this.outputValue = this.output.outputValue;
|
||||
this.outputValue = this.defaultOutput.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
@ -85,7 +86,7 @@ public class ClusterReceptor : Cluster {
|
||||
this.parent.UpdateFromNucleus(this);
|
||||
}
|
||||
|
||||
foreach (Nucleus nucleus in this.nuclei)
|
||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||
nucleus.UpdateNuclei();
|
||||
}
|
||||
|
||||
|
||||
@ -74,9 +74,11 @@ public class BrainEditorWindow : EditorWindow {
|
||||
int ix = 0;
|
||||
foreach (Nucleus nucleus in prefab.nuclei) {
|
||||
nodes.Add(new DagNode() { id = ix, title = nucleus.name });
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
int receiverIx = prefab.GetNucleusIndex(receiver);
|
||||
edges.Add(new DagEdge() { fromId = ix, toId = receiverIx });
|
||||
if (nucleus is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
int receiverIx = prefab.GetNucleusIndex(receiver);
|
||||
edges.Add(new DagEdge() { fromId = ix, toId = receiverIx });
|
||||
}
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
@ -191,9 +193,9 @@ public class BrainEditorWindow : EditorWindow {
|
||||
Handles.DrawSolidDisc(n.position, Vector3.forward, n.radius);
|
||||
|
||||
if (GetIncomingEdges(n).Count == 0)
|
||||
DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f/zoom, 12f/zoom, Color.white);
|
||||
DrawArrowHead(n.position - new Vector2(n.radius + 10, 0), n.position - new Vector2(n.radius + 5, 0), 10f / zoom, 12f / zoom, Color.white);
|
||||
if (GetOutgoingEdges(n).Count == 0)
|
||||
DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f/zoom, 12f/zoom, Color.white);
|
||||
DrawArrowHead(n.position + new Vector2(n.radius + 10, 0), n.position + new Vector2(n.radius + 15, 0), 10f / zoom, 12f / zoom, Color.white);
|
||||
|
||||
Handles.color = Color.white;
|
||||
GUIStyle style = new(EditorStyles.label) {
|
||||
|
||||
@ -195,8 +195,8 @@ public class ClusterInspector : Editor {
|
||||
return;
|
||||
NeuroidLayer currentLayer = new() { ix = layerIx };
|
||||
|
||||
if (selectedNucleus.receivers != null) {
|
||||
foreach (Nucleus receiver in selectedNucleus.receivers) {
|
||||
if (selectedNucleus is Neuron selectedNeuron && selectedNeuron.receivers != null) {
|
||||
foreach (Nucleus receiver in selectedNeuron.receivers) {
|
||||
Nucleus outputNeuroid = receiver;
|
||||
if (outputNeuroid != null) {
|
||||
AddToLayer(currentLayer, outputNeuroid);
|
||||
@ -357,12 +357,20 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
|
||||
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||
int nodeCount = nucleus.receivers.Count();
|
||||
List<Nucleus> receivers = null;
|
||||
if (nucleus is Neuron neuron)
|
||||
receivers = neuron.receivers;
|
||||
else if (nucleus is Cluster cluster)
|
||||
receivers = cluster.CollectReceivers();
|
||||
else
|
||||
return;
|
||||
|
||||
int nodeCount = receivers.Count(); //neuron != null ? neuron.receivers.Count() : 1;
|
||||
|
||||
// Determine the maximum value in this layer
|
||||
// This is used to 'scale' the output value colors of the nuclei
|
||||
float maxValue = 0;
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
foreach (Nucleus receiver in receivers) {
|
||||
if (receiver is Neuron neuroid) {
|
||||
float value = length(neuroid.outputValue);
|
||||
if (value > maxValue)
|
||||
@ -376,7 +384,7 @@ public class ClusterInspector : Editor {
|
||||
|
||||
int row = 0;
|
||||
List<NucleusArray> drawnArrays = new();
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
foreach (Nucleus receiver in receivers) {
|
||||
if (receiver is Receptor receptor) {
|
||||
if (drawnArrays.Contains(receptor.array))
|
||||
continue;
|
||||
@ -409,7 +417,8 @@ public class ClusterInspector : Editor {
|
||||
if (drawnArrays.Contains(receptor.array))
|
||||
continue;
|
||||
drawnArrays.Add(receptor.array);
|
||||
} else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
}
|
||||
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
if (drawnArrays.Contains(clusterReceptor.array))
|
||||
continue;
|
||||
drawnArrays.Add(clusterReceptor.array);
|
||||
@ -432,7 +441,8 @@ public class ClusterInspector : Editor {
|
||||
if (drawnArrays.Contains(neuron.array))
|
||||
continue;
|
||||
drawnArrays.Add(neuron.array);
|
||||
} else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
}
|
||||
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
if (drawnArrays.Contains(clusterReceptor.array))
|
||||
continue;
|
||||
drawnArrays.Add(clusterReceptor.array);
|
||||
@ -731,56 +741,61 @@ public class ClusterInspector : Editor {
|
||||
if (this.currentNucleus.synapses.Count > 0) {
|
||||
Synapse[] synapses = this.currentNucleus.synapses.ToArray();
|
||||
foreach (Synapse synapse in synapses) {
|
||||
if (synapse.nucleus != null) {
|
||||
if (array != null) {
|
||||
if (array.nuclei.Contains(synapse.nucleus))
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (synapse.nucleus is Receptor receptor2 && receptor2.array != null && receptor2.array.nuclei.Length > 1)
|
||||
array = receptor2.array;
|
||||
}
|
||||
if (synapse.nucleus == null)
|
||||
continue;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (Application.isPlaying) {
|
||||
Vector3 value = synapse.nucleus.outputValue * synapse.weight;
|
||||
GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString());
|
||||
EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue));
|
||||
}
|
||||
else {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) {
|
||||
GUIStyle labelStyle = new(GUI.skin.label);
|
||||
float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x;
|
||||
EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
||||
string[] options = synapse.nucleus.parent.nuclei.Select(n => n.name).ToArray();
|
||||
int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name);
|
||||
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
|
||||
if (newIndex != selectedIndex) {
|
||||
ChangeSynapse(synapse, synapse.nucleus.parent.nuclei[newIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
EditorGUILayout.LabelField(synapse.nucleus.name);
|
||||
if (GUILayout.Button("Disconnect")) {
|
||||
synapse.nucleus.RemoveReceiver(this.currentNucleus);
|
||||
this.prefab.GarbageCollection();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
||||
EditorGUI.indentLevel--;
|
||||
if (array != null) {
|
||||
if (array.nuclei.Contains(synapse.nucleus))
|
||||
continue;
|
||||
if (array.nuclei.Contains(synapse.nucleus.parent))
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (synapse.nucleus.parent is ClusterReceptor clusterReceptor)
|
||||
array = clusterReceptor.array;
|
||||
else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1)
|
||||
array = receptor2.array;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (Application.isPlaying) {
|
||||
Vector3 value = synapse.nucleus.outputValue * synapse.weight;
|
||||
GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString());
|
||||
EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue));
|
||||
}
|
||||
else {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) {
|
||||
GUIStyle labelStyle = new(GUI.skin.label);
|
||||
float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x;
|
||||
EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
||||
string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray();
|
||||
int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name);
|
||||
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
|
||||
if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron)
|
||||
ChangeSynapse(synapse, newNeuron);
|
||||
}
|
||||
else
|
||||
EditorGUILayout.LabelField(synapse.nucleus.name);
|
||||
if (GUILayout.Button("Disconnect") && synapse.nucleus is Neuron synapseNeuron) {
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
this.prefab.GarbageCollection();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
}
|
||||
|
||||
// Activation
|
||||
|
||||
EditorGUILayout.Space();
|
||||
@ -811,7 +826,7 @@ public class ClusterInspector : Editor {
|
||||
|
||||
|
||||
if (GUILayout.Button("Delete this neuron"))
|
||||
DeleteNeuron(this.currentNucleus);
|
||||
DeleteNucleus(this.currentNucleus);
|
||||
|
||||
if (this.currentNucleus is Cluster subCluster) {
|
||||
if (GUILayout.Button("Edit Cluster"))
|
||||
@ -934,10 +949,10 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
|
||||
protected virtual void AddReceptorArrayInput(Nucleus nucleus) {
|
||||
ReceptorArray newReceptor = new(this.prefab, "New Receptor");
|
||||
newReceptor.AddReceiver(nucleus);
|
||||
this.currentNucleus = newReceptor;
|
||||
BuildLayers();
|
||||
// ReceptorArray newReceptor = new(this.prefab, "New Receptor");
|
||||
// newReceptor.AddReceiver(nucleus);
|
||||
// this.currentNucleus = newReceptor;
|
||||
// BuildLayers();
|
||||
}
|
||||
|
||||
protected virtual void AddClusterReceptorInput(Nucleus nucleus) {
|
||||
@ -946,12 +961,12 @@ public class ClusterInspector : Editor {
|
||||
|
||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) {
|
||||
Cluster subclusterInstance = new(prefab, this.prefab);
|
||||
subclusterInstance.AddReceiver(nucleus);
|
||||
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||
}
|
||||
|
||||
private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
||||
ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name);
|
||||
clusterInstance.AddReceiver(nucleus);
|
||||
clusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||
}
|
||||
|
||||
private void EditCluster(Cluster subCluster) {
|
||||
@ -962,7 +977,7 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
|
||||
// Connect to another nucleus in the same cluster
|
||||
protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleus) {
|
||||
protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) {
|
||||
if (cluster == null)
|
||||
return false;
|
||||
|
||||
@ -980,19 +995,25 @@ public class ClusterInspector : Editor {
|
||||
if (selectedIndex < 0)
|
||||
return false;
|
||||
|
||||
Nucleus receptor = nuclei.ElementAt(selectedIndex);
|
||||
receptor.AddReceiver(this.currentNucleus);
|
||||
Nucleus nucleus = nuclei.ElementAt(selectedIndex);
|
||||
if (nucleus is Neuron neuron)
|
||||
neuron.AddReceiver(this.currentNucleus);
|
||||
else if (nucleus is Cluster subCluster)
|
||||
subCluster.defaultOutput.AddReceiver(this.currentNucleus);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void DeleteNeuron(Nucleus nucleus) {
|
||||
protected virtual void DeleteNucleus(Nucleus nucleus) {
|
||||
if (nucleus == null)
|
||||
return;
|
||||
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
if (receiver != null) {
|
||||
this.currentNucleus = receiver;
|
||||
break;
|
||||
if (nucleus is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (receiver != null) {
|
||||
this.currentNucleus = receiver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.prefab.nuclei.Remove(nucleus);
|
||||
@ -1021,9 +1042,17 @@ public class ClusterInspector : Editor {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void ChangeSynapse(Synapse synapse, Nucleus newNucleus) {
|
||||
synapse.nucleus.RemoveReceiver(this.currentNucleus);
|
||||
newNucleus.AddReceiver(this.currentNucleus);
|
||||
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
||||
Neuron synapseNeuron = synapse.nucleus as Neuron;
|
||||
if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
|
||||
// it is a neuron in a subcluster
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
newNucleus.AddReceiver(this.currentNucleus);
|
||||
}
|
||||
else {
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
newNucleus.AddReceiver(this.currentNucleus);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DisconnectNucleus(Neuron nucleus) {
|
||||
@ -1032,10 +1061,10 @@ public class ClusterInspector : Editor {
|
||||
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray();
|
||||
int selectedIndex = -1;
|
||||
selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names);
|
||||
//if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.brain.perceptei.Count) {
|
||||
if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) {
|
||||
Synapse synapse = this.currentNucleus.synapses[selectedIndex];
|
||||
synapse.nucleus.RemoveReceiver(this.currentNucleus);
|
||||
Neuron synapseNeuron = synapse.nucleus as Neuron;
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ public class NanoBrainComponent_Editor : Editor {
|
||||
root.Add(brainField);
|
||||
}
|
||||
|
||||
ClusterInspector.CreateInspector(root, brain.prefab, brain.output, component.gameObject);
|
||||
ClusterInspector.CreateInspector(root, brain.prefab, brain.defaultOutput, component.gameObject);
|
||||
|
||||
if (Application.isPlaying == false)
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
5
IReceptor.cs
Normal file
5
IReceptor.cs
Normal file
@ -0,0 +1,5 @@
|
||||
public interface IReceptor {
|
||||
public NucleusArray array {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
2
IReceptor.cs.meta
Normal file
2
IReceptor.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f052292ad16bb53a3c07aa1694c705
|
||||
@ -18,7 +18,7 @@ public class NanoBrain : MonoBehaviour {
|
||||
}
|
||||
|
||||
public static void UpdateWeight(Cluster brain, string name, float weight) {
|
||||
Nucleus root = brain.output;
|
||||
Nucleus root = brain.defaultOutput;
|
||||
foreach (Synapse synapse in root.synapses) {
|
||||
if (synapse.nucleus.name == name) {
|
||||
if (synapse.weight != weight) {
|
||||
|
||||
54
Neuron.cs
54
Neuron.cs
@ -12,7 +12,7 @@ public class Neuron : Nucleus {
|
||||
public Neuron(Cluster parent, string name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.parent?.nuclei.Add(this);
|
||||
this.parent?.clusterNuclei.Add(this);
|
||||
}
|
||||
public Neuron(ClusterPrefab prefab, string name) {
|
||||
this.clusterPrefab = prefab;
|
||||
@ -25,7 +25,6 @@ public class Neuron : Nucleus {
|
||||
|
||||
#region Serialization
|
||||
|
||||
//public Type type = Type.Neuron;
|
||||
public enum CombinatorType {
|
||||
Sum,
|
||||
Product,
|
||||
@ -160,11 +159,14 @@ public class Neuron : Nucleus {
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Nucleus receiver in nucleus.receivers) {
|
||||
if (receiver != null && receiver.synapses != null)
|
||||
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||
if (nucleus is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (receiver != null && receiver.synapses != null)
|
||||
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nucleus.clusterPrefab != null) {
|
||||
nucleus.clusterPrefab.nuclei.RemoveAll(n => n == nucleus);
|
||||
nucleus.clusterPrefab.GarbageCollection();
|
||||
@ -259,6 +261,48 @@ public class Neuron : Nucleus {
|
||||
|
||||
#endregion Activator
|
||||
|
||||
#region Receivers
|
||||
|
||||
[SerializeReference]
|
||||
private List<Nucleus> _receivers = new();
|
||||
public virtual List<Nucleus> receivers {
|
||||
get { return _receivers; }
|
||||
set { _receivers = value; }
|
||||
}
|
||||
|
||||
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||
if (this is IReceptor receptor) {
|
||||
foreach (Nucleus element in receptor.array.nuclei) {
|
||||
if (element is Neuron neuron) {
|
||||
neuron._receivers.Add(receiverToAdd);
|
||||
receiverToAdd.AddSynapse(element, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._receivers.Add(receiverToAdd);
|
||||
receiverToAdd.AddSynapse(this, weight);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
|
||||
if (this is IReceptor receptor) {
|
||||
foreach (Nucleus element in receptor.array.nuclei) {
|
||||
if (element is Neuron neuron) {
|
||||
neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion Receivers
|
||||
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) {
|
||||
this.stale = 0;
|
||||
this.bias = inputValue;
|
||||
|
||||
25
Nucleus.cs
25
Nucleus.cs
@ -17,7 +17,6 @@ public abstract class Nucleus {
|
||||
public virtual float3 outputValue {
|
||||
get { return _outputValue; }
|
||||
set {
|
||||
//this.stale = 0;
|
||||
_outputValue = value;
|
||||
if (this.isFiring)
|
||||
WhenFiring?.Invoke();
|
||||
@ -68,29 +67,13 @@ public abstract class Nucleus {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RemoveSynapse(Nucleus sendingNucleus) {
|
||||
this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus);
|
||||
}
|
||||
|
||||
#endregion Synapses
|
||||
|
||||
#region Receivers
|
||||
|
||||
[SerializeReference]
|
||||
private List<Nucleus> _receivers = new();
|
||||
public virtual List<Nucleus> receivers {
|
||||
get { return _receivers; }
|
||||
set { _receivers = value; }
|
||||
}
|
||||
|
||||
public virtual void AddReceiver(Nucleus receivingNucleus, float weight = 1) {
|
||||
this._receivers.Add(receivingNucleus);
|
||||
receivingNucleus.AddSynapse(this, weight);
|
||||
}
|
||||
|
||||
public void RemoveReceiver(Nucleus receiverNucleus) {
|
||||
this._receivers.RemoveAll(receiver => receiver == receiverNucleus);
|
||||
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
|
||||
}
|
||||
|
||||
|
||||
#endregion Receivers
|
||||
|
||||
#region Update
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[System.Serializable]
|
||||
public class Receptor : Neuron {
|
||||
public class Receptor : Neuron, IReceptor {
|
||||
public Receptor(Cluster parent, string name) : base(parent, name) { }
|
||||
public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { }
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public class ReceptorArray : Nucleus {
|
||||
this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") {
|
||||
receptor = this
|
||||
};
|
||||
this.parent?.nuclei.Add(this);
|
||||
this.parent?.clusterNuclei.Add(this);
|
||||
}
|
||||
public ReceptorArray(ClusterPrefab prefab, string name) {
|
||||
this.clusterPrefab = prefab;
|
||||
@ -89,9 +89,9 @@ public class ReceptorArray : Nucleus {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
foreach (Nucleus receiver in this.receivers) {
|
||||
clone.AddReceiver(receiver);
|
||||
}
|
||||
// foreach (Nucleus receiver in this.receivers) {
|
||||
// clone.AddReceiver(receiver);
|
||||
// }
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user