Compare commits

..

No commits in common. "91c4500b0a1288dc674dc4a89b675b344aa861e6" and "a64ff841ac0dde229f22b4228f8cf479fea3ebff" have entirely different histories.

12 changed files with 271 additions and 399 deletions

View File

@ -4,9 +4,12 @@ using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[Serializable] [System.Serializable]
public class Cluster : INucleus { public class Cluster : INucleus {
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
public readonly ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
[SerializeField] [SerializeField]
protected string _name; protected string _name;
@ -15,113 +18,17 @@ public class Cluster : INucleus {
set => _name = value; set => _name = value;
} }
#region Init // Hmm, a cluster instance can never be part of a scriptable object...(Cluster)
public Cluster(ClusterPrefab parent, ClusterPrefab prefab) {
public Cluster(ClusterPrefab prefab, Cluster parent) {
this.prefab = prefab; this.prefab = prefab;
this.name = prefab.name;
this.parent = parent;
this.parent?.nuclei.Add(this);
ClonePrefab();
this.sortedNuclei = TopologicalSort(this.nuclei);
}
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
this.prefab = prefab;
this.name = prefab.name;
this.cluster = parent; this.cluster = parent;
if (this.cluster != null) if (this.cluster != null)
this.cluster.nuclei.Add(this); this.cluster.nuclei.Add(this);
ClonePrefab(); // foreach (IReceptor nucleus in this.prefab.nuclei) {
this.sortedNuclei = TopologicalSort(this.nuclei); // IReceptor clone = nucleus.CloneTo(null);
} // this.dynamicNuclei.Add(clone);
// public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
// this.prefab = realPrefab;
// this.name = realPrefab.name;
// this.cluster = parent;
// if (this.cluster != null)
// this.cluster.nuclei.Add(this);
// ClonePrefab();
// } // }
private void ClonePrefab() {
IReceptor[] nucleiArray = this.prefab.nuclei.ToArray();
// first clone the nuclei without their connections
foreach (IReceptor nucleus in this.prefab.nuclei)
nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
IReceptor receptor = nucleiArray[nucleusIx];
IReceptor clonedSender = clonedNuclei[nucleusIx];
if (clonedSender == null)
continue;
// Copy the receivers, which will also create the synapses
foreach (INucleus receiver in receptor.receivers) {
int ix = GetNucleusIndex(nucleiArray, receiver);
if (ix < 0)
continue;
if (clonedNuclei[ix] is not INucleus clonedReceiver)
continue;
// Find the synapse for the weight
float weight = 1;
foreach (Synapse synapse in receiver.synapses) {
if (synapse.nucleus == receptor) {
weight = synapse.weight;
break;
}
}
clonedSender.AddReceiver(clonedReceiver, weight);
}
}
}
// Sort the nuclei in a correct evaluation order
private List<IReceptor> TopologicalSort(List<IReceptor> nodes) {
Dictionary<IReceptor, int> inDegree = new();
foreach (IReceptor node in nodes)
inDegree[node] = 0; // Initialize in-degree to zero
// Calculate in-degrees
foreach (IReceptor node in nodes) {
foreach (INucleus receiver in node.receivers)
inDegree[receiver]++;
}
Queue<IReceptor> queue = new();
foreach (IReceptor node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node);
}
List<IReceptor> sortedOrder = new();
while (queue.Count > 0) {
IReceptor current = queue.Dequeue();
sortedOrder.Add(current); // Process the node
foreach (INucleus receiver in current.receivers) {
inDegree[receiver]--;
if (inDegree[receiver] == 0) // If all dependencies resolved
queue.Enqueue(receiver);
}
}
// Check for cycles in the graph
if (sortedOrder.Count != nodes.Count)
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
return sortedOrder;
} }
public virtual IReceptor Clone() { public virtual IReceptor Clone() {
@ -139,59 +46,6 @@ public class Cluster : INucleus {
return clone; return clone;
} }
public IReceptor ShallowCloneTo(Cluster parent) {
Cluster clone = new(this.prefab, parent) {
name = this.name,
};
return clone;
}
private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) {
for (int i = 0; i < nucleiArray.Length; i++) {
if (nucleus == nucleiArray[i])
return i;
}
return -1;
}
#endregion Init
public ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; }
[SerializeReference]
public List<IReceptor> nuclei = new();
// the nuclei sorted using topological sorting
// to ensure that the cluster is computer in the right order
public List<IReceptor> sortedNuclei;
public List<INucleus> _inputs = null;
public virtual List<INucleus> inputs {
get {
if (this._inputs == null) {
this._inputs = new();
foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
}
}
return this._inputs;
}
}
public virtual INucleus output {//=> this.nuclei[0] as INucleus;
get {
if (this.nuclei.Count > 0)
return this.nuclei[0] as INucleus;
return null;
}
}
// Not sure if this belongs here... // Not sure if this belongs here...
[SerializeReference] [SerializeReference]
private NucleusArray _array; private NucleusArray _array;
@ -202,14 +56,27 @@ public class Cluster : INucleus {
#region Synapses #region Synapses
// class ClusterSynapse : Synapse {
// public IReceptor receptor;
// public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) {
// this.receptor = receptor;
// }
// }
[SerializeField] [SerializeField]
private List<Synapse> _synapses = new(); private List<Synapse> _synapses = new();
public List<Synapse> synapses => _synapses; public List<Synapse> synapses => _synapses;
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { public Synapse AddSynapse(IReceptor sendingNucleus) {
Synapse synapse = new(sendingNucleus, weight); Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]);
this._synapses.Add(synapse); this._synapses.Add(synapse);
return synapse; return synapse;
// else {
// INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName);
// ClusterSynapse synapse = new(sendingNucleus, receptor);
// receptor.AddSynapse(sendingNucleus);
// }
// // Add synapse to which neuron?
// return null;
} }
// Does this even exist already? // Does this even exist already?
@ -228,9 +95,9 @@ public class Cluster : INucleus {
set { _receivers = value; } set { _receivers = value; }
} }
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight); receivingNucleus.AddSynapse(this);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -238,6 +105,48 @@ public class Cluster : INucleus {
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
} }
// public void AddReceiver(INucleus receivingNucleus) {
// int newLength = this._receivers.Count + 1;
// INucleus[] newReceivers = new INucleus[newLength];
// // Copy the existing receivers
// for (int ix = 0; ix < this._receivers.Count; ix++)
// newReceivers[ix] = this._receivers[ix];
// // Add the new receivers
// newReceivers[this._receivers.Count] = receivingNucleus;
// // Replace the receivers with the new receivers
// this._receivers = new(newReceivers);
// receivingNucleus.AddSynapse(this);
// }
// public void RemoveReceiver(INucleus receivingNucleus) {
// Debug.Log("Clusterinstance. remote receiver");
// int newLength = this._receivers.Count - 1;
// if (newLength < 0)
// // Array was empty, so we cannot remove anything
// return;
// INucleus[] newReceivers = new INucleus[newLength];
// int newIx = 0;
// // Copy all receivers except receivingNucleus
// for (int ix = 0; ix < this._receivers.Count; ix++) {
// if (this._receivers[ix] == receivingNucleus)
// // skip the receiver we want to remote
// continue;
// if (newIx >= newLength)
// // We want to copy more elements than expected
// // the receivingNucleus is not found
// // and the original array is returned
// return;
// newReceivers[newIx] = this._receivers[ix];
// newIx++;
// }
// this._receivers = new(newReceivers);
// }
#endregion Receivers #endregion Receivers
#region Runtime #region Runtime
@ -262,55 +171,16 @@ public class Cluster : INucleus {
UpdateState(new float3(0, 0, 0)); UpdateState(new float3(0, 0, 0));
} }
public void UpdateState(float3 bias) { public void UpdateState(float3 inputValue) {
float3 sum = bias; // new(0, 0, 0); float3 sum = inputValue; // new(0, 0, 0);
//Applying the weight factors //Applying the weight factgors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue; sum += synapse.weight * synapse.nucleus.outputValue;
} }
//this.inputs[0].UpdateState(sum); // This does not work because the prefab nucleus does not have a state
this.inputs[0].UpdateStateIsolated(sum); this.prefab.inputs[0].UpdateState(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
UpdateResult(this.output.outputValue);
}
public void UpdateStateIsolated() {
float3 bias = new(0,0,0);
UpdateStateIsolated(bias);
}
public void UpdateStateIsolated(float3 bias) {
float3 sum = bias; // new(0, 0, 0);
//Applying the weight factors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
}
//this.inputs[0].UpdateState(sum);
this.inputs[0].UpdateStateIsolated(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
this.outputValue = this.output.outputValue;
}
public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) {
// //Debug.Log($"insignificant update: {d}");
// return;
// }
this.outputValue = result;
foreach (INucleus receiver in this.receivers)
receiver.UpdateState();
} }
public void UpdateNuclei() { public void UpdateNuclei() {
@ -318,12 +188,72 @@ public class Cluster : INucleus {
if (this.stale > 2) if (this.stale > 2)
_outputValue = Vector3.zero; _outputValue = Vector3.zero;
//foreach (IReceptor nucleus in this.prefab.nuclei) foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (IReceptor nucleus in this.nuclei)
nucleus.UpdateNuclei(); nucleus.UpdateNuclei();
} }
#endregion Update #endregion Update
#endregion Runtime #endregion Runtime
/*
[SerializeField]
private List<IReceptor> _dynamicNuclei;
public List<IReceptor> dynamicNuclei {// = new();
get {
if (_dynamicNuclei == null) {
this._dynamicNuclei = new();
foreach (IReceptor nucleus in this.prefab.nuclei) {
IReceptor clone = nucleus.CloneTo(null);
this._dynamicNuclei.Add(clone);
}
}
return this._dynamicNuclei;
}
}
public List<INucleus> _inputs = null;
public List<INucleus> inputs {
get {
this._inputs = new();
if (this.dynamicNuclei != null) {
foreach (IReceptor receptor in this.dynamicNuclei) {
if (receptor is INucleus nucleus)
this._inputs.Add(nucleus);
}
}
return this._inputs;
}
}
public INucleus output => this.dynamicNuclei[0] as INucleus;
public float3 outputValue => this.output.outputValue;
public IReceptor CloneTo(ClusterPrefab parent) {
Cluster clone = new(parent, this.prefab);
return clone;
}
public IReceptor Clone() {
Cluster clone = new(this.cluster, this.prefab);
return clone;
}
#region Properties
public string name {
get { return prefab.name; }
set { prefab.name = value; }
}
public bool isSleeping => lengthsq(this.outputValue) == 0;
public NucleusArray array { get; set; }
#endregion Properties
*/
} }

