Compare commits
21 Commits
d2b5d2feac
...
b3423b99a7
| Author | SHA1 | Date | |
|---|---|---|---|
| b3423b99a7 | |||
| 4805e81f09 | |||
| 28ef70c773 | |||
| ccb7a41577 | |||
| 8a9700981b | |||
| 28ffae8ce7 | |||
| 1dfe65eefa | |||
| 172d7ca8e8 | |||
| 9c730709f1 | |||
| cbc8296e55 | |||
| f8b487cef7 | |||
| abbce40992 | |||
| 3cdca017d6 | |||
| bd24e6e19b | |||
| 96b240ad6c | |||
| 463bef0868 | |||
| b0ee3add3a | |||
| 83e8bd70f1 | |||
| 97ea988cca | |||
| f9ce73fd7a | |||
| 2ef9629e4d |
271
Cluster.cs
271
Cluster.cs
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
@ -8,6 +7,15 @@ using static Unity.Mathematics.math;
|
||||
[Serializable]
|
||||
public class Cluster : Nucleus {
|
||||
|
||||
public string baseName {
|
||||
get {
|
||||
int colonPositon = this.name.IndexOf(':');
|
||||
if (colonPositon < 0)
|
||||
return this.name;
|
||||
return this.name[..colonPositon];
|
||||
}
|
||||
}
|
||||
|
||||
#region Init
|
||||
|
||||
public Cluster(ClusterPrefab prefab, Cluster parent) {
|
||||
@ -39,7 +47,6 @@ public class Cluster : Nucleus {
|
||||
Nucleus[] prefabNuclei = this.prefab.nuclei.ToArray();
|
||||
// first clone the nuclei without their connections
|
||||
foreach (Nucleus nucleus in this.prefab.nuclei) {
|
||||
// Debug.Log($"prefab clone {nucleus.name}");
|
||||
nucleus.ShallowCloneTo(this);
|
||||
}
|
||||
Nucleus[] clonedNuclei = this.clusterNuclei.ToArray();
|
||||
@ -68,7 +75,7 @@ public class Cluster : Nucleus {
|
||||
float weight = 1;
|
||||
foreach (Synapse synapse in receiver.synapses) {
|
||||
// Find the weight for this synapse
|
||||
if (synapse.nucleus == prefabNucleus) {
|
||||
if (synapse.neuron == prefabNucleus) {
|
||||
weight = synapse.weight;
|
||||
break;
|
||||
}
|
||||
@ -78,40 +85,46 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
}
|
||||
|
||||
// Copy nucleus arrays
|
||||
// Copy nucleus arrays for receptors
|
||||
for (int nucleusIx = 0; nucleusIx < prefabNuclei.Length; nucleusIx++) {
|
||||
Nucleus prefabReceptor = prefabNuclei[nucleusIx];
|
||||
if (prefabReceptor is not Receptor prefabNucleus)
|
||||
Nucleus prefabNucleus = prefabNuclei[nucleusIx];
|
||||
if (prefabNucleus is not IReceptor prefabReceptor)
|
||||
continue;
|
||||
|
||||
if (prefabNucleus.nucleiArray == null || prefabNucleus.nucleiArray.Length == 0)
|
||||
if (prefabReceptor.nucleiArray == null || prefabReceptor.nucleiArray.Length == 0)
|
||||
continue;
|
||||
|
||||
Receptor clonedNucleus = clonedNuclei[nucleusIx] as Receptor;
|
||||
if (prefabNucleus == prefabNucleus.nucleiArray[0]) {
|
||||
IReceptor clonedNucleus = clonedNuclei[nucleusIx] as IReceptor;
|
||||
if (prefabReceptor == prefabReceptor.nucleiArray[0]) {
|
||||
// We clone the array only for the first entry
|
||||
NucleusArray clonedArray = new(prefabNucleus.nucleiArray.Length, "array");
|
||||
NucleusArray clonedArray = new(prefabReceptor.nucleiArray.Length, "array");
|
||||
int arrayIx = 0;
|
||||
foreach (Nucleus prefabArrayNucleus in prefabNucleus.nucleiArray) {
|
||||
foreach (Nucleus prefabArrayNucleus in prefabReceptor.nucleiArray) {
|
||||
int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus);
|
||||
if (arrayNucleusIx >= 0) {
|
||||
Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx];
|
||||
clonedArray.nuclei[arrayIx] = clonedArrayNucleus;
|
||||
}
|
||||
else {
|
||||
Debug.LogError($" Could not find prefab nuclues {prefabNucleus.name} in the clones");
|
||||
Debug.LogError($" Could not find prefab nucleus {prefabNucleus.name} in the clones");
|
||||
}
|
||||
arrayIx++;
|
||||
}
|
||||
clonedNucleus.array = clonedArray;
|
||||
//clonedNucleus.array = clonedArray;
|
||||
clonedNucleus.nucleiArray = clonedArray.nuclei;
|
||||
}
|
||||
else {
|
||||
// The others will refer to the array created for the first nucleus in the array
|
||||
int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.nucleiArray[0]);
|
||||
Receptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Receptor;
|
||||
int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabReceptor.nucleiArray[0]);
|
||||
IReceptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as IReceptor;
|
||||
clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is Cluster clonedSubCluster)
|
||||
RestoreAllExternalReceivers(clonedSubCluster, this.prefab, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the nuclei in a correct evaluation order
|
||||
@ -122,7 +135,11 @@ public class Cluster : Nucleus {
|
||||
|
||||
// Calculate in-degrees
|
||||
foreach (Nucleus node in nodes) {
|
||||
if (node is Neuron neuron) {
|
||||
if (node is Cluster cluster) {
|
||||
foreach (Nucleus receiver in cluster.CollectReceivers())
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
else if (node is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers)
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
@ -147,6 +164,13 @@ public class Cluster : Nucleus {
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
else if (current is Cluster cluster) {
|
||||
foreach (Nucleus receiver in cluster.CollectReceivers()) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for cycles in the graph
|
||||
@ -160,7 +184,7 @@ public class Cluster : Nucleus {
|
||||
Cluster clone = new(this.prefab, parent);
|
||||
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
|
||||
@ -185,48 +209,45 @@ public class Cluster : Nucleus {
|
||||
name = this.name,
|
||||
clusterPrefab = this.clusterPrefab,
|
||||
};
|
||||
// This cloned the prefab with the clusternuclei,
|
||||
// but did not clone the receivers outside the cluster
|
||||
RestoreExternalReceivers(clone, this.clusterPrefab, parent);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected void RestoreExternalReceivers(Cluster clone, ClusterPrefab prefabParent, Cluster clonedParent) {
|
||||
for (int nucleusIx = 0; nucleusIx < this.clusterNuclei.Count; nucleusIx++) {
|
||||
Nucleus prefabNucleus = this.clusterNuclei[nucleusIx];
|
||||
if (prefabNucleus is not Neuron prefabNeuron)
|
||||
private static void RestoreAllExternalReceivers(Cluster clonedCluster, ClusterPrefab prefabParent, Cluster clonedParent) {
|
||||
int clonedClusterIx = GetNucleusIndex(clonedParent.clusterNuclei, clonedCluster);
|
||||
if (prefabParent.nuclei[clonedClusterIx] is not Cluster sourceCluster)
|
||||
return;
|
||||
|
||||
for (int nucleusIx = 0; nucleusIx < sourceCluster.clusterNuclei.Count; nucleusIx++) {
|
||||
Nucleus sourceNucleus = sourceCluster.clusterNuclei[nucleusIx];
|
||||
if (sourceNucleus is not Neuron sourceNeuron)
|
||||
continue;
|
||||
|
||||
Nucleus clonedNucleus = clone.clusterNuclei[nucleusIx];
|
||||
if (clonedNucleus == null || clonedNucleus is not Neuron clonedNeuron)
|
||||
if (clonedCluster.clusterNuclei[nucleusIx] is not Neuron clonedNeuron)
|
||||
continue;
|
||||
|
||||
// Copy the receivers, which will also create the synapses
|
||||
foreach (Nucleus receiver in prefabNeuron.receivers) {
|
||||
// copy the receivers (and thus synapses) from the source to the clone
|
||||
foreach (Nucleus receiver in sourceNeuron.receivers) {
|
||||
int ix = GetNucleusIndex(prefabParent.nuclei, receiver);
|
||||
if (ix < 0)
|
||||
if (ix < 0 || ix >= clonedParent.clusterNuclei.Count)
|
||||
continue;
|
||||
|
||||
//if (clone.clusterNuclei[ix] is not Nucleus clonedReceiver)
|
||||
if (clonedParent.clusterNuclei[ix] is not Nucleus clonedReceiver)
|
||||
continue;
|
||||
Nucleus clonedReceiver = clonedParent.clusterNuclei[ix];
|
||||
|
||||
// Find the synapse for the weight
|
||||
float weight = 1;
|
||||
foreach (Synapse synapse in receiver.synapses) {
|
||||
// Find the weight for this synapse
|
||||
if (synapse.nucleus == prefabNucleus) {
|
||||
if (synapse.neuron == sourceNucleus) {
|
||||
weight = synapse.weight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clonedNeuron.AddReceiver(clonedReceiver, weight);
|
||||
// Debug.Log($"external: {clonedReceiver.name} receives from {clonedNeuron.name} {clonedNeuron.GetHashCode()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected int GetNucleusIndex(Nucleus[] nuclei, Nucleus nucleus) {
|
||||
@ -237,12 +258,13 @@ public class Cluster : Nucleus {
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected int GetNucleusIndex(List<Nucleus> nuclei, Nucleus nucleus) {
|
||||
public static int GetNucleusIndex(List<Nucleus> nuclei, Nucleus nucleus) {
|
||||
int i = 0;
|
||||
foreach (Nucleus nucleiElement in nuclei) {
|
||||
//for (int i = 0; i < nuclei.Length; i++) {
|
||||
if (nucleus == nucleiElement)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -277,19 +299,17 @@ public class Cluster : Nucleus {
|
||||
|
||||
public Dictionary<Nucleus, List<Nucleus>> computeOrders = new();
|
||||
private void ComputeOrders() {
|
||||
foreach (Nucleus input in this._inputs) {
|
||||
foreach (Nucleus input in this._inputs)
|
||||
computeOrders[input] = TopologicalSort2(input);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Nucleus> TopologicalSort2(Nucleus startNode) {
|
||||
Dictionary<Nucleus, int> inDegree = new Dictionary<Nucleus, int>();
|
||||
HashSet<Nucleus> visited = new HashSet<Nucleus>();
|
||||
Dictionary<Nucleus, int> inDegree = new();
|
||||
HashSet<Nucleus> visited = new();
|
||||
|
||||
// Initialize in-degrees and mark all nodes as unvisited
|
||||
foreach (Nucleus node in this.clusterNuclei) {
|
||||
foreach (Nucleus node in this.clusterNuclei)
|
||||
inDegree[node] = 0;
|
||||
}
|
||||
|
||||
// Calculate in-degrees for all nodes reachable from the start node
|
||||
Queue<Nucleus> queue = new Queue<Nucleus>();
|
||||
@ -298,23 +318,28 @@ public class Cluster : Nucleus {
|
||||
|
||||
while (queue.Count > 0) {
|
||||
Nucleus current = queue.Dequeue();
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (!visited.Contains(receiver)) {
|
||||
visited.Add(receiver);
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
inDegree[receiver]++;
|
||||
List<Nucleus> receivers = null;
|
||||
if (current is Neuron neuron)
|
||||
receivers = neuron.receivers;
|
||||
else if (current is Cluster cluster)
|
||||
receivers = cluster.CollectReceivers();
|
||||
|
||||
// if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in receivers) {
|
||||
if (!visited.Contains(receiver)) {
|
||||
visited.Add(receiver);
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
// Perform topological sort on all reachable nodes
|
||||
queue.Clear();
|
||||
foreach (var node in visited) {
|
||||
if (inDegree[node] == 0) {
|
||||
foreach (Nucleus node in visited) {
|
||||
if (inDegree[node] == 0)
|
||||
queue.Enqueue(node);
|
||||
}
|
||||
}
|
||||
|
||||
List<Nucleus> sortedOrder = new List<Nucleus>();
|
||||
@ -322,58 +347,27 @@ public class Cluster : Nucleus {
|
||||
Nucleus current = queue.Dequeue();
|
||||
sortedOrder.Add(current); // Process the node
|
||||
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (visited.Contains(receiver)) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Nucleus> receivers = null;
|
||||
if (current is Neuron neuron)
|
||||
receivers = neuron.receivers;
|
||||
else if (current is Cluster cluster)
|
||||
receivers = cluster.CollectReceivers();
|
||||
|
||||
// Check for cycles in the graph
|
||||
if (sortedOrder.Count != visited.Count)
|
||||
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||
//if (current is Neuron neuron) {
|
||||
|
||||
return sortedOrder;
|
||||
}
|
||||
|
||||
private List<Nucleus> TopologicalSort3(Nucleus startNode) {
|
||||
Dictionary<Nucleus, int> inDegree = new();
|
||||
foreach (Nucleus node in this.clusterNuclei)
|
||||
inDegree[node] = 0; // Initialize in-degree to zero
|
||||
|
||||
// Calculate in-degrees
|
||||
foreach (Nucleus node in this.clusterNuclei) {
|
||||
if (node is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers)
|
||||
inDegree[receiver]++;
|
||||
}
|
||||
}
|
||||
|
||||
Queue<Nucleus> queue = new();
|
||||
queue.Enqueue(startNode);
|
||||
|
||||
List<Nucleus> sortedOrder = new();
|
||||
while (queue.Count > 0) {
|
||||
Nucleus current = queue.Dequeue();
|
||||
sortedOrder.Add(current); // Process the node
|
||||
|
||||
if (current is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
foreach (Nucleus receiver in receivers) {
|
||||
if (visited.Contains(receiver)) {
|
||||
inDegree[receiver]--;
|
||||
if (inDegree[receiver] == 0) // If all dependencies resolved
|
||||
queue.Enqueue(receiver);
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
Debug.Log($"Compute order for {startNode.name} length = {sortedOrder.Count}");
|
||||
// Check for cycles in the graph
|
||||
// if (sortedOrder.Count != this.nuclei.Count)
|
||||
// throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||
if (sortedOrder.Count != visited.Count)
|
||||
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
|
||||
|
||||
return sortedOrder;
|
||||
}
|
||||
@ -412,31 +406,50 @@ public class Cluster : Nucleus {
|
||||
}
|
||||
|
||||
public Nucleus GetNucleus(string nucleusName) {
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus.name == nucleusName)
|
||||
return nucleus;
|
||||
int dotPosition = nucleusName.IndexOf('.');
|
||||
if (dotPosition >= 0) {
|
||||
string clusterName = nucleusName[..dotPosition];
|
||||
string clusterName0 = clusterName + ": 0";
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is Cluster cluster) {
|
||||
if (cluster.name == clusterName || cluster.name == clusterName0) {
|
||||
string subNucleusName = nucleusName[(dotPosition + 1)..];
|
||||
return cluster.GetNucleus(subNucleusName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
string nucleusName0 = nucleusName + ": 0";
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is IReceptor receptor) {
|
||||
if (nucleus.name == nucleusName | nucleus.name == nucleusName0)
|
||||
return nucleus;
|
||||
}
|
||||
else if (nucleus.name == nucleusName)
|
||||
return nucleus;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IReceptor GetReceptor(string receptorName) {
|
||||
string receptorName0 = receptorName + ": 0";
|
||||
foreach (Nucleus nucleus in this.clusterNuclei) {
|
||||
if (nucleus is IReceptor receptor) {
|
||||
if (nucleus.name == receptorName | nucleus.name == receptorName0)
|
||||
//if (receptor.GetName() == receptorName)
|
||||
return receptor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// [Obsolete("Use GetNucleus instead")]
|
||||
// public IReceptor GetReceptor(string receptorName) {
|
||||
// return GetNucleus(receptorName) as IReceptor;
|
||||
// }
|
||||
|
||||
#region Receivers
|
||||
|
||||
public virtual List<Nucleus> CollectReceivers() {
|
||||
List<Nucleus> receivers = new();
|
||||
foreach (Neuron output in this.outputs) {
|
||||
receivers.AddRange(output.receivers);
|
||||
foreach (Nucleus receiver in output.receivers) {
|
||||
// Only add receivers outside this cluster
|
||||
if (receiver.clusterPrefab != this.prefab)
|
||||
receivers.Add(receiver);
|
||||
//receivers.AddRange(output.receivers);
|
||||
}
|
||||
}
|
||||
return receivers;
|
||||
}
|
||||
@ -448,39 +461,41 @@ public class Cluster : Nucleus {
|
||||
public void UpdateFromNucleus(Nucleus startNucleus) {
|
||||
// no bias+synapse input state calculation for now...
|
||||
|
||||
if (this.computeOrders.ContainsKey(startNucleus) == false) {
|
||||
//Debug.LogError($"{this.name} compute orders does not contain an order for {startNucleus.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Nucleus> computeOrder = this.computeOrders[startNucleus];
|
||||
if (startNucleus.trace)
|
||||
Debug.Log($"Update from {startNucleus.name}");
|
||||
foreach (Nucleus nucleus in computeOrder) {
|
||||
nucleus.UpdateStateIsolated();
|
||||
if (startNucleus.trace)
|
||||
Debug.Log($" {nucleus.name} = {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;
|
||||
// continue in parent
|
||||
this.parent?.UpdateFromNucleus(this);
|
||||
|
||||
UpdateNuclei();
|
||||
}
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
float3 sum = this.bias;
|
||||
throw new Exception("Cluster should not be updated!");
|
||||
// float3 sum = this.bias;
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
// //Applying the weight factors
|
||||
// foreach (Synapse synapse in this.synapses) {
|
||||
// if (lengthsq(synapse.neuron.outputValue) > 0) {
|
||||
// sum += synapse.weight * synapse.neuron.outputValue;
|
||||
// }
|
||||
// }
|
||||
|
||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
nucleus.UpdateStateIsolated();
|
||||
// foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
// nucleus.UpdateStateIsolated();
|
||||
|
||||
this.outputValue = this.defaultOutput.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
// UpdateNuclei();
|
||||
}
|
||||
|
||||
public override void UpdateNuclei() {
|
||||
|
||||
@ -64,7 +64,6 @@ public class ClusterPrefab : ScriptableObject {
|
||||
HashSet<Nucleus> visitedNuclei = new();
|
||||
foreach (Nucleus output in this.outputs)
|
||||
MarkNuclei(visitedNuclei, output);
|
||||
//MarkNuclei(visitedNuclei, this.output);
|
||||
//Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei");
|
||||
this.nuclei.RemoveAll(nucleus => visitedNuclei.Contains(nucleus) == false);
|
||||
}
|
||||
@ -80,9 +79,9 @@ public class ClusterPrefab : ScriptableObject {
|
||||
if (nucleus.synapses != null) {
|
||||
HashSet<Synapse> visitedSynapses = new();
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
if (synapse != null && synapse.nucleus != null) {
|
||||
if (synapse != null && synapse.neuron != null) {
|
||||
visitedSynapses.Add(synapse);
|
||||
if (synapse.nucleus is Nucleus synapse_nucleus)
|
||||
if (synapse.neuron is Nucleus synapse_nucleus)
|
||||
MarkNuclei(visitedNuclei, synapse_nucleus);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,14 +3,18 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using System.Linq;
|
||||
|
||||
[Serializable]
|
||||
public class ClusterReceptor : Cluster, IReceptor {
|
||||
public ClusterReceptor(ClusterPrefab prefab, Cluster parent, string name) : base(prefab, parent) {
|
||||
this.name = name;
|
||||
this.array ??= new NucleusArray(this);
|
||||
this.array = new NucleusArray(this);
|
||||
if (this.name.IndexOf(":") < 0)
|
||||
this.name += ": 0";
|
||||
|
||||
}
|
||||
public ClusterReceptor(ClusterPrefab prefabToInstantiate, ClusterPrefab parent, string name) : base(prefabToInstantiate, parent) {
|
||||
public ClusterReceptor(ClusterPrefab prefab, ClusterPrefab parent, string name) : base(prefab, parent) {
|
||||
this.name = name;
|
||||
this.array = new NucleusArray(this);
|
||||
}
|
||||
@ -22,30 +26,21 @@ public class ClusterReceptor : Cluster, IReceptor {
|
||||
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||
ClusterReceptor clone = new(this.prefab, parent, this.name) {
|
||||
clusterPrefab = this.clusterPrefab,
|
||||
array = this.array
|
||||
};
|
||||
|
||||
// This cloned the prefab with the clusternuclei,
|
||||
// but did not clone the receivers outside the cluster
|
||||
RestoreExternalReceivers(clone, this.clusterPrefab, parent);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public override Nucleus Clone(ClusterPrefab parent) {
|
||||
ClusterReceptor clone = new(prefab, parent, this.name) {
|
||||
array = this.array
|
||||
array = this._array
|
||||
};
|
||||
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
|
||||
// foreach (Nucleus receiver in this.receivers) {
|
||||
// clone.AddReceiver(receiver);
|
||||
// }
|
||||
|
||||
this._outputs = null; // Make sure the output are regenerated
|
||||
foreach (Neuron output in this.outputs) {
|
||||
int ix = GetNucleusIndex(this.clusterNuclei, output);
|
||||
@ -58,53 +53,162 @@ public class ClusterReceptor : Cluster, IReceptor {
|
||||
return clone;
|
||||
}
|
||||
|
||||
public override List<Nucleus> CollectReceivers() {
|
||||
List<Nucleus> receivers = new();
|
||||
foreach (Nucleus element in this.nucleiArray) {
|
||||
if (element is not Cluster clusterElement)
|
||||
continue;
|
||||
|
||||
foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) {
|
||||
if (outputNucleus is not Neuron output)
|
||||
continue;
|
||||
|
||||
// this should be clusterElement.outputs,
|
||||
// but outputs is not updated when correctly and may contain old data...
|
||||
foreach (Nucleus receiver in output.receivers) {
|
||||
// Only add receivers outside clusterElement cluster
|
||||
if (receiver.clusterPrefab != clusterElement.prefab &&
|
||||
receivers.Contains(receiver) == false)
|
||||
receivers.Add(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
return receivers;
|
||||
}
|
||||
|
||||
[SerializeReference]
|
||||
private NucleusArray _array;
|
||||
public NucleusArray array {
|
||||
get { return _array; }
|
||||
set { _array = value; }
|
||||
}
|
||||
|
||||
//[SerializeReference]
|
||||
//private Nucleus[] _nucleusArray;
|
||||
public Nucleus[] nucleiArray {
|
||||
get { return _array.nuclei; }
|
||||
set { _array.nuclei = value; }
|
||||
}
|
||||
|
||||
public void AddReceptorElement(ClusterPrefab prefab) {
|
||||
this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab);
|
||||
IReceptorHelpers.AddReceptorElement(this, prefab);
|
||||
}
|
||||
|
||||
public void RemoveReceptorElement() {
|
||||
this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray);
|
||||
IReceptorHelpers.RemoveReceptorElement(this);
|
||||
}
|
||||
|
||||
public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
|
||||
}
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
float3 sum = this.bias;
|
||||
|
||||
foreach (Nucleus nucleus in this.sortedNuclei)
|
||||
nucleus.UpdateStateIsolated();
|
||||
|
||||
this.outputValue = this.defaultOutput.outputValue;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
// Clusters don't do anything,
|
||||
// The nuclei in them do the work
|
||||
// and should be called directly, not from the cluster
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
foreach (Nucleus nucleus in this.clusterNuclei)
|
||||
nucleus.UpdateNuclei();
|
||||
}
|
||||
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||
this.array ??= new NucleusArray(this.parent);
|
||||
this.array.ProcessStimulus(thingId, inputValue, thingName);
|
||||
public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||
Debug.LogError("Process Stimulus was called on clusterreceptor without a neuron specified");
|
||||
}
|
||||
|
||||
private readonly Dictionary<int, ClusterReceptor> thingReceivers = new();
|
||||
|
||||
public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||
CleanupReceivers();
|
||||
|
||||
if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver))
|
||||
selectedReceiver = FindReceiver2(thingId, inputValue, input);
|
||||
if (selectedReceiver == null)
|
||||
return;
|
||||
|
||||
if (thingName != null) {
|
||||
string baseName = selectedReceiver.name;
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
baseName = selectedReceiver.name[..colonPos];
|
||||
selectedReceiver.name = baseName + ": " + thingName;
|
||||
}
|
||||
|
||||
int inputIx = GetNucleusIndex(this.clusterNuclei, input);
|
||||
if (inputIx < 0)
|
||||
return;
|
||||
|
||||
if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron)
|
||||
selectedNeuron.ProcessStimulusDirect(inputValue);
|
||||
}
|
||||
|
||||
private ClusterReceptor FindReceiver2(int thingId, float3 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 = float3(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 = length(selectedReceiver.defaultOutput.outputValue);
|
||||
}
|
||||
// Look for the receiver with the lowest output magnitude
|
||||
else {
|
||||
float magnitude = length(receiver.defaultOutput.outputValue);
|
||||
|
||||
if (length(receiver.defaultOutput.outputValue) < selectedMagnitude) {
|
||||
selectedReceiver = receiver;
|
||||
selectedMagnitude = length(selectedReceiver.defaultOutput.outputValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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.defaultOutput.isSleeping)
|
||||
receiversToRemove.Add(item.Key);
|
||||
}
|
||||
foreach (int thingId in receiversToRemove) {
|
||||
Nucleus selectedReceiver = thingReceivers[thingId];
|
||||
|
||||
thingReceivers.Remove(thingId);
|
||||
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
selectedReceiver.name = selectedReceiver.name[..colonPos];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,12 +19,6 @@ public class ClusterInspector : Editor {
|
||||
public override VisualElement CreateInspectorGUI() {
|
||||
ClusterPrefab prefab = target as ClusterPrefab;
|
||||
|
||||
// string path = AssetDatabase.GetAssetPath(prefab); // or known path
|
||||
// Debug.Log($"{path}");
|
||||
// ClusterPrefab currentWrapper = AssetDatabase.LoadAssetAtPath<ClusterPrefab>(path);
|
||||
// if (currentWrapper == null)
|
||||
// Debug.LogError("CreateInspectorGUI: Cluster Prefab is not found on disk");
|
||||
|
||||
if (prefab != null)
|
||||
prefab.EnsureInitialization();
|
||||
|
||||
@ -182,7 +176,7 @@ public class ClusterInspector : Editor {
|
||||
if (this.prefabAsset == null) {
|
||||
// create in memory save if it doesn't exist
|
||||
this.prefabAsset = CreateInstance<ClusterPrefab>();
|
||||
Debug.LogError("Cluster Prefab is not found on disk");
|
||||
//Debug.LogError("Cluster Prefab is not found on disk");
|
||||
}
|
||||
DrawInspector(inspectorContainer);
|
||||
}
|
||||
@ -221,7 +215,7 @@ public class ClusterInspector : Editor {
|
||||
|
||||
if (selectedNucleus.synapses != null) {
|
||||
foreach (Synapse synapse in selectedNucleus.synapses) {
|
||||
Nucleus input = synapse.nucleus;
|
||||
Nucleus input = synapse.neuron;
|
||||
AddToLayer(currentLayer, input);
|
||||
// Debug.Log($"layer {layerIx} nucleus {input.name}");
|
||||
}
|
||||
@ -265,45 +259,14 @@ public class ClusterInspector : Editor {
|
||||
|
||||
// Draw selected Nucleus
|
||||
if (expandArray) {
|
||||
// if (this.currentNucleus is ReceptorArray receptor) {
|
||||
// float maxValue = 0;
|
||||
// foreach (Nucleus nucleus in receptor.instances) {
|
||||
// float value = length(nucleus.outputValue);
|
||||
// if (value > maxValue)
|
||||
// maxValue = value;
|
||||
// }
|
||||
|
||||
// float spacing = 400f / receptor.instances.Count();
|
||||
// float margin = 10 + spacing / 2;
|
||||
// float xMin = 150 - size;
|
||||
// float xMax = 150 + size;
|
||||
// float yMin = 10 + margin - size / 2;
|
||||
// float yMax = 400 - margin + size;
|
||||
// Vector3[] verts = new Vector3[4] {
|
||||
// new(xMin, yMin, 0),
|
||||
// new(xMax, yMin, 0),
|
||||
// new(xMax, yMax, 0),
|
||||
// new(xMin, yMax, 0)
|
||||
// };
|
||||
// Handles.color = Color.black;
|
||||
// Handles.DrawAAConvexPolygon(verts);
|
||||
// int row = 0;
|
||||
// foreach (Nucleus nucleus in receptor.instances) {
|
||||
// Vector3 pos = new(150, margin + row * spacing, 0.0f);
|
||||
// Handles.color = Color.white;
|
||||
// // The selected nucleus highlight ring
|
||||
// Handles.DrawSolidDisc(pos, Vector3.forward, size + 2);
|
||||
// DrawNucleus(nucleus, pos, maxValue, size);
|
||||
// row++;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
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();
|
||||
@ -348,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);
|
||||
|
||||
}
|
||||
}
|
||||
@ -356,12 +325,17 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
|
||||
List<Nucleus> receivers = null;
|
||||
List<Nucleus> receivers;
|
||||
if (nucleus is Neuron neuron)
|
||||
receivers = neuron.receivers;
|
||||
else if (nucleus is Cluster cluster)
|
||||
@ -417,20 +391,25 @@ public class ClusterInspector : Editor {
|
||||
int neuronCount = 0;
|
||||
List<Nucleus[]> drawnArrays = new();
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
if (synapse.nucleus is Receptor receptor) {
|
||||
if (synapse.neuron == null)
|
||||
continue;
|
||||
|
||||
if (synapse.neuron is Receptor receptor) {
|
||||
if (drawnArrays.Contains(receptor.nucleiArray))
|
||||
continue;
|
||||
drawnArrays.Add(receptor.nucleiArray);
|
||||
}
|
||||
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
|
||||
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
|
||||
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.neuron 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++;
|
||||
}
|
||||
|
||||
@ -441,12 +420,15 @@ public class ClusterInspector : Editor {
|
||||
int row = 0;
|
||||
drawnArrays = new();
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
if (synapse.nucleus is Receptor neuron) {
|
||||
if (synapse.neuron is null)
|
||||
continue;
|
||||
|
||||
if (synapse.neuron is Receptor neuron) {
|
||||
if (drawnArrays.Contains(neuron.nucleiArray))
|
||||
continue;
|
||||
drawnArrays.Add(neuron.nucleiArray);
|
||||
}
|
||||
else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) {
|
||||
else if (synapse.neuron.parent is ClusterReceptor clusterReceptor) {
|
||||
if (drawnArrays.Contains(clusterReceptor.nucleiArray))
|
||||
continue;
|
||||
drawnArrays.Add(clusterReceptor.nucleiArray);
|
||||
@ -458,18 +440,20 @@ 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.neuron 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) {
|
||||
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) {
|
||||
// the synapse nucleus is part of a subcluster
|
||||
DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color);
|
||||
DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color);
|
||||
}
|
||||
// else if (synapse.nucleus.cluster != null && synapse.nucleus.cluster != this.currentNucleus.cluster) {
|
||||
// DrawNucleus(synapse.nucleus.parent, pos, maxValue, size, color);
|
||||
// }
|
||||
else {
|
||||
DrawNucleus(synapse.nucleus, pos, maxValue, size, color);
|
||||
DrawNucleus(synapse.neuron, pos, maxValue, size, color);
|
||||
}
|
||||
row++;
|
||||
}
|
||||
@ -478,7 +462,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
|
||||
@ -505,11 +491,11 @@ public class ClusterInspector : Editor {
|
||||
fontStyle = FontStyle.Bold,
|
||||
};
|
||||
|
||||
if (nucleus is Receptor receptor1) {
|
||||
// draw the array size label
|
||||
if (expandArray) { //} && receptor1.array.nuclei.First() == this.currentNucleus) {
|
||||
if (nucleus is IReceptor receptor1) {
|
||||
if (expandArray) {
|
||||
// Put array indices above elements
|
||||
style.alignment = TextAnchor.LowerCenter;
|
||||
Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc along up axis
|
||||
Vector3 labelPos1 = position + Vector3.down * (size + 5); // below disc
|
||||
int colonPos1 = nucleus.name.IndexOf(":");
|
||||
if (colonPos1 > 0) {
|
||||
string extName = nucleus.name[(colonPos1 + 2)..];
|
||||
@ -517,6 +503,7 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// draw the array size label
|
||||
if (color.grayscale > 0.5f)
|
||||
style.normal.textColor = Color.black;
|
||||
else
|
||||
@ -525,59 +512,27 @@ public class ClusterInspector : Editor {
|
||||
style.normal.textColor = Color.white;
|
||||
}
|
||||
}
|
||||
// if (nucleus is ReceptorArray receptor) {
|
||||
// if (color.grayscale > 0.5f)
|
||||
// style.normal.textColor = Color.black;
|
||||
// else
|
||||
// style.normal.textColor = Color.white;
|
||||
// Handles.Label(labelPosition, receptor.instances.Count().ToString(), style);
|
||||
// }
|
||||
|
||||
if (nucleus is ClusterReceptor clusterReceptor) {
|
||||
// draw the array size label
|
||||
if (expandArray && clusterReceptor.array.nuclei.First() == this.currentNucleus) {
|
||||
style.alignment = TextAnchor.LowerCenter;
|
||||
Vector3 labelPos2 = position + Vector3.down * (size + 5); // below disc along up axis
|
||||
int colonPos2 = nucleus.name.IndexOf(":");
|
||||
if (colonPos2 > 0) {
|
||||
string extName = nucleus.name[(colonPos2 + 2)..];
|
||||
Handles.Label(labelPos2, extName, style);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (color.grayscale > 0.5f)
|
||||
style.normal.textColor = Color.black;
|
||||
else
|
||||
style.normal.textColor = Color.white;
|
||||
Handles.Label(labelPosition, clusterReceptor.array.nuclei.Length.ToString(), style);
|
||||
style.normal.textColor = Color.white;
|
||||
if (expandArray == false || nucleus is not IReceptor) {
|
||||
// put name below nucleus
|
||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below neuron
|
||||
style.alignment = TextAnchor.UpperCenter;
|
||||
|
||||
int colonPos = nucleus.name.IndexOf(":");
|
||||
if (colonPos > 0 && colonPos < nucleus.name.Length - 2) {
|
||||
// if it is an array, we should not show the :0 of the first element
|
||||
string baseName = nucleus.name[..colonPos];
|
||||
Handles.Label(labelPos, baseName, style);
|
||||
}
|
||||
else
|
||||
Handles.Label(labelPos, nucleus.name, style);
|
||||
|
||||
}
|
||||
|
||||
// if (expandArray && nucleus is Receptor receptor2 && receptor2.array.nuclei.First() == this.currentNucleus) {
|
||||
// style.alignment = TextAnchor.LowerCenter;
|
||||
// Vector3 labelPos = position + Vector3.down * (size + 5); // below disc along up axis
|
||||
// int colonPos = nucleus.name.IndexOf(":");
|
||||
// if (colonPos > 0) {
|
||||
// string extName = nucleus.name[(colonPos + 2)..];
|
||||
// Handles.Label(labelPos, extName, style);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
style.alignment = TextAnchor.UpperCenter;
|
||||
Vector3 labelPos = position - Vector3.down * (size + 5); // below disc along up axis
|
||||
int colonPos = nucleus.name.IndexOf(":");
|
||||
if (expandArray && nucleus is Receptor) { //} || (colonPos > 0 && colonPos < nucleus.name.Length - 2)) {
|
||||
// string baseName = nucleus.name[..colonPos];
|
||||
// Handles.Label(labelPos, baseName, style);
|
||||
}
|
||||
else
|
||||
Handles.Label(labelPos, nucleus.name, style);
|
||||
// }
|
||||
|
||||
// Draw Cluster ring
|
||||
if (nucleus is Cluster) {
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawWireDisc(position, Vector3.forward, size + 10);
|
||||
Handles.DrawWireDisc(position, Vector3.forward, size + 5);
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
@ -599,9 +554,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;
|
||||
|
||||
@ -619,11 +578,11 @@ public class ClusterInspector : Editor {
|
||||
else
|
||||
expandArray = false;
|
||||
}
|
||||
else if (nucleus is ReceptorInstance receptor) {
|
||||
this.currentNucleus = receptor.receptor;
|
||||
expandArray = false;
|
||||
BuildLayers();
|
||||
}
|
||||
// else if (nucleus is ReceptorInstance receptor) {
|
||||
// this.currentNucleus = receptor.receptor;
|
||||
// expandArray = false;
|
||||
// BuildLayers();
|
||||
// }
|
||||
else {
|
||||
this.currentNucleus = nucleus;
|
||||
expandArray = false;
|
||||
@ -631,6 +590,7 @@ public class ClusterInspector : Editor {
|
||||
}
|
||||
}
|
||||
|
||||
private VisualElement inspectorIMGUIContainer;
|
||||
private bool showSynapses = true;
|
||||
private bool showActivation = true;
|
||||
protected bool breakOnWake = false;
|
||||
@ -645,9 +605,9 @@ public class ClusterInspector : Editor {
|
||||
|
||||
// create a SerializedObject wrapper so Unity inspector controls work (and Undo)
|
||||
SerializedObject so = new(prefabAsset);
|
||||
IMGUIContainer container = new(() => InspectorHandler(so));
|
||||
this.inspectorIMGUIContainer = new IMGUIContainer(() => InspectorHandler(so));
|
||||
|
||||
inspectorContainer.Add(container);
|
||||
inspectorContainer.Add(inspectorIMGUIContainer);
|
||||
}
|
||||
|
||||
void InspectorHandler(SerializedObject serializedObject) {
|
||||
@ -675,11 +635,16 @@ public class ClusterInspector : Editor {
|
||||
this.currentNucleus.name = newName;
|
||||
this.prefab.RefreshOutputs();
|
||||
outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList();
|
||||
anythingChanged = true;
|
||||
}
|
||||
|
||||
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(" ");
|
||||
@ -687,162 +652,164 @@ public class ClusterInspector : Editor {
|
||||
if (this.currentNucleus is MemoryCell memory) {
|
||||
memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory);
|
||||
}
|
||||
if (this.currentNucleus is ReceptorArray receptor) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.IntField("Receptor size", receptor.instances.Count());
|
||||
if (GUILayout.Button("Add")) {
|
||||
Undo.RecordObject(prefabAsset, "Receptor add " + prefabAsset.name);
|
||||
receptor.AddReceptor(this.prefab);
|
||||
anythingChanged = true;
|
||||
}
|
||||
if (GUILayout.Button("Del")) {
|
||||
Undo.RecordObject(prefabAsset, "Receptor delete " + prefabAsset.name);
|
||||
receptor.RemoveReceptor();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
if (this.currentNucleus is Receptor receptor1) {
|
||||
|
||||
if (this.currentNucleus is IReceptor receptor1) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count());
|
||||
if (GUILayout.Button("Add")) {
|
||||
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||
//receptor1.array.AddNucleus(this.prefab);
|
||||
receptor1.AddReceptorElement(this.prefab);
|
||||
anythingChanged = true;
|
||||
}
|
||||
if (GUILayout.Button("Del")) {
|
||||
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
||||
//receptor1.array.RemoveNucleus();
|
||||
receptor1.RemoveReceptorElement();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else if (this.currentNucleus is ClusterReceptor receptor2) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.IntField("Array size", receptor2.array.nuclei.Count());
|
||||
if (GUILayout.Button("Add")) {
|
||||
Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name);
|
||||
receptor2.array.AddNucleus(this.prefab);
|
||||
anythingChanged = true;
|
||||
}
|
||||
if (GUILayout.Button("Del")) {
|
||||
Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name);
|
||||
receptor2.array.RemoveNucleus();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
// Synapses
|
||||
|
||||
if (this.currentNucleus is not Receptor && this.currentNucleus is not ClusterReceptor) {
|
||||
showSynapses = EditorGUILayout.BeginFoldoutHeaderGroup(showSynapses, "Synapses");
|
||||
if (showSynapses) {
|
||||
|
||||
anythingChanged = ConnectNucleus(this.prefab, this.currentNucleus);
|
||||
anythingChanged = AddSynapse(this.prefab, this.currentNucleus);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (this.currentNucleus is Neuron neuron2) {
|
||||
Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator);
|
||||
anythingChanged |= newCombinator != neuron2.combinator;
|
||||
neuron2.combinator = newCombinator;
|
||||
}
|
||||
|
||||
EditorGUIUtility.wideMode = true;
|
||||
EditorGUIUtility.labelWidth = 100;
|
||||
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", this.currentNucleus.bias);
|
||||
anythingChanged |= newBias != this.currentNucleus.bias;
|
||||
this.currentNucleus.bias = newBias;
|
||||
|
||||
Nucleus[] array = null;
|
||||
int elementIx = -1;
|
||||
if (this.currentNucleus.synapses.Count > 0) {
|
||||
Synapse[] synapses = this.currentNucleus.synapses.ToArray();
|
||||
foreach (Synapse synapse in synapses) {
|
||||
if (synapse.nucleus == null)
|
||||
if (synapse.neuron == null)
|
||||
continue;
|
||||
|
||||
if (array != null) {
|
||||
if (array.Contains(synapse.nucleus))
|
||||
continue;
|
||||
if (array.Contains(synapse.nucleus.parent))
|
||||
if (synapse.neuron.parent is Cluster iCluster && elementIx > 0) {
|
||||
int thisElementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
||||
if (thisElementIx == elementIx)
|
||||
continue;
|
||||
else
|
||||
elementIx = thisElementIx;
|
||||
}
|
||||
// if (array.Contains(synapse.nucleus))
|
||||
// continue;
|
||||
else if (array.Contains(synapse.neuron.parent))
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (synapse.nucleus.parent is ClusterReceptor clusterReceptor)
|
||||
array = clusterReceptor.nucleiArray;
|
||||
else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1)
|
||||
array = receptor2.nucleiArray;
|
||||
if (synapse.neuron.parent is IReceptor iReceptor) {
|
||||
array = iReceptor.nucleiArray;
|
||||
if (iReceptor is Cluster iCluster)
|
||||
elementIx = Cluster.GetNucleusIndex(iCluster.clusterNuclei, synapse.neuron);
|
||||
}
|
||||
// else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1)
|
||||
// array = receptor2.nucleiArray;
|
||||
}
|
||||
|
||||
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.neuron is Neuron synapseNeuron) {
|
||||
Vector3 value = synapseNeuron.outputValue * synapse.weight;
|
||||
GUIContent synapseValueLabel = new(synapse.neuron.name, synapseNeuron.outputValue.ToString());
|
||||
EditorGUILayout.FloatField(synapseValueLabel, length(synapseNeuron.outputValue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (synapse.nucleus.parent != null && synapse.nucleus.parent != this.currentNucleus) {
|
||||
if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus) {
|
||||
// If it is a cluster
|
||||
GUIStyle labelStyle = new(GUI.skin.label);
|
||||
float labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.nucleus.clusterPrefab.name}.")).x;
|
||||
EditorGUILayout.LabelField($"{synapse.nucleus.clusterPrefab.name}", GUILayout.Width(labelWidth));
|
||||
string[] options = synapse.nucleus.parent.clusterNuclei.Select(n => n.name).ToArray();
|
||||
int selectedIndex = System.Array.IndexOf(options, synapse.nucleus.name);
|
||||
float labelWidth = 200;
|
||||
if (synapse.neuron.clusterPrefab != null) {
|
||||
labelWidth = labelStyle.CalcSize(new GUIContent($"{synapse.neuron.parent.baseName}.")).x;
|
||||
GUILayout.Label($"{synapse.neuron.parent.baseName}", GUILayout.Width(labelWidth));
|
||||
}
|
||||
string[] options = synapse.neuron.parent.clusterNuclei.Select(n => n.name).ToArray();
|
||||
int selectedIndex = System.Array.IndexOf(options, synapse.neuron.name);
|
||||
int newIndex = EditorGUILayout.Popup(selectedIndex, options);
|
||||
if (newIndex != selectedIndex && synapse.nucleus.parent.clusterNuclei[newIndex] is Neuron newNeuron)
|
||||
if (newIndex != selectedIndex && synapse.neuron.parent.clusterNuclei[newIndex] is Neuron newNeuron)
|
||||
ChangeSynapse(synapse, newNeuron);
|
||||
}
|
||||
else
|
||||
EditorGUILayout.LabelField(synapse.nucleus.name);
|
||||
if (GUILayout.Button("Disconnect") && synapse.nucleus is Neuron synapseNeuron) {
|
||||
GUILayout.Label(synapse.neuron.name);
|
||||
|
||||
bool disconnecting = GUILayout.Button("Disconnect", GUILayout.Width(80));
|
||||
if (disconnecting && synapse.neuron is Neuron synapseNeuron) {
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
this.prefab.GarbageCollection();
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
synapse.weight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
||||
float newWeight = EditorGUILayout.FloatField("Weight", synapse.weight);
|
||||
if (newWeight != synapse.weight) {
|
||||
if (synapse.neuron.parent is IReceptor receptor) {
|
||||
Nucleus[] receptorArray = receptor.nucleiArray;
|
||||
foreach (Synapse s in this.currentNucleus.synapses) {
|
||||
if (s.neuron.parent is IReceptor r && r.nucleiArray == receptorArray)
|
||||
s.weight = newWeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
synapse.weight = newWeight;
|
||||
anythingChanged = true;
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
anythingChanged |= ConnectNucleus(this.prefab, this.currentNucleus);
|
||||
anythingChanged |= AddSynapse(this.prefab, this.currentNucleus);
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
}
|
||||
|
||||
// Activation
|
||||
|
||||
EditorGUILayout.Space();
|
||||
showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation");
|
||||
if (showActivation) {
|
||||
if (this.currentNucleus is Neuron neuron) {
|
||||
if (this.currentNucleus is not MemoryCell) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
|
||||
if (neuron.curveMax > 0)
|
||||
EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax));
|
||||
else
|
||||
EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax));
|
||||
Neuron.CurvePresets newPreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100));
|
||||
anythingChanged |= newPreset != neuron.curvePreset;
|
||||
neuron.curvePreset = newPreset;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
if (neuron is Receptor receptor2) {
|
||||
if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0)
|
||||
receptor2.array = new NucleusArray(neuron);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentNucleus is not Cluster) {
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation");
|
||||
if (showActivation) {
|
||||
if (this.currentNucleus is Neuron neuron) {
|
||||
if (this.currentNucleus is not MemoryCell) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Activation Curve", GUILayout.Width(150));
|
||||
if (neuron.curveMax > 0)
|
||||
EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax));
|
||||
else
|
||||
EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax));
|
||||
Neuron.CurvePresets newPreset = (Neuron.CurvePresets)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.Width(100));
|
||||
anythingChanged |= newPreset != neuron.curvePreset;
|
||||
neuron.curvePreset = newPreset;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
if (neuron is Receptor receptor2) {
|
||||
if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0)
|
||||
receptor2.array = new NucleusArray(neuron);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
EditorGUILayout.EndFoldoutHeaderGroup();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Delete this neuron"))
|
||||
DeleteNucleus(this.currentNucleus);
|
||||
@ -854,8 +821,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);
|
||||
@ -870,26 +837,20 @@ public class ClusterInspector : Editor {
|
||||
|
||||
void OnSceneGUI(SceneView sceneView) {
|
||||
if (this.gameObject != null) {
|
||||
if (this.currentNucleus is ReceptorArray receptor && expandArray) {
|
||||
foreach (Nucleus nucleus in receptor.instances) {
|
||||
Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue);
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.currentNucleus is Receptor receptor1) {
|
||||
foreach (Nucleus nucleus in receptor1.nucleiArray) {
|
||||
Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue);
|
||||
if (this.currentNucleus is IReceptor receptor) {
|
||||
foreach (Nucleus nucleus in receptor.nucleiArray) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -905,21 +866,21 @@ 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;
|
||||
case Nucleus.Type.ReceptorArray:
|
||||
AddReceptorArrayInput(nucleus);
|
||||
break;
|
||||
// case Nucleus.Type.ReceptorArray:
|
||||
// AddReceptorArrayInput(nucleus);
|
||||
// break;
|
||||
case Nucleus.Type.ClusterReceptor:
|
||||
AddClusterReceptorInput(nucleus);
|
||||
break;
|
||||
@ -935,19 +896,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");
|
||||
@ -959,6 +920,10 @@ public class ClusterInspector : Editor {
|
||||
protected virtual void AddClusterInput(Nucleus nucleus) {
|
||||
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
|
||||
}
|
||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) {
|
||||
Cluster subclusterInstance = new(prefab, this.prefab);
|
||||
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||
}
|
||||
|
||||
protected virtual void AddReceptorInput(Nucleus nucleus) {
|
||||
Receptor newReceptor = new(this.prefab, "New Receptor");
|
||||
@ -967,25 +932,14 @@ public class ClusterInspector : Editor {
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
protected virtual void AddReceptorArrayInput(Nucleus nucleus) {
|
||||
// ReceptorArray newReceptor = new(this.prefab, "New Receptor");
|
||||
// newReceptor.AddReceiver(nucleus);
|
||||
// this.currentNucleus = newReceptor;
|
||||
// BuildLayers();
|
||||
}
|
||||
|
||||
protected virtual void AddClusterReceptorInput(Nucleus nucleus) {
|
||||
ClusterPickerWindow.ShowPicker(prefab => OnClusterReceptorPicked(nucleus, prefab), "Select Cluster");
|
||||
}
|
||||
|
||||
private void OnClusterPicked(Nucleus nucleus, ClusterPrefab prefab) {
|
||||
Cluster subclusterInstance = new(prefab, this.prefab);
|
||||
subclusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||
}
|
||||
|
||||
private void OnClusterReceptorPicked(Nucleus nucleus, ClusterPrefab selectedPrefab) {
|
||||
ClusterReceptor clusterInstance = new(selectedPrefab, this.prefab, "New " + selectedPrefab.name);
|
||||
clusterInstance.defaultOutput.AddReceiver(nucleus);
|
||||
this.currentNucleus = clusterInstance;
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
private void EditCluster(Cluster subCluster) {
|
||||
@ -995,32 +949,41 @@ public class ClusterInspector : Editor {
|
||||
var editor = Editor.CreateEditor(subCluster.prefab);
|
||||
}
|
||||
|
||||
int selectedConnectNucleus = -1;
|
||||
// Connect to another nucleus in the same cluster
|
||||
protected virtual bool ConnectNucleus(ClusterPrefab cluster, Nucleus nucleusToConnect) {
|
||||
if (cluster == null)
|
||||
return false;
|
||||
|
||||
IEnumerable<Nucleus> synapseNuclei = this.currentNucleus.synapses
|
||||
.Where(synapse => synapse.nucleus != null)
|
||||
.Select(synapse => synapse.nucleus);
|
||||
.Where(synapse => synapse.neuron != null)
|
||||
.Select(synapse => synapse.neuron);
|
||||
|
||||
IEnumerable<Nucleus> nuclei = cluster.nuclei
|
||||
.Except(synapseNuclei);
|
||||
IEnumerable<string> nucleiNames = nuclei.Select(n => n.name);
|
||||
IEnumerable<string> nucleiNames = nuclei
|
||||
.Select(n => {
|
||||
int idx = n.name.IndexOf(':');
|
||||
return idx < 0 ? n.name : n.name[..idx];
|
||||
})
|
||||
.Distinct();
|
||||
|
||||
string[] names = nucleiNames.ToArray();
|
||||
int selectedIndex = -1;
|
||||
selectedIndex = EditorGUILayout.Popup("Connect", selectedIndex, names);
|
||||
if (selectedIndex < 0)
|
||||
return false;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
selectedConnectNucleus = EditorGUILayout.Popup(selectedConnectNucleus, names);
|
||||
bool connecting = GUILayout.Button("Connect", GUILayout.Width(80));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (connecting) {
|
||||
Nucleus nucleus = nuclei.ElementAt(selectedConnectNucleus);
|
||||
if (nucleus is IReceptor receptor)
|
||||
receptor.AddArrayReceiver(this.currentNucleus);
|
||||
else if (nucleus is Neuron neuron)
|
||||
neuron.AddReceiver(this.currentNucleus);
|
||||
else if (nucleus is Cluster subCluster)
|
||||
subCluster.defaultOutput.AddReceiver(this.currentNucleus);
|
||||
|
||||
Nucleus nucleus = nuclei.ElementAt(selectedIndex);
|
||||
if (nucleus is Neuron neuron)
|
||||
neuron.AddReceiver(this.currentNucleus);
|
||||
else if (nucleus is Cluster subCluster)
|
||||
subCluster.defaultOutput.AddReceiver(this.currentNucleus);
|
||||
|
||||
return true;
|
||||
}
|
||||
return connecting;
|
||||
}
|
||||
|
||||
protected virtual void DeleteNucleus(Nucleus nucleus) {
|
||||
@ -1049,24 +1012,61 @@ public class ClusterInspector : Editor {
|
||||
BuildLayers();
|
||||
}
|
||||
|
||||
Nucleus.Type selectedType = Nucleus.Type.None;
|
||||
protected virtual bool AddSynapse(ClusterPrefab cluster, Nucleus nucleus) {
|
||||
if (cluster == null)
|
||||
return false;
|
||||
|
||||
Nucleus.Type selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup("Add", Nucleus.Type.None);
|
||||
if (selectedType == Nucleus.Type.None)
|
||||
return false;
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
selectedType = (Nucleus.Type)EditorGUILayout.EnumPopup(selectedType);
|
||||
bool connecting = GUILayout.Button("Add", GUILayout.Width(80));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
AddInput(selectedType, this.currentNucleus);
|
||||
return true;
|
||||
if (connecting) {
|
||||
AddInput(selectedType, this.currentNucleus);
|
||||
}
|
||||
return connecting;
|
||||
// if (selectedType == Nucleus.Type.None)
|
||||
// return false;
|
||||
|
||||
// AddInput(selectedType, this.currentNucleus);
|
||||
// return true;
|
||||
}
|
||||
|
||||
protected virtual void ChangeSynapse(Synapse synapse, Neuron newNucleus) {
|
||||
Neuron synapseNeuron = synapse.nucleus as Neuron;
|
||||
if (synapse.nucleus.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
|
||||
// it is a neuron in a subcluster
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
newNucleus.AddReceiver(this.currentNucleus);
|
||||
Neuron synapseNeuron = synapse.neuron as Neuron;
|
||||
if (synapse.neuron.parent is Cluster subCluster && subCluster.prefab != this.prefab) {
|
||||
if (synapse.neuron.parent is ClusterReceptor receptor) {
|
||||
// the new nucleus is part of a (cluster) receptor,
|
||||
// so we have to change all synapses to this nucleus array elements
|
||||
int oldNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.neuron);
|
||||
int newNucleusIx = Cluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus);
|
||||
foreach (Nucleus element in receptor.nucleiArray) {
|
||||
if (element is not ClusterReceptor clusterReceptor)
|
||||
continue;
|
||||
// Get the same neuron as the synapse.nucleus in a different element
|
||||
// of the ClusterReceptor array
|
||||
Nucleus oldElementNucleus = clusterReceptor.clusterNuclei[oldNucleusIx];
|
||||
if (oldElementNucleus is not Neuron oldElementNeuron)
|
||||
continue;
|
||||
// Get the same neuron as newNucleus in a different element
|
||||
// of the ClusterReceptor array
|
||||
Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx];
|
||||
if (newElementNucleus is not Neuron newElementNeuron)
|
||||
continue;
|
||||
|
||||
oldElementNeuron.RemoveReceiver(this.currentNucleus);
|
||||
newElementNeuron.AddReceiver(this.currentNucleus);
|
||||
// Now find the synapse which pointed to the old Neuron
|
||||
// Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron);
|
||||
// synapseForUpdate.nucleus = newElementNeuron;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// it is a neuron in a subcluster
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
newNucleus.AddReceiver(this.currentNucleus);
|
||||
}
|
||||
}
|
||||
else {
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
@ -1077,12 +1077,12 @@ public class ClusterInspector : Editor {
|
||||
protected virtual void DisconnectNucleus(Neuron nucleus) {
|
||||
if (this.currentNucleus.clusterPrefab == null)
|
||||
return;
|
||||
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.nucleus.name).ToArray();
|
||||
string[] names = this.currentNucleus.synapses.Select(synapse => synapse.neuron.name).ToArray();
|
||||
int selectedIndex = -1;
|
||||
selectedIndex = EditorGUILayout.Popup("Disconnect from", selectedIndex, names);
|
||||
if (selectedIndex >= 0 && selectedIndex < this.currentNucleus.clusterPrefab.nuclei.Count) {
|
||||
Synapse synapse = this.currentNucleus.synapses[selectedIndex];
|
||||
Neuron synapseNeuron = synapse.nucleus as Neuron;
|
||||
Neuron synapseNeuron = synapse.neuron as Neuron;
|
||||
synapseNeuron.RemoveReceiver(this.currentNucleus);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,8 +17,10 @@ public class NanoBrainComponent_Editor : Editor {
|
||||
public void OnEnable() {
|
||||
component = target as NanoBrain;
|
||||
|
||||
if (Application.isPlaying == false)
|
||||
brainProp = serializedObject.FindProperty(nameof(NanoBrain.defaultBrain));
|
||||
if (Application.isPlaying == false && serializedObject != null) {
|
||||
string propertyName = nameof(NanoBrain.defaultBrain);
|
||||
brainProp = serializedObject.FindProperty(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public override VisualElement CreateInspectorGUI() {
|
||||
|
||||
62
IReceptor.cs
62
IReceptor.cs
@ -3,49 +3,71 @@ using UnityEngine;
|
||||
public interface IReceptor {
|
||||
public string GetName();
|
||||
|
||||
// public NucleusArray array {
|
||||
// get; set;
|
||||
// }
|
||||
public Nucleus[] nucleiArray { get; set; }
|
||||
|
||||
public void AddReceptorElement(ClusterPrefab prefab);
|
||||
public void RemoveReceptorElement();
|
||||
|
||||
public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1);
|
||||
|
||||
public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null);
|
||||
}
|
||||
|
||||
public static class IReceptorHelpers {
|
||||
public static Nucleus[] AddReceptorElement(Nucleus[] nucleiArray, ClusterPrefab prefab) {
|
||||
if (nucleiArray.Length == 0) {
|
||||
|
||||
public static void AddReceptorElement(IReceptor receptor, ClusterPrefab prefab) {
|
||||
if (receptor.nucleiArray.Length == 0) {
|
||||
Debug.LogError("Empty perceptoid array, cannot add");
|
||||
return null;
|
||||
}
|
||||
int newLength = nucleiArray.Length + 1;
|
||||
int newLength = receptor.nucleiArray.Length + 1;
|
||||
Nucleus[] newArray = new Nucleus[newLength];
|
||||
|
||||
for (int i = 0; i < nucleiArray.Length; i++)
|
||||
newArray[i] = nucleiArray[i];
|
||||
if (nucleiArray[0] is Nucleus nucleus) {
|
||||
string baseName = receptor.GetName();
|
||||
int colonPos = baseName.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
baseName = baseName[..colonPos];
|
||||
|
||||
for (int i = 0; i < receptor.nucleiArray.Length; i++)
|
||||
newArray[i] = receptor.nucleiArray[i];
|
||||
if (receptor.nucleiArray[0] is Nucleus nucleus) {
|
||||
newArray[newLength - 1] = nucleus.Clone(prefab);
|
||||
newArray[newLength - 1].name += $": {newLength - 1}";
|
||||
newArray[newLength - 1].name = $"{baseName}: {newLength - 1}";
|
||||
}
|
||||
|
||||
return newArray;
|
||||
foreach (Nucleus element in receptor.nucleiArray) {
|
||||
if (element is IReceptor receptorElement) {
|
||||
receptorElement.nucleiArray = newArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Nucleus[] RemoveReceptorElement(Nucleus[] nucleiArray) {
|
||||
int newLength = nucleiArray.Length - 1;
|
||||
public static void RemoveReceptorElement(IReceptor receptor) {
|
||||
int newLength = receptor.nucleiArray.Length - 1;
|
||||
if (newLength == 0) {
|
||||
Debug.LogWarning("Perceptoid array cannot be empty");
|
||||
return null;
|
||||
}
|
||||
Nucleus[] newPerceptei = new Nucleus[newLength];
|
||||
Nucleus[] newArray = new Nucleus[newLength];
|
||||
for (int i = 0; i < newLength; i++)
|
||||
newPerceptei[i] = nucleiArray[i];
|
||||
newArray[i] = receptor.nucleiArray[i];
|
||||
// Delete the last perception
|
||||
if (nucleiArray[newLength] is Nucleus nucleus)
|
||||
Neuron.Delete(nucleus); //this._nuclei[newLength]);
|
||||
if (receptor.nucleiArray[newLength] is Nucleus nucleus)
|
||||
Neuron.Delete(nucleus);
|
||||
|
||||
foreach (Nucleus element in receptor.nucleiArray) {
|
||||
if (element is IReceptor receptorElement) {
|
||||
receptorElement.nucleiArray = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void AddArrayReceiver(IReceptor receptor, Nucleus receiverToAdd, float weight = 1) {
|
||||
foreach (Nucleus element in receptor.nucleiArray) {
|
||||
if (element is Cluster cluster)
|
||||
cluster.defaultOutput.AddReceiver(receiverToAdd, weight);
|
||||
if (element is Neuron neuron)
|
||||
neuron.AddReceiver(receiverToAdd, weight);
|
||||
}
|
||||
|
||||
return newPerceptei;
|
||||
}
|
||||
}
|
||||
8
Icons.meta
Normal file
8
Icons.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 885c5a70637820322b07e023ce18fdd5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Icons/NeuraalNetwerkIcoonSchets1.png
Normal file
BIN
Icons/NeuraalNetwerkIcoonSchets1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
117
Icons/NeuraalNetwerkIcoonSchets1.png.meta
Normal file
117
Icons/NeuraalNetwerkIcoonSchets1.png.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 288088fdc016525a59f83f1c608e514d
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Icons/NeuraalNetwerkIcoonSchets2.png
Normal file
BIN
Icons/NeuraalNetwerkIcoonSchets2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
117
Icons/NeuraalNetwerkIcoonSchets2.png.meta
Normal file
117
Icons/NeuraalNetwerkIcoonSchets2.png.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e16264b4b7305e5c5b5b1389d6b2f13e
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Icons/NeuraalNetwerkIcoonSchets3.png
Normal file
BIN
Icons/NeuraalNetwerkIcoonSchets3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
117
Icons/NeuraalNetwerkIcoonSchets3.png.meta
Normal file
117
Icons/NeuraalNetwerkIcoonSchets3.png.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 948c13386d926b7bbbca85239a974d85
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -11,20 +11,25 @@ MonoBehaviour:
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
|
||||
m_Name: Identity
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Cluster
|
||||
m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab
|
||||
nuclei:
|
||||
- rid: 2243601383627161705
|
||||
- rid: 2262690531574022216
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 2243601383627161705
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
- rid: 2262690531574022216
|
||||
type: {class: Neuron, ns: , asm: Assembly-CSharp}
|
||||
data:
|
||||
_name: Output
|
||||
name: Output
|
||||
clusterPrefab: {fileID: 11400000}
|
||||
parent:
|
||||
rid: -2
|
||||
trace: 0
|
||||
bias: {x: 0, y: 0, z: 0}
|
||||
_synapses: []
|
||||
_receivers: []
|
||||
_array:
|
||||
rid: 2243601383627161706
|
||||
combinator: 0
|
||||
_curvePreset: 0
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
@ -51,10 +56,4 @@ MonoBehaviour:
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
curveMax: 1
|
||||
average: 0
|
||||
- rid: 2243601383627161706
|
||||
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
|
||||
data:
|
||||
_nuclei:
|
||||
- rid: 2243601383627161705
|
||||
name: Output
|
||||
_receivers: []
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[Serializable]
|
||||
public class MemoryCell : Neuron {
|
||||
|
||||
@ -20,7 +20,7 @@ public class NanoBrain : MonoBehaviour {
|
||||
public static void UpdateWeight(Cluster brain, string name, float weight) {
|
||||
Nucleus root = brain.defaultOutput;
|
||||
foreach (Synapse synapse in root.synapses) {
|
||||
if (synapse.nucleus.name == name) {
|
||||
if (synapse.neuron.name == name) {
|
||||
if (synapse.weight != weight) {
|
||||
synapse.weight = weight;
|
||||
// Debug.Log($"Updated weight for {name}");
|
||||
|
||||
82
Neuroid.cs
82
Neuroid.cs
@ -1,82 +0,0 @@
|
||||
/*
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[System.Serializable]
|
||||
public class Neuroid : Neuron {
|
||||
|
||||
public bool average = false;
|
||||
|
||||
public Neuroid(Cluster brain, string name) : base(name) {
|
||||
this.cluster = brain;
|
||||
if (this.cluster != null) {
|
||||
this.cluster.nuclei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
}
|
||||
|
||||
public Neuroid(string name) : base(name) { }
|
||||
|
||||
public override INucleus Clone() {
|
||||
Neuroid clone = new(this.name) {
|
||||
cluster = this.cluster,
|
||||
array = this.array,
|
||||
curve = this.curve,
|
||||
curvePreset = this.curvePreset,
|
||||
curveMax = this.curveMax,
|
||||
average = this.average
|
||||
};
|
||||
if (clone.cluster != null)
|
||||
clone.cluster.nuclei.Add(clone);
|
||||
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
foreach (INucleus receiver in this.receivers) {
|
||||
clone.AddReceiver(receiver);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
public override void UpdateState() {
|
||||
float3 sum = new(0, 0, 0);
|
||||
int n = 0;
|
||||
|
||||
//Applying the weight factgors
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
sum = sum + (synapse.weight * synapse.nucleus.outputValue);
|
||||
if (lengthsq(synapse.nucleus.outputValue) != 0)
|
||||
n++;
|
||||
}
|
||||
if (average)
|
||||
sum /= n;
|
||||
|
||||
// Activation function
|
||||
Vector3 result;
|
||||
switch (this.curvePreset) {
|
||||
case CurvePresets.Linear:
|
||||
result = sum;
|
||||
break;
|
||||
case CurvePresets.Sqrt:
|
||||
result = normalize(sum) * System.MathF.Sqrt(length(sum));
|
||||
break;
|
||||
case CurvePresets.Power:
|
||||
result = normalize(sum) * System.MathF.Pow(length(sum), 2);
|
||||
break;
|
||||
case CurvePresets.Reciprocal:
|
||||
result = normalize(sum) * (1 / length(sum));
|
||||
break;
|
||||
default:
|
||||
float activatedValue = this.curve.Evaluate(length(sum));
|
||||
result = normalize(sum) * activatedValue;
|
||||
break;
|
||||
}
|
||||
UpdateResult(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 771f64aec709af240a39b1d918bbc829
|
||||
78
Neuron.cs
78
Neuron.cs
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using Unity.Mathematics;
|
||||
@ -117,6 +116,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);
|
||||
@ -128,7 +144,7 @@ public class Neuron : Nucleus {
|
||||
Neuron clone = new(prefab, this.name);
|
||||
CloneFields(clone);
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.neuron);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
foreach (Nucleus receiver in this.receivers) {
|
||||
@ -148,7 +164,7 @@ public class Neuron : Nucleus {
|
||||
|
||||
public static void Delete(Nucleus nucleus) {
|
||||
foreach (Synapse synapse in nucleus.synapses) {
|
||||
if (synapse.nucleus is Neuron synapse_nucleus) {
|
||||
if (synapse.neuron is Neuron synapse_nucleus) {
|
||||
if (synapse_nucleus.receivers.Count > 1) {
|
||||
// there is another nucleus feeding into this input nucleus
|
||||
synapse_nucleus.receivers.RemoveAll(r => r == nucleus);
|
||||
@ -162,13 +178,14 @@ public class Neuron : Nucleus {
|
||||
if (nucleus is Neuron neuron) {
|
||||
foreach (Nucleus receiver in neuron.receivers) {
|
||||
if (receiver != null && receiver.synapses != null)
|
||||
receiver.synapses.RemoveAll(s => s.nucleus == nucleus);
|
||||
receiver.synapses.RemoveAll(s => s.neuron == 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) {
|
||||
receiver.synapses.RemoveAll(s => s.nucleus == output);
|
||||
receiver.synapses.RemoveAll(s => s.neuron == output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,29 +215,30 @@ public class Neuron : Nucleus {
|
||||
public float3 CombinatorSum() {
|
||||
float3 sum = this.bias;
|
||||
foreach (Synapse synapse in this.synapses)
|
||||
sum += synapse.weight * synapse.nucleus.outputValue;
|
||||
sum += synapse.weight * synapse.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) {
|
||||
product *= synapse.weight * synapse.neuron.outputValue;
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
public float3 CombinatorMax() {
|
||||
float3 max = this.bias;
|
||||
float maxSqrLength = lengthsq(max);
|
||||
float maxLength = length(max);
|
||||
|
||||
//Applying the weight factors
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
float3 input = synapse.weight * synapse.nucleus.outputValue;
|
||||
float3 input = synapse.weight * synapse.neuron.outputValue;
|
||||
|
||||
float inputSqrlength = lengthsq(input);
|
||||
if (inputSqrlength > maxSqrLength) {
|
||||
float inputLength = length(input);
|
||||
if (inputLength > maxLength) {
|
||||
max = input;
|
||||
maxSqrLength = inputSqrlength;
|
||||
maxLength = inputLength;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
@ -230,7 +248,7 @@ public class Neuron : Nucleus {
|
||||
|
||||
#region Activator
|
||||
|
||||
protected Func<float3, float3> Activator => this.curvePreset switch {
|
||||
public Func<float3, float3> Activator => this.curvePreset switch {
|
||||
CurvePresets.Linear => ActivatorLinear,
|
||||
CurvePresets.Sqrt => ActivatorSqrt,
|
||||
CurvePresets.Power => ActivatorPower,
|
||||
@ -278,19 +296,9 @@ public class Neuron : Nucleus {
|
||||
set { _receivers = value; }
|
||||
}
|
||||
|
||||
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) {
|
||||
// neuron._receivers.Add(receiverToAdd);
|
||||
// receiverToAdd.AddSynapse(element, weight);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
this._receivers.Add(receiverToAdd);
|
||||
receiverToAdd.AddSynapse(this, weight);
|
||||
// }
|
||||
public virtual void AddReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||
this._receivers.Add(receiverToAdd);
|
||||
receiverToAdd.AddSynapse(this, weight);
|
||||
}
|
||||
|
||||
public virtual void RemoveReceiver(Nucleus receiverToRemove) {
|
||||
@ -298,23 +306,29 @@ public class Neuron : Nucleus {
|
||||
foreach (Nucleus element in receptor.nucleiArray) {
|
||||
if (element is Neuron neuron) {
|
||||
neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == neuron);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._receivers.RemoveAll(receiver => receiver == receiverToRemove);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == this);
|
||||
receiverToRemove.synapses.RemoveAll(synapse => synapse.neuron == this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion Receivers
|
||||
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, string thingName = null) {
|
||||
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
|
||||
ProcessStimulusDirect(inputValue, thingId, thingName);
|
||||
}
|
||||
|
||||
public void ProcessStimulusDirect(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||
this.stale = 0;
|
||||
this.bias = inputValue;
|
||||
this.parent.UpdateFromNucleus(this);
|
||||
}
|
||||
|
||||
}
|
||||
1305
NewVelocity.asset
Normal file
1305
NewVelocity.asset
Normal file
File diff suppressed because it is too large
Load Diff
8
NewVelocity.asset.meta
Normal file
8
NewVelocity.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61eea9f818639ec20b7a7bf4e86fff66
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Nucleus.cs
33
Nucleus.cs
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[Serializable]
|
||||
public abstract class Nucleus {
|
||||
@ -13,22 +11,6 @@ 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;
|
||||
|
||||
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);
|
||||
@ -38,11 +20,8 @@ public abstract class Nucleus {
|
||||
None,
|
||||
Neuron,
|
||||
MemoryCell,
|
||||
Selector,
|
||||
Cluster,
|
||||
Pulsar,
|
||||
Receptor,
|
||||
ReceptorArray,
|
||||
ClusterReceptor,
|
||||
}
|
||||
|
||||
@ -54,7 +33,7 @@ public abstract class Nucleus {
|
||||
private List<Synapse> _synapses = new();
|
||||
public List<Synapse> synapses => _synapses;
|
||||
|
||||
public Synapse AddSynapse(Nucleus sendingNucleus, float weight = 1.0f) {
|
||||
public Synapse AddSynapse(Neuron sendingNucleus, float weight = 1.0f) {
|
||||
Synapse synapse = new(sendingNucleus, weight);
|
||||
this.synapses.Add(synapse);
|
||||
return synapse;
|
||||
@ -62,19 +41,17 @@ public abstract class Nucleus {
|
||||
|
||||
public Synapse GetSynapse(Nucleus sender) {
|
||||
foreach (Synapse synapse in this.synapses)
|
||||
if (synapse.nucleus == sender)
|
||||
if (synapse.neuron == sender)
|
||||
return synapse;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RemoveSynapse(Nucleus sendingNucleus) {
|
||||
this.synapses.RemoveAll(synapse => synapse.nucleus == sendingNucleus);
|
||||
this.synapses.RemoveAll(synapse => synapse.neuron == sendingNucleus);
|
||||
}
|
||||
|
||||
#endregion Synapses
|
||||
|
||||
|
||||
|
||||
#region Update
|
||||
|
||||
public abstract void UpdateStateIsolated();
|
||||
@ -83,11 +60,13 @@ public abstract class Nucleus {
|
||||
}
|
||||
|
||||
public virtual void SetBias(Vector3 inputValue) {
|
||||
this.stale = 0;
|
||||
this.bias = inputValue;
|
||||
this.parent.UpdateFromNucleus(this);
|
||||
}
|
||||
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = "") {
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
|
||||
}
|
||||
@ -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);
|
||||
@ -111,6 +113,10 @@ public class NucleusArray {
|
||||
|
||||
public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||
CleanupReceivers();
|
||||
|
||||
if (this._nuclei[0] is Neuron neuron)
|
||||
inputValue = neuron.Activator(inputValue);
|
||||
|
||||
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
|
||||
// No existing nucleus for this thing
|
||||
selectedReceiver = FindReceiver(thingId, inputValue);
|
||||
@ -127,15 +133,14 @@ public class NucleusArray {
|
||||
}
|
||||
|
||||
if (selectedReceiver is Neuron selectedNucleus)
|
||||
selectedNucleus.ProcessStimulus(inputValue);
|
||||
//selectedReceiver.parent.UpdateFromNucleus(selectedReceiver);
|
||||
selectedNucleus.ProcessStimulusDirect(inputValue);
|
||||
}
|
||||
|
||||
private void CleanupReceivers() {
|
||||
// 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) {
|
||||
|
||||
105
Perceptoid.cs
105
Perceptoid.cs
@ -1,105 +0,0 @@
|
||||
/*
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class Perceptoid : Neuroid {
|
||||
// A neuroid which has no neurons as input
|
||||
// But receives value from a receptor
|
||||
|
||||
public NanoBrain brain;
|
||||
public Receptor receptor;
|
||||
public string baseName;
|
||||
|
||||
public int thingId;
|
||||
|
||||
//[SerializeField]
|
||||
// Needs serialization!!!!
|
||||
[SerializeReference]
|
||||
public PercepteiArray array;
|
||||
|
||||
#region Serialization
|
||||
|
||||
[SerializeField]
|
||||
public int thingType;
|
||||
|
||||
public override void Rebuild(NanoBrain brain) {
|
||||
base.Rebuild(brain);
|
||||
this.receptor = Receptor.GetReceptor(brain, thingType);
|
||||
this.receptor.perceptei.Add(this);
|
||||
if (string.IsNullOrEmpty(this.baseName))
|
||||
this.baseName = this.name;
|
||||
}
|
||||
|
||||
public override void Deserialize(Nucleus nucleus) {
|
||||
base.Deserialize(nucleus);
|
||||
|
||||
if (nucleus is Perceptoid perceptoid)
|
||||
this.receptor.thingType = perceptoid.thingType;
|
||||
|
||||
// Point all receivers to this perceptoid instead of the default nucleus
|
||||
foreach (INucleus receiver in nucleus.receivers) {
|
||||
foreach (Synapse synapse in receiver.synapses) {
|
||||
if (synapse.nucleus == nucleus)
|
||||
synapse.nucleus = this;
|
||||
}
|
||||
}
|
||||
// Point all synapses to this perceptoid instead of the default nucleus
|
||||
// foreach (Synapse synapse in nucleus.synapses) {
|
||||
// foreach (INucleus r in synapse.nucleus.receivers) {
|
||||
// if (r == nucleus)
|
||||
// this.receiver = this;
|
||||
// }
|
||||
// }
|
||||
// Copying disabled for now
|
||||
// // Copy all the synapses
|
||||
// this.synapses = nucleus.synapses;
|
||||
// // Copy all receivers
|
||||
// this.receivers = nucleus.receivers;
|
||||
}
|
||||
|
||||
#endregion Serialization
|
||||
|
||||
public Perceptoid(NanoBrain brain, int thingType, string name = "sensor") : base(name) {
|
||||
this.brain = brain;
|
||||
this.cluster = brain.cluster;
|
||||
if (this.cluster != null) {
|
||||
brain.perceptei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
|
||||
this.nucleusType = nameof(Perceptoid);
|
||||
this.name = name;
|
||||
this.baseName = name;
|
||||
this.thingType = thingType;
|
||||
this.receptor = Receptor.GetReceptor(brain, thingType);
|
||||
this.receptor.perceptei.Add(this);
|
||||
this.array = new PercepteiArray(this);
|
||||
}
|
||||
|
||||
public Perceptoid(PercepteiArray array) : base(array.name) {
|
||||
this.array = array;
|
||||
Perceptoid source = array.perceptei[0];
|
||||
this.brain = source.brain;
|
||||
this.cluster = source.cluster;
|
||||
if (this.brain != null) {
|
||||
this.brain.perceptei.Add(this);
|
||||
}
|
||||
else
|
||||
Debug.LogError("No neuroid network");
|
||||
|
||||
this.nucleusType = nameof(Perceptoid);
|
||||
this.name = source.baseName;
|
||||
this.baseName = source.baseName;
|
||||
this.thingType = source.thingType;
|
||||
this.receptor = Receptor.GetReceptor(this.brain, this.thingType);
|
||||
this.receptor.perceptei.Add(this);
|
||||
}
|
||||
|
||||
public override void UpdateState() {
|
||||
Vector3 result = this.receptor.localPosition;
|
||||
UpdateResult(result);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 702f634001a21a9d7ae1057c8ce356e9
|
||||
54
Pulsar.cs
54
Pulsar.cs
@ -1,54 +0,0 @@
|
||||
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);
|
||||
}
|
||||
|
||||
public override Nucleus ShallowCloneTo(Cluster newParent) {
|
||||
Pulsar clone = new(newParent, this.name);
|
||||
CloneFields(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Activation function
|
||||
this.outputValue = Activator(product);
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46bd155173053a01585411c3e07f85d4
|
||||
13
Receptor.cs
13
Receptor.cs
@ -48,24 +48,19 @@ public class Receptor : Neuron, IReceptor {
|
||||
}
|
||||
|
||||
public void AddReceptorElement(ClusterPrefab prefab) {
|
||||
this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab);
|
||||
IReceptorHelpers.AddReceptorElement(this, prefab);
|
||||
}
|
||||
|
||||
public void RemoveReceptorElement() {
|
||||
this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray);
|
||||
IReceptorHelpers.RemoveReceptorElement(this);
|
||||
}
|
||||
|
||||
public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) {
|
||||
foreach (Nucleus element in this._array.nuclei) {
|
||||
if (element is Neuron neuron) {
|
||||
neuron.AddReceiver(receiverToAdd, weight);
|
||||
}
|
||||
}
|
||||
IReceptorHelpers.AddArrayReceiver(this, receiverToAdd, weight);
|
||||
}
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
this.outputValue = this.bias;
|
||||
//Debug.Log($"Receptor {this.name} outputvalue = {this.outputValue}");
|
||||
}
|
||||
|
||||
public override void UpdateNuclei() {
|
||||
@ -76,7 +71,7 @@ public class Receptor : Neuron, IReceptor {
|
||||
}
|
||||
}
|
||||
|
||||
public virtual 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.ProcessStimulus(thingId, inputValue, thingName);
|
||||
}
|
||||
|
||||
261
ReceptorArray.cs
261
ReceptorArray.cs
@ -1,261 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[Serializable]
|
||||
public class ReceptorInstance : Nucleus {
|
||||
public ReceptorInstance(Cluster parent, string name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
// We explicitly do not add this to the parent, as it is serialized in the ReceptorArray
|
||||
}
|
||||
public ReceptorInstance(ClusterPrefab prefab, string name) {
|
||||
this.clusterPrefab = prefab;
|
||||
this.name = name;
|
||||
// We explicitly do not add this to the prefab, as it is serialized in the ReceptorArray
|
||||
}
|
||||
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||
ReceptorInstance clone = new(parent, name + " +1") {
|
||||
receptor = this.receptor
|
||||
};
|
||||
return clone;
|
||||
}
|
||||
public override Nucleus Clone(ClusterPrefab prefab) {
|
||||
ReceptorInstance clone = new(prefab, name) {
|
||||
receptor = this.receptor
|
||||
};
|
||||
return clone;
|
||||
}
|
||||
|
||||
[SerializeReference]
|
||||
public ReceptorArray receptor;
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ReceptorArray : Nucleus {
|
||||
public ReceptorArray(Cluster parent, string name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this._instances = new ReceptorInstance[1];
|
||||
this._instances[0] = new ReceptorInstance(parent, this.name + "[0]") {
|
||||
receptor = this
|
||||
};
|
||||
this.parent?.clusterNuclei.Add(this);
|
||||
}
|
||||
public ReceptorArray(ClusterPrefab prefab, string name) {
|
||||
this.clusterPrefab = prefab;
|
||||
this.name = name;
|
||||
this._instances = new ReceptorInstance[1];
|
||||
this._instances[0] = new ReceptorInstance(prefab, this.name + "[0]") {
|
||||
receptor = this
|
||||
};
|
||||
if (this.clusterPrefab != null)
|
||||
this.clusterPrefab.nuclei.Add(this);
|
||||
else
|
||||
Debug.LogError("No prefab when adding receptor to prefab");
|
||||
|
||||
}
|
||||
|
||||
public override Nucleus ShallowCloneTo(Cluster parent) {
|
||||
ReceptorArray clone = new(parent, name) {
|
||||
_instances = new ReceptorInstance[this.instances.Length]
|
||||
};
|
||||
for (int ix = 0; ix < this.instances.Length; ix++) {
|
||||
clone._instances[ix] = new ReceptorInstance(parent, $"{this.name} [{ix}]") {
|
||||
receptor = clone
|
||||
};
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
public override Nucleus Clone(ClusterPrefab prefab) {
|
||||
ReceptorArray clone = new(prefab, this.name) {
|
||||
_instances = new ReceptorInstance[this.instances.Length]
|
||||
};
|
||||
for (int ix = 0; ix < this.instances.Length; ix++) {
|
||||
clone._instances[ix] = new ReceptorInstance(prefab, this.name) {
|
||||
receptor = this
|
||||
};
|
||||
}
|
||||
|
||||
foreach (Synapse synapse in this.synapses) {
|
||||
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
||||
clonedSynapse.weight = synapse.weight;
|
||||
}
|
||||
// foreach (Nucleus receiver in this.receivers) {
|
||||
// clone.AddReceiver(receiver);
|
||||
// }
|
||||
return clone;
|
||||
}
|
||||
|
||||
[SerializeReference]
|
||||
private ReceptorInstance[] _instances = new ReceptorInstance[0];
|
||||
public ReceptorInstance[] instances {
|
||||
get {
|
||||
return _instances;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddReceptor(ClusterPrefab prefab) {
|
||||
if (this._instances.Length == 0) {
|
||||
Debug.LogError("Empty receptor array, cannot add");
|
||||
return;
|
||||
}
|
||||
int newLength = this._instances.Length + 1;
|
||||
ReceptorInstance[] newArray = new ReceptorInstance[newLength];
|
||||
|
||||
for (int i = 0; i < this._instances.Length; i++)
|
||||
newArray[i] = this._instances[i];
|
||||
ReceptorInstance newReceptor = (ReceptorInstance)this._instances[0].Clone(prefab);
|
||||
newReceptor.name = $"{this.name} [{this._instances.Length}]";
|
||||
newArray[newLength - 1] = newReceptor;
|
||||
|
||||
this._instances = newArray;
|
||||
}
|
||||
|
||||
public void RemoveReceptor() {
|
||||
int newLength = this._instances.Length - 1;
|
||||
if (newLength == 0) {
|
||||
Debug.LogWarning("Receptor array cannot be empty");
|
||||
return;
|
||||
}
|
||||
ReceptorInstance[] newPerceptei = new ReceptorInstance[newLength];
|
||||
for (int i = 0; i < newLength; i++)
|
||||
newPerceptei[i] = this._instances[i];
|
||||
// Delete the last perception
|
||||
if (this._instances[newLength] is Nucleus nucleus)
|
||||
Neuron.Delete(nucleus); //this._nuclei[newLength]);
|
||||
|
||||
this._instances = newPerceptei;
|
||||
}
|
||||
|
||||
private Dictionary<int, Nucleus> thingReceivers = new();
|
||||
|
||||
// public override void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) {
|
||||
// ProcessStimulus(inputValue, thingId, thingName);
|
||||
// }
|
||||
public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) {
|
||||
CleanupReceivers();
|
||||
if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) {
|
||||
//Debug.Log($" no receiver found for {thingId}");
|
||||
// No existing nucleus for this thing
|
||||
selectedReceiver = SelectReceptor(thingId, inputValue);
|
||||
}
|
||||
if (selectedReceiver == null)
|
||||
return;
|
||||
|
||||
if (thingName != null) {
|
||||
string baseName = selectedReceiver.name;
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
baseName = selectedReceiver.name[..colonPos];
|
||||
selectedReceiver.name = baseName + ": " + thingName;
|
||||
}
|
||||
|
||||
//if (selectedReceiver is Neuron selectedNucleus) {
|
||||
selectedReceiver.stale = 0;
|
||||
selectedReceiver.outputValue = inputValue;
|
||||
this.parent.UpdateFromNucleus(this);
|
||||
//selectedNucleus.ProcessStimulus(inputValue);
|
||||
//}
|
||||
}
|
||||
|
||||
private void CleanupReceivers() {
|
||||
// Remove a thing-receiver connection when the nucleus is inactive
|
||||
List<int> receiversToRemove = new();
|
||||
thingReceivers ??= new();
|
||||
|
||||
foreach (KeyValuePair<int, Nucleus> item in thingReceivers) {
|
||||
if (item.Value.isSleeping)
|
||||
receiversToRemove.Add(item.Key);
|
||||
}
|
||||
foreach (int thingId in receiversToRemove) {
|
||||
Nucleus selectedReceiver = thingReceivers[thingId];
|
||||
|
||||
// Debug.Log($" removed receiver for {thingId}");
|
||||
thingReceivers.Remove(thingId);
|
||||
|
||||
int colonPos = selectedReceiver.name.IndexOf(":");
|
||||
if (colonPos > 0)
|
||||
selectedReceiver.name = selectedReceiver.name[..colonPos];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Nucleus SelectReceptor(int thingId, float3 inputValue) {
|
||||
// No existing nucleus for this thing
|
||||
float inputMagnitude = length(inputValue);
|
||||
Nucleus selectedReceiver = null;
|
||||
float selectedMagnitude = 0;
|
||||
this._instances ??= new ReceptorInstance[0];
|
||||
foreach (Nucleus receiver in this._instances) {
|
||||
if (thingReceivers.ContainsValue(receiver) == false) {
|
||||
// We found an unusued receiver
|
||||
// Debug.Log($"{thingId} -> [{receiver.name}]");
|
||||
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);
|
||||
Debug.Log($"{thingId} -> [{selectedReceiver.name}]");
|
||||
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;
|
||||
}
|
||||
|
||||
public override void UpdateStateIsolated() {
|
||||
float3 sum = this.bias;
|
||||
|
||||
// Receptors do not have inputs, so we ignore the synapses
|
||||
foreach (Nucleus nucleus in this._instances)
|
||||
sum += nucleus.outputValue;
|
||||
|
||||
this.outputValue = sum / _instances.Length;
|
||||
this.stale = 0;
|
||||
|
||||
UpdateNuclei();
|
||||
}
|
||||
|
||||
public override void UpdateNuclei() {
|
||||
foreach (Nucleus nucleus in this.instances) {
|
||||
nucleus.stale++;
|
||||
if (nucleus.stale > staleValueForSleep && lengthsq(nucleus.outputValue) > 0) {
|
||||
nucleus.outputValue = Vector3.zero;
|
||||
//this.UpdateStateIsolated();
|
||||
this.parent.UpdateFromNucleus(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e915c8563642f23891b20522b3589cf
|
||||
BIN
Scripts/NeuraalNetwerkIcoonSchets1.png
Normal file
BIN
Scripts/NeuraalNetwerkIcoonSchets1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
117
Scripts/NeuraalNetwerkIcoonSchets1.png.meta
Normal file
117
Scripts/NeuraalNetwerkIcoonSchets1.png.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cad48149d984d2eddae5808eb1517cb5
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Scripts/NeuraalNetwerkIcoonSchets2.png
Normal file
BIN
Scripts/NeuraalNetwerkIcoonSchets2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
117
Scripts/NeuraalNetwerkIcoonSchets2.png.meta
Normal file
117
Scripts/NeuraalNetwerkIcoonSchets2.png.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e644ed036e8939bf94586314a4f4607
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Selector.cs
62
Selector.cs
@ -1,62 +0,0 @@
|
||||
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) {}
|
||||
|
||||
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);
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4218c2f3f15af944db0eadd6e1500d17
|
||||
@ -4,12 +4,12 @@ using UnityEngine;
|
||||
[Serializable]
|
||||
public class Synapse {
|
||||
[SerializeReference]
|
||||
public Nucleus nucleus;
|
||||
public Neuron neuron;
|
||||
|
||||
public float weight;
|
||||
|
||||
public Synapse(Nucleus nucleus, float weight = 1.0f) {
|
||||
this.nucleus = nucleus;
|
||||
public Synapse(Neuron nucleus, float weight = 1.0f) {
|
||||
this.neuron = nucleus;
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
@ -13,18 +13,31 @@ MonoBehaviour:
|
||||
m_Name: Velocity
|
||||
m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab
|
||||
nuclei:
|
||||
- rid: 2243601425629446539
|
||||
- rid: 2262690551513219315
|
||||
- rid: 2262690551513219316
|
||||
- rid: 2262690551513219317
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 2243601425629446539
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
- rid: 2262690551513219315
|
||||
type: {class: Neuron, ns: , asm: Assembly-CSharp}
|
||||
data:
|
||||
_name: Output
|
||||
_synapses: []
|
||||
_receivers: []
|
||||
_array:
|
||||
rid: 2243601425629446540
|
||||
name: Velocity
|
||||
clusterPrefab: {fileID: 11400000}
|
||||
parent:
|
||||
rid: -2
|
||||
trace: 0
|
||||
bias: {x: 0, y: 0, z: 0}
|
||||
_synapses:
|
||||
- nucleus:
|
||||
rid: 2262690551513219316
|
||||
weight: 1
|
||||
- nucleus:
|
||||
rid: 2262690551513219317
|
||||
weight: 1
|
||||
combinator: 0
|
||||
_curvePreset: 0
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
@ -51,10 +64,65 @@ MonoBehaviour:
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
curveMax: 1
|
||||
average: 0
|
||||
- rid: 2243601425629446540
|
||||
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
|
||||
_receivers: []
|
||||
- rid: 2262690551513219316
|
||||
type: {class: Neuron, ns: , asm: Assembly-CSharp}
|
||||
data:
|
||||
_nuclei:
|
||||
- rid: 2243601425629446539
|
||||
name: Output
|
||||
name: Position
|
||||
clusterPrefab: {fileID: 11400000}
|
||||
parent:
|
||||
rid: -2
|
||||
trace: 0
|
||||
bias: {x: 0, y: 0, z: 0}
|
||||
_synapses: []
|
||||
combinator: 0
|
||||
_curvePreset: 0
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 1
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 1000
|
||||
value: 1000
|
||||
inSlope: 1
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
curveMax: 1
|
||||
_receivers:
|
||||
- rid: 2262690551513219315
|
||||
- rid: 2262690551513219317
|
||||
type: {class: MemoryCell, ns: , asm: Assembly-CSharp}
|
||||
data:
|
||||
name: New memory cell
|
||||
clusterPrefab: {fileID: 11400000}
|
||||
parent:
|
||||
rid: -2
|
||||
trace: 0
|
||||
bias: {x: 0, y: 0, z: 0}
|
||||
_synapses: []
|
||||
combinator: 0
|
||||
_curvePreset: 0
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve: []
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
curveMax: 1
|
||||
_receivers:
|
||||
- rid: 2262690551513219315
|
||||
staticMemory: 0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user