Fix multiple pheromone placement
This commit is contained in:
parent
c011e04650
commit
360346eeac
123
Cluster.cs
123
Cluster.cs
@ -18,6 +18,7 @@ public class Cluster : Nucleus {
|
|||||||
this.parent?.nuclei.Add(this);
|
this.parent?.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
// Does not work because we have nuclei with the same names in an nucleusArray
|
// Does not work because we have nuclei with the same names in an nucleusArray
|
||||||
// 'Pheromone steering'
|
// 'Pheromone steering'
|
||||||
@ -33,6 +34,7 @@ public class Cluster : Nucleus {
|
|||||||
this.cluster.nuclei.Add(this);
|
this.cluster.nuclei.Add(this);
|
||||||
|
|
||||||
ClonePrefab();
|
ClonePrefab();
|
||||||
|
_ = this.inputs;
|
||||||
this.sortedNuclei = TopologicalSort(this.nuclei);
|
this.sortedNuclei = TopologicalSort(this.nuclei);
|
||||||
//this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name);
|
//this.nucleiDict = nuclei.ToDictionary(nucleus => nucleus.name);
|
||||||
}
|
}
|
||||||
@ -127,6 +129,7 @@ public class Cluster : Nucleus {
|
|||||||
if (inDegree[node] == 0) // Nodes with no dependencies
|
if (inDegree[node] == 0) // Nodes with no dependencies
|
||||||
queue.Enqueue(node);
|
queue.Enqueue(node);
|
||||||
}
|
}
|
||||||
|
// The queue basically stores all input nuclei?
|
||||||
|
|
||||||
List<Nucleus> sortedOrder = new();
|
List<Nucleus> sortedOrder = new();
|
||||||
while (queue.Count > 0) {
|
while (queue.Count > 0) {
|
||||||
@ -200,11 +203,107 @@ public class Cluster : Nucleus {
|
|||||||
if (nucleus.synapses.Count == 0)
|
if (nucleus.synapses.Count == 0)
|
||||||
this._inputs.Add(nucleus);
|
this._inputs.Add(nucleus);
|
||||||
}
|
}
|
||||||
|
ComputeOrders();
|
||||||
}
|
}
|
||||||
return this._inputs;
|
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;
|
public virtual Nucleus output {//=> this.nuclei[0] as Nucleus;
|
||||||
get {
|
get {
|
||||||
if (this.nuclei.Count > 0)
|
if (this.nuclei.Count > 0)
|
||||||
@ -250,6 +349,24 @@ public class Cluster : Nucleus {
|
|||||||
|
|
||||||
#region Update
|
#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() {
|
public override void UpdateStateIsolated() {
|
||||||
Vector3 sum = this.bias;
|
Vector3 sum = this.bias;
|
||||||
|
|
||||||
@ -271,9 +388,9 @@ public class Cluster : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateNuclei() {
|
public override void UpdateNuclei() {
|
||||||
this.stale++;
|
// this.stale++;
|
||||||
if (this.stale > staleValueForSleep)
|
// if (this.stale > staleValueForSleep)
|
||||||
_outputValue = Vector3.zero;
|
// _outputValue = Vector3.zero;
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.nuclei)
|
foreach (Nucleus nucleus in this.nuclei)
|
||||||
nucleus.UpdateNuclei();
|
nucleus.UpdateNuclei();
|
||||||
|
|||||||
@ -500,6 +500,7 @@ public class ClusterInspector : Editor {
|
|||||||
private bool showSynapses = true;
|
private bool showSynapses = true;
|
||||||
private bool showActivation = true;
|
private bool showActivation = true;
|
||||||
protected bool breakOnWake = false;
|
protected bool breakOnWake = false;
|
||||||
|
protected bool trace = false;
|
||||||
void DrawInspector(VisualElement inspectorContainer) {
|
void DrawInspector(VisualElement inspectorContainer) {
|
||||||
if (inspectorContainer == null)
|
if (inspectorContainer == null)
|
||||||
return;
|
return;
|
||||||
@ -638,6 +639,9 @@ public class ClusterInspector : Editor {
|
|||||||
if (this.currentNucleus.isSleeping == false)
|
if (this.currentNucleus.isSleeping == false)
|
||||||
Debug.Break();
|
Debug.Break();
|
||||||
}
|
}
|
||||||
|
trace = EditorGUILayout.Toggle("Trace", trace);
|
||||||
|
this.currentNucleus.trace = trace;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
inspectorContainer.Add(container);
|
inspectorContainer.Add(container);
|
||||||
|
|||||||
@ -31,6 +31,7 @@ public abstract class Nucleus {
|
|||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public int stale = 1000;
|
public int stale = 1000;
|
||||||
public readonly int staleValueForSleep = 20;
|
public readonly int staleValueForSleep = 20;
|
||||||
|
public bool trace = false;
|
||||||
|
|
||||||
public abstract Nucleus ShallowCloneTo(Cluster parent);
|
public abstract Nucleus ShallowCloneTo(Cluster parent);
|
||||||
public abstract Nucleus Clone(ClusterPrefab prefab);
|
public abstract Nucleus Clone(ClusterPrefab prefab);
|
||||||
@ -101,6 +102,9 @@ public abstract class Nucleus {
|
|||||||
public abstract void UpdateStateIsolated();
|
public abstract void UpdateStateIsolated();
|
||||||
|
|
||||||
public virtual void UpdateNuclei() {
|
public virtual void UpdateNuclei() {
|
||||||
|
if (this.array == null || this.array.nuclei == null || this.array.nuclei.Length <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
this.stale++;
|
this.stale++;
|
||||||
if (this.stale > staleValueForSleep) {
|
if (this.stale > staleValueForSleep) {
|
||||||
//Debug.Log($"{this.name} goes to sleep, stale = {this.stale}");
|
//Debug.Log($"{this.name} goes to sleep, stale = {this.stale}");
|
||||||
|
|||||||
@ -127,7 +127,8 @@ public class NucleusArray {
|
|||||||
|
|
||||||
if (selectedReceiver is Neuron selectedNucleus)
|
if (selectedReceiver is Neuron selectedNucleus)
|
||||||
selectedNucleus.ProcessStimulus(inputValue);
|
selectedNucleus.ProcessStimulus(inputValue);
|
||||||
selectedReceiver.parent.UpdateStateIsolated();
|
//selectedReceiver.parent.UpdateStateIsolated();
|
||||||
|
selectedReceiver.parent.UpdateFromNucleus(selectedReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanupReceivers() {
|
private void CleanupReceivers() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user