Add static memory option

This commit is contained in:
Pascal Serrarens 2026-02-10 15:02:24 +01:00
parent d562c7192b
commit c011e04650
3 changed files with 74 additions and 88 deletions

View File

@ -396,7 +396,7 @@ public class ClusterInspector : Editor {
}
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size, Color color) {
if (nucleus is MemoryCell memory) {
if (nucleus is MemoryCell) {
Handles.color = Color.white;
Handles.DrawWireDisc(position + Vector3.right * 10, Vector3.forward, size);
}
@ -413,17 +413,17 @@ public class ClusterInspector : Editor {
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
if (nucleus is Nucleus neuron) {
if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0)
neuron.array = new NucleusArray(neuron);
//if (nucleus is Nucleus neuron) {
if (nucleus.array == null || nucleus.array.nuclei == null || nucleus.array.nuclei.Count() == 0)
nucleus.array = new NucleusArray(nucleus);
if ((!expandArray || neuron.array.nuclei.First() != this.currentNucleus) && neuron.array.nuclei.Count() > 1) {
Handles.Label(labelPosition, neuron.array.nuclei.Count().ToString(), style);
if ((!expandArray || nucleus.array.nuclei.First() != this.currentNucleus) && nucleus.array.nuclei.Count() > 1) {
Handles.Label(labelPosition, nucleus.array.nuclei.Count().ToString(), style);
}
if (expandArray && neuron.array.nuclei.First() == this.currentNucleus) {
if (expandArray && nucleus.array.nuclei.First() == this.currentNucleus) {
int arrayIx = 0;
foreach (Nucleus n in neuron.array.nuclei) {
if (n == neuron)
foreach (Nucleus n in nucleus.array.nuclei) {
if (n == nucleus)
break;
arrayIx++;
}
@ -441,17 +441,18 @@ public class ClusterInspector : Editor {
Handles.Label(labelPos, nucleus.name, style);
}
if (nucleus is Cluster cluster) {
if (nucleus is Cluster) {
Handles.color = Color.white;
Handles.DrawWireDisc(position, Vector3.forward, size + 10);
}
}
else {
style.alignment = TextAnchor.UpperCenter;
Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis
Handles.Label(labelPos, nucleus.name, style);
}
// }
// else {
// style.alignment = TextAnchor.UpperCenter;
// Vector3 labelPos = position - Vector3.down * (size + 10); // below disc along up axis
// Handles.Label(labelPos, nucleus.name, style);
// }
// Tooltip
Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2);
int id = GUIUtility.GetControlID(FocusType.Passive);
Event e = Event.current;
@ -533,31 +534,6 @@ public class ClusterInspector : Editor {
outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList();
//outputsField.value = newName;
}
//if (this.currentNucleus is Neuron neuron) {
// if (this.currentNucleus is MemoryCell memory) {
// }
// else {
// EditorGUILayout.BeginHorizontal();
// EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
// if (neuron.curveMax > 0)
// EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax));
// else
// EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax));
// neuron.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100));
// EditorGUILayout.EndHorizontal();
// }
// if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Count() == 0)
// neuron.array = new NucleusArray(neuron);
// EditorGUILayout.BeginHorizontal();
// EditorGUILayout.IntField("Array size", neuron.array.nuclei.Count());
// if (GUILayout.Button("Add"))
// neuron.array.AddNucleus(this.prefab);
// if (GUILayout.Button("Del"))
// neuron.array.RemoveNucleus();
// EditorGUILayout.EndHorizontal();
//}
if (Application.isPlaying) {
GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString());
@ -566,6 +542,12 @@ public class ClusterInspector : Editor {
else
EditorGUILayout.LabelField(" ");
if (this.currentNucleus is MemoryCell memory) {
memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory);
}
// Synapses
showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses");
if (showSynapses) {
ConnectNucleus(this.prefab, this.currentNucleus);
@ -616,7 +598,7 @@ public class ClusterInspector : Editor {
if (showActivation) {
if (this.currentNucleus is Neuron neuron) {
if (this.currentNucleus is not MemoryCell memory) {
if (this.currentNucleus is not MemoryCell) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
if (neuron.curveMax > 0)
@ -650,13 +632,6 @@ public class ClusterInspector : Editor {
EditCluster(subCluster);
}
// if (this.gameObject != null) {
// Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue);
// //Debug.DrawRay(this.gameObject.transform.position, worldVector, Color.yellow);
// Handles.color = Color.yellow;
// Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
// }
EditorGUILayout.Space();
breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake);
if (breakOnWake) {
@ -700,22 +675,22 @@ public class ClusterInspector : Editor {
}
}
protected virtual void AddInput(int selectedInputType, Nucleus nucleus) {
switch (selectedInputType) {
case 0: // Neuron
AddNeuronInput(nucleus);
break;
case 1: // MemoryCell
AddMemoryCellInput(nucleus);
break;
case 2: // Selector
AddSelectorInput(nucleus);
break;
case 3: // Cluster
AddClusterInput(nucleus);
break;
}
}
// protected virtual void AddInput(int selectedInputType, Nucleus nucleus) {
// switch (selectedInputType) {
// case 0: // Neuron
// AddNeuronInput(nucleus);
// break;
// case 1: // MemoryCell
// AddMemoryCellInput(nucleus);
// break;
// case 2: // Selector
// AddSelectorInput(nucleus);
// break;
// case 3: // Cluster
// AddClusterInput(nucleus);
// break;
// }
// }
protected virtual void AddNeuronInput(Nucleus nucleus) {
//Neuron newNeuroid = new(this.cluster, "New neuron");

View File

@ -9,27 +9,30 @@ public class MemoryCell : Neuron {
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { }
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
public bool staticMemory = false;
public override bool isSleeping {
get {
if (staticMemory)
return false;
return base.isSleeping;
}
}
public override Nucleus ShallowCloneTo(Cluster newParent) {
MemoryCell clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
MemoryCell clone = new(newParent, this.name);
CloneFields(clone);
clone.staticMemory = this.staticMemory;
return clone;
}
#region State
private float3 _memorizedValue;
private float _memorizedTime;
private bool initialized = false;
// public override void UpdateStateIsolated() {
// float3 bias = new(0, 0, 0);
// UpdateStateIsolated(bias);
// }
public override void UpdateStateIsolated() { //float3 bias) {
private float3 _memorizedValue;
public override void UpdateStateIsolated() {
// A memorycell does not have an activation function
Vector3 result = this.bias;
int n = 0;
@ -44,11 +47,25 @@ public class MemoryCell : Neuron {
if (this.average)
result /= n;
this.outputValue = this._memorizedValue;
if (initialized)
// Output the previous, memorized value
this.outputValue = this._memorizedValue;
else {
// The first time, the result is directly set in output
this.outputValue = result;
this.initialized = true;
}
// Store the result for the next time
this._memorizedValue = result;
this._memorizedTime = Time.time;
}
public override void UpdateNuclei() {
if (staticMemory)
// Static memory does not get stale or go to sleep
return;
base.UpdateNuclei();
}
#endregion State

View File

@ -27,7 +27,7 @@ public abstract class Nucleus {
public bool isFiring => length(_outputValue) > 0.5f;
public Action WhenFiring;
public bool isSleeping => lengthsq(this.outputValue) == 0;
public virtual bool isSleeping => lengthsq(this.outputValue) == 0;
[NonSerialized]
public int stale = 1000;
public readonly int staleValueForSleep = 20;
@ -99,12 +99,6 @@ public abstract class Nucleus {
#region Update
public abstract void UpdateStateIsolated();
// UpdateStateIsolated(new float3(0, 0, 0));
// }
//public abstract void UpdateStateIsolated(float3 bias);
// public virtual void UpdateStateIsolated(float3 bias) {
// }
public virtual void UpdateNuclei() {
this.stale++;