Fix Stimulus reset

This commit is contained in:
Pascal Serrarens 2026-08-14 15:56:35 +02:00
parent 760168a6f7
commit 8b456e2b7c
3 changed files with 79 additions and 27 deletions

View File

@ -70,8 +70,9 @@ namespace NanoBrain {
/// </summary>
/// In a multi-cluster each instance can be used for a thing.
/// Cluster instance may also not (yet) be mapped to a thing.
[NonSerialized]
public Dictionary<int, Cluster> thingClusters = new();
// [NonSerialized]
// public Dictionary<int, Cluster> thingClusters = new();
public int thingId;
/// <summary>
/// All nuclei in this cluster
@ -105,11 +106,13 @@ namespace NanoBrain {
}
if (ix >= 0) {
Debug.Log($"update {neuronName} {timestamp}");
actions[ix].action = action;
actions[ix].timestamp = timestamp;
return;
}
Debug.Log($"new {neuronName} {timestamp}");
// No existing item; compute insertion point (sorted by timestamp ascending)
for (int i = 0; i < actions.Count; i++) {
if (actions[i].timestamp > timestamp) {
@ -121,8 +124,27 @@ namespace NanoBrain {
TimedAction newAction = new(neuronName, action, timestamp);
actions.Insert(insertIx, newAction);
}
public static void Check(List<TimedAction> actions) {
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
if (actions.Count > 0) {
Debug.Log($"{actions.Count} actions, {actions[0].neuronName} {actions[0].timestamp} {now} {actions[0].timestamp - now}");
}
while (actions.Count > 0 && actions[0].timestamp <= now) {
Action action = actions[0].action;
actions.RemoveAt(0);
action();
}
}
}
public readonly List<TimedAction> actions = new();
public void CheckActions() {
TimedAction.Check(this.actions);
foreach (Nucleus nucleus in this.nuclei) {
if (nucleus is not Cluster cluster)
continue;
cluster.CheckActions();
}
}
#region Init
@ -531,17 +553,18 @@ namespace NanoBrain {
/// Remove a mapping from a thing to a cluster such that it becomes available for new things
/// </summary>
/// <param name="cluster">The multi-cluster instance which not no longer be mapped</param>
private void RemoveThingCluster(Cluster cluster) {
int keyToRemove = -1;
foreach (KeyValuePair<int, Cluster> kvp in this.thingClusters) {
if (kvp.Value == cluster) {
keyToRemove = kvp.Key;
break;
}
}
public void RemoveThingCluster(Cluster cluster) {
cluster.thingId = 0;
// int keyToRemove = -1;
// foreach (KeyValuePair<int, Cluster> kvp in this.thingClusters) {
// if (kvp.Value == cluster) {
// keyToRemove = kvp.Key;
// break;
// }
// }
if (keyToRemove >= 0)
this.thingClusters.Remove(keyToRemove);
// if (keyToRemove >= 0)
// this.thingClusters.Remove(keyToRemove);
}
public List<Neuron> GetAllInstances(Neuron nucleus) {
@ -776,13 +799,18 @@ namespace NanoBrain {
/// <returns>The found neuron or null when it is not found</returns>
/// The cluster instance mapped to the thing will be neuron.parent if a neuron is found.
public Neuron GetNeuron(int thingId, string neuronName, string thingName = null) {
// If this is not an ClusterArray, just take the neuron
if (this.instances == null || this.instances.Length <= 1)
return this.GetNeuron(neuronName);
// See if we are already using a cluster for thingId
thingClusters ??= new();
if (thingClusters.TryGetValue(thingId, out Cluster cluster))
return cluster.GetNeuron(neuronName);
// thingClusters ??= new();
// if (thingClusters.TryGetValue(thingId, out Cluster cluster))
// return cluster.GetNeuron(neuronName);
foreach (Cluster sibling in this.instances) {
if (sibling.thingId == thingId)
return sibling.GetNeuron(neuronName);
}
// Find the cluster with the lowest value neuron
Neuron lowestNeuron = null;
@ -794,7 +822,8 @@ namespace NanoBrain {
Cluster selectedCluster = lowestNeuron.parent;
RemoveThingCluster(selectedCluster);
selectedCluster.name = baseName + ": " + thingName;
thingClusters[thingId] = selectedCluster;
//thingClusters[thingId] = selectedCluster;
selectedCluster.thingId = thingId;
return lowestNeuron;
}

View File

@ -185,13 +185,17 @@ namespace NanoBrain {
/// </summary>
public virtual float3 outputValue {
get {
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
List<Cluster.TimedAction> actions = this.parent.actions;
while (actions.Count > 0 && actions[0].timestamp <= now) {
Action action = actions[0].action;
actions.RemoveAt(0);
action();
}
// long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
// List<Cluster.TimedAction> actions = this.parent.actions;
// if (actions.Count > 0) {
// Debug.Log($"{actions.Count} actions, {actions[0].neuronName} {actions[0].timestamp} {now} {actions[0].timestamp - now}");
// }
// while (actions.Count > 0 && actions[0].timestamp <= now) {
// Action action = actions[0].action;
// actions.RemoveAt(0);
// action();
// }
this.parent.CheckActions();
return _outputValue;
}
set {
@ -253,7 +257,7 @@ namespace NanoBrain {
/// <summary>
/// When true, the value will not be reset after timeToSleep.
/// </summary>
public bool persistOutput = false;
//public bool persistOutput = false;
/// <summary>
/// True when the neuron is not persisting and has not be updated for timeToSleep seconds
/// </summary>
@ -304,7 +308,7 @@ namespace NanoBrain {
protected virtual void CloneFields(Neuron clone) {
clone.bias = this.bias;
clone.trainableBias = this.trainableBias;
clone.persistOutput = this.persistOutput;
//clone.persistOutput = this.persistOutput;
clone.combinator = this.combinator;
clone.activator = this.activator;
clone.breakOnUpdate = this.breakOnUpdate;
@ -812,13 +816,15 @@ namespace NanoBrain {
if (autoResetDelay > 0) {
long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
long resetTime = now + (long)(autoResetDelay * 1000.0f);
Cluster.TimedAction.AddTo(this.parent.actions, this.name, this.resetStimulus, resetTime);
Cluster.TimedAction.AddTo(this.parent.actions, this.parent.name + "." +this.name, this.resetStimulus, resetTime);
}
}
private void ResetStimulus() {
// Debug.Log("reset stimulus");
Debug.Log($"reset stimulus {this.parent.name + "." +this.name}");
this.parent.name = this.parent.baseName;
this.bias = Vector3.zero;
this.parent.thingId = 0;
this.parent?.UpdateFromNucleus(this);
}
}

View File

@ -47,6 +47,7 @@ namespace NanoBrain {
Debug.Log($"Selected {i}: {member.performance}");
member.initialized = true;
selectedMembers.Add(member);
LogTrainableWeights(member.brain);
}
}
@ -86,7 +87,9 @@ namespace NanoBrain {
member.brain.CopyWeightsFrom(ants[parent1].brain);
member.brain.ProcessWeightsFrom(ants[parent2].brain, Average);
LogTrainableWeights(member.brain);
member.brain.GaussianAdditiveMutation(1e-1f);
LogTrainableWeights(member.brain);
}
private static float Average(float a, float b) {
@ -114,5 +117,19 @@ namespace NanoBrain {
}
return selectedMembers;
}
private void LogTrainableWeights(Cluster cluster) {
string s = "";
foreach (Nucleus nucleus in cluster.nuclei) {
if (nucleus is Neuron neuron) {
foreach (Synapse synapse in neuron.synapses) {
if (synapse.trainable) {
s += synapse.weight + " ";
}
}
}
}
Debug.Log(s);
}
}
}