From cd268c95974e7a2a097f931bb28800d03e2b11ca Mon Sep 17 00:00:00 2001 From: Christian Heinemann Date: Sat, 4 Jul 2026 08:27:44 +0200 Subject: [PATCH] Mutate first offspring genome instead of host genome Clone and mutate the genome for the first offspring (currentOffspring == 0) directly after the offspring creature is created, leaving the host genome untouched. Co-Authored-By: Claude Opus 4.8 --- source/EngineKernels/ConstructorProcessor.cuh | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/source/EngineKernels/ConstructorProcessor.cuh b/source/EngineKernels/ConstructorProcessor.cuh index 737de6c26..0820e3ab3 100644 --- a/source/EngineKernels/ConstructorProcessor.cuh +++ b/source/EngineKernels/ConstructorProcessor.cuh @@ -172,13 +172,16 @@ __inline__ __device__ void ConstructorProcessor::processCell(SimulationData& dat if (readyToConstruct) { readyToConstruct = checkHostEnergyAndRequestExternalEnergyIfNeeded(data, object); } + if (readyToConstruct) { + constructor.offspring = findOrCreateNewCreature(data, object); + } } __syncthreads(); if (!readyToConstruct) { return; } - // Important: mutate the host genome before it is cloned for the offspring. + // Mutate the freshly cloned genome of the first offspring, leaving the host genome untouched. mutateGenome(data, object); // The actual construction runs on a single thread. @@ -186,8 +189,6 @@ __inline__ __device__ void ConstructorProcessor::processCell(SimulationData& dat return; } - constructor.offspring = findOrCreateNewCreature(data, object); - // Check again after cloning the creature, because the offspring genome may diverge from the host genome. if (ConstructorHelper::isFinished(object, *constructor.offspring->genome)) { return; @@ -219,29 +220,24 @@ __inline__ __device__ void ConstructorProcessor::processCell(SimulationData& dat __inline__ __device__ void ConstructorProcessor::mutateGenome(SimulationData& data, Object* object) { - auto& cell = object->typeData.cell; - auto& constructor = cell.constructor; + auto& constructor = object->typeData.cell.constructor; + auto offspring = constructor.offspring; - __shared__ Genome* clonedGenome; + __shared__ Genome* genomeToMutate; if (threadIdx.x == 0) { - clonedGenome = nullptr; - if (ConstructorHelper::createsNewCreature(constructor)) { - auto& creature = cell.creature; - int origMutationState = atomicExch(&creature->mutationState, MutationState_Mutated); + genomeToMutate = nullptr; + // Only the first offspring is mutated; its genome was cloned for it in findOrCreateNewCreature. + if (constructor.currentOffspring == 0 && ConstructorHelper::createsNewCreature(constructor)) { + int origMutationState = atomicExch(&offspring->mutationState, MutationState_Mutated); if (origMutationState == MutationState_NotMutated) { - EntityFactory factory; - factory.init(&data); - clonedGenome = factory.cloneGenome(creature->genome); + genomeToMutate = offspring->genome; } } } __syncthreads(); - if (clonedGenome != nullptr) { - MutationProcessor::applyMutations(data, cell.creature, clonedGenome); - if (threadIdx.x == 0) { - cell.creature->genome = clonedGenome; - } + if (genomeToMutate != nullptr) { + MutationProcessor::applyMutations(data, offspring, genomeToMutate); } __syncthreads(); } @@ -274,6 +270,11 @@ __inline__ __device__ Creature* ConstructorProcessor::findOrCreateNewCreature(Si auto result = factory.cloneCreature(object->typeData.cell.creature); result->numCells = 0; + // Give the first offspring its own genome copy so it can be mutated without affecting the host + if (constructor.currentOffspring == 0) { + result->genome = factory.cloneGenome(object->typeData.cell.creature->genome); + } + return result; }