measure(step2a): candidate bins alone are slower -- the per-sample GetDensityAt call must go

Editor-only ablation (explore commandlet, -regioneval, default off): 8^3 bins for rooms,
room-floor joins and tunnel chains, but every point still goes through GetDensityAt.
259^3 ring, seed 1337, six workers:
  live  : 6.776 s wall, 29.16 s worker CPU, 1.679 us/sample, 21.2 candidate visits/sample
  binned: 19.54 s wall, 50.02 s worker CPU, 2.879 us/sample, 16.4 candidate visits/sample
Correctness: zero Q16 (x16, ties away from zero) disagreements on the full ring and ~284k probes
on 4 more seeds (composer recipes, warped rooms, passages, landings, strate edges, edits);
shrinking room reach to 0.5 -> 18,107 Q16 / 735 sign differences (the check bites).
Not the planned region program: the step-2 question is still open. Baseline for the next attempt:
1.68 us CPU per sample on the live path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-09-30 01:19:11 +02:00
1 parent 3b4d6855fe
commit 41a9265ebd
8 files changed
+1693 -31

No files matched your search

@@ -1,5 +1,6 @@
#include "VoxelForgeExploreCommandlet.h"
#include "VoxelStackOfflineSymbolizer.h"
#include "VoxelForgeRegionEvalExperiment.h"
#include "CoreMinimal.h"
#include "Async/ParallelFor.h"
@@ -40,6 +41,7 @@
#include "VoxelStrateDefinition.h"
#include "VoxelStrateManager.h"
#include "VoxelStrateMeasure.h"
#include "VoxelStrateComposer.h"
#include "VoxelTypes.h"
#include <algorithm>
@@ -1456,6 +1458,737 @@ struct FExploreWorld
}
};
struct FRegionEvalPass
{
VoxelForgeRegionEval::FTiming Timing;
VoxelForgeRegionEval::FCandidateVisits Visits;
TArray<float> Densities;
TArray<int64> SampleIndices;
FIntVector Origin = FIntVector::ZeroValue;
int32 RecipeIndex = INDEX_NONE;
uint32 RecipeHash = 0;
int32 PassageCount = 0;
int32 EditChunkCount = 0;
int32 TargetedSampleCount = 0;
double WorldPrepareSeconds = 0.0;
FString StartedUtc;
FString EndedUtc;
};
int32 FindRoomGraphRecipeIndex(int32 Seed)
{
for (int32 Index = 0; Index < 64; ++Index)
{
const FVoxelOpStackRecipe Recipe = VF_RollStrateStructure(Seed, Index);
if (Recipe.ShapeSource.OpClass == EVoxelStrateOpClass::RoomGraphSource)
{
return Index;
}
}
return INDEX_NONE;
}
bool PrepareRegionEvalWorld(
FExploreWorld& World,
const FExploreArguments& BaseArguments,
int32 Seed,
int32& OutRecipeIndex,
uint32& OutRecipeHash,
int32& OutEditChunkCount,
FString& OutError)
{
FExploreArguments Arguments = BaseArguments;
Arguments.Seed = Seed;
Arguments.bSeedOverride = true;
Arguments.bRender = false;
Arguments.bWalk = false;
Arguments.bExport = false;
Arguments.bBlockEarlyOut = false;
if (!World.Build(Arguments, OutError))
{
return false;
}
if (!World.Definitions.IsValidIndex(Arguments.Slot))
{
OutError = TEXT("Region evaluator target definition is missing.");
return false;
}
UVoxelStrateDefinition* Definition = World.Definitions[Arguments.Slot].Get();
if (Definition == nullptr || Definition->GeneratorType != ECaveGeneratorType::TunnelNetwork)
{
OutError = TEXT("Region evaluator requires the owner TunnelNetwork target slot.");
return false;
}
OutRecipeIndex = FindRoomGraphRecipeIndex(Seed);
if (OutRecipeIndex == INDEX_NONE)
{
OutError = FString::Printf(
TEXT("No RoomGraphSource recipe found in the 64-entry structure roll for seed %d."), Seed);
return false;
}
const FVoxelOpStackRecipe Recipe = VF_RollStrateStructure(Seed, OutRecipeIndex);
OutRecipeHash = VF_HashStrateStructureRecipe(Recipe);
// Make the selected RoomGraph recipe exercise the authored warp path. The definition is a
// transient duplicate of DA_Strate3, and both the live and prepared passes receive the same
// operator parameters and recipe.
FVoxelStrateArchetypeParams NativeParams;
NativeParams.TunnelNetworkParams = Definition->GenerationParams;
NativeParams.TunnelNetworkParams.TunnelWarpStrength = FMath::Max(
NativeParams.TunnelNetworkParams.TunnelWarpStrength, 1.25f);
NativeParams.SlabParams = Definition->SlabParams;
NativeParams.MazeParams = Definition->MazeParams;
NativeParams.SurfaceParams = Definition->SurfaceParams;
NativeParams.VerticalShaftParams = Definition->VerticalShaftParams;
NativeParams.FloatingIslandParams = Definition->FloatingIslandParams;
FString ComposerError;
if (!World.Manager->SetComposerOverrideForStrate(
Arguments.Slot, Seed, Definition->GeneratorType,
NativeParams, true, &Recipe, ComposerError))
{
OutError = FString::Printf(
TEXT("Could not install rolled composer recipe for seed %d: %s"),
Seed, *ComposerError);
return false;
}
const int32 CenterZ = (World.TargetTopWorldZ + World.TargetBottomWorldZ) / 2;
FVoxelModification Carve;
Carve.Center = FVector(8.0f, 4.0f, static_cast<float>(CenterZ));
Carve.Radius = 6.0f;
Carve.Strength = -12.0f;
Carve.Shape = EVoxelBrushShape::Sphere;
const TArray<FIntVector> CarvedChunks = World.DiffLayer->ApplyModification(Carve);
FVoxelModification Fill;
Fill.Center = FVector(-12.0f, 6.0f, static_cast<float>(CenterZ - 10));
Fill.Radius = 4.0f;
Fill.Strength = 12.0f;
Fill.Shape = EVoxelBrushShape::Sphere;
const TArray<FIntVector> FilledChunks = World.DiffLayer->ApplyModification(Fill);
if (CarvedChunks.IsEmpty() || FilledChunks.IsEmpty())
{
OutError = TEXT("Transient player carve/fill edits did not enter the diff layer.");
return false;
}
OutEditChunkCount = CarvedChunks.Num() + FilledChunks.Num();
int32 RecipeSeed = 0;
ECaveGeneratorType RecipeArchetype = ECaveGeneratorType::TunnelNetwork;
FVoxelStrateArchetypeParams ResolvedParams;
FVoxelOpStackRecipe ResolvedRecipe;
const int32 ChunkZ = FMath::FloorToInt(static_cast<float>(CenterZ) / CHUNK_SIZE);
if (!World.Manager->GetRecipeForChunk(
FIntVector(0, 0, ChunkZ), RecipeSeed, RecipeArchetype,
ResolvedParams, ResolvedRecipe)
|| !VF_AreStrateStructureRecipesIdentical(Recipe, ResolvedRecipe))
{
OutError = TEXT("Composer recipe was not active on the target density lattice.");
return false;
}
return true;
}
void AddRegionSampleIndex(
TSet<int64>& Unique,
int32 X, int32 Y, int32 Z,
FIntVector Origin, int32 Dimension)
{
const int32 LX = X - Origin.X;
const int32 LY = Y - Origin.Y;
const int32 LZ = Z - Origin.Z;
if (LX >= 0 && LX < Dimension && LY >= 0 && LY < Dimension
&& LZ >= 0 && LZ < Dimension)
{
Unique.Add(VoxelForgeRegionEval::LinearIndex(LX, LY, LZ, Dimension));
}
}
TArray<int64> BuildRegionEvalSampleIndices(
const FExploreWorld& World,
FIntVector Origin,
int32 Dimension,
int32 RequestedRandomSamples,
int32 Seed,
int32& OutTargetedSamples)
{
const int64 Total = static_cast<int64>(Dimension) * Dimension * Dimension;
const int32 RandomCount = FMath::Clamp(RequestedRandomSamples, 1, static_cast<int32>(Total));
TArray<int64> Indices;
Indices.Reserve(RandomCount + 50000);
auto Gcd = [](int64 A, int64 B)
{
while (B != 0)
{
const int64 R = A % B;
A = B;
B = R;
}
return A;
};
int64 Multiplier = 104729;
while (Gcd(Multiplier, Total) != 1)
{
Multiplier += 2;
}
const int64 Offset = (static_cast<int64>(Seed) * 48271ll) % Total;
for (int32 Sample = 0; Sample < RandomCount; ++Sample)
{
Indices.Add((static_cast<int64>(Sample) * Multiplier + Offset) % Total);
}
TSet<int64> Unique;
Unique.Reserve(50000);
for (const int64 Index : Indices)
{
Unique.Add(Index);
}
const int32 RandomUniqueCount = Unique.Num();
// Dense probes around both edited volumes.
const int32 CenterZ = (World.TargetTopWorldZ + World.TargetBottomWorldZ) / 2;
const FVector EditCenters[] = {
FVector(8.0f, 4.0f, static_cast<float>(CenterZ)),
FVector(-12.0f, 6.0f, static_cast<float>(CenterZ - 10)),
};
for (const FVector& Center : EditCenters)
{
const int32 CX = FMath::FloorToInt(Center.X);
const int32 CY = FMath::FloorToInt(Center.Y);
const int32 CZ = FMath::FloorToInt(Center.Z);
for (int32 Z = CZ - 8; Z <= CZ + 8; ++Z)
{
for (int32 Y = CY - 8; Y <= CY + 8; ++Y)
{
for (int32 X = CX - 8; X <= CX + 8; ++X)
{
AddRegionSampleIndex(Unique, X, Y, Z, Origin, Dimension);
}
}
}
}
// Include lattice sites around each authored route tube, landing room, and floor anchor.
for (const FVoxelPassage& Passage : World.Manager->GetPassages())
{
TArray<FVector> Anchors;
Anchors.Add(Passage.UpperPoint);
Anchors.Add(Passage.LowerPoint);
Anchors.Add(Passage.UpperLanding.StandingPoint);
Anchors.Add(Passage.UpperLanding.DoorPoint);
Anchors.Add(Passage.LowerLanding.StandingPoint);
Anchors.Add(Passage.LowerLanding.DoorPoint);
Anchors.Append(Passage.ControlPoints);
for (const FVector& Anchor : Anchors)
{
const int32 AX = FMath::FloorToInt(Anchor.X);
const int32 AY = FMath::FloorToInt(Anchor.Y);
const int32 AZ = FMath::FloorToInt(Anchor.Z);
for (int32 Z = AZ - 3; Z <= AZ + 3; ++Z)
{
for (int32 Y = AY - 3; Y <= AY + 3; ++Y)
{
for (int32 X = AX - 3; X <= AX + 3; ++X)
{
AddRegionSampleIndex(Unique, X, Y, Z, Origin, Dimension);
}
}
}
}
}
// Both strate boundaries are swept across the horizontal region, including ±3 lattice rows.
const int32 Boundaries[] = { World.TargetTopWorldZ, World.TargetBottomWorldZ };
for (const int32 BoundaryZ : Boundaries)
{
for (int32 Dz = -3; Dz <= 3; ++Dz)
{
for (int32 Y = -128; Y <= 128; Y += 8)
{
for (int32 X = -128; X <= 128; X += 8)
{
AddRegionSampleIndex(Unique, X, Y, BoundaryZ + Dz, Origin, Dimension);
}
}
}
}
Indices = Unique.Array();
Indices.Sort();
OutTargetedSamples = FMath::Max(0, Indices.Num() - RandomUniqueCount);
return Indices;
}
bool RunRegionEvalPass(
const FExploreArguments& BaseArguments,
int32 Seed,
bool bPrepared,
float ReachScale,
bool bFullRing,
const TArray<int64>* RequestedIndices,
int32 RequestedSamples,
bool bCountCandidates,
bool bKeepDensities,
FRegionEvalPass& OutPass,
FString& OutError)
{
OutPass = FRegionEvalPass();
FExploreWorld World;
const double PrepareStartSeconds = FPlatformTime::Seconds();
if (!PrepareRegionEvalWorld(
World, BaseArguments, Seed, OutPass.RecipeIndex,
OutPass.RecipeHash, OutPass.EditChunkCount, OutError))
{
return false;
}
OutPass.WorldPrepareSeconds = FPlatformTime::Seconds() - PrepareStartSeconds;
OutPass.PassageCount = World.Manager->GetPassages().Num();
const int32 CenterZ = (World.TargetTopWorldZ + World.TargetBottomWorldZ) / 2;
OutPass.Origin = FIntVector(-129, -129, CenterZ - 129);
if (OutPass.PassageCount <= 0)
{
OutError = FString::Printf(TEXT("Seed %d generated no inter-strate route passages."), Seed);
return false;
}
if (RequestedIndices != nullptr)
{
OutPass.SampleIndices = *RequestedIndices;
}
else
{
OutPass.SampleIndices = BuildRegionEvalSampleIndices(
World, OutPass.Origin, VoxelForgeRegionEval::RingDimension,
RequestedSamples, Seed, OutPass.TargetedSampleCount);
}
if (OutPass.SampleIndices.IsEmpty())
{
OutError = TEXT("Region evaluator produced an empty correctness sample set.");
return false;
}
OutPass.StartedUtc = FDateTime::UtcNow().ToIso8601();
const bool bEvaluated = VoxelForgeRegionEval::Evaluate(
*World.Generator, OutPass.Origin, VoxelForgeRegionEval::RingDimension,
bFullRing ? nullptr : &OutPass.SampleIndices,
bFullRing, bPrepared, ReachScale,
bKeepDensities ? &OutPass.Densities : nullptr,
OutPass.Timing);
OutPass.EndedUtc = FDateTime::UtcNow().ToIso8601();
if (!bEvaluated)
{
OutError = FString::Printf(
TEXT("Density evaluation failed or emitted a non-finite value (seed %d)."), Seed);
return false;
}
if (bCountCandidates)
{
OutPass.Visits = VoxelForgeRegionEval::CountCandidates(
*World.Generator, OutPass.Origin,
VoxelForgeRegionEval::RingDimension,
OutPass.SampleIndices, bPrepared, ReachScale);
if (OutPass.Visits.SampleCount != OutPass.SampleIndices.Num())
{
OutError = TEXT("Candidate counter sweep did not consume the full fixed sample set.");
return false;
}
}
return true;
}
TSharedRef<FJsonObject> RegionEvalTimingJson(const FRegionEvalPass& Pass, bool bPrepared)
{
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
Json->SetStringField(TEXT("path"), bPrepared ? TEXT("prepared_8cube_bins") : TEXT("live_GetDensityAt"));
Json->SetStringField(TEXT("started_utc"), Pass.StartedUtc);
Json->SetStringField(TEXT("ended_utc"), Pass.EndedUtc);
Json->SetNumberField(TEXT("worker_count"), Pass.Timing.Workers);
Json->SetNumberField(TEXT("observed_worker_threads"), Pass.Timing.ObservedWorkerThreads);
Json->SetNumberField(TEXT("samples"), static_cast<double>(Pass.Timing.SampleCount));
Json->SetNumberField(TEXT("world_setup_seconds_before_density_ring"), Pass.WorldPrepareSeconds);
Json->SetNumberField(TEXT("wall_seconds"), Pass.Timing.WallSeconds);
Json->SetNumberField(TEXT("worker_cpu_seconds"), Pass.Timing.WorkerCpuSeconds);
Json->SetNumberField(TEXT("worker_cpu_ns_per_sample"), Pass.Timing.NanosecondsPerSample);
Json->SetStringField(TEXT("worker_cpu_source"), Pass.Timing.bWorkerCpuFromOsThreadTimes
? TEXT("summed Windows GetThreadTimes user+kernel CPU across six fixed work partitions")
: TEXT("summed worker elapsed fallback; OS thread CPU counters unavailable"));
Json->SetStringField(TEXT("quantized_hash_fnv1a64"),
FString::Printf(TEXT("%016llx"), static_cast<unsigned long long>(Pass.Timing.QuantizedHash)));
Json->SetStringField(TEXT("raw_float_hash_fnv1a64"),
FString::Printf(TEXT("%016llx"), static_cast<unsigned long long>(Pass.Timing.RawFloatHash)));
Json->SetNumberField(TEXT("saturated_samples"), static_cast<double>(Pass.Timing.SaturatedSamples));
Json->SetNumberField(TEXT("non_finite_samples"), static_cast<double>(Pass.Timing.NonFiniteSamples));
if (Pass.Visits.SampleCount > 0)
{
Json->SetNumberField(TEXT("candidate_visits_per_sample"), Pass.Visits.PerSample);
Json->SetNumberField(TEXT("room_candidate_visits"), static_cast<double>(Pass.Visits.Room));
Json->SetNumberField(TEXT("tunnel_candidate_visits"), static_cast<double>(Pass.Visits.Tunnel));
Json->SetNumberField(TEXT("tunnel_core_candidate_visits"), static_cast<double>(Pass.Visits.TunnelCore));
Json->SetNumberField(TEXT("passage_candidate_visits"), static_cast<double>(Pass.Visits.Passage));
Json->SetNumberField(TEXT("tunnel_cache_lookups"), static_cast<double>(Pass.Visits.TunnelCacheLookups));
Json->SetNumberField(TEXT("tunnel_cache_hits"), static_cast<double>(Pass.Visits.TunnelCacheHits));
Json->SetNumberField(TEXT("tunnel_cache_misses"), static_cast<double>(Pass.Visits.TunnelCacheMisses));
Json->SetNumberField(TEXT("sdf_cache_builds"), static_cast<double>(Pass.Visits.SdfCacheBuilds));
Json->SetNumberField(TEXT("candidate_counter_samples"), static_cast<double>(Pass.Visits.SampleCount));
Json->SetNumberField(TEXT("attribution_sample_interval"), Pass.Visits.AttributionSampleInterval);
Json->SetStringField(TEXT("attribution_basis"), TEXT("sampled VoxelDensityProfile phases; diagnostic only, excluded from clean timing"));
Json->SetNumberField(TEXT("get_density_at_attributed_ns_per_sample"), Pass.Visits.GetDensityAtAttributedNsPerSample);
Json->SetNumberField(TEXT("density_prologue_attributed_ns_per_sample"), Pass.Visits.DensityPrologueAttributedNsPerSample);
Json->SetNumberField(TEXT("density_core_attributed_ns_per_sample"), Pass.Visits.DensityCoreAttributedNsPerSample);
Json->SetNumberField(TEXT("density_disturbances_attributed_ns_per_sample"), Pass.Visits.DensityDisturbancesAttributedNsPerSample);
Json->SetNumberField(TEXT("density_structural_posts_attributed_ns_per_sample"), Pass.Visits.DensityStructuralPostsAttributedNsPerSample);
Json->SetNumberField(TEXT("density_boundary_seal_attributed_ns_per_sample"), Pass.Visits.DensityBoundarySealAttributedNsPerSample);
Json->SetNumberField(TEXT("density_diff_layer_attributed_ns_per_sample"), Pass.Visits.DensityDiffLayerAttributedNsPerSample);
Json->SetNumberField(TEXT("density_tail_attributed_ns_per_sample"), Pass.Visits.DensityTailAttributedNsPerSample);
}
return Json;
}
struct FQuantizedComparison
{
int64 Disagreements = 0;
int64 SignDisagreements = 0;
double MaxAbsoluteFloatDelta = 0.0;
int64 FirstIndex = INDEX_NONE;
};
FQuantizedComparison CompareQuantizedArrays(
const TArray<float>& A, const TArray<float>& B,
const TArray<int64>* LatticeIndices = nullptr)
{
FQuantizedComparison Result;
if (A.Num() != B.Num())
{
Result.Disagreements = FMath::Max(A.Num(), B.Num());
return Result;
}
for (int32 Index = 0; Index < A.Num(); ++Index)
{
bool bSaturatedA = false, bFiniteA = false;
bool bSaturatedB = false, bFiniteB = false;
const int16 QA = VoxelForgeRegionEval::QuantizeDensity(A[Index], bSaturatedA, bFiniteA);
const int16 QB = VoxelForgeRegionEval::QuantizeDensity(B[Index], bSaturatedB, bFiniteB);
Result.MaxAbsoluteFloatDelta = FMath::Max(
Result.MaxAbsoluteFloatDelta,
FMath::Abs(static_cast<double>(A[Index]) - static_cast<double>(B[Index])));
if (!bFiniteA || !bFiniteB || bSaturatedA || bSaturatedB || QA != QB)
{
++Result.Disagreements;
if (Result.FirstIndex == INDEX_NONE)
{
Result.FirstIndex = LatticeIndices != nullptr
? (*LatticeIndices)[Index] : static_cast<int64>(Index);
}
}
if ((QA < 0) != (QB < 0))
{
++Result.SignDisagreements;
}
}
return Result;
}
TSharedRef<FJsonObject> RegionEvalComparisonJson(const FQuantizedComparison& Comparison)
{
TSharedRef<FJsonObject> Json = MakeShared<FJsonObject>();
Json->SetNumberField(TEXT("quantized_disagreements"), static_cast<double>(Comparison.Disagreements));
Json->SetNumberField(TEXT("quantized_sign_disagreements"), static_cast<double>(Comparison.SignDisagreements));
Json->SetNumberField(TEXT("max_abs_float_delta"), Comparison.MaxAbsoluteFloatDelta);
Json->SetNumberField(TEXT("first_disagreement_linear_index"), static_cast<double>(Comparison.FirstIndex));
return Json;
}
int32 RunRegionEval(const FString& Params)
{
FExploreArguments Arguments;
FString Error;
if (!ParseArguments(Params, Arguments, Error))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] argument error: %s"), *Error);
return 2;
}
int32 RequestedSamples = 262144;
FParse::Value(*Params, TEXT("regionsamples="), RequestedSamples);
RequestedSamples = FMath::Clamp(RequestedSamples, 32768, 1000000);
IFileManager::Get().MakeDirectory(*Arguments.OutDirectory, true);
const int32 Seeds[] = { 1337, 7331, 19427, 30241, 41011 };
TArray<TSharedPtr<FJsonValue>> SeedReports;
TArray<TSharedPtr<FJsonValue>> OldTimingReports;
TArray<TSharedPtr<FJsonValue>> PreparedTimingReports;
TArray<float> OldFullDensities;
TArray<float> PreparedFullDensities;
TArray<int64> PrimarySampleIndices;
FQuantizedComparison FullComparison;
uint64 OldFullRawHash = 0;
uint64 PreparedFullRawHash = 0;
uint64 OldFullSaturatedSamples = 0;
uint64 PreparedFullSaturatedSamples = 0;
bool bAllSeedComparisonsPass = true;
bool bFullDeterminismPass = true;
int32 PrimaryTargetedSampleCount = 0;
int32 PrimaryPassageCount = 0;
int32 PrimaryEditChunkCount = 0;
int32 PrimaryRecipeIndex = INDEX_NONE;
uint32 PrimaryRecipeHash = 0;
// Cold full-ring timings use independent transient worlds for every pass. Caches cannot be
// warmed by the comparison leg, and the seed/layout/composer/edit payload remains identical.
for (int32 Trial = 0; Trial < 2; ++Trial)
{
FRegionEvalPass Pass;
const bool bOk = RunRegionEvalPass(
Arguments, Seeds[0], false, 1.0f, true, nullptr,
RequestedSamples, Trial == 0, true, Pass, Error);
if (!bOk)
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] live full-ring trial failed: %s"), *Error);
return 2;
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
if (Trial == 0)
{
OldFullDensities = MoveTemp(Pass.Densities);
OldFullRawHash = Pass.Timing.RawFloatHash;
OldFullSaturatedSamples = Pass.Timing.SaturatedSamples;
PrimarySampleIndices = Pass.SampleIndices;
PrimaryTargetedSampleCount = Pass.TargetedSampleCount;
PrimaryPassageCount = Pass.PassageCount;
PrimaryEditChunkCount = Pass.EditChunkCount;
PrimaryRecipeIndex = Pass.RecipeIndex;
PrimaryRecipeHash = Pass.RecipeHash;
}
else
{
bFullDeterminismPass &= Pass.Timing.RawFloatHash == OldFullRawHash;
}
OldTimingReports.Add(MakeShared<FJsonValueObject>(RegionEvalTimingJson(Pass, false)));
}
if (PrimarySampleIndices.IsEmpty())
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] primary statistical sample set is empty."));
return 2;
}
for (int32 Trial = 0; Trial < 2; ++Trial)
{
FRegionEvalPass Pass;
const bool bOk = RunRegionEvalPass(
Arguments, Seeds[0], true, 1.0f, true, nullptr,
RequestedSamples, Trial == 0, true, Pass, Error);
if (!bOk)
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] prepared full-ring trial failed: %s"), *Error);
return 2;
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
if (Trial == 0)
{
PreparedFullDensities = MoveTemp(Pass.Densities);
PreparedFullRawHash = Pass.Timing.RawFloatHash;
PreparedFullSaturatedSamples = Pass.Timing.SaturatedSamples;
FullComparison = CompareQuantizedArrays(OldFullDensities, PreparedFullDensities);
}
else
{
bFullDeterminismPass &= Pass.Timing.RawFloatHash == PreparedFullRawHash;
}
PreparedTimingReports.Add(MakeShared<FJsonValueObject>(RegionEvalTimingJson(Pass, true)));
}
bAllSeedComparisonsPass &= FullComparison.Disagreements == 0
&& FullComparison.SignDisagreements == 0
&& OldFullSaturatedSamples == 0
&& PreparedFullSaturatedSamples == 0;
// Statistical fixed-lattice comparisons across four additional independent seeds. The sample
// set is a deterministic affine permutation of the entire 259^3 ring plus dense strata,
// passage-floor, landing, carve, and fill probes.
for (int32 SeedIndex = 1; SeedIndex < UE_ARRAY_COUNT(Seeds); ++SeedIndex)
{
FRegionEvalPass OldPass;
if (!RunRegionEvalPass(
Arguments, Seeds[SeedIndex], false, 1.0f, false, nullptr,
RequestedSamples, true, true, OldPass, Error))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] seed %d live sample failed: %s"),
Seeds[SeedIndex], *Error);
return 2;
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
FRegionEvalPass NewPass;
if (!RunRegionEvalPass(
Arguments, Seeds[SeedIndex], true, 1.0f, false, &OldPass.SampleIndices,
RequestedSamples, true, true, NewPass, Error))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] seed %d prepared sample failed: %s"),
Seeds[SeedIndex], *Error);
return 2;
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
const FQuantizedComparison Comparison = CompareQuantizedArrays(
OldPass.Densities, NewPass.Densities, &OldPass.SampleIndices);
bAllSeedComparisonsPass &= Comparison.Disagreements == 0
&& Comparison.SignDisagreements == 0
&& OldPass.Timing.SaturatedSamples == 0
&& NewPass.Timing.SaturatedSamples == 0;
TSharedRef<FJsonObject> SeedJson = MakeShared<FJsonObject>();
SeedJson->SetNumberField(TEXT("seed"), Seeds[SeedIndex]);
SeedJson->SetNumberField(TEXT("samples"), OldPass.Timing.SampleCount);
SeedJson->SetNumberField(TEXT("targeted_route_edit_boundary_samples"), OldPass.TargetedSampleCount);
SeedJson->SetNumberField(TEXT("composer_recipe_index"), OldPass.RecipeIndex);
SeedJson->SetStringField(TEXT("composer_recipe_hash"), FString::Printf(TEXT("%08x"), OldPass.RecipeHash));
SeedJson->SetNumberField(TEXT("passage_count"), OldPass.PassageCount);
SeedJson->SetNumberField(TEXT("edit_chunk_count"), OldPass.EditChunkCount);
SeedJson->SetObjectField(TEXT("comparison"), RegionEvalComparisonJson(Comparison));
SeedJson->SetObjectField(TEXT("live_candidate_visits"), RegionEvalTimingJson(OldPass, false));
SeedJson->SetObjectField(TEXT("prepared_candidate_visits"), RegionEvalTimingJson(NewPass, true));
SeedReports.Add(MakeShared<FJsonValueObject>(SeedJson));
}
// Deliberately shrink one reach, evaluate the same statistical lattice points, and require
// the reference comparison to catch omitted room influence. The scale is scoped to this one
// commandlet pass and every worker resets it to 1.0 afterward.
FRegionEvalPass ShrunkPass;
if (!RunRegionEvalPass(
Arguments, Seeds[0], true, 0.50f, false, &PrimarySampleIndices,
RequestedSamples, false, true, ShrunkPass, Error))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] deliberate reach-shrink run failed: %s"), *Error);
return 2;
}
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
FQuantizedComparison ShrinkComparison;
ShrinkComparison.FirstIndex = INDEX_NONE;
for (int32 Sample = 0; Sample < ShrunkPass.Densities.Num(); ++Sample)
{
const int64 LatticeIndex = PrimarySampleIndices[Sample];
bool bSaturatedOld = false, bFiniteOld = false;
bool bSaturatedShrink = false, bFiniteShrink = false;
const int16 QOld = VoxelForgeRegionEval::QuantizeDensity(
OldFullDensities[static_cast<int32>(LatticeIndex)], bSaturatedOld, bFiniteOld);
const int16 QShrink = VoxelForgeRegionEval::QuantizeDensity(
ShrunkPass.Densities[Sample], bSaturatedShrink, bFiniteShrink);
ShrinkComparison.MaxAbsoluteFloatDelta = FMath::Max(
ShrinkComparison.MaxAbsoluteFloatDelta,
FMath::Abs(static_cast<double>(OldFullDensities[static_cast<int32>(LatticeIndex)])
- static_cast<double>(ShrunkPass.Densities[Sample])));
if (!bFiniteOld || !bFiniteShrink || bSaturatedOld || bSaturatedShrink || QOld != QShrink)
{
++ShrinkComparison.Disagreements;
if (ShrinkComparison.FirstIndex == INDEX_NONE) ShrinkComparison.FirstIndex = LatticeIndex;
}
if ((QOld < 0) != (QShrink < 0)) ++ShrinkComparison.SignDisagreements;
}
double PreparedWallSum = 0.0;
for (const TSharedPtr<FJsonValue>& Value : PreparedTimingReports)
{
const TSharedPtr<FJsonObject> Json = Value->AsObject();
PreparedWallSum += Json->GetNumberField(TEXT("wall_seconds"));
}
const double PreparedMedianWall = PreparedWallSum / 2.0;
double OldWallSum = 0.0;
for (const TSharedPtr<FJsonValue>& Value : OldTimingReports)
{
OldWallSum += Value->AsObject()->GetNumberField(TEXT("wall_seconds"));
}
const double OldMedianWall = OldWallSum / 2.0;
bool bSixWorkersObserved = true;
for (const TSharedPtr<FJsonValue>& Value : OldTimingReports)
{
bSixWorkersObserved &= Value->AsObject()->GetNumberField(TEXT("observed_worker_threads"))
>= VoxelForgeRegionEval::WorkerCount;
}
for (const TSharedPtr<FJsonValue>& Value : PreparedTimingReports)
{
bSixWorkersObserved &= Value->AsObject()->GetNumberField(TEXT("observed_worker_threads"))
>= VoxelForgeRegionEval::WorkerCount;
}
const bool bSpeedPass = PreparedMedianWall <= 0.600 && bSixWorkersObserved;
TSharedRef<FJsonObject> Report = MakeShared<FJsonObject>();
Report->SetNumberField(TEXT("schema_version"), 1);
Report->SetStringField(TEXT("route"), TEXT("editor-only explore commandlet; required Unreal composer, manager, and generator types"));
Report->SetStringField(TEXT("evaluator"), TEXT("live GetDensityAt final field with editor-only 8^3 SDF room/join/tunnel candidate bins"));
Report->SetStringField(TEXT("comparison_quantization"), TEXT("signed int16; round ties away from zero; multiply density by 16; saturate outside [-2048, 2047.9375] density voxels"));
Report->SetNumberField(TEXT("worker_count"), VoxelForgeRegionEval::WorkerCount);
Report->SetNumberField(TEXT("ring_dimension"), VoxelForgeRegionEval::RingDimension);
Report->SetNumberField(TEXT("ring_lattice_samples"), static_cast<double>(VoxelForgeRegionEval::RingDimension) * VoxelForgeRegionEval::RingDimension * VoxelForgeRegionEval::RingDimension);
Report->SetNumberField(TEXT("ring_interval_span_voxels"), VoxelForgeRegionEval::RingDimension - 1);
Report->SetNumberField(TEXT("ring_wall_p50_live_seconds"), OldMedianWall);
Report->SetNumberField(TEXT("ring_wall_p50_prepared_seconds"), PreparedMedianWall);
Report->SetBoolField(TEXT("speed_pass_600ms"), bSpeedPass);
Report->SetBoolField(TEXT("all_full_ring_trials_used_six_threads"), bSixWorkersObserved);
Report->SetBoolField(TEXT("five_seed_correctness_pass"), bAllSeedComparisonsPass);
Report->SetBoolField(TEXT("two_run_determinism_pass"), bFullDeterminismPass);
Report->SetStringField(TEXT("determinism_basis"), TEXT("bitwise float32 lattice hash on two independent cold worlds for live and prepared paths"));
Report->SetObjectField(TEXT("full_ring_comparison"), RegionEvalComparisonJson(FullComparison));
Report->SetArrayField(TEXT("live_full_ring_trials"), OldTimingReports);
Report->SetArrayField(TEXT("prepared_full_ring_trials"), PreparedTimingReports);
Report->SetArrayField(TEXT("additional_seed_comparisons"), SeedReports);
TSharedRef<FJsonObject> Coverage = MakeShared<FJsonObject>();
Coverage->SetStringField(TEXT("owner_settings"), Arguments.SettingsReference);
Coverage->SetStringField(TEXT("owner_strate"), Arguments.StrateReference);
Coverage->SetNumberField(TEXT("primary_seed"), Seeds[0]);
Coverage->SetNumberField(TEXT("primary_targeted_route_edit_boundary_samples"), PrimaryTargetedSampleCount);
Coverage->SetNumberField(TEXT("target_passages"), PrimaryPassageCount);
Coverage->SetNumberField(TEXT("transient_edit_chunks"), PrimaryEditChunkCount);
Coverage->SetNumberField(TEXT("composer_recipe_index"), PrimaryRecipeIndex);
Coverage->SetStringField(TEXT("composer_recipe_hash"), FString::Printf(TEXT("%08x"), PrimaryRecipeHash));
Coverage->SetStringField(TEXT("composer_recipe_family"), TEXT("RoomGraphSource with TunnelNetwork params; rolled by VF_RollStrateStructure"));
Coverage->SetNumberField(TEXT("room_warp_strength_lower_bound"), 1.25);
Coverage->SetStringField(TEXT("room_bin_reach"), TEXT("cached CullRadiusSq: shape extent + floor-relief envelope + 3x SDF blend + conservative terrain-op reach; mouth-rise reach uses center-to-mouth distance + blend"));
Coverage->SetStringField(TEXT("tunnel_bin_reach"), TEXT("union of finalized warped-SDF and world-chain centerline bounds expanded by their influence radii, plus both conservative bounding spheres"));
Coverage->SetStringField(TEXT("warp_coordinates"), TEXT("room bins are queried after the exact live cave warp in the same coordinate domain; tunnel bins union warped-SDF and unwarped world-chain reach"));
Coverage->SetStringField(TEXT("tunnel_bin_unit"), TEXT("whole cached tunnel chain; per-chain segment loops remain in the exact evaluator"));
Coverage->SetStringField(TEXT("unbinned_writers"), TEXT("passage/landing posts, disturbances, and player diff edits stay in canonical GetDensityAt tail; this is the candidate-bin ablation, not the full region compiler"));
Coverage->SetBoolField(TEXT("route_landing_floor_probes"), PrimaryPassageCount > 0);
Coverage->SetBoolField(TEXT("strata_top_and_bottom_boundary_sweep"), true);
Coverage->SetBoolField(TEXT("player_carve_and_fill_edits"), true);
Report->SetObjectField(TEXT("content_coverage"), Coverage);
TSharedRef<FJsonObject> Shrink = MakeShared<FJsonObject>();
Shrink->SetNumberField(TEXT("room_reach_scale"), 0.50);
Shrink->SetBoolField(TEXT("deliberately_shrunk_bin_was_caught"), ShrinkComparison.Disagreements > 0);
Shrink->SetNumberField(TEXT("saturated_samples"), static_cast<double>(ShrunkPass.Timing.SaturatedSamples));
Shrink->SetNumberField(TEXT("quantized_disagreements"), static_cast<double>(ShrinkComparison.Disagreements));
Shrink->SetNumberField(TEXT("sign_disagreements"), static_cast<double>(ShrinkComparison.SignDisagreements));
Shrink->SetNumberField(TEXT("max_abs_float_delta"), ShrinkComparison.MaxAbsoluteFloatDelta);
Shrink->SetNumberField(TEXT("first_disagreement_linear_index"), static_cast<double>(ShrinkComparison.FirstIndex));
Report->SetObjectField(TEXT("deliberate_reach_shrink"), Shrink);
const bool bPassed = bAllSeedComparisonsPass && bFullDeterminismPass
&& ShrinkComparison.Disagreements > 0
&& ShrunkPass.Timing.SaturatedSamples == 0;
Report->SetStringField(TEXT("status"), bPassed ? TEXT("correctness_pass_speed_measured") : TEXT("correctness_failed"));
Report->SetBoolField(TEXT("pass"), bPassed);
Report->SetStringField(TEXT("speed_verdict"), bSpeedPass
? TEXT("meets 600 ms") : TEXT("misses 600 ms; candidate bins are an ablation, not a full region compiler"));
FString JsonText;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonText);
if (!FJsonSerializer::Serialize(Report, Writer)
|| !FFileHelper::SaveStringToFile(
JsonText, *FPaths::Combine(Arguments.OutDirectory, TEXT("region_eval.json")),
FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelForgeRegionEval] could not write region_eval.json."));
return 2;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeRegionEval] status=%s speed600=%s live_ms=%.3f prepared_ms=%.3f "
"full_q16_diff=%lld five_seed=%s deterministic=%s shrink_q16_diff=%lld report=%s"),
bPassed ? TEXT("pass") : TEXT("fail"), bSpeedPass ? TEXT("yes") : TEXT("no"),
OldMedianWall * 1000.0, PreparedMedianWall * 1000.0,
static_cast<long long>(FullComparison.Disagreements),
bAllSeedComparisonsPass ? TEXT("pass") : TEXT("fail"),
bFullDeterminismPass ? TEXT("pass") : TEXT("fail"),
static_cast<long long>(ShrinkComparison.Disagreements),
*FPaths::Combine(Arguments.OutDirectory, TEXT("region_eval.json")));
return bPassed ? 0 : 2;
}
class FGeneratorDensitySampler final : public IVoxelStrateDensitySampler
{
public:
@@ -8593,6 +9326,14 @@ int32 RunBatch(const FString& Params)
int32 UVoxelForgeExploreCommandlet::Main(const FString& Params)
{
const bool bRegionEvalSwitch = FParse::Param(*Params, TEXT("regioneval"));
int32 RegionEvalFlag = 0;
const bool bRegionEvalValue = FParse::Value(*Params, TEXT("regioneval="), RegionEvalFlag);
if (bRegionEvalSwitch || (bRegionEvalValue && RegionEvalFlag != 0))
{
return RunRegionEval(Params);
}
FString SymbolizeCsvPath;
if (FParse::Value(*Params, TEXT("symbolizestacks="), SymbolizeCsvPath))
{