diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj
index 1f5f66b..cc796da 100644
--- a/Assembly-CSharp.csproj
+++ b/Assembly-CSharp.csproj
@@ -76,6 +76,7 @@
+
diff --git a/Assets/NanoBrain/MemoryCell.cs b/Assets/NanoBrain/MemoryCell.cs
new file mode 100644
index 0000000..5e32009
--- /dev/null
+++ b/Assets/NanoBrain/MemoryCell.cs
@@ -0,0 +1,65 @@
+using System;
+using UnityEngine;
+using Unity.Mathematics;
+using static Unity.Mathematics.math;
+
+[Serializable]
+public class MemoryCell : Neuron {
+
+ public MemoryCell(Cluster cluster, string name) : base(cluster, name) {}
+
+ #region Parameters
+
+ // Returns the memorized value weighted by time
+ // return lastValue * (current time - last time)
+ [SerializeField]
+ public bool deltaValue = false;
+
+ #endregion Parameters
+
+ #region State
+
+ private float3 _memorizedValue;
+ private float _memorizedTime;
+
+ public override void UpdateState() {
+ // A memorycell does not have an activation function
+ float3 result = new(0, 0, 0);
+ int n = 0;
+
+ //Applying the weight factgors
+ foreach (Synapse synapse in this.synapses) {
+ if (synapse.nucleus == this) {
+ float deltaTime = Time.time - this.lastTime;
+ synapse.weight = deltaTime;
+ }
+ result += synapse.weight * synapse.nucleus.outputValue;
+ if (lengthsq(synapse.nucleus.outputValue) != 0)
+ n++;
+ }
+
+ if (this.average)
+ result /= n;
+
+ UpdateResult(result);
+ }
+
+ public override void UpdateResult(Vector3 result) {
+ // output value is the previous value
+ if (this.deltaValue) {
+ float deltaTime = Time.time - this._memorizedTime;
+ this._outputValue = this._memorizedValue * deltaTime;
+ }
+ else
+ this._outputValue = this._memorizedValue;
+
+ // Store the result for the next time
+ this._memorizedValue = result;
+ this._memorizedTime = Time.time;
+
+ foreach (INucleus receiver in this.receivers)
+ receiver.UpdateState();
+ }
+
+ #endregion State
+}
diff --git a/Assets/NanoBrain/MemoryCell.cs.meta b/Assets/NanoBrain/MemoryCell.cs.meta
new file mode 100644
index 0000000..ef74aba
--- /dev/null
+++ b/Assets/NanoBrain/MemoryCell.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 29633aa3fe5cd9dcc8d886051f45d4d8
\ No newline at end of file
diff --git a/Assets/NanoBrain/Neuron.cs b/Assets/NanoBrain/Neuron.cs
index 3ccaaa6..ff14d0c 100644
--- a/Assets/NanoBrain/Neuron.cs
+++ b/Assets/NanoBrain/Neuron.cs
@@ -54,8 +54,13 @@ public class Neuron : INucleus {
}
public AnimationCurve curve;
public float curveMax = 1.0f;
+
+ #region Parameters
+
public bool average = false;
+ #endregion Parameters
+
public AnimationCurve GenerateCurve() {
switch (this.curvePreset) {
case CurvePresets.Linear:
@@ -132,8 +137,8 @@ public class Neuron : INucleus {
#endregion Activation
- private float3 _outputValue;
- public float3 outputValue {
+ protected float3 _outputValue;
+ public virtual float3 outputValue {
get { return _outputValue; }
set {
this.stale = 0;
@@ -147,6 +152,7 @@ public class Neuron : INucleus {
private bool _isSleeping = false;
public bool isSleeping => _isSleeping;
+ public float lastTime { get; private set; }
public void UpdateNuclei() {
this.stale++;
@@ -238,11 +244,16 @@ public class Neuron : INucleus {
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
+ if (synapse.nucleus == this) {
+ float deltaTime = Time.time - this.lastTime;
+ synapse.weight = deltaTime;
+ }
sum += synapse.weight * synapse.nucleus.outputValue;
+ // Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
- if (average)
+ if (this.average)
sum /= n;
// Activation function
@@ -267,7 +278,8 @@ public class Neuron : INucleus {
}
UpdateResult(result);
}
- public void UpdateResult(Vector3 result) {
+
+ public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) {
// //Debug.Log($"insignificant update: {d}");
@@ -275,6 +287,7 @@ public class Neuron : INucleus {
// }
this.outputValue = result;
+ this.lastTime = Time.time;
foreach (INucleus receiver in this.receivers)
receiver.UpdateState();
diff --git a/Assets/NanoBrain/Velocity.asset b/Assets/NanoBrain/Velocity.asset
new file mode 100644
index 0000000..9615d6d
--- /dev/null
+++ b/Assets/NanoBrain/Velocity.asset
@@ -0,0 +1,61 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
+ m_Name: Velocity
+ m_EditorClassIdentifier: Assembly-CSharp::Cluster
+ asset: {fileID: 0}
+ nuclei:
+ - rid: 2243601362379866169
+ references:
+ version: 2
+ RefIds:
+ - rid: 2243601362379866169
+ type: {class: Neuron, ns: , asm: Assembly-CSharp}
+ data:
+ _name: Output
+ _synapses: []
+ _receivers: []
+ _array:
+ rid: 2243601362379866170
+ _curvePreset: 0
+ curve:
+ serializedVersion: 2
+ m_Curve:
+ - serializedVersion: 3
+ time: 0
+ value: 0
+ inSlope: 0
+ outSlope: 1
+ tangentMode: 0
+ weightedMode: 0
+ inWeight: 0
+ outWeight: 0
+ - serializedVersion: 3
+ time: 1000
+ value: 1000
+ inSlope: 1
+ outSlope: 0
+ tangentMode: 0
+ weightedMode: 0
+ inWeight: 0
+ outWeight: 0
+ m_PreInfinity: 2
+ m_PostInfinity: 2
+ m_RotationOrder: 4
+ curveMax: 1
+ average: 0
+ - rid: 2243601362379866170
+ type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
+ data:
+ _nuclei:
+ - rid: 2243601362379866169
+ name: Output
diff --git a/Assets/NanoBrain/Velocity.asset.meta b/Assets/NanoBrain/Velocity.asset.meta
new file mode 100644
index 0000000..07ecb98
--- /dev/null
+++ b/Assets/NanoBrain/Velocity.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dd622ac7ed09e70ea8edac595047ac82
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs
index 86a09fd..cd4d6c7 100644
--- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs
+++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs
@@ -488,14 +488,20 @@ public class ClusterInspector : Editor {
this.currentNucleus.name = EditorGUILayout.TextField(this.currentNucleus.name);
if (this.currentNucleus is Neuron neuroid) {
- EditorGUILayout.BeginHorizontal();
- EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
- if (neuroid.curveMax > 0)
- EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax));
- else
- EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax));
- neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100));
- EditorGUILayout.EndHorizontal();
+ if (this.currentNucleus is MemoryCell memory) {
+ // should use serializedProperty
+ memory.deltaValue = EditorGUILayout.Toggle("DeltaValue", memory.deltaValue);
+ }
+ else {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
+ if (neuroid.curveMax > 0)
+ EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, 0, 1, neuroid.curveMax));
+ else
+ EditorGUILayout.CurveField(neuroid.curve, Color.cyan, new Rect(0, neuroid.curveMax, 1, -neuroid.curveMax));
+ neuroid.curvePreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuroid.curvePreset, GUILayout.Width(100));
+ EditorGUILayout.EndHorizontal();
+ }
if (neuroid.array == null || neuroid.array.nuclei == null || neuroid.array.nuclei.Count() == 0)
neuroid.array = new NucleusArray(neuroid);
@@ -544,6 +550,8 @@ public class ClusterInspector : Editor {
ConnectNucleus(this.cluster, this.currentNucleus);
if (GUILayout.Button("Add Input Neuron"))
AddInputNeuron(this.currentNucleus);
+ if (GUILayout.Button("Add Input MemoryCell"))
+ AddInputMemoryCell(this.currentNucleus);
if (GUILayout.Button("Add Input Cluster"))
AddCluster(this.currentNucleus);
@@ -598,6 +606,13 @@ public class ClusterInspector : Editor {
BuildLayers();
}
+ protected virtual void AddInputMemoryCell(INucleus nucleus) {
+ MemoryCell newMemory = new(this.cluster.cluster, "New memory cell");
+ newMemory.AddReceiver(nucleus);
+ this.currentNucleus = newMemory;
+ BuildLayers();
+ }
+
protected virtual void AddCluster(INucleus nucleus) {
BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
}