Add topological evaluation order
This commit is contained in:
parent
9ae3607911
commit
b4f8e5a4d8
88
Cluster.cs
88
Cluster.cs
@ -15,41 +15,45 @@ public class Cluster : INucleus {
|
|||||||
set => _name = value;
|
set => _name = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClusterPrefab storedPrefab;
|
#region Init
|
||||||
|
|
||||||
|
public Cluster(ClusterPrefab prefab, Cluster parent) {
|
||||||
|
this.prefab = prefab;
|
||||||
|
this.name = prefab.name;
|
||||||
|
|
||||||
public Cluster(Cluster parent, ClusterPrefab realPrefab) {
|
|
||||||
this.storedPrefab = realPrefab;
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.parent?.nuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cluster(ClusterPrefab realPrefab) {
|
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
|
||||||
this.storedPrefab = realPrefab;
|
this.prefab = prefab;
|
||||||
this.name = realPrefab.name;
|
this.name = prefab.name;
|
||||||
this.cluster = null;
|
|
||||||
if (this.cluster != null)
|
|
||||||
this.cluster.nuclei.Add(this);
|
|
||||||
|
|
||||||
ClonePrefab();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
|
|
||||||
this.storedPrefab = realPrefab;
|
|
||||||
//this.prefab = realPrefab.Clone();
|
|
||||||
this.name = realPrefab.name;
|
|
||||||
this.cluster = parent;
|
this.cluster = parent;
|
||||||
|
|
||||||
if (this.cluster != null)
|
if (this.cluster != null)
|
||||||
this.cluster.nuclei.Add(this);
|
this.cluster.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
|
||||||
|
// this.prefab = realPrefab;
|
||||||
|
// this.name = realPrefab.name;
|
||||||
|
// this.cluster = parent;
|
||||||
|
// if (this.cluster != null)
|
||||||
|
// this.cluster.nuclei.Add(this);
|
||||||
|
|
||||||
|
// ClonePrefab();
|
||||||
|
// }
|
||||||
|
|
||||||
private void ClonePrefab() {
|
private void ClonePrefab() {
|
||||||
IReceptor[] nucleiArray = this.storedPrefab.nuclei.ToArray();
|
IReceptor[] nucleiArray = this.prefab.nuclei.ToArray();
|
||||||
// first clone the nuclei without their connections
|
// first clone the nuclei without their connections
|
||||||
foreach (IReceptor nucleus in this.storedPrefab.nuclei)
|
foreach (IReceptor nucleus in this.prefab.nuclei)
|
||||||
nucleus.ShallowCloneTo(this);
|
nucleus.ShallowCloneTo(this);
|
||||||
IReceptor[] clonedNuclei = this.nuclei.ToArray();
|
IReceptor[] clonedNuclei = this.nuclei.ToArray();
|
||||||
|
|
||||||
@ -83,6 +87,43 @@ public class Cluster : INucleus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the nuclei in a correct evaluation order
|
||||||
|
private List<IReceptor> TopologicalSort(List<IReceptor> nodes) {
|
||||||
|
Dictionary<IReceptor, int> inDegree = new();
|
||||||
|
foreach (IReceptor node in nodes)
|
||||||
|
inDegree[node] = 0; // Initialize in-degree to zero
|
||||||
|
|
||||||
|
// Calculate in-degrees
|
||||||
|
foreach (IReceptor node in nodes) {
|
||||||
|
foreach (INucleus receiver in node.receivers)
|
||||||
|
inDegree[receiver]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue<IReceptor> queue = new();
|
||||||
|
foreach (IReceptor node in nodes) {
|
||||||
|
if (inDegree[node] == 0) // Nodes with no dependencies
|
||||||
|
queue.Enqueue(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IReceptor> sortedOrder = new();
|
||||||
|
while (queue.Count > 0) {
|
||||||
|
IReceptor current = queue.Dequeue();
|
||||||
|
sortedOrder.Add(current); // Process the node
|
||||||
|
|
||||||
|
foreach (INucleus receiver in current.receivers) {
|
||||||
|
inDegree[receiver]--;
|
||||||
|
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||||
|
queue.Enqueue(receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for cycles in the graph
|
||||||
|
if (sortedOrder.Count != nodes.Count)
|
||||||
|
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||||
|
|
||||||
|
return sortedOrder;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IReceptor Clone() {
|
public virtual IReceptor Clone() {
|
||||||
Neuron clone = new(this.cluster, this.name) {
|
Neuron clone = new(this.cluster, this.name) {
|
||||||
array = this.array,
|
array = this.array,
|
||||||
@ -99,7 +140,7 @@ public class Cluster : INucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReceptor ShallowCloneTo(Cluster parent) {
|
public IReceptor ShallowCloneTo(Cluster parent) {
|
||||||
Cluster clone = new(parent, this.storedPrefab) {
|
Cluster clone = new(this.prefab, parent) {
|
||||||
name = this.name,
|
name = this.name,
|
||||||
};
|
};
|
||||||
return clone;
|
return clone;
|
||||||
@ -113,11 +154,18 @@ public class Cluster : INucleus {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Init
|
||||||
|
|
||||||
|
public ClusterPrefab prefab;
|
||||||
|
|
||||||
public ClusterPrefab cluster { get; set; }
|
public ClusterPrefab cluster { get; set; }
|
||||||
public Cluster parent { get; set; }
|
public Cluster parent { get; set; }
|
||||||
|
|
||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
public List<IReceptor> nuclei = new();
|
public List<IReceptor> nuclei = new();
|
||||||
|
// the nuclei sorted using topological sorting
|
||||||
|
// to ensure that the cluster is computer in the right order
|
||||||
|
public List<IReceptor> sortedNuclei;
|
||||||
|
|
||||||
public List<INucleus> _inputs = null;
|
public List<INucleus> _inputs = null;
|
||||||
public virtual List<INucleus> inputs {
|
public virtual List<INucleus> inputs {
|
||||||
|
|||||||
@ -29,10 +29,6 @@ public class MemoryCell : Neuron {
|
|||||||
|
|
||||||
//Applying the weight factgors
|
//Applying the weight factgors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
if (synapse.nucleus == this) {
|
|
||||||
float deltaTime = Time.time - this.lastTime;
|
|
||||||
synapse.weight = deltaTime;
|
|
||||||
}
|
|
||||||
result += synapse.weight * synapse.nucleus.outputValue;
|
result += synapse.weight * synapse.nucleus.outputValue;
|
||||||
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
||||||
n++;
|
n++;
|
||||||
|
|||||||
@ -154,7 +154,6 @@ public class Neuron : INucleus {
|
|||||||
// private bool _isSleeping = false;
|
// private bool _isSleeping = false;
|
||||||
// public bool isSleeping => _isSleeping;
|
// public bool isSleeping => _isSleeping;
|
||||||
public bool isSleeping => lengthsq(this.outputValue) == 0;
|
public bool isSleeping => lengthsq(this.outputValue) == 0;
|
||||||
public float lastTime { get; private set; }
|
|
||||||
|
|
||||||
public void UpdateNuclei() {
|
public void UpdateNuclei() {
|
||||||
this.stale++;
|
this.stale++;
|
||||||
@ -292,10 +291,6 @@ public class Neuron : INucleus {
|
|||||||
|
|
||||||
//Applying the weight factgors
|
//Applying the weight factgors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
if (synapse.nucleus == this) {
|
|
||||||
float deltaTime = Time.time - this.lastTime;
|
|
||||||
synapse.weight = deltaTime;
|
|
||||||
}
|
|
||||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||||
|
|
||||||
// Perhaps synapses should be removed when the output value goes to 0....
|
// Perhaps synapses should be removed when the output value goes to 0....
|
||||||
@ -340,7 +335,6 @@ public class Neuron : INucleus {
|
|||||||
Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}");
|
Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastTime = Time.time;
|
|
||||||
foreach (INucleus receiver in this.receivers)
|
foreach (INucleus receiver in this.receivers)
|
||||||
receiver.UpdateState();
|
receiver.UpdateState();
|
||||||
|
|
||||||
|
|||||||
@ -621,7 +621,7 @@ public class ClusterInspector : Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) {
|
private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) {
|
||||||
Cluster subclusterInstance = new(this.cluster, prefab);
|
Cluster subclusterInstance = new(prefab, this.cluster);
|
||||||
subclusterInstance.AddReceiver(nucleus);
|
subclusterInstance.AddReceiver(nucleus);
|
||||||
// This does not work somehow
|
// This does not work somehow
|
||||||
// this.currentNucleus = subclusterInstance;
|
// this.currentNucleus = subclusterInstance;
|
||||||
@ -630,9 +630,9 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
private void EditCluster(Cluster subCluster) {
|
private void EditCluster(Cluster subCluster) {
|
||||||
// May be used with storedPrefab...
|
// May be used with storedPrefab...
|
||||||
Selection.activeObject = subCluster.storedPrefab;
|
Selection.activeObject = subCluster.prefab;
|
||||||
EditorGUIUtility.PingObject(subCluster.storedPrefab);
|
EditorGUIUtility.PingObject(subCluster.prefab);
|
||||||
var editor = Editor.CreateEditor(subCluster.storedPrefab);
|
var editor = Editor.CreateEditor(subCluster.prefab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to another nucleus in the same cluster
|
// Connect to another nucleus in the same cluster
|
||||||
|
|||||||
@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (brain != null && board != null)
|
if (brain != null && board != null)
|
||||||
board.SetGraph(component.gameObject, brain.storedPrefab, brain.output, inspectorContainer);
|
board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer);
|
||||||
// else
|
// else
|
||||||
// Debug.LogWarning(" No brain!");
|
// Debug.LogWarning(" No brain!");
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user