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