Cluster no longer has output
This commit is contained in:
parent
172d7ca8e8
commit
1dfe65eefa
22
Cluster.cs
22
Cluster.cs
@ -104,7 +104,7 @@ public class Cluster : Nucleus {
|
|||||||
foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) {
|
foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) {
|
||||||
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
||||||
if (arrayNucleusIx >= 0) {
|
if (arrayNucleusIx >= 0) {
|
||||||
Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx];
|
Neuron clonedArrayNucleus = clonedNuclei[arrayNucleusIx] as Neuron;
|
||||||
clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
|
clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -473,12 +473,12 @@ public class Cluster : Nucleus {
|
|||||||
Debug.Log($"Update from {startNucleus.name}");
|
Debug.Log($"Update from {startNucleus.name}");
|
||||||
foreach (Nucleus nucleus in computeOrder) {
|
foreach (Nucleus nucleus in computeOrder) {
|
||||||
nucleus.UpdateStateIsolated();
|
nucleus.UpdateStateIsolated();
|
||||||
if (startNucleus.trace)
|
if (startNucleus.trace && nucleus is Neuron neuron)
|
||||||
Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {nucleus.outputValue}");
|
Debug.Log($" {nucleus.name}[{nucleus.GetHashCode()}] = {neuron.outputValue}");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.outputValue = this.defaultOutput.outputValue;
|
// this.outputValue = this.defaultOutput.outputValue;
|
||||||
this.stale = 0;
|
// this.stale = 0;
|
||||||
|
|
||||||
// continue in parent
|
// continue in parent
|
||||||
this.parent?.UpdateFromNucleus(this);
|
this.parent?.UpdateFromNucleus(this);
|
||||||
@ -491,17 +491,19 @@ public class Cluster : Nucleus {
|
|||||||
|
|
||||||
//Applying the weight factors
|
//Applying the weight factors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
if (lengthsq(synapse.nucleus.outputValue) > 0) {
|
if (synapse.nucleus is Neuron neuron) {
|
||||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
if (lengthsq(neuron.outputValue) > 0) {
|
||||||
this.stale = 0;
|
sum += synapse.weight * neuron.outputValue;
|
||||||
|
//this.stale = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||||
nucleus.UpdateStateIsolated();
|
nucleus.UpdateStateIsolated();
|
||||||
|
|
||||||
this.outputValue = this.defaultOutput.outputValue;
|
// this.outputValue = this.defaultOutput.outputValue;
|
||||||
this.stale = 0;
|
// this.stale = 0;
|
||||||
|
|
||||||
UpdateNuclei();
|
UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,8 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
set { _array.nuclei = value; }
|
set { _array.nuclei = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public ClusterReceptor[] nucleiArray;
|
||||||
|
|
||||||
public void AddReceptorElement(ClusterPrefab prefab) {
|
public void AddReceptorElement(ClusterPrefab prefab) {
|
||||||
IReceptorHelpers.AddReceptorElement(this, prefab);
|
IReceptorHelpers.AddReceptorElement(this, prefab);
|
||||||
}
|
}
|
||||||
@ -129,30 +131,31 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateNuclei() {
|
public override void UpdateNuclei() {
|
||||||
this.stale++;
|
// this.stale++;
|
||||||
if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) {
|
// if (this.stale > staleValueForSleep && lengthsq(this.bias) > 0) {
|
||||||
this.bias = new float3(0, 0, 0);
|
// this.bias = new float3(0, 0, 0);
|
||||||
this.parent.UpdateFromNucleus(this);
|
// this.parent.UpdateFromNucleus(this);
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||||
nucleus.UpdateNuclei();
|
nucleus.UpdateNuclei();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
this._array ??= new NucleusArray(this.parent);
|
//this._array ??= new NucleusArray(this.parent);
|
||||||
this._array.ProcessStimulus(thingId, inputValue, thingName);
|
//this._array.ProcessStimulus(thingId, inputValue, thingName);
|
||||||
|
Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<int, ClusterReceptor> thingReceivers = new();
|
private readonly Dictionary<int, ClusterReceptor> thingReceivers = new();
|
||||||
|
|
||||||
public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) {
|
public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
CleanupReceivers();
|
CleanupReceivers();
|
||||||
|
|
||||||
inputValue = input.Activator(inputValue);
|
//inputValue = input.Activator(inputValue);
|
||||||
|
|
||||||
if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver))
|
if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver))
|
||||||
selectedReceiver = FindReceiver(thingId, inputValue);
|
selectedReceiver = FindReceiver2(thingId, inputValue);
|
||||||
if (selectedReceiver == null)
|
if (selectedReceiver == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -172,18 +175,61 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
selectedNeuron.ProcessStimulusDirect(inputValue);
|
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClusterReceptor FindReceiver(int thingId, float3 inputValue) {
|
// private ClusterReceptor FindReceiver(int thingId, float3 inputValue) {
|
||||||
|
// // No existing nucleus for this thing
|
||||||
|
// float inputMagnitude = length(inputValue);
|
||||||
|
// ClusterReceptor selectedReceiver = null;
|
||||||
|
// float selectedMagnitude = 0;
|
||||||
|
// foreach (ClusterReceptor receiver in nucleiArray.Cast<ClusterReceptor>()) {
|
||||||
|
// if (thingReceivers.ContainsValue(receiver) == false) {
|
||||||
|
// // We found an unusued receiver
|
||||||
|
// thingReceivers.Add(thingId, receiver);
|
||||||
|
// return receiver;
|
||||||
|
// }
|
||||||
|
// else if (receiver.isSleeping) {
|
||||||
|
// // A sleeping receiver is not active and can therefore always be used
|
||||||
|
// thingReceivers.Add(thingId, receiver);
|
||||||
|
// return receiver;
|
||||||
|
// }
|
||||||
|
// else if (selectedReceiver == null) {
|
||||||
|
// // If we haven't found a receiver yet, just start by taking the first
|
||||||
|
// selectedReceiver = receiver;
|
||||||
|
// selectedMagnitude = length(selectedReceiver.outputValue);
|
||||||
|
// }
|
||||||
|
// // Look for the receiver with the lowest magnitude
|
||||||
|
// else {
|
||||||
|
// float magnitude = length(receiver.outputValue);
|
||||||
|
|
||||||
|
// if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) {
|
||||||
|
// selectedReceiver = receiver;
|
||||||
|
// selectedMagnitude = length(selectedReceiver.outputValue);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (selectedReceiver != null) {
|
||||||
|
// // Replace the receiver
|
||||||
|
// // Find the thingId current associated with the receiver
|
||||||
|
// int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key;
|
||||||
|
// if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove))
|
||||||
|
// thingReceivers.Remove(keyToRemove);
|
||||||
|
// // And add the new association
|
||||||
|
// thingReceivers.Add(thingId, selectedReceiver);
|
||||||
|
// }
|
||||||
|
// return selectedReceiver;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue) {
|
||||||
// No existing nucleus for this thing
|
// No existing nucleus for this thing
|
||||||
float inputMagnitude = length(inputValue);
|
//float inputMagnitude = length(inputValue);
|
||||||
ClusterReceptor selectedReceiver = null;
|
ClusterReceptor selectedReceiver = null;
|
||||||
float selectedMagnitude = 0;
|
float selectedMagnitude = 0;
|
||||||
foreach (ClusterReceptor receiver in nucleiArray.Cast<ClusterReceptor>()) {
|
foreach (ClusterReceptor receiver in this.nucleiArray.Cast<ClusterReceptor>()) {
|
||||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||||
// We found an unusued receiver
|
// We found an unusued receiver
|
||||||
thingReceivers.Add(thingId, receiver);
|
thingReceivers.Add(thingId, receiver);
|
||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
else if (receiver.isSleeping) {
|
else if (receiver.defaultOutput.isSleeping) {
|
||||||
// A sleeping receiver is not active and can therefore always be used
|
// A sleeping receiver is not active and can therefore always be used
|
||||||
thingReceivers.Add(thingId, receiver);
|
thingReceivers.Add(thingId, receiver);
|
||||||
return receiver;
|
return receiver;
|
||||||
@ -191,15 +237,15 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
else if (selectedReceiver == null) {
|
else if (selectedReceiver == null) {
|
||||||
// If we haven't found a receiver yet, just start by taking the first
|
// If we haven't found a receiver yet, just start by taking the first
|
||||||
selectedReceiver = receiver;
|
selectedReceiver = receiver;
|
||||||
selectedMagnitude = length(selectedReceiver.outputValue);
|
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
||||||
}
|
}
|
||||||
// Look for the receiver with the lowest magnitude
|
// Look for the receiver with the lowest output magnitude
|
||||||
else {
|
else {
|
||||||
float magnitude = length(receiver.outputValue);
|
float magnitude = length(receiver.defaultOutput.outputValue);
|
||||||
|
|
||||||
if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) {
|
if (length(receiver.defaultOutput.outputValue) < selectedMagnitude) {
|
||||||
selectedReceiver = receiver;
|
selectedReceiver = receiver;
|
||||||
selectedMagnitude = length(selectedReceiver.outputValue);
|
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +266,7 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
// Remove a thing-receiver connection when the nucleus is inactive
|
// Remove a thing-receiver connection when the nucleus is inactive
|
||||||
List<int> receiversToRemove = new();
|
List<int> receiversToRemove = new();
|
||||||
foreach (KeyValuePair<int, ClusterReceptor> item in thingReceivers) {
|
foreach (KeyValuePair<int, ClusterReceptor> item in thingReceivers) {
|
||||||
if (item.Value != null && item.Value.isSleeping)
|
if (item.Value != null && item.Value.defaultOutput.isSleeping)
|
||||||
receiversToRemove.Add(item.Key);
|
receiversToRemove.Add(item.Key);
|
||||||
}
|
}
|
||||||
foreach (int thingId in receiversToRemove) {
|
foreach (int thingId in receiversToRemove) {
|
||||||
|
|||||||
@ -262,9 +262,11 @@ public class ClusterInspector : Editor {
|
|||||||
if (this.currentNucleus is IReceptor receptor1) {
|
if (this.currentNucleus is IReceptor receptor1) {
|
||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
foreach (Nucleus nucleus in receptor1.nucleiArray) {
|
foreach (Nucleus nucleus in receptor1.nucleiArray) {
|
||||||
float value = length(nucleus.outputValue);
|
if (nucleus is Neuron neuron) {
|
||||||
if (value > maxValue)
|
float value = length(neuron.outputValue);
|
||||||
maxValue = value;
|
if (value > maxValue)
|
||||||
|
maxValue = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float spacing = 400f / receptor1.nucleiArray.Count();
|
float spacing = 400f / receptor1.nucleiArray.Count();
|
||||||
@ -309,7 +311,13 @@ public class ClusterInspector : Editor {
|
|||||||
Handles.color = Color.white;
|
Handles.color = Color.white;
|
||||||
// The selected nucleus highlight ring
|
// The selected nucleus highlight ring
|
||||||
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
||||||
DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20);
|
float maxValue = 1;
|
||||||
|
if (this.currentNucleus is Neuron neuron)
|
||||||
|
maxValue = length(neuron.outputValue);
|
||||||
|
else if (this.currentNucleus is Cluster cluster)
|
||||||
|
maxValue = length(cluster.defaultOutput.outputValue);
|
||||||
|
|
||||||
|
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,7 +325,12 @@ public class ClusterInspector : Editor {
|
|||||||
Handles.color = Color.white;
|
Handles.color = Color.white;
|
||||||
// The selected nucleus highlight ring
|
// The selected nucleus highlight ring
|
||||||
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
||||||
DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20);
|
float maxValue = 1;
|
||||||
|
if (this.currentNucleus is Neuron neuron)
|
||||||
|
maxValue = length(neuron.outputValue);
|
||||||
|
else if (this.currentNucleus is Cluster cluster)
|
||||||
|
maxValue = length(cluster.defaultOutput.outputValue);
|
||||||
|
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,10 +401,12 @@ public class ClusterInspector : Editor {
|
|||||||
continue;
|
continue;
|
||||||
drawnArrays.Add(clusterReceptor.nucleiArray);
|
drawnArrays.Add(clusterReceptor.nucleiArray);
|
||||||
}
|
}
|
||||||
float value = length(synapse.nucleus.outputValue) * synapse.weight;
|
if (synapse.nucleus is Neuron synapseNeuron) {
|
||||||
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
|
float value = length(synapseNeuron.outputValue) * synapse.weight;
|
||||||
if (value > maxValue)
|
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
|
||||||
maxValue = value;
|
if (value > maxValue)
|
||||||
|
maxValue = value;
|
||||||
|
}
|
||||||
neuronCount++;
|
neuronCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +434,9 @@ public class ClusterInspector : Editor {
|
|||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
if (maxValue == 0 || !float.IsFinite(maxValue))
|
if (maxValue == 0 || !float.IsFinite(maxValue))
|
||||||
maxValue = 1;
|
maxValue = 1;
|
||||||
float brightness = length(synapse.nucleus.outputValue * synapse.weight) / maxValue;
|
float brightness = 0;
|
||||||
|
if (synapse.nucleus is Neuron synapseNeuron)
|
||||||
|
brightness = length(synapseNeuron.outputValue * synapse.weight) / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
}
|
}
|
||||||
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) {
|
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus.parent) {
|
||||||
@ -439,7 +456,9 @@ public class ClusterInspector : Editor {
|
|||||||
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
|
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
|
||||||
Color color;
|
Color color;
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
float brightness = length(nucleus.outputValue) / maxValue;
|
float brightness = 0;
|
||||||
|
if (nucleus is Neuron neuron)
|
||||||
|
brightness = length(neuron.outputValue) / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -529,9 +548,13 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
private void HandleMouseHover(Nucleus nucleus, Rect rect) {
|
private void HandleMouseHover(Nucleus nucleus, Rect rect) {
|
||||||
GUIContent tooltip;
|
GUIContent tooltip;
|
||||||
tooltip = new(
|
if (nucleus is Neuron neuron) {
|
||||||
$"{nucleus.name}" +
|
tooltip = new(
|
||||||
$"\nValue: {length(nucleus.outputValue)}");
|
$"{nucleus.name}" +
|
||||||
|
$"\nValue: {length(neuron.outputValue)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tooltip = new($"{nucleus.name}");
|
||||||
|
|
||||||
Vector2 mousePosition = Event.current.mousePosition;
|
Vector2 mousePosition = Event.current.mousePosition;
|
||||||
|
|
||||||
@ -609,8 +632,12 @@ public class ClusterInspector : Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
GUIContent nameLabel = new("Output", this.currentNucleus.outputValue.ToString());
|
if (currentNucleus is Neuron currentNeuron1) {
|
||||||
EditorGUILayout.FloatField(nameLabel, length(this.currentNucleus.outputValue));
|
GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString());
|
||||||
|
EditorGUILayout.FloatField(nameLabel, length(currentNeuron1.outputValue));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
EditorGUILayout.LabelField(" ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EditorGUILayout.LabelField(" ");
|
EditorGUILayout.LabelField(" ");
|
||||||
@ -686,9 +713,11 @@ public class ClusterInspector : Editor {
|
|||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
Vector3 value = synapse.nucleus.outputValue * synapse.weight;
|
if (synapse.nucleus is Neuron synapseNeuron) {
|
||||||
GUIContent synapseValueLabel = new(synapse.nucleus.name, synapse.nucleus.outputValue.ToString());
|
Vector3 value = synapseNeuron.outputValue * synapse.weight;
|
||||||
EditorGUILayout.FloatField(synapseValueLabel, length(synapse.nucleus.outputValue));
|
GUIContent synapseValueLabel = new(synapse.nucleus.name, synapseNeuron.outputValue.ToString());
|
||||||
|
EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
@ -784,8 +813,8 @@ public class ClusterInspector : Editor {
|
|||||||
|
|
||||||
EditorGUILayout.Space();
|
EditorGUILayout.Space();
|
||||||
breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake);
|
breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake);
|
||||||
if (breakOnWake) {
|
if (breakOnWake && this.currentNucleus is Neuron currentNeuron) {
|
||||||
if (this.currentNucleus.isSleeping == false)
|
if (currentNeuron.isSleeping == false)
|
||||||
Debug.Break();
|
Debug.Break();
|
||||||
}
|
}
|
||||||
trace = EditorGUILayout.Toggle("Trace", trace);
|
trace = EditorGUILayout.Toggle("Trace", trace);
|
||||||
@ -802,15 +831,19 @@ public class ClusterInspector : Editor {
|
|||||||
if (this.gameObject != null) {
|
if (this.gameObject != null) {
|
||||||
if (this.currentNucleus is IReceptor receptor) {
|
if (this.currentNucleus is IReceptor receptor) {
|
||||||
foreach (Nucleus nucleus in receptor.nucleiArray) {
|
foreach (Nucleus nucleus in receptor.nucleiArray) {
|
||||||
Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue);
|
if (nucleus is Neuron neuron) {
|
||||||
Handles.color = Color.yellow;
|
Vector3 worldVector = this.gameObject.transform.TransformVector(neuron.outputValue);
|
||||||
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
Handles.color = Color.yellow;
|
||||||
|
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue);
|
if (this.currentNucleus is Neuron currentNeuron) {
|
||||||
Handles.color = Color.yellow;
|
Vector3 worldVector = this.gameObject.transform.TransformVector(currentNeuron.outputValue);
|
||||||
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
Handles.color = Color.yellow;
|
||||||
|
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -825,15 +858,15 @@ public class ClusterInspector : Editor {
|
|||||||
case Nucleus.Type.MemoryCell:
|
case Nucleus.Type.MemoryCell:
|
||||||
AddMemoryCellInput(nucleus);
|
AddMemoryCellInput(nucleus);
|
||||||
break;
|
break;
|
||||||
case Nucleus.Type.Selector:
|
// case Nucleus.Type.Selector:
|
||||||
AddSelectorInput(nucleus);
|
// AddSelectorInput(nucleus);
|
||||||
break;
|
// break;
|
||||||
case Nucleus.Type.Cluster:
|
case Nucleus.Type.Cluster:
|
||||||
AddClusterInput(nucleus);
|
AddClusterInput(nucleus);
|
||||||
break;
|
break;
|
||||||
case Nucleus.Type.Pulsar:
|
// case Nucleus.Type.Pulsar:
|
||||||
AddPulsarInput(nucleus);
|
// AddPulsarInput(nucleus);
|
||||||
break;
|
// break;
|
||||||
case Nucleus.Type.Receptor:
|
case Nucleus.Type.Receptor:
|
||||||
AddReceptorInput(nucleus);
|
AddReceptorInput(nucleus);
|
||||||
break;
|
break;
|
||||||
@ -855,19 +888,19 @@ public class ClusterInspector : Editor {
|
|||||||
BuildLayers();
|
BuildLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AddSelectorInput(Nucleus nucleus) {
|
// protected void AddSelectorInput(Nucleus nucleus) {
|
||||||
Selector newSelector = new(this.prefab, "New Selector");
|
// Selector newSelector = new(this.prefab, "New Selector");
|
||||||
newSelector.AddReceiver(nucleus);
|
// newSelector.AddReceiver(nucleus);
|
||||||
this.currentNucleus = newSelector;
|
// this.currentNucleus = newSelector;
|
||||||
BuildLayers();
|
// BuildLayers();
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected void AddPulsarInput(Nucleus nucleus) {
|
// protected void AddPulsarInput(Nucleus nucleus) {
|
||||||
Pulsar newPulsar = new(this.prefab, "New Pulsar");
|
// Pulsar newPulsar = new(this.prefab, "New Pulsar");
|
||||||
newPulsar.AddReceiver(nucleus);
|
// newPulsar.AddReceiver(nucleus);
|
||||||
this.currentNucleus = newPulsar;
|
// this.currentNucleus = newPulsar;
|
||||||
BuildLayers();
|
// BuildLayers();
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected virtual void AddMemoryCellInput(Nucleus nucleus) {
|
protected virtual void AddMemoryCellInput(Nucleus nucleus) {
|
||||||
MemoryCell newMemory = new(this.prefab, "New memory cell");
|
MemoryCell newMemory = new(this.prefab, "New memory cell");
|
||||||
|
|||||||
53
Neuron.cs
53
Neuron.cs
@ -117,6 +117,23 @@ public class Neuron : Nucleus {
|
|||||||
|
|
||||||
#endregion Serialization
|
#endregion Serialization
|
||||||
|
|
||||||
|
protected float3 _outputValue;
|
||||||
|
public virtual float3 outputValue {
|
||||||
|
get { return _outputValue; }
|
||||||
|
set {
|
||||||
|
_outputValue = value;
|
||||||
|
if (this.isFiring)
|
||||||
|
WhenFiring?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool isFiring => length(_outputValue) > 0.5f;
|
||||||
|
public Action WhenFiring;
|
||||||
|
|
||||||
|
public virtual bool isSleeping => lengthsq(this.outputValue) == 0;
|
||||||
|
[NonSerialized]
|
||||||
|
public int stale = 1000;
|
||||||
|
public readonly int staleValueForSleep = 20;
|
||||||
|
|
||||||
// this clone the nucleus without the synapses and receivers
|
// this clone the nucleus without the synapses and receivers
|
||||||
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
||||||
Neuron clone = new(newParent, this.name);
|
Neuron clone = new(newParent, this.name);
|
||||||
@ -164,7 +181,8 @@ public class Neuron : Nucleus {
|
|||||||
if (receiver != null && receiver.synapses != null)
|
if (receiver != null && receiver.synapses != null)
|
||||||
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
|
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||||
}
|
}
|
||||||
} else if (nucleus is Cluster cluster) {
|
}
|
||||||
|
else if (nucleus is Cluster cluster) {
|
||||||
// remove all receivers for this cluster
|
// remove all receivers for this cluster
|
||||||
foreach (Neuron output in cluster.outputs) {
|
foreach (Neuron output in cluster.outputs) {
|
||||||
foreach (Nucleus receiver in output.receivers) {
|
foreach (Nucleus receiver in output.receivers) {
|
||||||
@ -197,15 +215,19 @@ public class Neuron : Nucleus {
|
|||||||
|
|
||||||
public float3 CombinatorSum() {
|
public float3 CombinatorSum() {
|
||||||
float3 sum = this.bias;
|
float3 sum = this.bias;
|
||||||
foreach (Synapse synapse in this.synapses)
|
foreach (Synapse synapse in this.synapses) {
|
||||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
if (synapse.nucleus is Neuron neuron)
|
||||||
|
sum += synapse.weight * neuron.outputValue;
|
||||||
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float3 CombinatorProduct() {
|
public float3 CombinatorProduct() {
|
||||||
float3 product = this.bias;
|
float3 product = this.bias;
|
||||||
foreach (Synapse synapse in this.synapses)
|
foreach (Synapse synapse in this.synapses) {
|
||||||
product *= synapse.weight * synapse.nucleus.outputValue;
|
if (synapse.nucleus is Neuron neuron)
|
||||||
|
product *= synapse.weight * neuron.outputValue;
|
||||||
|
}
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,12 +237,14 @@ public class Neuron : Nucleus {
|
|||||||
|
|
||||||
//Applying the weight factors
|
//Applying the weight factors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
foreach (Synapse synapse in this.synapses) {
|
||||||
float3 input = synapse.weight * synapse.nucleus.outputValue;
|
if (synapse.nucleus is Neuron neuron) {
|
||||||
|
float3 input = synapse.weight * neuron.outputValue;
|
||||||
|
|
||||||
float inputLength = length(input);
|
float inputLength = length(input);
|
||||||
if (inputLength > maxLength) {
|
if (inputLength > maxLength) {
|
||||||
max = input;
|
max = input;
|
||||||
maxLength = inputLength;
|
maxLength = inputLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max;
|
return max;
|
||||||
@ -288,8 +312,8 @@ public class Neuron : Nucleus {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// else {
|
// else {
|
||||||
this._receivers.Add(receiverToAdd);
|
this._receivers.Add(receiverToAdd);
|
||||||
receiverToAdd.AddSynapse(this, weight);
|
receiverToAdd.AddSynapse(this, weight);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,8 +337,9 @@ public class Neuron : Nucleus {
|
|||||||
|
|
||||||
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||||
if (this.parent is ClusterReceptor clusterReceptor) {
|
if (this.parent is ClusterReceptor clusterReceptor) {
|
||||||
clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
|
clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ProcessStimulusDirect(inputValue, thingId, thingName);
|
ProcessStimulusDirect(inputValue, thingId, thingName);
|
||||||
// this.stale = 0;
|
// this.stale = 0;
|
||||||
// this.bias = inputValue;
|
// this.bias = inputValue;
|
||||||
|
|||||||
32
Nucleus.cs
32
Nucleus.cs
@ -13,22 +13,22 @@ public abstract class Nucleus {
|
|||||||
[SerializeReference]
|
[SerializeReference]
|
||||||
public Cluster parent;
|
public Cluster parent;
|
||||||
|
|
||||||
protected float3 _outputValue;
|
// protected float3 _outputValue;
|
||||||
public virtual float3 outputValue {
|
// public virtual float3 outputValue {
|
||||||
get { return _outputValue; }
|
// get { return _outputValue; }
|
||||||
set {
|
// set {
|
||||||
_outputValue = value;
|
// _outputValue = value;
|
||||||
if (this.isFiring)
|
// if (this.isFiring)
|
||||||
WhenFiring?.Invoke();
|
// WhenFiring?.Invoke();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
public bool isFiring => length(_outputValue) > 0.5f;
|
// public bool isFiring => length(_outputValue) > 0.5f;
|
||||||
public Action WhenFiring;
|
// public Action WhenFiring;
|
||||||
|
|
||||||
public virtual bool isSleeping => lengthsq(this.outputValue) == 0;
|
// public virtual bool isSleeping => lengthsq(this.outputValue) == 0;
|
||||||
[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 bool trace = false;
|
||||||
|
|
||||||
public abstract Nucleus ShallowCloneTo(Cluster parent);
|
public abstract Nucleus ShallowCloneTo(Cluster parent);
|
||||||
@ -81,7 +81,7 @@ public abstract class Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetBias(Vector3 inputValue) {
|
public virtual void SetBias(Vector3 inputValue) {
|
||||||
this.stale = 0;
|
//this.stale = 0;
|
||||||
this.bias = inputValue;
|
this.bias = inputValue;
|
||||||
this.parent.UpdateFromNucleus(this);
|
this.parent.UpdateFromNucleus(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,9 +69,11 @@ public class NucleusArray {
|
|||||||
private Nucleus FindReceiver(int thingId, float3 inputValue) {
|
private Nucleus FindReceiver(int thingId, float3 inputValue) {
|
||||||
// No existing nucleus for this thing
|
// No existing nucleus for this thing
|
||||||
float inputMagnitude = length(inputValue);
|
float inputMagnitude = length(inputValue);
|
||||||
Nucleus selectedReceiver = null;
|
Neuron selectedReceiver = null;
|
||||||
float selectedMagnitude = 0;
|
float selectedMagnitude = 0;
|
||||||
foreach (Nucleus receiver in this._nuclei) {
|
foreach (Nucleus nucleusReceiver in this._nuclei) {
|
||||||
|
if (nucleusReceiver is not Neuron receiver)
|
||||||
|
continue;
|
||||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||||
// We found an unusued receiver
|
// We found an unusued receiver
|
||||||
thingReceivers.Add(thingId, receiver);
|
thingReceivers.Add(thingId, receiver);
|
||||||
@ -138,7 +140,7 @@ public class NucleusArray {
|
|||||||
// Remove a thing-receiver connection when the nucleus is inactive
|
// Remove a thing-receiver connection when the nucleus is inactive
|
||||||
List<int> receiversToRemove = new();
|
List<int> receiversToRemove = new();
|
||||||
foreach (KeyValuePair<int, Nucleus> item in thingReceivers) {
|
foreach (KeyValuePair<int, Nucleus> item in thingReceivers) {
|
||||||
if (item.Value != null && item.Value.isSleeping)
|
if (item.Value != null && item.Value is Neuron neuron && neuron.isSleeping)
|
||||||
receiversToRemove.Add(item.Key);
|
receiversToRemove.Add(item.Key);
|
||||||
}
|
}
|
||||||
foreach (int thingId in receiversToRemove) {
|
foreach (int thingId in receiversToRemove) {
|
||||||
|
|||||||
98
Pulsar.cs
98
Pulsar.cs
@ -1,54 +1,54 @@
|
|||||||
using System;
|
// using System;
|
||||||
using Unity.Mathematics;
|
// using Unity.Mathematics;
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// The Pulsar represents a type of neuron that operates based on
|
// /// The Pulsar represents a type of neuron that operates based on
|
||||||
/// the product of its weighted inputs rather than the traditional summation.
|
// /// the product of its weighted inputs rather than the traditional summation.
|
||||||
/// Drawing inspiration from the concept of pulsars in astrophysics
|
// /// Drawing inspiration from the concept of pulsars in astrophysics
|
||||||
/// —highly magnetized rotating neutron stars that emit beams of radiation—
|
// /// —highly magnetized rotating neutron stars that emit beams of radiation—
|
||||||
/// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors.
|
// /// the Pulsar could symbolize dynamic, focused output based on the interaction of multiple factors.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// Multiplicative Functionality:
|
// /// Multiplicative Functionality:
|
||||||
/// Instead of summing inputs, the Pulsar takes the weighted product of its inputs.
|
// /// Instead of summing inputs, the Pulsar takes the weighted product of its inputs.
|
||||||
/// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate.
|
// /// This means that all inputs must be active (non-zero) for the neuron to "pulse" or activate.
|
||||||
/// Output Behavior:
|
// /// Output Behavior:
|
||||||
/// The output could amplify or diminish depending on the magnitude of the inputs.
|
// /// The output could amplify or diminish depending on the magnitude of the inputs.
|
||||||
/// The product would be sensitive to small values,
|
// /// The product would be sensitive to small values,
|
||||||
/// which means that even a small input could significantly lower the overall output if multiplied.
|
// /// which means that even a small input could significantly lower the overall output if multiplied.
|
||||||
/// Activation Mechanism:
|
// /// Activation Mechanism:
|
||||||
/// The activation function can further refine the output from the product result.
|
// /// The activation function can further refine the output from the product result.
|
||||||
/// For instance, a certain threshold could be used to determine if a pulse occurs.
|
// /// For instance, a certain threshold could be used to determine if a pulse occurs.
|
||||||
/// Modeling Complex Interactions:
|
// /// Modeling Complex Interactions:
|
||||||
/// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add.
|
// /// The Pulsar could be particularly beneficial for modeling situations where interactions multiply rather than add.
|
||||||
/// This is useful in fields such as economics (e.g., compound growth models),
|
// /// This is useful in fields such as economics (e.g., compound growth models),
|
||||||
/// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist.
|
// /// biology (e.g., interaction of hormones), and machine learning where multiplicative relationships exist.
|
||||||
[Serializable]
|
// [Serializable]
|
||||||
public class Pulsar : Neuron {
|
// public class Pulsar : Neuron {
|
||||||
public Pulsar(Cluster parent, string name) : base(parent, name) {
|
// public Pulsar(Cluster parent, string name) : base(parent, name) {
|
||||||
// To prevent mistakes, bias one (instead of zero for standard neurons)
|
// // To prevent mistakes, bias one (instead of zero for standard neurons)
|
||||||
this.bias = new float3(1, 1, 1);
|
// this.bias = new float3(1, 1, 1);
|
||||||
}
|
// }
|
||||||
public Pulsar(ClusterPrefab parent, string name) : base(parent, name) {
|
// public Pulsar(ClusterPrefab parent, string name) : base(parent, name) {
|
||||||
// To prevent mistakes, bias one (instead of zero for standard neurons)
|
// // To prevent mistakes, bias one (instead of zero for standard neurons)
|
||||||
this.bias = new float3(1, 1, 1);
|
// this.bias = new float3(1, 1, 1);
|
||||||
}
|
// }
|
||||||
|
|
||||||
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
// public override Nucleus ShallowCloneTo(Cluster newParent) {
|
||||||
Pulsar clone = new(newParent, this.name);
|
// Pulsar clone = new(newParent, this.name);
|
||||||
CloneFields(clone);
|
// CloneFields(clone);
|
||||||
return clone;
|
// return clone;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
// public override void UpdateStateIsolated() {
|
||||||
float3 product = this.bias;
|
// float3 product = this.bias;
|
||||||
|
|
||||||
//Applying the weight factors
|
// //Applying the weight factors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
// foreach (Synapse synapse in this.synapses) {
|
||||||
float3 input = synapse.weight * synapse.nucleus.outputValue;
|
// float3 input = synapse.weight * synapse.nucleus.outputValue;
|
||||||
product *= input;
|
// product *= input;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Activation function
|
// // Activation function
|
||||||
this.outputValue = Activator(product);
|
// this.outputValue = Activator(product);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
112
Selector.cs
112
Selector.cs
@ -1,62 +1,62 @@
|
|||||||
using System;
|
// using System;
|
||||||
using Unity.Mathematics;
|
// using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
// using static Unity.Mathematics.math;
|
||||||
|
|
||||||
[Serializable]
|
// [Serializable]
|
||||||
public class Selector : Neuron {
|
// public class Selector : Neuron {
|
||||||
public Selector(Cluster parent, string name) : base(parent, name) { }
|
// public Selector(Cluster parent, string name) : base(parent, name) { }
|
||||||
public Selector(ClusterPrefab parent, string name) : base(parent, name) {}
|
// public Selector(ClusterPrefab parent, string name) : base(parent, name) {}
|
||||||
|
|
||||||
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
// public override Nucleus ShallowCloneTo(Cluster newParent) {
|
||||||
Selector clone = new(newParent, this.name) {
|
// Selector clone = new(newParent, this.name) {
|
||||||
// array = this.array,
|
// // array = this.array,
|
||||||
curve = this.curve,
|
// curve = this.curve,
|
||||||
curvePreset = this.curvePreset,
|
// curvePreset = this.curvePreset,
|
||||||
curveMax = this.curveMax,
|
// curveMax = this.curveMax,
|
||||||
};
|
// };
|
||||||
return clone;
|
// return clone;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public override void UpdateStateIsolated() { //float3 bias) {
|
// public override void UpdateStateIsolated() { //float3 bias) {
|
||||||
float3 max = this.bias;
|
// float3 max = this.bias;
|
||||||
float maxSqrLength = lengthsq(max);
|
// float maxSqrLength = lengthsq(max);
|
||||||
|
|
||||||
//Applying the weight factors
|
// //Applying the weight factors
|
||||||
foreach (Synapse synapse in this.synapses) {
|
// foreach (Synapse synapse in this.synapses) {
|
||||||
float3 input = synapse.weight * synapse.nucleus.outputValue;
|
// float3 input = synapse.weight * synapse.nucleus.outputValue;
|
||||||
|
|
||||||
float inputSqrlength = lengthsq(input);
|
// float inputSqrlength = lengthsq(input);
|
||||||
if (inputSqrlength > maxSqrLength) {
|
// if (inputSqrlength > maxSqrLength) {
|
||||||
max = input;
|
// max = input;
|
||||||
maxSqrLength = inputSqrlength;
|
// maxSqrLength = inputSqrlength;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Activation function
|
// // Activation function
|
||||||
float3 result;
|
// float3 result;
|
||||||
switch (this.curvePreset) {
|
// switch (this.curvePreset) {
|
||||||
case CurvePresets.Linear:
|
// case CurvePresets.Linear:
|
||||||
result = max;
|
// result = max;
|
||||||
break;
|
// break;
|
||||||
case CurvePresets.Sqrt:
|
// case CurvePresets.Sqrt:
|
||||||
result = normalize(max) * System.MathF.Sqrt(length(max));
|
// result = normalize(max) * System.MathF.Sqrt(length(max));
|
||||||
break;
|
// break;
|
||||||
case CurvePresets.Power:
|
// case CurvePresets.Power:
|
||||||
result = normalize(max) * System.MathF.Pow(length(max), 2);
|
// result = normalize(max) * System.MathF.Pow(length(max), 2);
|
||||||
break;
|
// break;
|
||||||
case CurvePresets.Reciprocal: {
|
// case CurvePresets.Reciprocal: {
|
||||||
float magnitude = length(max);
|
// float magnitude = length(max);
|
||||||
if (magnitude > 0)
|
// if (magnitude > 0)
|
||||||
result = normalize(max) * (1 / magnitude);
|
// result = normalize(max) * (1 / magnitude);
|
||||||
else
|
// else
|
||||||
result = float3(0, 0, 0);
|
// result = float3(0, 0, 0);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
default:
|
// default:
|
||||||
float activatedValue = this.curve.Evaluate(length(max));
|
// float activatedValue = this.curve.Evaluate(length(max));
|
||||||
result = normalize(max) * activatedValue;
|
// result = normalize(max) * activatedValue;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
this.outputValue = result;
|
// this.outputValue = result;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Loading…
x
Reference in New Issue
Block a user