diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index 3f8275e..143f1ed 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -70,8 +70,9 @@ namespace NanoBrain { /// /// 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 thingClusters = new(); + // [NonSerialized] + // public Dictionary thingClusters = new(); + public int thingId; /// /// 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 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 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 /// /// The multi-cluster instance which not no longer be mapped - private void RemoveThingCluster(Cluster cluster) { - int keyToRemove = -1; - foreach (KeyValuePair 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 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 GetAllInstances(Neuron nucleus) { @@ -776,13 +799,18 @@ namespace NanoBrain { /// The found neuron or null when it is not found /// 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; } diff --git a/Runtime/Scripts/Core/Neuron.cs b/Runtime/Scripts/Core/Neuron.cs index efb0594..56c8b31 100644 --- a/Runtime/Scripts/Core/Neuron.cs +++ b/Runtime/Scripts/Core/Neuron.cs @@ -185,13 +185,17 @@ namespace NanoBrain { /// public virtual float3 outputValue { get { - long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - List 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 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 { /// /// When true, the value will not be reset after timeToSleep. /// - public bool persistOutput = false; + //public bool persistOutput = false; /// /// True when the neuron is not persisting and has not be updated for timeToSleep seconds /// @@ -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); } } diff --git a/Runtime/Scripts/Core/Population.cs b/Runtime/Scripts/Core/Population.cs index 29c3ced..1c19569 100644 --- a/Runtime/Scripts/Core/Population.cs +++ b/Runtime/Scripts/Core/Population.cs @@ -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); + } } } \ No newline at end of file