From 23c379f84a4f91e963a0f949097b81dc4341d394 Mon Sep 17 00:00:00 2001 From: Christian Heinemann Date: Fri, 5 Jul 2024 18:15:11 +0200 Subject: [PATCH] allow sensors to scan for less complex mutants --- .../EngineGpuKernels/ConstructorProcessor.cuh | 6 +- source/EngineGpuKernels/DensityMap.cuh | 39 +++++ source/EngineGpuKernels/SensorProcessor.cuh | 19 +- .../EngineInterface/CellFunctionConstants.h | 1 + .../DescriptionEditService.cpp | 3 +- .../EngineInterface/DescriptionEditService.h | 1 + source/EngineInterface/Descriptions.h | 5 + source/EngineTests/SensorTests.cpp | 162 ++++++++++++++++++ source/Gui/GenomeEditorWindow.cpp | 2 +- source/Gui/InspectorWindow.cpp | 2 +- 10 files changed, 228 insertions(+), 12 deletions(-) diff --git a/source/EngineGpuKernels/ConstructorProcessor.cuh b/source/EngineGpuKernels/ConstructorProcessor.cuh index bc2c18901..5d81ecc51 100644 --- a/source/EngineGpuKernels/ConstructorProcessor.cuh +++ b/source/EngineGpuKernels/ConstructorProcessor.cuh @@ -67,7 +67,7 @@ private: __inline__ __device__ static bool checkAndReduceHostEnergy(SimulationData& data, Cell* hostCell, ConstructionData const& constructionData); __inline__ __device__ static bool isSelfReplicator(Cell* cell); - __inline__ __device__ static int calcGenomeComplexity(int color, uint8_t* genome, uint16_t genomeSize); + __inline__ __device__ static uint32_t calcGenomeComplexity(int color, uint8_t* genome, uint16_t genomeSize); }; /************************************************************************/ @@ -778,7 +778,7 @@ __inline__ __device__ bool ConstructorProcessor::isSelfReplicator(Cell* cell) return GenomeDecoder::containsSelfReplication(cell->cellFunctionData.constructor); } -__inline__ __device__ int ConstructorProcessor::calcGenomeComplexity(int color, uint8_t* genome, uint16_t genomeSize) +__inline__ __device__ uint32_t ConstructorProcessor::calcGenomeComplexity(int color, uint8_t* genome, uint16_t genomeSize) { int lastDepth = 0; auto result = 0.0f; @@ -794,5 +794,5 @@ __inline__ __device__ int ConstructorProcessor::calcGenomeComplexity(int color, lastDepth = depth; ++acceleration; }); - return toInt(result); + return static_cast(result); } diff --git a/source/EngineGpuKernels/DensityMap.cuh b/source/EngineGpuKernels/DensityMap.cuh index 8d2986b55..69ebf169a 100644 --- a/source/EngineGpuKernels/DensityMap.cuh +++ b/source/EngineGpuKernels/DensityMap.cuh @@ -16,6 +16,8 @@ public: CudaMemoryManager::getInstance().acquireMemory(_densityMapSize.x * _densityMapSize.y, _sameMutantDensityMap1); CudaMemoryManager::getInstance().acquireMemory(_densityMapSize.x * _densityMapSize.y, _sameMutantDensityMap2); CudaMemoryManager::getInstance().acquireMemory(_densityMapSize.x * _densityMapSize.y, _specificMutantDensityMap); + CudaMemoryManager::getInstance().acquireMemory(_densityMapSize.x * _densityMapSize.y, _lessGenomeComplexityDensityMap1); + CudaMemoryManager::getInstance().acquireMemory(_densityMapSize.x * _densityMapSize.y, _lessGenomeComplexityDensityMap2); _slotSize = slotSize; } @@ -26,6 +28,8 @@ public: CudaMemoryManager::getInstance().freeMemory(_sameMutantDensityMap1); CudaMemoryManager::getInstance().freeMemory(_sameMutantDensityMap2); CudaMemoryManager::getInstance().freeMemory(_specificMutantDensityMap); + CudaMemoryManager::getInstance().freeMemory(_lessGenomeComplexityDensityMap1); + CudaMemoryManager::getInstance().freeMemory(_lessGenomeComplexityDensityMap2); } __device__ __inline__ void clear() @@ -37,6 +41,8 @@ public: _sameMutantDensityMap1[index] = 0; _sameMutantDensityMap2[index] = 0; _specificMutantDensityMap[index] = 0; + _lessGenomeComplexityDensityMap1[index] = 0; + _lessGenomeComplexityDensityMap2[index] = 0; } } @@ -102,6 +108,20 @@ public: return 0ul; } + __device__ __inline__ uint32_t getLowerComplexMutantDensity(float2 const& pos, uint32_t genomeComplexity) const + { + auto index = toInt(pos.x) / _slotSize + toInt(pos.y) / _slotSize * _densityMapSize.x; + if (index >= 0 && index < _densityMapSize.x * _densityMapSize.y) { + auto bucket = min(16, max(0, 31 - __clz(genomeComplexity))); + if (bucket < 8) { + return (_lessGenomeComplexityDensityMap1[index] >> (bucket * 8)) & 0xff; + } else { + return (_lessGenomeComplexityDensityMap2[index] >> ((bucket - 8) * 8)) & 0xff; + } + } + return 0ul; + } + __device__ __inline__ void addCell(uint64_t const& timestep, Cell* cell) { auto index = toInt(cell->pos.x) / _slotSize + toInt(cell->pos.y) / _slotSize * _densityMapSize.x; @@ -125,6 +145,23 @@ public: alienAtomicAdd64(&_sameMutantDensityMap1[index], static_cast((1ull << (bucket1 * 8)) | (1ull << ((bucket2 + 3) * 8)))); alienAtomicAdd64(&_sameMutantDensityMap2[index], static_cast(1ull << (bucket3 * 8))); } + { + auto bucket = 32 - __clz(cell->genomeComplexity); + if (bucket < 8) { + auto bitset = static_cast(1ull << bucket * 8); + for (int i = 0; i < 7; ++i) { + bitset |= (bitset << 8); + } + alienAtomicAdd64(&_lessGenomeComplexityDensityMap1[index], bitset); + alienAtomicAdd64(&_lessGenomeComplexityDensityMap2[index], 0x0101010101010101ull); + } else if (bucket < 16) { + auto bitset = static_cast(1ull << ((bucket - 8) * 8)); + for (int i = 0; i < 7; ++i) { + bitset |= (bitset << 8); + } + alienAtomicAdd64(&_lessGenomeComplexityDensityMap2[index], bitset); + } + } } } } @@ -144,5 +181,7 @@ private: uint64_t* _sameMutantDensityMap2; uint32_t* _respawnedMutantDensityMap; uint32_t* _specificMutantDensityMap; + uint64_t* _lessGenomeComplexityDensityMap1; + uint64_t* _lessGenomeComplexityDensityMap2; }; diff --git a/source/EngineGpuKernels/SensorProcessor.cuh b/source/EngineGpuKernels/SensorProcessor.cuh index 3c28cb17d..435c42577 100644 --- a/source/EngineGpuKernels/SensorProcessor.cuh +++ b/source/EngineGpuKernels/SensorProcessor.cuh @@ -17,7 +17,7 @@ private: __inline__ __device__ static void processCell(SimulationData& data, SimulationStatistics& statistics, Cell* cell); __inline__ __device__ static uint32_t getCellDensity( uint64_t const& timestep, - uint32_t const& mutationId, + Cell* const& cell, uint8_t const& restrictToColor, SensorRestrictToMutants const& restrictToMutants, DensityMap const& densityMap, @@ -73,7 +73,7 @@ __inline__ __device__ void SensorProcessor::processCell(SimulationData& data, Si __inline__ __device__ uint32_t SensorProcessor::getCellDensity( uint64_t const& timestep, - uint32_t const& mutationId, + Cell* const& cell, uint8_t const& restrictToColor, SensorRestrictToMutants const& restrictToMutants, DensityMap const& densityMap, @@ -89,10 +89,10 @@ __inline__ __device__ uint32_t SensorProcessor::getCellDensity( } } else { if (restrictToMutants == SensorRestrictToMutants_RestrictToSameMutants) { - result = densityMap.getSameMutantDensity(scanPos, mutationId); + result = densityMap.getSameMutantDensity(scanPos, cell->mutationId); } if (restrictToMutants == SensorRestrictToMutants_RestrictToOtherMutants) { - result = densityMap.getOtherMutantDensity(timestep, scanPos, mutationId); + result = densityMap.getOtherMutantDensity(timestep, scanPos, cell->mutationId); } if (restrictToMutants == SensorRestrictToMutants_RestrictToRespawnedMutants) { result = densityMap.getRespawnedMutantDensity(scanPos); @@ -100,6 +100,9 @@ __inline__ __device__ uint32_t SensorProcessor::getCellDensity( if (restrictToMutants == SensorRestrictToMutants_RestrictToZeroMutants) { result = densityMap.getZeroMutantDensity(scanPos); } + if (restrictToMutants == SensorRestrictToMutants_RestrictToLessComplexMutants) { + result = densityMap.getLowerComplexMutantDensity(scanPos, cell->genomeComplexity); + } if (restrictToColor != 255) { result = min(result, densityMap.getColorDensity(scanPos, restrictToColor)); } @@ -136,7 +139,7 @@ SensorProcessor::searchNeighborhood(SimulationData& data, SimulationStatistics& auto scanPos = cell->pos + delta; data.cellMap.correctPosition(scanPos); - uint32_t density = getCellDensity(data.timestep, cell->mutationId, restrictToColor, restrictToMutants, densityMap, scanPos); + uint32_t density = getCellDensity(data.timestep, cell, restrictToColor, restrictToMutants, densityMap, scanPos); if (density < minDensity) { continue; } @@ -206,7 +209,7 @@ SensorProcessor::searchByAngle(SimulationData& data, SimulationStatistics& stati auto scanPos = cell->pos + searchDelta * distance; data.cellMap.correctPosition(scanPos); - uint32_t density = getCellDensity(data.timestep, cell->mutationId, restrictToColor, restrictToMutants, densityMap, scanPos); + uint32_t density = getCellDensity(data.timestep, cell, restrictToColor, restrictToMutants, densityMap, scanPos); if (density < minDensity) { continue; @@ -266,6 +269,10 @@ __inline__ __device__ void SensorProcessor::flagDetectedCells(SimulationData& da if (restrictToMutants == SensorRestrictToMutants_RestrictToZeroMutants && otherCell->mutationId != 0) { continue; } + if (restrictToMutants == SensorRestrictToMutants_RestrictToLessComplexMutants + && (otherCell->genomeComplexity >= cell->genomeComplexity || otherCell->mutationId == 0 && otherCell->mutationId == 1)) { + continue; + } //if (restrictToOtherMutants && otherCell->mutationId != 0 // && ((cell->mutationId <= otherCell->mutationId && cell->genomeComplexity <= otherCell->genomeComplexity) // || static_cast(cell->mutationId & 0xff) == otherCell->ancestorMutationId)) { diff --git a/source/EngineInterface/CellFunctionConstants.h b/source/EngineInterface/CellFunctionConstants.h index 9357a2b51..3d2b9f63c 100644 --- a/source/EngineInterface/CellFunctionConstants.h +++ b/source/EngineInterface/CellFunctionConstants.h @@ -59,6 +59,7 @@ enum SensorRestrictToMutants_ SensorRestrictToMutants_RestrictToOtherMutants, SensorRestrictToMutants_RestrictToRespawnedMutants, SensorRestrictToMutants_RestrictToZeroMutants, + SensorRestrictToMutants_RestrictToLessComplexMutants, SensorRestrictToMutants_Count }; diff --git a/source/EngineInterface/DescriptionEditService.cpp b/source/EngineInterface/DescriptionEditService.cpp index df1a4d627..7eb32ee7f 100644 --- a/source/EngineInterface/DescriptionEditService.cpp +++ b/source/EngineInterface/DescriptionEditService.cpp @@ -25,7 +25,8 @@ DataDescription DescriptionEditService::createRect(CreateRectParameters const& p .setColor(parameters._color) .setBarrier(parameters._barrier) .setCreatureId(creatureId) - .setMutationId(parameters._mutationId)); + .setMutationId(parameters._mutationId) + .setGenomeComplexity(parameters._genomeComplexity)); } } reconnectCells(result, parameters._cellDistance * 1.1f); diff --git a/source/EngineInterface/DescriptionEditService.h b/source/EngineInterface/DescriptionEditService.h index 3fa3deb3d..e0ffdb381 100644 --- a/source/EngineInterface/DescriptionEditService.h +++ b/source/EngineInterface/DescriptionEditService.h @@ -20,6 +20,7 @@ class DescriptionEditService MEMBER_DECLARATION(CreateRectParameters, bool, barrier, false); MEMBER_DECLARATION(CreateRectParameters, bool, randomCreatureId, true); MEMBER_DECLARATION(CreateRectParameters, int, mutationId, 0); + MEMBER_DECLARATION(CreateRectParameters, int, genomeComplexity, 0); }; static DataDescription createRect(CreateRectParameters const& parameters); diff --git a/source/EngineInterface/Descriptions.h b/source/EngineInterface/Descriptions.h index e68fb27c2..4d15cdcc5 100644 --- a/source/EngineInterface/Descriptions.h +++ b/source/EngineInterface/Descriptions.h @@ -498,6 +498,11 @@ struct CellDescription mutationId = value; return *this; } + CellDescription& setGenomeComplexity(int value) + { + genomeComplexity = value; + return *this; + } bool hasGenome() const; std::vector& getGenomeRef(); diff --git a/source/EngineTests/SensorTests.cpp b/source/EngineTests/SensorTests.cpp index 64b06833e..367ede343 100644 --- a/source/EngineTests/SensorTests.cpp +++ b/source/EngineTests/SensorTests.cpp @@ -686,3 +686,165 @@ TEST_F(SensorTests, scanNeighborhood_targetedCreature_respawnedMutant_notFound) EXPECT_TRUE(approxCompare(0.0f, actualSensorCell.activity.channels[0])); } + +TEST_F(SensorTests, scanNeighborhood_targetedCreature_lessComplexMutant_found) +{ + _parameters.cellFunctionAttackerSensorDetectionFactor[0] = 1.0f; + _simController->setSimulationParameters(_parameters); + + for (int otherGenomeComplexity = 0; otherGenomeComplexity < 500; ++otherGenomeComplexity) { + DataDescription data; + data.addCells( + {CellDescription() + .setId(1) + .setMutationId(5) + .setPos({100.0f, 100.0f}) + .setMaxConnections(2) + .setGenomeComplexity(1000) + .setExecutionOrderNumber(0) + .setInputExecutionOrderNumber(5) + .setCellFunction(SensorDescription().setRestrictToMutants(SensorRestrictToMutants_RestrictToLessComplexMutants)), + CellDescription() + .setId(2) + .setPos({101.0f, 100.0f}) + .setMaxConnections(1) + .setExecutionOrderNumber(5) + .setCellFunction(NerveDescription()) + .setActivity({1, 0, 0, 0, 0, 0, 0, 0})}); + data.addConnection(1, 2); + + data.add(DescriptionEditService::createRect(DescriptionEditService::CreateRectParameters() + .center({10.0f, 100.0f}) + .width(16) + .height(16) + .cellDistance(0.5f) + .mutationId(6) + .genomeComplexity(otherGenomeComplexity))); + + _simController->clear(); + _simController->setCurrentTimestep(0ull); + _simController->setSimulationData(data); + _simController->calcTimesteps(1); + + auto actualData = _simController->getSimulationData(); + auto actualSensorCell = getCell(actualData, 1); + + EXPECT_TRUE(approxCompare(1.0f, actualSensorCell.activity.channels[0])); + } +} + +TEST_F(SensorTests, scanNeighborhood_targetedCreature_lessComplexMutant_notFound_otherMutant) +{ + _parameters.cellFunctionAttackerSensorDetectionFactor[0] = 1.0f; + _simController->setSimulationParameters(_parameters); + + for (int otherGenomeComplexity = 1000; otherGenomeComplexity < 2001; ++otherGenomeComplexity) { + DataDescription data; + data.addCells( + {CellDescription() + .setId(1) + .setMutationId(5) + .setPos({100.0f, 100.0f}) + .setMaxConnections(2) + .setGenomeComplexity(1000) + .setExecutionOrderNumber(0) + .setInputExecutionOrderNumber(5) + .setCellFunction(SensorDescription().setRestrictToMutants(SensorRestrictToMutants_RestrictToLessComplexMutants)), + CellDescription() + .setId(2) + .setPos({101.0f, 100.0f}) + .setMaxConnections(1) + .setExecutionOrderNumber(5) + .setCellFunction(NerveDescription()) + .setActivity({1, 0, 0, 0, 0, 0, 0, 0})}); + data.addConnection(1, 2); + + data.add(DescriptionEditService::createRect(DescriptionEditService::CreateRectParameters() + .center({10.0f, 100.0f}) + .width(16) + .height(16) + .cellDistance(0.5f) + .mutationId(6) + .genomeComplexity(otherGenomeComplexity))); + + _simController->clear(); + _simController->setCurrentTimestep(0ull); + _simController->setSimulationData(data); + _simController->calcTimesteps(1); + + auto actualData = _simController->getSimulationData(); + auto actualSensorCell = getCell(actualData, 1); + + EXPECT_TRUE(approxCompare(0.0f, actualSensorCell.activity.channels[0])); + } +} + +TEST_F(SensorTests, scanNeighborhood_targetedCreature_lessComplexMutant_notFound_zeroMutant) +{ + _parameters.cellFunctionAttackerSensorDetectionFactor[0] = 1.0f; + _simController->setSimulationParameters(_parameters); + DataDescription data; + data.addCells( + {CellDescription() + .setId(1) + .setMutationId(100) + .setPos({100.0f, 100.0f}) + .setMaxConnections(2) + .setExecutionOrderNumber(0) + .setInputExecutionOrderNumber(5) + .setCellFunction(SensorDescription().setRestrictToMutants(SensorRestrictToMutants_RestrictToLessComplexMutants)), + CellDescription() + .setId(2) + .setPos({101.0f, 100.0f}) + .setMaxConnections(1) + .setExecutionOrderNumber(5) + .setCellFunction(NerveDescription()) + .setActivity({1, 0, 0, 0, 0, 0, 0, 0})}); + data.addConnection(1, 2); + + data.add(DescriptionEditService::createRect( + DescriptionEditService::CreateRectParameters().center({10.0f, 100.0f}).width(16).height(16).cellDistance(0.5f).mutationId(0))); + + _simController->setSimulationData(data); + _simController->calcTimesteps(1); + + auto actualData = _simController->getSimulationData(); + auto actualSensorCell = getCell(actualData, 1); + + EXPECT_TRUE(approxCompare(0.0f, actualSensorCell.activity.channels[0])); +} + +TEST_F(SensorTests, scanNeighborhood_targetedCreature_lessComplexMutant_notFound_respawnedCell) +{ + _parameters.cellFunctionAttackerSensorDetectionFactor[0] = 1.0f; + _simController->setSimulationParameters(_parameters); + DataDescription data; + data.addCells( + {CellDescription() + .setId(1) + .setMutationId(100) + .setPos({100.0f, 100.0f}) + .setMaxConnections(2) + .setExecutionOrderNumber(0) + .setInputExecutionOrderNumber(5) + .setCellFunction(SensorDescription().setRestrictToMutants(SensorRestrictToMutants_RestrictToLessComplexMutants)), + CellDescription() + .setId(2) + .setPos({101.0f, 100.0f}) + .setMaxConnections(1) + .setExecutionOrderNumber(5) + .setCellFunction(NerveDescription()) + .setActivity({1, 0, 0, 0, 0, 0, 0, 0})}); + data.addConnection(1, 2); + + data.add(DescriptionEditService::createRect( + DescriptionEditService::CreateRectParameters().center({10.0f, 100.0f}).width(16).height(16).cellDistance(0.5f).mutationId(1))); + + _simController->setSimulationData(data); + _simController->calcTimesteps(1); + + auto actualData = _simController->getSimulationData(); + auto actualSensorCell = getCell(actualData, 1); + + EXPECT_TRUE(approxCompare(0.0f, actualSensorCell.activity.channels[0])); +} diff --git a/source/Gui/GenomeEditorWindow.cpp b/source/Gui/GenomeEditorWindow.cpp index 54db3ac89..67de36747 100644 --- a/source/Gui/GenomeEditorWindow.cpp +++ b/source/Gui/GenomeEditorWindow.cpp @@ -644,7 +644,7 @@ void _GenomeEditorWindow::processNode( AlienImGui::Combo( AlienImGui::ComboParameters() .name("Scan mutants") - .values({"None", "Same mutants", "Other mutants", "Respawned", "Artificial"}) + .values({"None", "Same mutants", "Other mutants", "Respawned", "Artificial", "Less complex mutants"}) .textWidth(ContentTextWidth) .tooltip(Const::GenomeSensorRestrictToOtherMutantsTooltip), sensor.restrictToMutants); diff --git a/source/Gui/InspectorWindow.cpp b/source/Gui/InspectorWindow.cpp index 1aeeb3135..fd0daf997 100644 --- a/source/Gui/InspectorWindow.cpp +++ b/source/Gui/InspectorWindow.cpp @@ -683,7 +683,7 @@ void _InspectorWindow::processSensorContent(SensorDescription& sensor) AlienImGui::Combo( AlienImGui::ComboParameters() .name("Scan mutants") - .values({"None", "Same mutants", "Other mutants", "Respawned", "Artificial"}) + .values({"None", "Same mutants", "Other mutants", "Respawned", "Artificial", "Less complex mutants"}) .textWidth(CellFunctionTextWidth) .tooltip(Const::GenomeSensorRestrictToOtherMutantsTooltip), sensor.restrictToMutants);