Made Unity.Mathematics optional
This commit is contained in:
parent
b3423b99a7
commit
bef7ee24e5
@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
#endif
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Cluster : Nucleus {
|
public class Cluster : Nucleus {
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
#endif
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@ -140,6 +142,8 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
selectedNeuron.ProcessStimulusDirect(inputValue);
|
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) {
|
private ClusterReceptor FindReceiver2(int thingId, float3 inputValue, Neuron input) {
|
||||||
// No existing nucleus for this thing
|
// No existing nucleus for this thing
|
||||||
ClusterReceptor selectedReceiver = null;
|
ClusterReceptor selectedReceiver = null;
|
||||||
@ -192,6 +196,61 @@ public class ClusterReceptor : Cluster, IReceptor {
|
|||||||
return selectedReceiver;
|
return selectedReceiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
private ClusterReceptor FindReceiver2(int thingId, Vector3 inputValue, Neuron input) {
|
||||||
|
// No existing nucleus for this thing
|
||||||
|
ClusterReceptor selectedReceiver = null;
|
||||||
|
float selectedMagnitude = 0;
|
||||||
|
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.defaultOutput.isSleeping) {
|
||||||
|
// A sleeping receiver is not active and can therefore always be used
|
||||||
|
thingReceivers.Add(thingId, receiver);
|
||||||
|
receiver.bias = new Vector3(0, 0, 0);
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
else if (selectedReceiver == null) {
|
||||||
|
// If we haven't found a receiver yet, just start by taking the first
|
||||||
|
selectedReceiver = receiver;
|
||||||
|
selectedMagnitude = selectedReceiver.defaultOutput.outputValue.magnitude;
|
||||||
|
}
|
||||||
|
// Look for the receiver with the lowest output magnitude
|
||||||
|
else {
|
||||||
|
float magnitude = receiver.defaultOutput.outputValue.magnitude;
|
||||||
|
|
||||||
|
if (receiver.defaultOutput.outputValue.magnitude < selectedMagnitude) {
|
||||||
|
selectedReceiver = receiver;
|
||||||
|
selectedMagnitude = selectedReceiver.defaultOutput.outputValue.magnitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedReceiver != null) {
|
||||||
|
// To re-initialize the cluster (esp. memory cells)
|
||||||
|
// we update the cluster neuron twice.
|
||||||
|
// Bit of a hack.....
|
||||||
|
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
||||||
|
if (inputIx >= 0) {
|
||||||
|
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
||||||
|
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
private void CleanupReceivers() {
|
private void CleanupReceivers() {
|
||||||
// Remove a thing-receiver connection when the nucleus is inactive
|
// Remove a thing-receiver connection when the nucleus is inactive
|
||||||
|
|||||||
@ -4,8 +4,10 @@ using UnityEditor;
|
|||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
using Unity.Mathematics;
|
// #if UNITY_MATHEMATICS
|
||||||
using static Unity.Mathematics.math;
|
// using Unity.Mathematics;
|
||||||
|
// using static Unity.Mathematics.math;
|
||||||
|
// #endif
|
||||||
|
|
||||||
[CustomEditor(typeof(ClusterPrefab))]
|
[CustomEditor(typeof(ClusterPrefab))]
|
||||||
public class ClusterInspector : Editor {
|
public class ClusterInspector : Editor {
|
||||||
@ -263,7 +265,7 @@ public class ClusterInspector : Editor {
|
|||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
foreach (Nucleus nucleus in receptor1.nucleiArray) {
|
foreach (Nucleus nucleus in receptor1.nucleiArray) {
|
||||||
if (nucleus is Neuron neuron) {
|
if (nucleus is Neuron neuron) {
|
||||||
float value = length(neuron.outputValue);
|
float value = neuron.outputMagnitude;
|
||||||
if (value > maxValue)
|
if (value > maxValue)
|
||||||
maxValue = value;
|
maxValue = value;
|
||||||
}
|
}
|
||||||
@ -313,9 +315,9 @@ public class ClusterInspector : Editor {
|
|||||||
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
||||||
float maxValue = 1;
|
float maxValue = 1;
|
||||||
if (this.currentNucleus is Neuron neuron)
|
if (this.currentNucleus is Neuron neuron)
|
||||||
maxValue = length(neuron.outputValue);
|
maxValue = neuron.outputMagnitude;
|
||||||
else if (this.currentNucleus is Cluster cluster)
|
else if (this.currentNucleus is Cluster cluster)
|
||||||
maxValue = length(cluster.defaultOutput.outputValue);
|
maxValue = cluster.defaultOutput.outputMagnitude;
|
||||||
|
|
||||||
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
||||||
|
|
||||||
@ -327,9 +329,9 @@ public class ClusterInspector : Editor {
|
|||||||
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
Handles.DrawSolidDisc(position, Vector3.forward, size + 2);
|
||||||
float maxValue = 1;
|
float maxValue = 1;
|
||||||
if (this.currentNucleus is Neuron neuron)
|
if (this.currentNucleus is Neuron neuron)
|
||||||
maxValue = length(neuron.outputValue);
|
maxValue = neuron.outputMagnitude;
|
||||||
else if (this.currentNucleus is Cluster cluster)
|
else if (this.currentNucleus is Cluster cluster)
|
||||||
maxValue = length(cluster.defaultOutput.outputValue);
|
maxValue = cluster.defaultOutput.outputMagnitude;
|
||||||
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
DrawNucleus(this.currentNucleus, position, maxValue, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,7 +352,7 @@ public class ClusterInspector : Editor {
|
|||||||
float maxValue = 0;
|
float maxValue = 0;
|
||||||
foreach (Nucleus receiver in receivers) {
|
foreach (Nucleus receiver in receivers) {
|
||||||
if (receiver is Neuron neuroid) {
|
if (receiver is Neuron neuroid) {
|
||||||
float value = length(neuroid.outputValue);
|
float value = neuroid.outputMagnitude;
|
||||||
if (value > maxValue)
|
if (value > maxValue)
|
||||||
maxValue = value;
|
maxValue = value;
|
||||||
}
|
}
|
||||||
@ -405,7 +407,7 @@ public class ClusterInspector : Editor {
|
|||||||
drawnArrays.Add(clusterReceptor.nucleiArray);
|
drawnArrays.Add(clusterReceptor.nucleiArray);
|
||||||
}
|
}
|
||||||
if (synapse.neuron is Neuron synapseNeuron) {
|
if (synapse.neuron is Neuron synapseNeuron) {
|
||||||
float value = length(synapseNeuron.outputValue) * synapse.weight;
|
float value = synapseNeuron.outputMagnitude * synapse.weight;
|
||||||
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
|
// Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}");
|
||||||
if (value > maxValue)
|
if (value > maxValue)
|
||||||
maxValue = value;
|
maxValue = value;
|
||||||
@ -442,7 +444,7 @@ public class ClusterInspector : Editor {
|
|||||||
maxValue = 1;
|
maxValue = 1;
|
||||||
float brightness = 0;
|
float brightness = 0;
|
||||||
if (synapse.neuron is Neuron synapseNeuron)
|
if (synapse.neuron is Neuron synapseNeuron)
|
||||||
brightness = length(synapseNeuron.outputValue * synapse.weight) / maxValue;
|
brightness = synapseNeuron.outputMagnitude * synapse.weight / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
}
|
}
|
||||||
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) {
|
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) {
|
||||||
@ -464,7 +466,7 @@ public class ClusterInspector : Editor {
|
|||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
float brightness = 0;
|
float brightness = 0;
|
||||||
if (nucleus is Neuron neuron)
|
if (nucleus is Neuron neuron)
|
||||||
brightness = length(neuron.outputValue) / maxValue;
|
brightness = neuron.outputMagnitude / maxValue;
|
||||||
color = new Color(brightness, brightness, brightness, 1f);
|
color = new Color(brightness, brightness, brightness, 1f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -557,7 +559,7 @@ public class ClusterInspector : Editor {
|
|||||||
if (nucleus is Neuron neuron) {
|
if (nucleus is Neuron neuron) {
|
||||||
tooltip = new(
|
tooltip = new(
|
||||||
$"{nucleus.name}" +
|
$"{nucleus.name}" +
|
||||||
$"\nValue: {length(neuron.outputValue)}");
|
$"\nValue: {neuron.outputMagnitude}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tooltip = new($"{nucleus.name}");
|
tooltip = new($"{nucleus.name}");
|
||||||
@ -641,7 +643,7 @@ public class ClusterInspector : Editor {
|
|||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
if (currentNucleus is Neuron currentNeuron1) {
|
if (currentNucleus is Neuron currentNeuron1) {
|
||||||
GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString());
|
GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString());
|
||||||
EditorGUILayout.FloatField(nameLabel, length(currentNeuron1.outputValue));
|
EditorGUILayout.FloatField(nameLabel, currentNeuron1.outputMagnitude);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
EditorGUILayout.LabelField(" ");
|
EditorGUILayout.LabelField(" ");
|
||||||
@ -723,7 +725,7 @@ public class ClusterInspector : Editor {
|
|||||||
if (synapse.neuron is Neuron synapseNeuron) {
|
if (synapse.neuron is Neuron synapseNeuron) {
|
||||||
Vector3 value = synapseNeuron.outputValue * synapse.weight;
|
Vector3 value = synapseNeuron.outputValue * synapse.weight;
|
||||||
GUIContent synapseValueLabel = new(synapse.neuron.name, synapseNeuron.outputValue.ToString());
|
GUIContent synapseValueLabel = new(synapse.neuron.name, synapseNeuron.outputValue.ToString());
|
||||||
EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue));
|
EditorGUILayout.FloatField(synapseValueLabel, synapseNeuron.outputMagnitude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
78
Editor/ConfigurationChecker.cs
Normal file
78
Editor/ConfigurationChecker.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
|
||||||
|
class ConfigurationChecker {
|
||||||
|
|
||||||
|
[DidReloadScripts]
|
||||||
|
protected static void DidReloadScripts() {
|
||||||
|
CheckUnityMathematics();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CheckUnityMathematics() {
|
||||||
|
bool available = isUnityMathematicsAvailable;
|
||||||
|
UpdateDefine(available, "UNITY_MATHEMATICS");
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void UpdateDefine(bool enabled, string define) {
|
||||||
|
if (enabled)
|
||||||
|
GlobalDefine(define);
|
||||||
|
else
|
||||||
|
GlobalUndefine(define);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void GlobalDefine(string name) {
|
||||||
|
UnityEngine.Debug.Log("Define " + name);
|
||||||
|
BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
|
||||||
|
NamedBuildTarget namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
|
||||||
|
//string scriptDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
|
||||||
|
string scriptDefines = PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget);
|
||||||
|
if (!scriptDefines.Contains(name)) {
|
||||||
|
string newScriptDefines = scriptDefines + " " + name;
|
||||||
|
if (EditorUserBuildSettings.selectedBuildTargetGroup != 0)
|
||||||
|
PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, newScriptDefines);
|
||||||
|
//PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newScriptDefines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GlobalUndefine(string name) {
|
||||||
|
UnityEngine.Debug.Log("Undefine " + name);
|
||||||
|
BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
|
||||||
|
NamedBuildTarget namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup);
|
||||||
|
// string scriptDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
|
||||||
|
string scriptDefines = PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget);
|
||||||
|
if (scriptDefines.Contains(name)) {
|
||||||
|
int playMakerIndex = scriptDefines.IndexOf(name);
|
||||||
|
string newScriptDefines = scriptDefines.Remove(playMakerIndex, name.Length);
|
||||||
|
PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, newScriptDefines);
|
||||||
|
// PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newScriptDefines);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Availability
|
||||||
|
|
||||||
|
#region Packages
|
||||||
|
|
||||||
|
private static bool isUnityMathematicsAvailable {
|
||||||
|
get => DoesTypeExist("Unity.Mathematics.float3");
|
||||||
|
// {
|
||||||
|
// return DoesTypeExist("Passer.Tracking.HydraBaseStation");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
#endregion Packages
|
||||||
|
|
||||||
|
public static bool DoesTypeExist(string className) {
|
||||||
|
System.Reflection.Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
foreach (System.Reflection.Assembly assembly in assemblies) {
|
||||||
|
if (assembly.GetType(className) != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Availability
|
||||||
|
}
|
||||||
2
Editor/ConfigurationChecker.cs.meta
Normal file
2
Editor/ConfigurationChecker.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c7539a20f7894542ca347730cd8417b1
|
||||||
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
#endif
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class MemoryCell : Neuron {
|
public class MemoryCell : Neuron {
|
||||||
@ -28,11 +30,15 @@ public class MemoryCell : Neuron {
|
|||||||
|
|
||||||
private bool initialized = false;
|
private bool initialized = false;
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
private float3 _memorizedValue;
|
private float3 _memorizedValue;
|
||||||
|
#else
|
||||||
|
private UnityEngine.Vector3 _memorizedValue;
|
||||||
|
#endif
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
public override void UpdateStateIsolated() {
|
||||||
// A memorycell does not have an activation function
|
// A memorycell does not have an activation function
|
||||||
float3 result = Combinator();
|
var result = Combinator();
|
||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
// Output the previous, memorized value
|
// Output the previous, memorized value
|
||||||
|
|||||||
115
Neuron.cs
115
Neuron.cs
@ -2,8 +2,10 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
#endif
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Neuron : Nucleus {
|
public class Neuron : Nucleus {
|
||||||
@ -116,6 +118,8 @@ public class Neuron : Nucleus {
|
|||||||
|
|
||||||
#endregion Serialization
|
#endregion Serialization
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
protected float3 _outputValue;
|
protected float3 _outputValue;
|
||||||
public virtual float3 outputValue {
|
public virtual float3 outputValue {
|
||||||
get { return _outputValue; }
|
get { return _outputValue; }
|
||||||
@ -125,10 +129,30 @@ public class Neuron : Nucleus {
|
|||||||
WhenFiring?.Invoke();
|
WhenFiring?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public float outputMagnitude => length(_outputValue);
|
||||||
|
|
||||||
public bool isFiring => length(_outputValue) > 0.5f;
|
public bool isFiring => length(_outputValue) > 0.5f;
|
||||||
|
public virtual bool isSleeping => lengthsq(this.outputValue) == 0;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
protected Vector3 _outputValue;
|
||||||
|
public virtual Vector3 outputValue {
|
||||||
|
get { return _outputValue; }
|
||||||
|
set {
|
||||||
|
_outputValue = value;
|
||||||
|
if (this.isFiring)
|
||||||
|
WhenFiring?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float outputMagnitude => _outputValue.magnitude;
|
||||||
|
|
||||||
|
public bool isFiring => _outputValue.magnitude > 0.5f;
|
||||||
|
public virtual bool isSleeping => this.outputValue.sqrMagnitude == 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
public Action WhenFiring;
|
public Action WhenFiring;
|
||||||
|
|
||||||
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;
|
||||||
@ -199,12 +223,14 @@ public class Neuron : Nucleus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateStateIsolated() {
|
public override void UpdateStateIsolated() {
|
||||||
float3 result = Combinator();
|
var result = Combinator();
|
||||||
this.outputValue = Activator(result);
|
this.outputValue = Activator(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Combinator
|
#region Combinator
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
protected Func<float3> Combinator => combinator switch {
|
protected Func<float3> Combinator => combinator switch {
|
||||||
CombinatorType.Sum => CombinatorSum,
|
CombinatorType.Sum => CombinatorSum,
|
||||||
CombinatorType.Product => CombinatorProduct,
|
CombinatorType.Product => CombinatorProduct,
|
||||||
@ -244,10 +270,54 @@ public class Neuron : Nucleus {
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
protected Func<Vector3> Combinator => combinator switch {
|
||||||
|
CombinatorType.Sum => CombinatorSum,
|
||||||
|
CombinatorType.Product => CombinatorProduct,
|
||||||
|
CombinatorType.Max => CombinatorMax,
|
||||||
|
_ => CombinatorSum
|
||||||
|
};
|
||||||
|
|
||||||
|
public Vector3 CombinatorSum() {
|
||||||
|
Vector3 sum = this.bias;
|
||||||
|
foreach (Synapse synapse in this.synapses)
|
||||||
|
sum += synapse.weight * synapse.neuron.outputValue;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 CombinatorProduct() {
|
||||||
|
Vector3 product = this.bias;
|
||||||
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
//product *= synapse.weight * synapse.neuron.outputValue;
|
||||||
|
product = Vector3.Scale(product, synapse.weight * synapse.neuron.outputValue);
|
||||||
|
}
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 CombinatorMax() {
|
||||||
|
Vector3 max = this.bias;
|
||||||
|
float maxLength = max.magnitude;
|
||||||
|
|
||||||
|
//Applying the weight factors
|
||||||
|
foreach (Synapse synapse in this.synapses) {
|
||||||
|
Vector3 input = synapse.weight * synapse.neuron.outputValue;
|
||||||
|
|
||||||
|
float inputLength = input.magnitude;
|
||||||
|
if (inputLength > maxLength) {
|
||||||
|
max = input;
|
||||||
|
maxLength = inputLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endregion Combinator
|
#endregion Combinator
|
||||||
|
|
||||||
#region Activator
|
#region Activator
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
public Func<float3, float3> Activator => this.curvePreset switch {
|
public Func<float3, float3> Activator => this.curvePreset switch {
|
||||||
CurvePresets.Linear => ActivatorLinear,
|
CurvePresets.Linear => ActivatorLinear,
|
||||||
CurvePresets.Sqrt => ActivatorSqrt,
|
CurvePresets.Sqrt => ActivatorSqrt,
|
||||||
@ -285,6 +355,47 @@ public class Neuron : Nucleus {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
public Func<Vector3, Vector3> Activator => this.curvePreset switch {
|
||||||
|
CurvePresets.Linear => ActivatorLinear,
|
||||||
|
CurvePresets.Sqrt => ActivatorSqrt,
|
||||||
|
CurvePresets.Power => ActivatorPower,
|
||||||
|
CurvePresets.Reciprocal => ActivatorReciprocal,
|
||||||
|
_ => ActivatorCustom
|
||||||
|
};
|
||||||
|
|
||||||
|
protected Vector3 ActivatorLinear(Vector3 input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector3 ActivatorSqrt(Vector3 input) {
|
||||||
|
Vector3 result = input.normalized * System.MathF.Sqrt(input.magnitude);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector3 ActivatorPower(Vector3 input) {
|
||||||
|
Vector3 result = input.normalized * System.MathF.Pow(input.magnitude, 2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector3 ActivatorReciprocal(Vector3 input) {
|
||||||
|
float magnitude = input.magnitude;
|
||||||
|
if (magnitude == 0)
|
||||||
|
return new Vector3(0, 0, 0);
|
||||||
|
|
||||||
|
Vector3 result = input.normalized * (1 / magnitude);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector3 ActivatorCustom(Vector3 input) {
|
||||||
|
float activatedValue = this.curve.Evaluate(input.magnitude);
|
||||||
|
Vector3 result = input.normalized * activatedValue;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endregion Activator
|
#endregion Activator
|
||||||
|
|
||||||
#region Receivers
|
#region Receivers
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
#endif
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class NucleusArray {
|
public class NucleusArray {
|
||||||
@ -65,6 +67,7 @@ public class NucleusArray {
|
|||||||
|
|
||||||
public Dictionary<int, Nucleus> thingReceivers = new();
|
public Dictionary<int, Nucleus> thingReceivers = new();
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
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
|
||||||
@ -111,6 +114,54 @@ public class NucleusArray {
|
|||||||
return selectedReceiver;
|
return selectedReceiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
private Nucleus FindReceiver(int thingId, Vector3 inputValue) {
|
||||||
|
// No existing nucleus for this thing
|
||||||
|
float inputMagnitude = inputValue.magnitude;
|
||||||
|
Neuron selectedReceiver = null;
|
||||||
|
float selectedMagnitude = 0;
|
||||||
|
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);
|
||||||
|
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 = selectedReceiver.outputMagnitude;
|
||||||
|
}
|
||||||
|
// Look for the receiver with the lowest magnitude
|
||||||
|
else {
|
||||||
|
float magnitude = receiver.outputMagnitude;
|
||||||
|
|
||||||
|
if (magnitude < inputMagnitude && receiver.outputMagnitude < selectedMagnitude) {
|
||||||
|
selectedReceiver = receiver;
|
||||||
|
selectedMagnitude = selectedReceiver.outputMagnitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||||
CleanupReceivers();
|
CleanupReceivers();
|
||||||
|
|
||||||
|
|||||||
16
Receptor.cs
16
Receptor.cs
@ -1,6 +1,8 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using static Unity.Mathematics.math;
|
using static Unity.Mathematics.math;
|
||||||
|
#endif
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class Receptor : Neuron, IReceptor {
|
public class Receptor : Neuron, IReceptor {
|
||||||
@ -63,6 +65,8 @@ public class Receptor : Neuron, IReceptor {
|
|||||||
this.outputValue = this.bias;
|
this.outputValue = this.bias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
|
||||||
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) {
|
||||||
@ -71,6 +75,18 @@ public class Receptor : Neuron, IReceptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
public override void UpdateNuclei() {
|
||||||
|
this.stale++;
|
||||||
|
if (this.stale > staleValueForSleep && this.bias.sqrMagnitude > 0) {
|
||||||
|
this.bias = new Vector3(0, 0, 0);
|
||||||
|
this.parent.UpdateFromNucleus(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
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);
|
||||||
|
|||||||
8
Runtime.meta
Normal file
8
Runtime.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5a33d0cc40bc19fe98b76f6aed80a38e
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Runtime/Vector.cs
Normal file
8
Runtime/Vector.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#if UNITY_MATHEMATICS
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using static Unity.Mathematics.math;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
Runtime/Vector.cs.meta
Normal file
2
Runtime/Vector.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 76e9f0d4925b7ac278baa9932582ed10
|
||||||
Loading…
x
Reference in New Issue
Block a user