View File

@ -4,11 +4,18 @@ using UnityEngine;
[CreateAssetMenu(menuName = "Passer/Cluster")] [CreateAssetMenu(menuName = "Passer/Cluster")]
public class ClusterPrefab : ScriptableObject { public class ClusterPrefab : ScriptableObject {
//public virtual Cluster cluster {get;set;}
// The ScriptableObject asset from which the runtime object has been created // The ScriptableObject asset from which the runtime object has been created
//public Cluster asset;
[SerializeReference] [SerializeReference]
public List<IReceptor> nuclei = new(); public List<IReceptor> nuclei = new();
// public List<Cluster> subClusters = new();
// public void AddSubCluster(ClusterInstance subCluster) {
// this.nuclei.Add(subCluster);
// }
public virtual INucleus output => this.nuclei[0] as INucleus; public virtual INucleus output => this.nuclei[0] as INucleus;
@ -18,13 +25,10 @@ public class ClusterPrefab : ScriptableObject {
if (this._inputs == null) { if (this._inputs == null) {
this._inputs = new(); this._inputs = new();
foreach (IReceptor receptor in this.nuclei) { foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) { if (receptor is INucleus nucleus)
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus); this._inputs.Add(nucleus);
} }
} }
}
return this._inputs; return this._inputs;
} }
} }

