Fix multiple pheromone placement
This commit is contained in:
parent
c011e04650
commit
360346eeac
125
Cluster.cs
125
Cluster.cs
@ -18,6 +18,7 @@ public class Cluster : Nucleus {
|
||||
this.parent?.nuclei.Add(this);
|
||||
|
||||
ClonePrefab();
|
||||
_ = this.inputs;
|
||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||
// Does not work because we have nuclei with the same names in an nucleusArray
|
||||
// 'Pheromone steering'
|
||||
@ -33,6 +34,7 @@ public class Cluster : Nucleus {
|
||||
this.cluster.nuclei.Add(this);
|
||||
|
||||
ClonePrefab();
|
||||
_ = this.inputs;
|
||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||
//this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name);
|
||||
}
|
||||
@ -127,6 +129,7 @@ public class Cluster : Nucleus {
|
||||
if (inDegree[node] == 0) // Nodes with no dependencies
|
||||
queue.Enqueue(node);
|
||||
}
|
||||
// The queue basically stores all input nuclei?
|
||||
|
||||
List<Nucleus> sortedOrder = new();
|
||||
while (queue.Count > 0) {
|
||||
@ -200,11 +203,107 @@ public class Cluster : Nucleus {
|
||||
if (nucleus.synapses.Count == 0)
|
||||
this._inputs.Add(nucleus);
|
||||
}
|
||||
ComputeOrders();
|
||||
}
|
||||
return this._inputs;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
||||
private void ComputeOrders() {
|
||||
foreach (Nucleus input in this._inputs) {
|
||||
computeOrders[input] = TopologicalSort2(input);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
||||
Dictionary<Nucleus, int> inDegree = new Dictionary<Nucleus, int>();
|
||||
HashSet<Nucleus> visited = new HashSet<Nucleus>();
|
||||
|
||||
// Initialize in-degrees and mark all nodes as unvisited
|
||||
foreach (Nucleus node in this.nuclei) {
|
||||
inDegree[node] = 0;
|
||||
}
|
||||
|
||||
// Calculate in-degrees for all nodes reachable from the start node
|
||||
Queue<Nucleus> queue = new Queue<Nucleus>();
|
||||
queue.Enqueue(startNode);
|
||||
visited.Add(startNode);
|
||||
|
||||
while (queue.Count > 0) {
|
||||
Nucleus current = queue.Dequeue();
|
||||
foreach (Nucleus receiver in current.receivers) {
|
||||
if (!visited.Contains(receiver)) {
|
||||
visited.Add(receiver);
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform topological sort on all reachable nodes
|
||||
queue.Clear();
|
||||
foreach (var node in visited) {
|
||||
if (inDegree[node] == 0) {
|
||||
queue.Enqueue(node);
|
||||
}
|
||||
}
|
||||
|
||||
List<Nucleus> sortedOrder = new List<Nucleus>();
|
||||
while (queue.Count > 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for cycles in the graph
|
||||
if (sortedOrder.Count != visited.Count)
|
||||
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||
|
||||
return sortedOrder;
|
||||
}
|
||||
|
||||
private List<Nucleus> TopologicalSort3(Nucleus startNode) {
|
||||
Dictionary<Nucleus, int> inDegree = new();
|
||||
foreach (Nucleus node in this.nuclei)
|
||||
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]++;
|
||||
}
|
||||
|
||||
Queue<Nucleus> queue = new();
|
||||
queue.Enqueue(startNode);
|
||||
|
||||
List<Nucleus> sortedOrder = new();
|
||||
while (queue.Count > 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Compute order for {startNode.name} length = {sortedOrder.Count}");
|
||||
// Check for cycles in the graph
|
||||
// if (sortedOrder.Count != this.nuclei.Count)
|
||||
// throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||
|
||||
return sortedOrder;
|
||||
}
|
||||
|
||||
public virtual Nucleus output {//=> this.nuclei[0] as Nucleus;
|
||||
get {
|
||||
if (this.nuclei.Count > 0)
|
||||
@ -250,6 +349,24 @@ public class Cluster : Nucleus {
|
||||
|
||||
#region Update
|
||||
|
||||
public void UpdateFromNucleus(Nucleus startNucleus) {
|
||||
// no bias+synapse input state calculation for now...
|
||||
|
||||
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
||||
if (startNucleus.trace)
|
||||
Debug.Log($"Update from {startNucleus.name}");
|
||||
foreach (Nucleus nucleus in computeOrder) {
|
||||
nucleus.UpdateStateIsolated();
|
||||
if (startNucleus.trace)
|
||||
Debug.Log($" {nucleus.name} = {nucleus.outputValue}");
|
||||
}
|
||||
|
||||
this.outputValue = this.output.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
}
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
Vector3 sum = this.bias;
|
||||
|
||||
@ -263,7 +380,7 @@ public class Cluster : Nucleus {
|
||||
|
||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
nucleus.UpdateStateIsolated();
|
||||
|
||||
|
||||
this.outputValue = this.output.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
@ -271,9 +388,9 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
|
||||
public override void UpdateNuclei() {
|
||||
this.stale++;
|
||||
if (this.stale > staleValueForSleep)
|
||||
_outputValue = Vector3.zero;
|
||||
// this.stale++;
|
||||
// if (this.stale > staleValueForSleep)
|
||||
// _outputValue = Vector3.zero;
|
||||
|
||||
foreach (Nucleus nucleus in this.nuclei)
|
||||
nucleus.UpdateNuclei();
|
||||
|
||||
@ -500,6 +500,7 @@ public class ClusterInspector : Editor {
|
||||
private bool showSynapses = true;
|
||||
private bool showActivation = true;
|
||||
protected bool breakOnWake = false;
|
||||
protected bool trace = false;
|
||||
void DrawInspector(VisualElement inspectorContainer) {
|
||||
if (inspectorContainer == null)
|
||||
return;
|
||||
@ -638,6 +639,9 @@ public class ClusterInspector : Editor {
|
||||
if (this.currentNucleus.isSleeping == false)
|
||||
Debug.Break();
|
||||
}
|
||||
trace = EditorGUILayout.Toggle("Trace", trace);
|
||||
this.currentNucleus.trace = trace;
|
||||
|
||||
});
|
||||
|
||||
inspectorContainer.Add(container);
|
||||
|
||||
@ -31,6 +31,7 @@ public abstract class Nucleus {
|
||||
[NonSerialized]
|
||||
public int stale = 1000;
|
||||
public readonly int staleValueForSleep = 20;
|
||||
public bool trace = false;
|
||||
|
||||
public abstract Nucleus ShallowCloneTo(Cluster parent);
|
||||
public abstract Nucleus Clone(ClusterPrefab prefab);
|
||||
@ -101,6 +102,9 @@ public abstract class Nucleus {
|
||||
public abstract void UpdateStateIsolated();
|
||||
|
||||
public virtual void UpdateNuclei() {
|
||||
if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1)
|
||||
return;
|
||||
|
||||
this.stale++;
|
||||
if (this.stale > staleValueForSleep) {
|
||||
//Debug.Log($"{this.name} goes to sleep, stale = {this.stale}");
|
||||
|
||||
@ -127,7 +127,8 @@ public class NucleusArray {
|
||||
|
||||
if (selectedReceiver is Neuron selectedNucleus)
|
||||
selectedNucleus.ProcessStimulus(inputValue);
|
||||
selectedReceiver.parent.UpdateStateIsolated();
|
||||
//selectedReceiver.parent.UpdateStateIsolated();
|
||||
selectedReceiver.parent.UpdateFromNucleus(selectedReceiver);
|
||||
}
|
||||
|
||||
private void CleanupReceivers() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user