WIP: cloning of nucleusarrays is not working yet

This commit is contained in:
Pascal Serrarens 2026-02-04 17:42:16 +01:00
parent 60e2b3e33f
commit 3cc5f56f61
6 changed files with 89 additions and 46 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;
@ -51,22 +52,22 @@ public class Cluster : INucleus {
// }
private void ClonePrefab() {
IReceptor[] nucleiArray = this.prefab.nuclei.ToArray();
IReceptor[] nuclei = 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];
for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) {
IReceptor receptor = nuclei[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);
int ix = GetNucleusIndex(nuclei, receiver);
if (ix < 0)
continue;
@ -75,15 +76,42 @@ public class Cluster : INucleus {
// Find the synapse for the weight
float weight = 1;
NucleusArray nucleusArray = null;
foreach (Synapse synapse in receiver.synapses) {
if (synapse.nucleus == receptor) {
if (synapse.nucleus == receptor)
weight = synapse.weight;
break;
if (synapse.nucleus is INucleus synapseNucleus) {
if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) {
if (nucleusArray == null) {
// copy the array
nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array");
for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) {
IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx];
int ix2 = GetNucleusIndex(nuclei, arrayNucleus);
nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2];
}
}
synapseNucleus.array = nucleusArray;
}
}
}
clonedSender.AddReceiver(clonedReceiver, weight);
}
// if (receptor is INucleus nucleus) {
// if (clonedSender is not INucleus clonedNucleus) {
// Debug.LogError("INucleus clone is not an INucleus!");
// continue;
// }
// clonedNucleus.array = new NucleusArray(nucleus.array._nuclei.Length, "array");
// for (int arrayIx = 0; arrayIx < nucleus.array._nuclei.Length; arrayIx++) {
// //foreach (INucleus arrayNucleus in nucleus.array.nuclei) {
// IReceptor arrayNucleus = nucleus.array._nuclei[arrayIx];
// int ix = GetNucleusIndex(nuclei, arrayNucleus);
// clonedNucleus.array._nuclei[arrayIx] = clonedNuclei[ix];
// }
// }
}
}
@ -96,13 +124,13 @@ public class Cluster : INucleus {
// Calculate in-degrees
foreach (IReceptor node in nodes) {
foreach (INucleus receiver in node.receivers)
inDegree[receiver]++;
inDegree[receiver]++;
}
Queue<IReceptor> queue = new();
foreach (IReceptor node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node);
queue.Enqueue(node);
}
List<IReceptor> sortedOrder = new();
@ -119,7 +147,7 @@ public class Cluster : INucleus {
// Check for cycles in the graph
if (sortedOrder.Count != nodes.Count)
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
return sortedOrder;
}
@ -281,7 +309,7 @@ public class Cluster : INucleus {
// }
public void UpdateStateIsolated() {
float3 bias = new(0,0,0);
float3 bias = new(0, 0, 0);
UpdateStateIsolated(bias);
}
public void UpdateStateIsolated(float3 bias) {

View File

@ -210,7 +210,7 @@ public class ClusterInspector : Editor {
// Draw selected Nucleus
if (expandArray) {
float maxValue = 0;
foreach (INucleus nucleus in this.currentNucleus.array.nuclei) {
foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) {
float value = length(nucleus.outputValue);
if (value > maxValue)
maxValue = value;
@ -231,7 +231,7 @@ public class ClusterInspector : Editor {
Handles.color = Color.black;
Handles.DrawAAConvexPolygon(verts);
int row = 0;
foreach (INucleus nucleus in this.currentNucleus.array.nuclei) {
foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) {
Vector3 pos = new(150, margin + row * spacing, 0.0f);
Handles.color = Color.white;
// The selected nucleus highlight ring
@ -239,13 +239,13 @@ public class ClusterInspector : Editor {
DrawNucleus(nucleus, pos, maxValue, size);
row++;
}
GUIStyle style = new(EditorStyles.label) {
alignment = TextAnchor.UpperCenter,
normal = { textColor = Color.white },
fontStyle = FontStyle.Bold,
};
Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis
Handles.Label(labelPos, this.currentNucleus.name, style);
// GUIStyle style = new(EditorStyles.label) {
// alignment = TextAnchor.UpperCenter,
// normal = { textColor = Color.white },
// fontStyle = FontStyle.Bold,
// };
// Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 25); // below disc along up axis
// Handles.Label(labelPos, this.currentNucleus.name, style);
}
else {
Handles.color = Color.white;
@ -274,7 +274,12 @@ public class ClusterInspector : Editor {
float margin = 10 + spacing / 2;
int row = 0;
List<NucleusArray> drawnArrays = new();
foreach (INucleus receiver in nucleus.receivers) {
if (drawnArrays.Contains(receiver.array))
continue;
drawnArrays.Add(receiver.array);
INucleus receiverNucleus = receiver;
if (receiverNucleus == null)
continue;

View File

@ -13,17 +13,22 @@ public class NanoBrain : MonoBehaviour {
name = defaultBrain.name + " (Instance)"
};
}
SwarmControl sc = FindFirstObjectByType<SwarmControl>();
if (sc != null) {
UpdateWeight(brainInstance, "Containment", sc.containmentForce);
UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce);
UpdateWeight(brainInstance, "Separation", sc.separationForce);
UpdateWeight(brainInstance, "Alignment", sc.alignmentForce);
}
// SwarmControl sc = FindFirstObjectByType<SwarmControl>();
// if (sc != null) {
// UpdateWeight(brainInstance, "Containment", sc.containmentForce);
// UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce);
// UpdateWeight(brainInstance, "Separation", sc.separationForce);
// UpdateWeight(brainInstance, "Alignment", sc.alignmentForce);
// }
return brainInstance;
}
}
// public void Awake() {
// brainInstance = new Cluster(defaultBrain);
// }
public static void UpdateWeight(Cluster brain, string name, float weight) {
INucleus root = brain.output;
foreach (Synapse synapse in root.synapses) {

View File

@ -183,7 +183,7 @@ public class Neuron : INucleus {
// this clone the nucleus without the synapses and receivers
public virtual IReceptor ShallowCloneTo(Cluster newParent) {
Neuron clone = new(newParent, this.name) {
array = this.array,
array = null,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,

View File

@ -5,16 +5,11 @@ using UnityEngine;
[System.Serializable]
public class NucleusArray {
[SerializeReference]
private INucleus[] _nuclei;
private ClusterPrefab[] _clusters;
public IEnumerable<INucleus> nuclei {
private IReceptor[] _nuclei;
//private ClusterPrefab[] _clusters;
public IReceptor[] nuclei {
get {
// if (_nuclei == null)
// return _clusters;
// else if (_clusters == null)
return _nuclei;
// else
// return _nuclei.Concat(_clusters);
return _nuclei;
}
}
public string name;
@ -23,14 +18,19 @@ public class NucleusArray {
this.name = nucleus.name;
this._nuclei = new INucleus[1];
this._nuclei[0] = nucleus;
this._clusters = new ClusterPrefab[0];
//this._clusters = new ClusterPrefab[0];
}
public NucleusArray(ClusterPrefab cluster) {
this.name = cluster.name;
this._nuclei = new INucleus[0];
this._clusters = new ClusterPrefab[1];
this._clusters[0] = cluster;
// this._clusters = new ClusterPrefab[1];
// this._clusters[0] = cluster;
}
public NucleusArray(int size, string name) {
this.name = name;
this._nuclei = new INucleus[size];
}
public void AddNucleus() {
if (this._nuclei.Length == 0) {
@ -38,12 +38,12 @@ public class NucleusArray {
return;
}
int newLength = this._nuclei.Length + 1;
INucleus[] newArray = new INucleus[newLength];
IReceptor[] newArray = new INucleus[newLength];
for (int i = 0; i < this._nuclei.Length; i++)
newArray[i] = this._nuclei[i];
if (this._nuclei[0] is INucleus nucleus)
newArray[newLength - 1] = (INucleus) nucleus.Clone();
newArray[newLength - 1] = (INucleus)nucleus.Clone();
this._nuclei = newArray;
}
@ -54,11 +54,12 @@ public class NucleusArray {
Debug.LogWarning("Perceptoid array cannot be empty");
return;
}
INucleus[] newPerceptei = new INucleus[newLength];
IReceptor[] newPerceptei = new INucleus[newLength];
for (int i = 0; i < newLength; i++)
newPerceptei[i] = this._nuclei[i];
// Delete the last perception
Neuron.Delete(this._nuclei[newLength]);
if (this._nuclei[newLength] is INucleus nucleus)
Neuron.Delete(nucleus); //this._nuclei[newLength]);
this._nuclei = newPerceptei;
}

View File

@ -6,8 +6,6 @@ using static Unity.Mathematics.math;
public class Receptor : IReceptor {
private ClusterPrefab cluster;
private Cluster parent;
[SerializeField]
protected string _name;
@ -63,6 +61,9 @@ public class Receptor : IReceptor {
// return receptor;
}
private ClusterPrefab cluster;
private Cluster parent;
public virtual IReceptor ShallowCloneTo(Cluster parent) {
Receptor clone = new(parent);
return clone;
@ -188,7 +189,9 @@ public class Receptor : IReceptor {
}
receiverIx++;
}
Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}");
if (selectedReceiverIx >= thingIds.Length)
return;
thingIds[selectedReceiverIx] = thingId;
if (thingName != null) {
string baseName = selectedReceiver.name;
@ -197,6 +200,7 @@ public class Receptor : IReceptor {
baseName = selectedReceiver.name.Substring(0, colonPos);
selectedReceiver.name = baseName + ": " + thingName;
}
Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}");
selectedReceiver.parent.UpdateStateIsolated();
}