View File

@ -10,7 +10,7 @@ public interface INucleus : IReceptor {
// Senders // Senders
public List<Synapse> synapses { get; } public List<Synapse> synapses { get; }
public Synapse AddSynapse(IReceptor sender, float weight = 1.0f); public Synapse AddSynapse(IReceptor sender);
public NucleusArray array { get; set; } public NucleusArray array { get; set; }
@ -20,8 +20,7 @@ public interface INucleus : IReceptor {
public void UpdateState(); public void UpdateState();
public void UpdateState(float3 inputValue); public void UpdateState(float3 inputValue);
public void UpdateStateIsolated();
public void UpdateStateIsolated(float3 inputValue);
#endregion dynamic state #endregion dynamic state
} }
@ -34,7 +33,7 @@ public interface IReceptor {
// Receivers // Receivers
public List<INucleus> receivers { get; set; } public List<INucleus> receivers { get; set; }
public void AddReceiver(INucleus receiver, float weight = 1); public void AddReceiver(INucleus receiver);
public void RemoveReceiver(INucleus receiverNucleus); public void RemoveReceiver(INucleus receiverNucleus);
#endregion static #endregion static
@ -49,7 +48,7 @@ public interface IReceptor {
#endregion dynamic #endregion dynamic
public IReceptor ShallowCloneTo(Cluster parent); //public IReceptor CloneTo(ClusterPrefab parent);
public IReceptor Clone(); public IReceptor Clone();
} }

View File

@ -4,38 +4,35 @@ using Unity.Mathematics;
using static Unity.Mathematics.math; using static Unity.Mathematics.math;
[Serializable] [Serializable]
public class MemoryCell : Neuron, INucleus { public class MemoryCell : Neuron {
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { } public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {}
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
// this.parent = parent;
// this.name = name;
// this.parent?.nuclei.Add(this);
// }
public override IReceptor ShallowCloneTo(Cluster newParent) { #region Parameters
MemoryCell clone = new(newParent, this.name) {
array = this.array, // Returns the memorized value weighted by time
curve = this.curve, // return lastValue * (current time - last time)
curvePreset = this.curvePreset, [SerializeField]
curveMax = this.curveMax, public bool deltaValue = false;
average = this.average
}; #endregion Parameters
return clone;
}
#region State #region State
private float3 _memorizedValue; private float3 _memorizedValue;
private float _memorizedTime; private float _memorizedTime;
public override void UpdateState(float3 bias) { public override void UpdateState() {
// A memorycell does not have an activation function // A memorycell does not have an activation function
float3 result = bias; float3 result = new(0, 0, 0);
int n = 0; int n = 0;
//Applying the weight factgors //Applying the weight factgors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
result += synapse.weight * synapse.nucleus.outputValue; result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0) if (lengthsq(synapse.nucleus.outputValue) != 0)
n++; n++;
@ -47,40 +44,14 @@ public class MemoryCell : Neuron, INucleus {
UpdateResult(result); UpdateResult(result);
} }
public override void UpdateStateIsolated() {
float3 bias = new(0, 0, 0);
UpdateStateIsolated(bias);
}
public override void UpdateStateIsolated(float3 bias) {
// A memorycell does not have an activation function
float3 result = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average)
result /= n;
this.outputValue = this._memorizedValue;
// Store the result for the next time
this._memorizedValue = result;
this._memorizedTime = Time.time;
}
public override void UpdateResult(Vector3 result) { public override void UpdateResult(Vector3 result) {
// output value is the previous value // output value is the previous value
// if (this.deltaValue) { if (this.deltaValue) {
// float deltaTime = Time.time - this._memorizedTime; float deltaTime = Time.time - this._memorizedTime;
// this._outputValue = this._memorizedValue * deltaTime; this._outputValue = this._memorizedValue * deltaTime;
// } }
//else else
this.outputValue = this._memorizedValue; this._outputValue = this._memorizedValue;
// Store the result for the next time // Store the result for the next time
this._memorizedValue = result; this._memorizedValue = result;

View File

@ -88,7 +88,6 @@ public class Neuron : INucleus {
#region Runtime state (not serialized) #region Runtime state (not serialized)
public ClusterPrefab cluster { get; set; } public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; }
#region Activation #region Activation
@ -154,6 +153,7 @@ public class Neuron : INucleus {
// private bool _isSleeping = false; // private bool _isSleeping = false;
// public bool isSleeping => _isSleeping; // public bool isSleeping => _isSleeping;
public bool isSleeping => lengthsq(this.outputValue) == 0; public bool isSleeping => lengthsq(this.outputValue) == 0;
public float lastTime { get; private set; }
public void UpdateNuclei() { public void UpdateNuclei() {
this.stale++; this.stale++;
@ -165,11 +165,6 @@ public class Neuron : INucleus {
#endregion Runtime state #endregion Runtime state
public Neuron(Cluster parent, string name) {
this.parent = parent;
this.name = name;
this.parent?.nuclei.Add(this);
}
public Neuron(ClusterPrefab parent, string name) { public Neuron(ClusterPrefab parent, string name) {
this.cluster = parent; this.cluster = parent;
this.name = name; this.name = name;
@ -180,27 +175,9 @@ public class Neuron : INucleus {
// Debug.LogError("No neuroid network"); // Debug.LogError("No neuroid network");
} }
// this clone the nucleus without the synapses and receivers // public Neuron(string name) {
public virtual IReceptor ShallowCloneTo(Cluster newParent) { // this._name = name;
Neuron clone = new(newParent, this.name) { // }
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
public virtual IReceptor ShallowCloneTo(ClusterPrefab newParent) {
Neuron clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
public virtual IReceptor CloneTo(ClusterPrefab parent) { public virtual IReceptor CloneTo(ClusterPrefab parent) {
Neuron clone = new(parent, this.name) { Neuron clone = new(parent, this.name) {
@ -210,6 +187,8 @@ public class Neuron : INucleus {
curveMax = this.curveMax, curveMax = this.curveMax,
average = this.average average = this.average
}; };
// if (clone.cluster != null)
// clone.cluster.nuclei.Add(clone);
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus); Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
@ -241,9 +220,9 @@ public class Neuron : INucleus {
return clone; return clone;
} }
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight); receivingNucleus.AddSynapse(this);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -275,25 +254,27 @@ public class Neuron : INucleus {
} }
} }
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) { public Synapse AddSynapse(IReceptor sendingNucleus) {
Synapse synapse = new(sendingNucleus, weight); Synapse synapse = new(sendingNucleus);
this.synapses.Add(synapse); this.synapses.Add(synapse);
return synapse; return synapse;
} }
public virtual void UpdateState() { public virtual void UpdateState() {
//UpdateState(new float3(0, 0, 0)); UpdateState(new float3(0, 0, 0));
this.parent?.UpdateState();
} }
public virtual void UpdateState(float3 inputValue) { public virtual void UpdateState(float3 inputValue) {
float3 sum = inputValue; float3 sum = inputValue;//new(0, 0, 0);
int n = 0; int n = 0;
//Applying the weight factgors //Applying the weight factgors
foreach (Synapse synapse in this.synapses) { foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
sum += synapse.weight * synapse.nucleus.outputValue; sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0.... // Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0) if (lengthsq(synapse.nucleus.outputValue) != 0)
n++; n++;
@ -324,47 +305,6 @@ public class Neuron : INucleus {
UpdateResult(result); UpdateResult(result);
} }
public virtual void UpdateStateIsolated() {
UpdateStateIsolated(new float3(0, 0, 0));
}
public virtual void UpdateStateIsolated(float3 bias) {
float3 sum = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average && n > 0)
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;
}
this.outputValue = result;
}
public virtual void UpdateResult(Vector3 result) { public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue); // float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) { // if (d < 0.5f) {
@ -373,10 +313,7 @@ public class Neuron : INucleus {
// } // }
this.outputValue = result; this.outputValue = result;
if (lengthsq(outputValue) != 0) { this.lastTime = Time.time;
Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}");
}
foreach (INucleus receiver in this.receivers) foreach (INucleus receiver in this.receivers)
receiver.UpdateState(); receiver.UpdateState();

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Unity.Mathematics; using Unity.Mathematics;
@ -7,7 +6,6 @@ using static Unity.Mathematics.math;
public class Receptor : IReceptor { public class Receptor : IReceptor {
private ClusterPrefab cluster; private ClusterPrefab cluster;
private Cluster parent;
[SerializeField] [SerializeField]
protected string _name; protected string _name;
@ -16,11 +14,6 @@ public class Receptor : IReceptor {
set => _name = value; set => _name = value;
} }
public Receptor(Cluster parent) {
this.parent = parent;
if (parent != null)
parent.nuclei.Add(this);
}
public Receptor(ClusterPrefab cluster) { public Receptor(ClusterPrefab cluster) {
this.cluster = cluster; this.cluster = cluster;
if (cluster != null) if (cluster != null)
@ -34,13 +27,15 @@ public class Receptor : IReceptor {
this.AddReceiver(nucleus); this.AddReceiver(nucleus);
} }
public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) {
if (cluster == null) if (cluster == null)
return null; return null;
Receptor receptor = new(cluster); Receptor receptor = new(cluster);
foreach (INucleus nucleus in cluster.inputs) { foreach (INucleus nucleus in cluster.inputs) {
if (nucleus != null && nucleus.name == nucleusName) { if (nucleus != null && nucleus.name == nucleusName) {
// Receptor receptor = new(cluster, nucleus);
// return receptor;
receptor.AddReceiver(nucleus); receptor.AddReceiver(nucleus);
} }
} }
@ -50,15 +45,6 @@ public class Receptor : IReceptor {
return receptor; return receptor;
} }
public virtual IReceptor ShallowCloneTo(Cluster parent) {
Receptor clone = new(parent);
return clone;
}
public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) {
Receptor clone = new(parent);
return clone;
}
public virtual IReceptor CloneTo(ClusterPrefab parent) { public virtual IReceptor CloneTo(ClusterPrefab parent) {
Receptor clone = new(parent); Receptor clone = new(parent);
@ -98,9 +84,9 @@ public class Receptor : IReceptor {
protected int[] thingIds; // every receiver can handle a thing with this id protected int[] thingIds; // every receiver can handle a thing with this id
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) { public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus); this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight); receivingNucleus.AddSynapse(this);
} }
public void RemoveReceiver(INucleus receiverNucleus) { public void RemoveReceiver(INucleus receiverNucleus) {
@ -136,8 +122,6 @@ public class Receptor : IReceptor {
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
this.localPosition = newLocalPositionVector; this.localPosition = newLocalPositionVector;
if (this._receivers == null)
return;
thingIds ??= new int[this._receivers.Count]; thingIds ??= new int[this._receivers.Count];

View File

@ -11,20 +11,26 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3} m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
m_Name: Velocity m_Name: Velocity
m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab m_EditorClassIdentifier: Assembly-CSharp::Cluster
nuclei: nuclei:
- rid: 2243601425629446539 - rid: 2243601403683012671
- rid: 2243601403683012676
references: references:
version: 2 version: 2
RefIds: RefIds:
- rid: 2243601425629446539 - rid: -2
type: {class: , ns: , asm: }
- rid: 2243601403683012671
type: {class: Neuron, ns: , asm: Assembly-CSharp} type: {class: Neuron, ns: , asm: Assembly-CSharp}
data: data:
_name: Output _name: Output
_synapses: [] _synapses:
- nucleus:
rid: -2
weight: 1
_receivers: [] _receivers: []
_array: _array:
rid: 2243601425629446540 rid: 2243601403683012672
_curvePreset: 0 _curvePreset: 0
curve: curve:
serializedVersion: 2 serializedVersion: 2
@ -52,9 +58,51 @@ MonoBehaviour:
m_RotationOrder: 4 m_RotationOrder: 4
curveMax: 1 curveMax: 1
average: 0 average: 0
- rid: 2243601425629446540 - rid: 2243601403683012672
type: {class: NucleusArray, ns: , asm: Assembly-CSharp} type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data: data:
_nuclei: _nuclei:
- rid: 2243601425629446539 - rid: 2243601403683012671
name: Output name: Output
- rid: 2243601403683012676
type: {class: Neuron, ns: , asm: Assembly-CSharp}
data:
_name: Position
_synapses: []
_receivers:
- rid: 2243601403683012671
_array:
rid: 2243601403683012677
_curvePreset: 0
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 1
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1000
value: 1000
inSlope: 1
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
curveMax: 1
average: 0
- rid: 2243601403683012677
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data:
_nuclei:
- rid: 2243601403683012676
name: New neuron

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c61aecac62c26de4aaefb2612bcc9a5d guid: dd622ac7ed09e70ea8edac595047ac82
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 11400000 mainObjectFileID: 11400000

View File

@ -3,14 +3,14 @@ using UnityEngine;
using System; using System;
using System.Linq; using System.Linq;
public class ClusterPickerWindow : EditorWindow { public class BrainPickerWindow : EditorWindow {
private Vector2 scroll; private Vector2 scroll;
private ClusterPrefab[] items = new ClusterPrefab[0]; private ClusterPrefab[] items = new ClusterPrefab[0];
private Action<ClusterPrefab> onPicked; private Action<ClusterPrefab> onPicked;
private string search = ""; private string search = "";
public static void ShowPicker(Action<ClusterPrefab> onPicked, string title = "Select Cluster") { public static void ShowPicker(Action<ClusterPrefab> onPicked, string title = "Select Cluster") {
var w = CreateInstance<ClusterPickerWindow>(); var w = CreateInstance<BrainPickerWindow>();
w.titleContent = new GUIContent(title); w.titleContent = new GUIContent(title);
w.minSize = new Vector2(360, 320); w.minSize = new Vector2(360, 320);
w.onPicked = onPicked; w.onPicked = onPicked;
@ -21,7 +21,7 @@ public class ClusterPickerWindow : EditorWindow {
private void OnEnable() => RefreshList(); private void OnEnable() => RefreshList();
private void RefreshList() { private void RefreshList() {
var guids = AssetDatabase.FindAssets("t:ClusterPrefab"); var guids = AssetDatabase.FindAssets("t:Cluster");
items = guids items = guids
.Select(g => AssetDatabase.LoadAssetAtPath<ClusterPrefab>(AssetDatabase.GUIDToAssetPath(g))) .Select(g => AssetDatabase.LoadAssetAtPath<ClusterPrefab>(AssetDatabase.GUIDToAssetPath(g)))
.Where(b => b != null) .Where(b => b != null)

View File

@ -617,22 +617,22 @@ public class ClusterInspector : Editor {
} }
protected virtual void AddCluster(INucleus nucleus) { protected virtual void AddCluster(INucleus nucleus) {
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster"); BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
} }
private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) { private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) {
Cluster subclusterInstance = new(prefab, this.cluster); Cluster subclusterInstance = new(this.cluster, subCluster);
//this.cluster.AddSubCluster(subclusterInstance);
//this.cluster.nuclei.Add(subclusterInstance);
subclusterInstance.AddReceiver(nucleus); subclusterInstance.AddReceiver(nucleus);
// This does not work somehow
// this.currentNucleus = subclusterInstance;
// BuildLayers();
} }
private void EditCluster(Cluster subCluster) { private void EditCluster(Cluster subCluster) {
// May be used with storedPrefab... //var currentActiveObject = Selection.activeObject;
Selection.activeObject = subCluster.prefab; Selection.activeObject = subCluster.prefab;
EditorGUIUtility.PingObject(subCluster.prefab); EditorGUIUtility.PingObject(subCluster.prefab);
var editor = Editor.CreateEditor(subCluster.prefab); var editor = Editor.CreateEditor(subCluster.prefab);
//Selection.activeObject = currentActiveObject;
} }
// Connect to another nucleus in the same cluster // Connect to another nucleus in the same cluster

View File

@ -22,8 +22,8 @@ public class NanoBrainComponent_Editor : Editor {
} }
public override VisualElement CreateInspectorGUI() { public override VisualElement CreateInspectorGUI() {
//ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain; //NanoBrainComponent component = target as NanoBrainComponent;
Cluster brain = component.brain; ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain;
if (Application.isPlaying == false) if (Application.isPlaying == false)
serializedObject.Update(); serializedObject.Update();
@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor {
}); });
if (brain != null && board != null) if (brain != null && board != null)
board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer); board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer);
// else // else
// Debug.LogWarning(" No brain!"); // Debug.LogWarning(" No brain!");

View File

@ -1,15 +1,14 @@
using System;
using UnityEngine; using UnityEngine;
public class NanoBrainComponent : MonoBehaviour { public class NanoBrainComponent : MonoBehaviour {
public ClusterPrefab defaultBrain; public ClusterPrefab defaultBrain;
private ClusterPrefab brainInstance;
[NonSerialized] public INucleus root => brainInstance.output;
private Cluster brainInstance; public ClusterPrefab brain {
public Cluster brain {
get { get {
if (brainInstance == null && defaultBrain != null) { if (brainInstance == null && defaultBrain != null) {
brainInstance = new Cluster(defaultBrain); //Instantiate(defaultBrain); brainInstance = Instantiate(defaultBrain);
brainInstance.name = defaultBrain.name + " (Instance)"; brainInstance.name = defaultBrain.name + " (Instance)";
SwarmControl sc = FindFirstObjectByType<SwarmControl>(); SwarmControl sc = FindFirstObjectByType<SwarmControl>();
@ -24,7 +23,7 @@ public class NanoBrainComponent : MonoBehaviour {
} }
} }
public static void UpdateWeight(Cluster brain, string name, float weight) { public static void UpdateWeight(ClusterPrefab brain, string name, float weight) {
INucleus root = brain.output; INucleus root = brain.output;
foreach (Synapse synapse in root.synapses) { foreach (Synapse synapse in root.synapses) {
if (synapse.nucleus.name == name) { if (synapse.nucleus.name == name) {