This commit is contained in:
Efim Beshmenev
2026-07-10 22:26:37 +03:00
parent 7f9dc067a1
commit 8614dfe22a
3757 changed files with 95267 additions and 663 deletions
+11 -1
View File
@@ -34,9 +34,18 @@ Makefile
*.tlog
*.lastbuildstate
# Generated searches, checkpoints, reports, and logs
# Machine-local runtime files
/runtime/
# Search checkpoints under results/search are intentionally tracked so that
# disjoint topology ranges merge through Git. These files are derived locally.
/results/search/leaderboard.tsv
/results/search/run.log
/results/search/runs/**/run.log
/results/search/**/*.tmp
/results/search/**/*.tmp.*
/results/search/**/*.partial
# Python cache and virtual environments
__pycache__/
*.py[cod]
@@ -47,6 +56,7 @@ venv/
.DS_Store
Thumbs.db
Desktop.ini
*.lnk
# Wavefront .obj files are research data in this repository and are intentionally
# not ignored globally.
+30 -1
View File
@@ -6,12 +6,16 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
option(SZILASSI_ENABLE_CUDA "Build the FP32 CUDA global-search backend" ON)
set(EIGEN_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/external/eigen-3.4.0" CACHE PATH "Eigen include root")
if(NOT EXISTS "${EIGEN_ROOT}/Eigen/Dense")
message(FATAL_ERROR "Eigen not found at ${EIGEN_ROOT}. Download Eigen 3.4.0 into external/eigen-3.4.0 or pass -DEIGEN_ROOT=...")
endif()
add_library(neighborly_core
src/Checkpoint/GlobalCheckpoint.cpp
src/Checkpoint/GlobalCheckpoint.h
src/NeighborlyCore/plane.h
src/NeighborlyCore/precise_geometry.h
src/NeighborlyCore/util.cpp
@@ -21,9 +25,33 @@ add_library(neighborly_core
projects/Szilassi/solver.h
)
include(CheckLanguage)
if(SZILASSI_ENABLE_CUDA)
check_language(CUDA)
endif()
if(SZILASSI_ENABLE_CUDA AND CMAKE_CUDA_COMPILER)
enable_language(CUDA)
add_library(neighborly_cuda src/CudaSearch/cuda_search.cu)
set_target_properties(neighborly_cuda PROPERTIES
CUDA_ARCHITECTURES "89-real;120-real;120-virtual"
CUDA_STANDARD 17
CUDA_STANDARD_REQUIRED ON
)
target_compile_definitions(neighborly_cuda PUBLIC SZILASSI_HAS_CUDA=1)
else()
add_library(neighborly_cuda src/CudaSearch/cuda_search_stub.cpp)
message(STATUS "CUDA Toolkit not found: building a diagnostic stub backend")
endif()
target_include_directories(neighborly_cuda PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/CudaSearch"
)
target_include_directories(neighborly_core
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/NeighborlyCore"
"${CMAKE_CURRENT_SOURCE_DIR}/src/Checkpoint"
"${CMAKE_CURRENT_SOURCE_DIR}/projects/Szilassi"
"${EIGEN_ROOT}"
)
@@ -36,7 +64,7 @@ else()
endif()
add_executable(neighborly_main projects/Szilassi/main.cpp)
target_link_libraries(neighborly_main PRIVATE neighborly_core)
target_link_libraries(neighborly_main PRIVATE neighborly_core neighborly_cuda)
add_executable(verify_cpp projects/VerifyCpp/verify_cpp.cpp)
target_link_libraries(verify_cpp PRIVATE neighborly_core)
@@ -44,5 +72,6 @@ target_link_libraries(verify_cpp PRIVATE neighborly_core)
add_executable(polyhedron_gui WIN32 projects/PolyhedronGui/launcher_gui.cpp)
if(MSVC)
target_compile_definitions(polyhedron_gui PRIVATE UNICODE _UNICODE NOMINMAX)
target_compile_options(polyhedron_gui PRIVATE /utf-8)
target_link_libraries(polyhedron_gui PRIVATE shell32)
endif()
+53 -10
View File
@@ -9,17 +9,58 @@ The conclusion is: Sort of. I believe there isn't a shape that is _completely_ i
Build `Szilassi.slnx` as `Release|x64`, then open
`build\msbuild\bin\x64\Release\PolyhedronGui.exe`.
For an independent overnight run, leave `Threads` at `0`, set the desired number of
minutes, and click **Глобальный поиск 59**. This mode does not use the supplied near-miss:
The GUI intentionally has only **Запустить поиск** and **Остановить поиск** buttons.
Select an inclusive topology range, then start the search. Existing checkpoints are
loaded automatically. Stop waits for the current short CUDA kernel, synchronizes the
device, writes a durable checkpoint, and only then exits.
The GUI creates a fresh seed automatically for every new process. It is shown in the
GUI log and saved in the durable, Git-tracked `runs/<UUID>/run.tsv` manifest together
with the topology range and search parameters, so a run can be reproduced without
typing a seed into the interface.
The search process and CUDA stream run at low scheduling priority, so foreground work
keeps priority. There is no artificial duty-cycle throttle. Kernels remain short for
responsive stopping and Windows WDDM stability.
Leave `GPU chains` at `0` for automatic sizing. The CUDA backend derives the chain count
from the selected GPU's SM count and measured kernel occupancy, so Ada `sm_89` and
Blackwell `sm_120` use different appropriate values. Each selected topology keeps its
annealing session resident on the device, so refresh cycles cannot discard cooling,
stagnation, or restart state. The full 59-topology range uses about 1.4 GB of VRAM on
the 12 GB RTX 4070 Ti; narrower ranges allocate proportionally less.
For an independent overnight run, set the desired number of minutes and topology range.
This mode does not use the supplied near-miss:
it gives every topology fresh random starts, then alternates depth passes over the best
30/16/8 topologies with periodic breadth refreshes over all 59. A clean stop saves each
topology under `runtime\global_search\topology_N`; pressing the same button later resumes only
those checkpoints. `runtime\global_search\leaderboard.tsv` is the current ranking.
topology under `results\search\topology_N`; pressing the same button later resumes only
those checkpoints. `results\search\leaderboard.tsv` is the current ranking.
Coordinates and optimizer states use 64-bit `double`. Candidates with at most 12 total
defects are automatically reclassified with the custom `WideReal` double-double type
(about 31 decimal digits), and every claimed `0/0` is serialized and checked again at
multiple tolerances down to `1e-13`. OBJ and plane checkpoints retain 17 digits.
The CUDA hot path uses standard FP32 math. Persistent chains retain their RNG, cooling,
stagnation, and restart state between batches; fixed fresh cohorts preserve global
exploration during breadth/refresh passes. Every returned shortlist is reconstructed and checked on
the CPU in `double`; candidates with at most 12 total defects are reclassified with the
custom `WideReal` double-double type (about 31 decimal digits). Every claimed `0/0` is
serialized and checked again at multiple tolerances down to `1e-13`.
CUDA Toolkit 13.3 with Visual Studio integration is required for the GPU backend. The
build contains native targets for Ada `sm_89` and Blackwell `sm_120`. Without the Toolkit,
the project builds a diagnostic stub and refuses `--cuda` instead of silently falling
back to the CPU.
### Checkpoints and Git
Search state is stored in `results/search`, which is intentionally tracked by Git.
Each checkpoint is an immutable, self-contained `.szcp` file with CRC-32 and exact FP32
bit patterns. It is flushed to disk and atomically published; a damaged newest generation
is ignored in favor of the previous valid one.
For several computers, assign non-overlapping topology ranges. Each process uses a unique
run UUID, so checkpoint filenames do not collide. Commit `results/search` normally on each
computer and merge the branches with Git. `leaderboard.tsv`, run logs, and temporary files
are derived and ignored, so they cannot create merge conflicts; the next search start
rescans checkpoints, repeats CPU/DD validation, and rebuilds the leaderboard.
## Project layout
@@ -29,7 +70,8 @@ multiple tolerances down to `1e-13`. OBJ and plane checkpoints retain 17 digits.
* `src/NeighborlyCore` — shared geometry and utility code.
* `data` — topology definitions and input models.
* `results/topologies` and `results/showcases` — saved research models.
* `runtime` — generated candidates, reports, logs, and resumable search state.
* `results/search` — Git-mergeable search states and durable checkpoint generations.
* `runtime` — temporary stop files, reports, logs, and local candidates.
* `scripts` — helper launch and reporting scripts.
All Visual Studio projects are collected by the root `Szilassi.slnx`. MSBuild output is
@@ -39,7 +81,8 @@ centralized under `build/msbuild`; CMake output remains under `build/vs2026`.
To start a search, build and run the `Szilassi` project.
### Requirements
* C++17 compatible compiler (I'm using MSVC 2019).
* C++17 compatible compiler (Visual Studio 2026 is configured by the current presets).
* [CUDA Toolkit 13.3](https://developer.nvidia.com/cuda-downloads) with Visual Studio integration for GPU search.
* [Eigen-3.4.0](https://eigen.tuxfamily.org/) though similar versions should work as well.
* [Cairo-1.17.2](https://www.cairographics.org/) (optional) this is only needed to render paper cutouts.
File diff suppressed because it is too large Load Diff
+20 -4
View File
@@ -53,7 +53,11 @@
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<CudaToolkitAvailable Condition="'$(Platform)'=='x64' and Exists('$(VCTargetsPath)\BuildCustomizations\CUDA 13.3.props')">true</CudaToolkitAvailable>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\CUDA 13.3.props" Condition="'$(CudaToolkitAvailable)'=='true'" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
@@ -94,7 +98,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\src\Checkpoint;$(ProjectDir)..\..\src\CudaSearch;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
@@ -111,7 +115,7 @@
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\src\Checkpoint;$(ProjectDir)..\..\src\CudaSearch;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<BufferSecurityCheck>false</BufferSecurityCheck>
@@ -132,7 +136,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\src\Checkpoint;$(ProjectDir)..\..\src\CudaSearch;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
@@ -149,7 +153,7 @@
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\src\Checkpoint;$(ProjectDir)..\..\src\CudaSearch;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<BufferSecurityCheck>false</BufferSecurityCheck>
@@ -167,16 +171,28 @@
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="solver.cpp" />
<ClCompile Include="..\..\src\Checkpoint\GlobalCheckpoint.cpp" />
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(CudaToolkitAvailable)'!='true'">
<ClCompile Include="..\..\src\CudaSearch\cuda_search_stub.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(CudaToolkitAvailable)'=='true'">
<CudaCompile Include="..\..\src\CudaSearch\cuda_search.cu">
<CodeGeneration>compute_89,sm_89;compute_120,sm_120;compute_120,compute_120</CodeGeneration>
</CudaCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\NeighborlyCore\plane.h" />
<ClInclude Include="..\..\src\NeighborlyCore\precise_geometry.h" />
<ClInclude Include="solver.h" />
<ClInclude Include="..\..\src\Checkpoint\GlobalCheckpoint.h" />
<ClInclude Include="..\..\src\CudaSearch\cuda_search.h" />
<ClInclude Include="..\..\src\NeighborlyCore\util.h" />
<ClInclude Include="..\..\src\NeighborlyCore\wide_real.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\CUDA 13.3.targets" Condition="'$(CudaToolkitAvailable)'=='true'" />
</ImportGroup>
</Project>
@@ -21,6 +21,15 @@
<ClCompile Include="solver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Checkpoint\GlobalCheckpoint.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\CudaSearch\cuda_search_stub.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<CudaCompile Include="..\..\src\CudaSearch\cuda_search.cu">
<Filter>Source Files</Filter>
</CudaCompile>
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -29,6 +38,12 @@
<ClInclude Include="solver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Checkpoint\GlobalCheckpoint.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\CudaSearch\cuda_search.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\util.h">
<Filter>Header Files</Filter>
</ClInclude>
+649 -45
View File
@@ -2,6 +2,8 @@
#include "util.h"
#include "solver.h"
#include "wide_real.h"
#include "GlobalCheckpoint.h"
#include "cuda_search.h"
#include <iostream>
#include <sstream>
#include <fstream>
@@ -18,16 +20,25 @@
#include <chrono>
#include <cstdint>
#include <mutex>
#include <memory>
#include <numeric>
#include <thread>
#include <tuple>
#include <unordered_set>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
#ifdef USE_CAIRO
#include <cairo.h>
#endif
#define NUM_TOPOLOGIES 59
#define DUAL_PROBLEM 0
constexpr int GLOBAL_PLANE_VALUE_COUNT = 36;
constexpr int CUDA_SESSION_CACHE_LIMIT = NUM_TOPOLOGIES;
struct StudyOptions {
std::string obj_path = "data/shape_c2_i0_0.obj";
@@ -47,7 +58,7 @@ struct LocalRepairOptions {
std::string obj_path = "data/shape_c2_i0_0.obj";
std::string start_planes_path;
std::string stop_file_path;
std::string global_dir = "runtime/global_search";
std::string global_dir = "results/search";
std::string out_prefix = "runtime/candidates/top4_local";
std::string report_path = "runtime/reports/03_repair_local_cpp.md";
int topology = 4;
@@ -65,6 +76,13 @@ struct LocalRepairOptions {
int time_limit_seconds = 0;
double jump_chance = 0.08;
double min_step_ratio = 1e-5;
int topology_from = 0;
int topology_to = NUM_TOPOLOGIES - 1;
int cuda_chains = 0;
int cuda_iterations = 64;
int checkpoint_seconds = 30;
double degeneracy_weight = 0.02;
bool use_cuda = false;
};
bool save_plane_state(const std::filesystem::path& path, const VectorXd& x);
@@ -122,7 +140,14 @@ void print_usage(const char* exe_name) {
<< " --threads <n> batch-hunt worker threads. 0 = all cores.\n"
<< " --minutes <x> Clean time limit for batch-hunt. 0 = unlimited.\n"
<< " --stop-file <path> Stop cleanly when this file appears.\n"
<< " --global-dir <path> Checkpoints for --global-search. Default: runtime/global_search\n"
<< " --global-dir <path> Checkpoints for --global-search. Default: results/search\n"
<< " --topology-from <n> First topology to search, inclusive. Default: 0\n"
<< " --topology-to <n> Last topology to search, inclusive. Default: 58\n"
<< " --cuda Require the FP32 CUDA search backend.\n"
<< " --cuda-chains <n> Parallel GPU chains. 0 = automatic (default).\n"
<< " --cuda-iters <n> Iterations per short GPU batch. Default: 64\n"
<< " --checkpoint-seconds <n> Durable checkpoint period. Default: 30\n"
<< " --degeneracy-weight <x> Degenerate-geometry penalty. Default: 0.02\n"
<< " --start-planes <p> Continue batch-hunt from a saved .planes sidecar.\n"
<< " --restarts <n> hunt-local restarts. Default: 256\n"
<< " --stagnation <n> Iterations before hunt-local reheat. Default: 2000\n"
@@ -2170,15 +2195,50 @@ struct GlobalMetrics {
int intersections = std::numeric_limits<int>::max() / 4;
double crossing_loss = std::numeric_limits<double>::infinity();
double geometry_penalty = std::numeric_limits<double>::infinity();
double degeneracy_penalty = std::numeric_limits<double>::infinity();
double energy = std::numeric_limits<double>::infinity();
bool canonical = false;
bool precise = false;
};
double g_global_degeneracy_weight = 0.02;
std::string g_search_device_id = "CPU";
std::uint64_t topology_fingerprint() {
std::uint64_t hash = 1469598103934665603ULL;
auto add = [&](int value) {
hash ^= static_cast<std::uint64_t>(static_cast<std::uint32_t>(value));
hash *= 1099511628211ULL;
};
for (const Face& triangle : g_tris) {
add(static_cast<int>(triangle.size()));
for (int value : triangle) {
add(value);
}
}
for (const Face& polygon : g_polys) {
add(static_cast<int>(polygon.size()));
for (int value : polygon) {
add(value);
}
}
for (const Edge& edge : g_edges) {
add(edge.first);
add(edge.second);
}
return hash;
}
struct GlobalTopologyState {
int topology = 0;
int visits = 0;
std::uint64_t visits = 0;
std::uint64_t trials = 0;
std::uint64_t iterations = 0;
std::uint64_t run_visits = 0;
std::uint64_t run_trials = 0;
std::uint64_t run_iterations = 0;
std::uint64_t checkpoint_sequence = 0;
std::chrono::steady_clock::time_point last_checkpoint_at{};
bool has_state = false;
GlobalMetrics best;
VectorXd best_x;
@@ -2354,13 +2414,57 @@ GlobalMetrics evaluate_global_state(
scratch.verts, *metric_planes, 1e-8, &metrics.crossing_loss);
metrics.intersections = count_edge_face_intersections_strict(
scratch.verts, *metric_planes, 1e-8);
metrics.precise = promote_precise_counts_if_close(
metrics.precise = canonical && promote_precise_counts_if_close(
scratch.verts, *metric_planes, metrics.crossings, metrics.intersections);
const double condition = std::sqrt(max_edge_sq / min_edge_sq);
const double relative_min_edge = std::sqrt(min_edge_sq / max_edge_sq);
double min_plane_determinant = std::numeric_limits<double>::infinity();
for (const Face& triangle : g_tris) {
if (triangle.size() != 3) {
continue;
}
const Vector3d& a = (*metric_planes)[triangle[0]].n;
const Vector3d& b = (*metric_planes)[triangle[1]].n;
const Vector3d& c = (*metric_planes)[triangle[2]].n;
min_plane_determinant = std::min(
min_plane_determinant,
std::abs(a.dot(b.cross(c))));
}
if (!std::isfinite(min_plane_determinant)) {
return GlobalMetrics{};
}
double min_turn_sine = std::numeric_limits<double>::infinity();
for (const Face& face : g_polys) {
for (size_t i = 0; i < face.size(); ++i) {
const Vector3d a = scratch.verts[face[(i + face.size() - 1) % face.size()]] -
scratch.verts[face[i]];
const Vector3d b = scratch.verts[face[(i + 1) % face.size()]] -
scratch.verts[face[i]];
const double denominator = a.norm() * b.norm();
if (denominator > 1e-15) {
min_turn_sine = std::min(
min_turn_sine,
a.cross(b).norm() / denominator);
}
}
}
if (!std::isfinite(min_turn_sine)) {
return GlobalMetrics{};
}
const double determinant_barrier =
std::log1p(0.02 / std::max(1e-10, min_plane_determinant));
const double edge_barrier =
std::log1p(0.002 / std::max(1e-10, relative_min_edge));
const double turn_barrier =
std::log1p(0.002 / std::max(1e-10, min_turn_sine));
const double extent_barrier = 0.10 * std::log1p(max_vertex_norm / 100.0);
metrics.degeneracy_penalty = g_global_degeneracy_weight *
(determinant_barrier + edge_barrier + turn_barrier + extent_barrier);
metrics.geometry_penalty =
0.0010 * std::min(20.0, std::log1p(condition)) +
0.0002 * std::min(20.0, std::log1p(max_vertex_norm));
0.0002 * std::min(20.0, std::log1p(max_vertex_norm)) +
metrics.degeneracy_penalty;
metrics.energy =
0.05 * static_cast<double>(global_defects(metrics)) +
0.01 * static_cast<double>(metrics.crossings) +
@@ -2529,11 +2633,131 @@ bool load_global_topology_state(
return true;
}
void load_mergeable_checkpoints(
const LocalRepairOptions& options,
std::vector<GlobalTopologyState>& states
) {
using namespace szilassi::checkpoint;
const CheckpointScan scan = scan_checkpoints(options.global_dir);
const LatestCheckpointMap latest = select_latest_per_run_topology(scan);
for (const auto& entry : latest) {
const GlobalCheckpoint& checkpoint = entry.second.checkpoint;
if (checkpoint.topology < 0 || checkpoint.topology >= NUM_TOPOLOGIES ||
checkpoint.plane_coefficients.size() != static_cast<size_t>(GLOBAL_PLANE_VALUE_COUNT)) {
continue;
}
if (!load_global_topology_context(checkpoint.topology)) {
continue;
}
if (checkpoint.topology_fingerprint != 0 &&
checkpoint.topology_fingerprint != topology_fingerprint()) {
std::cerr << "Skipping checkpoint with a different topology fingerprint: "
<< entry.second.path.string() << std::endl;
continue;
}
VectorXd x(GLOBAL_PLANE_VALUE_COUNT);
for (int i = 0; i < GLOBAL_PLANE_VALUE_COUNT; ++i) {
x[i] = static_cast<double>(checkpoint.plane_coefficients[static_cast<size_t>(i)]);
}
if (!valid_plane_state(x)) {
continue;
}
PlaneEvaluationScratch scratch;
GlobalMetrics metrics = evaluate_global_state(x, true, scratch);
if (!std::isfinite(metrics.energy)) {
continue;
}
GlobalTopologyState& state = states[checkpoint.topology];
state.visits += checkpoint.visits;
state.trials += checkpoint.completed_trials;
state.iterations += checkpoint.completed_iterations;
if (!state.has_state || better_global_metrics(metrics, state.best)) {
state.best = metrics;
state.best_x = x;
state.has_state = true;
}
}
if (!scan.rejected.empty()) {
std::cerr << "Ignored " << scan.rejected.size()
<< " incomplete or corrupt checkpoint(s); older generations remain usable."
<< std::endl;
}
if (!scan.conflicts.empty()) {
std::cerr << "Ignored " << scan.conflicts.size()
<< " conflicting checkpoint sequence(s)." << std::endl;
}
}
bool commit_mergeable_checkpoint(
const LocalRepairOptions& options,
const szilassi::checkpoint::RunIdentity& identity,
GlobalTopologyState& state,
szilassi::checkpoint::CheckpointReason reason
) {
using namespace szilassi::checkpoint;
if (!state.has_state || state.best_x.size() != GLOBAL_PLANE_VALUE_COUNT) {
return false;
}
GlobalCheckpoint checkpoint;
checkpoint.run_id = identity.run_id;
checkpoint.node_id = identity.node_id;
checkpoint.producer_id = "Szilassi CUDA global search";
checkpoint.device_id = g_search_device_id;
checkpoint.sequence = ++state.checkpoint_sequence;
checkpoint.topology = state.topology;
checkpoint.topology_first = options.topology_from;
checkpoint.topology_last = options.topology_to;
checkpoint.objective_version = 2;
checkpoint.topology_fingerprint = topology_fingerprint();
checkpoint.base_seed = static_cast<std::uint64_t>(
static_cast<std::uint32_t>(options.seed));
checkpoint.next_work_unit = state.run_visits + 1;
checkpoint.completed_work_units = state.run_visits;
checkpoint.completed_trials = state.run_trials;
checkpoint.completed_iterations = state.run_iterations;
checkpoint.visits = state.run_visits;
checkpoint.plane_coefficients.resize(GLOBAL_PLANE_VALUE_COUNT);
VectorXd stored_x(GLOBAL_PLANE_VALUE_COUNT);
for (int i = 0; i < GLOBAL_PLANE_VALUE_COUNT; ++i) {
const float value = static_cast<float>(state.best_x[i]);
checkpoint.plane_coefficients[static_cast<size_t>(i)] = value;
stored_x[i] = static_cast<double>(value);
}
PlaneEvaluationScratch scratch;
GlobalMetrics stored_metrics = evaluate_global_state(stored_x, true, scratch);
if (!std::isfinite(stored_metrics.energy)) {
std::cerr << "FP32 checkpoint round-trip is invalid for topology "
<< state.topology << std::endl;
return false;
}
checkpoint.crossings = stored_metrics.crossings;
checkpoint.intersections = stored_metrics.intersections;
checkpoint.crossing_loss = stored_metrics.crossing_loss;
checkpoint.degeneracy_penalty = stored_metrics.degeneracy_penalty;
checkpoint.energy = stored_metrics.energy;
checkpoint.verification = stored_metrics.precise
? VerificationPrecision::DoubleDouble
: VerificationPrecision::Double;
checkpoint.reason = reason;
checkpoint.flags = CheckpointFlagCanonical |
(stored_metrics.precise ? CheckpointFlagDdVerified : CheckpointFlagNone) |
((stored_metrics.crossings == 0 && stored_metrics.intersections == 0)
? CheckpointFlagFound
: CheckpointFlagNone);
const CommitResult result = commit_checkpoint(options.global_dir, std::move(checkpoint));
if (!result) {
std::cerr << "Durable checkpoint failed for topology " << state.topology
<< ": " << result.error << std::endl;
return false;
}
return true;
}
void save_global_topology_state(
const LocalRepairOptions& options,
const GlobalTopologyState& state,
bool save_history,
int seed
bool,
int
) {
if (!state.has_state || state.best_x.size() == 0) {
return;
@@ -2542,23 +2766,6 @@ void save_global_topology_state(
std::filesystem::create_directories(dir);
save_plane_state(dir / "resume.planes", state.best_x);
export_plane_candidate((dir / "resume.obj").string().c_str(), state.best_x);
std::ofstream meta(dir / "resume.meta");
meta << 1 << " " << state.visits << " " << state.trials << "\n";
meta << state.best.crossings << " " << state.best.intersections << " "
<< std::setprecision(17) << state.best.energy << "\n";
if (save_history) {
std::ostringstream stem;
stem << "best_v" << state.visits
<< "_strict_c" << state.best.crossings
<< "_i" << state.best.intersections
<< "_seed" << seed;
const std::filesystem::path obj_path = dir / (stem.str() + ".obj");
export_plane_candidate(obj_path.string().c_str(), state.best_x);
std::filesystem::path planes_path = obj_path;
planes_path.replace_extension(".planes");
save_plane_state(planes_path, state.best_x);
}
}
void write_global_leaderboard(
@@ -2580,7 +2787,7 @@ void write_global_leaderboard(
const std::filesystem::path root(options.global_dir);
std::filesystem::create_directories(root);
std::ofstream out(root / "leaderboard.tsv");
out << "rank\ttopology\tC\tI\tdefects\tprecision\tvisits\ttrials\tenergy\n";
out << "rank\ttopology\tC\tI\tdefects\tprecision\tvisits\ttrials\tenergy\tdegeneracy\n";
int rank = 1;
for (int ix : order) {
const GlobalTopologyState& state = states[ix];
@@ -2590,22 +2797,254 @@ void write_global_leaderboard(
<< global_defects(state.best) << "\t"
<< (state.best.precise ? "dd31" : "double") << "\t"
<< state.visits << "\t"
<< state.trials << "\t" << std::setprecision(17) << state.best.energy;
<< state.trials << "\t" << std::setprecision(17) << state.best.energy << "\t"
<< state.best.degeneracy_penalty;
} else {
out << "-\t-\t-\t-\t0\t0\t-";
out << "-\t-\t-\t-\t0\t0\t-\t-";
}
out << "\n";
}
}
bool write_run_manifest(
const std::filesystem::path& run_directory,
const LocalRepairOptions& options,
const szilassi::checkpoint::RunIdentity& identity,
int effective_cuda_chains,
int effective_cuda_session_cache
) {
const std::filesystem::path manifest_path = run_directory / "run.tsv";
std::ofstream out(manifest_path, std::ios::binary | std::ios::trunc);
if (!out) {
std::cerr << "Cannot write run manifest: " << manifest_path << std::endl;
return false;
}
out << "format\tszilassi-global-search-v2\n"
<< "run_id\t" << identity.run_id << "\n"
<< "node_id\t" << identity.node_id << "\n"
<< "seed\t" << options.seed << "\n"
<< "topology_from\t" << options.topology_from << "\n"
<< "topology_to\t" << options.topology_to << "\n"
<< "backend\t" << (options.use_cuda ? "cuda-fp32" : "cpu-double") << "\n"
<< "cuda_math\tstandard-fp32\n"
<< "cuda_chains_requested\t" << options.cuda_chains << "\n"
<< "cuda_chains_effective\t" << effective_cuda_chains << "\n"
<< "cuda_iterations_per_batch\t" << options.cuda_iterations << "\n"
<< "cuda_depth_batches\t6\n"
<< "cuda_session_cache\t" << effective_cuda_session_cache << "\n"
<< "cpu_iterations_per_trial\t" << options.iterations << "\n"
<< "degeneracy_weight\t" << std::setprecision(17)
<< options.degeneracy_weight << "\n";
out.flush();
if (!out) {
std::cerr << "Cannot flush run manifest: " << manifest_path << std::endl;
return false;
}
#ifdef _WIN32
const HANDLE handle = CreateFileW(
manifest_path.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr);
if (handle == INVALID_HANDLE_VALUE || !FlushFileBuffers(handle)) {
std::cerr << "Cannot durably flush run manifest: " << manifest_path << std::endl;
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
}
return false;
}
CloseHandle(handle);
#endif
return true;
}
cuda_search::Topology make_cuda_topology() {
cuda_search::Topology topology;
for (int vertex = 0; vertex < cuda_search::kVertexCount; ++vertex) {
for (int component = 0; component < 3; ++component) {
topology.vertex_planes[vertex][component] = static_cast<std::uint8_t>(
g_tris[static_cast<size_t>(vertex)][static_cast<size_t>(component)]);
}
}
for (int face = 0; face < cuda_search::kPolygonCount; ++face) {
for (int vertex = 0; vertex < cuda_search::kPolygonVertexCount; ++vertex) {
topology.polygons[face][vertex] = static_cast<std::uint8_t>(
g_polys[static_cast<size_t>(face)][static_cast<size_t>(vertex)]);
}
}
for (int edge = 0; edge < cuda_search::kEdgeCount; ++edge) {
topology.edges[edge][0] = static_cast<std::uint8_t>(g_edges[edge].first);
topology.edges[edge][1] = static_cast<std::uint8_t>(g_edges[edge].second);
}
return topology;
}
struct CudaSessionSlot {
int topology = -1;
std::uint64_t last_used = 0;
cuda_search::BatchSession session;
};
bool run_global_topology_round_cuda(
const LocalRepairOptions& options,
GlobalTopologyState& state,
bool depth,
const std::atomic<bool>& stop_requested,
int round_seed,
int effective_chain_count,
cuda_search::BatchSession& session
) {
const GlobalMetrics previous_best = state.best;
const bool previous_has_state = state.has_state;
const bool session_was_initialized = session.initialized();
if (!session_was_initialized) {
cuda_search::SearchConfig config;
config.chain_count = effective_chain_count;
config.iterations_per_kernel = std::clamp(options.cuda_iterations, 1, 16);
config.iterations_per_batch = options.cuda_iterations;
config.shortlist_size = std::min(128, config.chain_count);
config.seed = static_cast<std::uint64_t>(static_cast<std::uint32_t>(round_seed));
config.initial_step = static_cast<float>(options.step);
config.minimum_step = static_cast<float>(
std::max(1e-7, options.step * options.min_step_ratio));
config.cooling = static_cast<float>(options.beta);
config.initial_temperature = static_cast<float>(options.temperature);
config.minimum_temperature = static_cast<float>(options.temperature * 0.04);
config.jump_chance = static_cast<float>(options.jump_chance);
config.initial_state_jitter = static_cast<float>(options.step * 0.10);
config.stagnation_iterations = std::max(256, options.stagnation);
config.degeneracy_weight = static_cast<float>(options.degeneracy_weight);
std::vector<cuda_search::PlaneState> initial_states;
if (state.has_state && state.best_x.size() == GLOBAL_PLANE_VALUE_COUNT) {
cuda_search::PlaneState initial;
for (int i = 0; i < GLOBAL_PLANE_VALUE_COUNT; ++i) {
initial.values[static_cast<size_t>(i)] =
static_cast<float>(state.best_x[i]);
}
initial_states.push_back(initial);
}
std::string initialize_error;
if (!session.initialize(
make_cuda_topology(), config, initial_states, initialize_error)) {
std::cerr << "CUDA session initialization failed for topology "
<< state.topology << ": " << initialize_error << std::endl;
return false;
}
}
const int requested_batches = depth ? 6 : 1;
int completed_batches = 0;
double kernel_milliseconds = 0.0;
double transfer_milliseconds = 0.0;
std::uint64_t evaluated_states = 0;
std::uint64_t new_trials = session_was_initialized
? 0
: static_cast<std::uint64_t>(effective_chain_count);
std::string device_name;
PlaneEvaluationScratch scratch;
for (int batch = 0; batch < requested_batches; ++batch) {
if (stop_requested.load(std::memory_order_relaxed)) {
break;
}
cuda_search::BatchRunConfig run_config;
run_config.step_scale = depth ? 1.0f : 1.5f;
if (batch == 0 && (previous_has_state || session_was_initialized)) {
run_config.fresh_numerator = depth ? 1 : 7;
run_config.fresh_denominator = depth ? 4 : 8;
if (session_was_initialized) {
const std::uint64_t chain_count =
static_cast<std::uint64_t>(effective_chain_count);
const std::uint64_t numerator =
static_cast<std::uint64_t>(run_config.fresh_numerator);
const std::uint64_t denominator =
static_cast<std::uint64_t>(run_config.fresh_denominator);
new_trials += (chain_count / denominator) * numerator +
std::min(chain_count % denominator, numerator);
}
}
const cuda_search::BatchResult gpu = session.run(run_config);
if (!gpu.success) {
std::cerr << "CUDA batch failed for topology " << state.topology
<< ": " << gpu.error << std::endl;
session.reset();
break;
}
device_name = gpu.device_name;
g_search_device_id = gpu.device_name;
kernel_milliseconds += gpu.kernel_milliseconds;
transfer_milliseconds += gpu.transfer_milliseconds;
evaluated_states += gpu.evaluated_states;
completed_batches += 1;
for (const cuda_search::Candidate& candidate : gpu.shortlist) {
VectorXd x(GLOBAL_PLANE_VALUE_COUNT);
for (int i = 0; i < GLOBAL_PLANE_VALUE_COUNT; ++i) {
x[i] = static_cast<double>(
candidate.state.values[static_cast<size_t>(i)]);
}
if (!valid_plane_state(x)) {
continue;
}
GlobalMetrics verified = evaluate_global_state(x, true, scratch);
if (!std::isfinite(verified.energy)) {
continue;
}
if (!state.has_state || better_global_metrics(verified, state.best)) {
state.best = verified;
state.best_x = x;
state.has_state = true;
}
}
}
if (completed_batches == 0) {
return false;
}
state.visits += 1;
state.run_visits += 1;
state.trials += new_trials;
state.run_trials += new_trials;
state.iterations += evaluated_states;
state.run_iterations += evaluated_states;
std::cout << " CUDA " << device_name
<< ": " << std::fixed << std::setprecision(1)
<< kernel_milliseconds << " ms kernel, "
<< transfer_milliseconds << " ms transfer, "
<< evaluated_states << " FP32 states in "
<< completed_batches << " batch(es)"
<< std::defaultfloat << std::setprecision(6) << std::endl;
return state.has_state &&
(!previous_has_state || better_global_metrics(state.best, previous_best));
}
bool run_global_topology_round(
const LocalRepairOptions& options,
GlobalTopologyState& state,
bool depth,
int worker_count,
const std::atomic<bool>& stop_requested,
int round_seed
int round_seed,
int effective_cuda_chains,
cuda_search::BatchSession* cuda_session
) {
if (options.use_cuda) {
if (cuda_session == nullptr) {
return false;
}
return run_global_topology_round_cuda(
options,
state,
depth,
stop_requested,
round_seed,
effective_cuda_chains,
*cuda_session);
}
const GlobalMetrics previous_best = state.best;
const bool previous_has_state = state.has_state;
GlobalMetrics shared_best = state.best;
@@ -2620,6 +3059,7 @@ bool run_global_topology_round(
: std::max(1000, options.iterations / 3);
std::atomic<int> next_trial{0};
std::atomic<int> completed{0};
std::atomic<std::uint64_t> completed_iterations{0};
std::mutex best_mutex;
std::vector<std::thread> workers;
workers.reserve(worker_count);
@@ -2656,6 +3096,9 @@ bool run_global_topology_round(
}
}
completed.fetch_add(1, std::memory_order_relaxed);
completed_iterations.fetch_add(
static_cast<std::uint64_t>(result.iterations),
std::memory_order_relaxed);
}
};
@@ -2668,7 +3111,15 @@ bool run_global_topology_round(
}
state.visits += 1;
state.trials += static_cast<std::uint64_t>(completed.load(std::memory_order_relaxed));
state.run_visits += 1;
const std::uint64_t round_trials =
static_cast<std::uint64_t>(completed.load(std::memory_order_relaxed));
const std::uint64_t round_iterations =
completed_iterations.load(std::memory_order_relaxed);
state.trials += round_trials;
state.iterations += round_iterations;
state.run_trials += round_trials;
state.run_iterations += round_iterations;
state.has_state = shared_has_state;
state.best = shared_best;
state.best_x = shared_best_x;
@@ -2683,9 +3134,38 @@ int global_search_all(const LocalRepairOptions& options) {
}
const std::filesystem::path root(options.global_dir);
std::filesystem::create_directories(root);
if (!options.stop_file_path.empty()) {
std::error_code remove_error;
std::filesystem::remove(options.stop_file_path, remove_error);
const szilassi::checkpoint::RunIdentity run_identity =
szilassi::checkpoint::make_run_identity();
g_global_degeneracy_weight = options.degeneracy_weight;
#ifdef _WIN32
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
#endif
cuda_search::BackendInfo cuda_backend;
int effective_cuda_chains = 0;
if (options.use_cuda) {
cuda_backend = cuda_search::query_backend(0);
if (!cuda_backend.available) {
std::cerr << "CUDA backend is unavailable: " << cuda_backend.error << std::endl;
std::cerr << "Install CUDA Toolkit 13.3 with Visual Studio integration, then rebuild x64."
<< std::endl;
return 3;
}
effective_cuda_chains = options.cuda_chains > 0
? options.cuda_chains
: cuda_backend.recommended_chain_count;
if (effective_cuda_chains <= 0) {
std::cerr << "CUDA backend did not provide a valid chain count." << std::endl;
return 3;
}
g_search_device_id = cuda_backend.device_name;
std::cout << "CUDA device: " << cuda_backend.device_name << std::endl;
std::cout << "CUDA SMs: " << cuda_backend.multiprocessor_count
<< ", resident blocks/SM: "
<< cuda_backend.active_blocks_per_multiprocessor << std::endl;
std::cout << "GPU scheduling: low-priority stream, no artificial throttle"
<< std::endl;
}
const unsigned int hardware_threads = std::thread::hardware_concurrency();
@@ -2720,24 +3200,60 @@ int global_search_all(const LocalRepairOptions& options) {
load_global_topology_state(options, states[topology]);
}
}
load_mergeable_checkpoints(options, states);
write_global_leaderboard(options, states);
std::ofstream run_log(root / "run.log", std::ios::app);
std::vector<int> active_topologies;
active_topologies.reserve(options.topology_to - options.topology_from + 1);
for (int topology = options.topology_from; topology <= options.topology_to; ++topology) {
active_topologies.push_back(topology);
}
const std::filesystem::path run_directory =
root / "runs" / run_identity.run_id;
std::filesystem::create_directories(run_directory);
const int effective_cuda_session_cache = options.use_cuda
? std::min(
CUDA_SESSION_CACHE_LIMIT,
static_cast<int>(active_topologies.size()))
: 0;
write_run_manifest(
run_directory,
options,
run_identity,
effective_cuda_chains,
effective_cuda_session_cache);
std::ofstream run_log(run_directory / "run.log", std::ios::app);
run_log << "\n=== global-search seed " << options.seed
<< ", run " << run_identity.run_id
<< ", node " << run_identity.node_id
<< ", threads " << worker_count
<< ", minutes " << (options.time_limit_seconds / 60.0)
<< " ===\n";
std::cout << "===================" << std::endl;
std::cout << "Mode : global-search" << std::endl;
std::cout << "Topologies: 59" << std::endl;
std::cout << "Seed : " << options.seed
<< " (saved in " << (run_directory / "run.tsv").string() << ")"
<< std::endl;
std::cout << "Topologies: " << options.topology_from << ".."
<< options.topology_to << " (" << active_topologies.size() << ")" << std::endl;
std::cout << "Start : independent random plane arrangements" << std::endl;
std::cout << "Coordinates: double (15-16 digits)" << std::endl;
std::cout << "Coordinates: "
<< (options.use_cuda ? "CUDA FP32 search" : "CPU double search")
<< std::endl;
std::cout << "Near goal : WideReal double-double (~"
<< WideReal::decimal_digits << " digits)" << std::endl;
std::cout << "Resume dir: " << options.global_dir << std::endl;
if (options.use_cuda) {
std::cout << "CUDA chains: " << effective_cuda_chains
<< (options.cuda_chains == 0 ? " (automatic)" : " (manual)")
<< std::endl;
std::cout << "CUDA iters/batch: " << options.cuda_iterations << std::endl;
} else {
std::cout << "Threads : " << worker_count << std::endl;
std::cout << "Depth iters/trial: " << options.iterations << std::endl;
}
if (options.time_limit_seconds > 0) {
std::cout << "Time limit: " << options.time_limit_seconds << " sec" << std::endl;
}
@@ -2745,6 +3261,34 @@ int global_search_all(const LocalRepairOptions& options) {
int completed_rounds = 0;
bool found = false;
std::vector<CudaSessionSlot> cuda_sessions(effective_cuda_session_cache);
std::uint64_t cuda_session_use_counter = 0;
auto acquire_cuda_session = [&](int topology) -> cuda_search::BatchSession* {
if (!options.use_cuda || cuda_sessions.empty()) {
return nullptr;
}
++cuda_session_use_counter;
for (CudaSessionSlot& slot : cuda_sessions) {
if (slot.topology == topology) {
slot.last_used = cuda_session_use_counter;
return &slot.session;
}
}
CudaSessionSlot* selected = nullptr;
for (CudaSessionSlot& slot : cuda_sessions) {
if (slot.topology < 0) {
selected = &slot;
break;
}
if (selected == nullptr || slot.last_used < selected->last_used) {
selected = &slot;
}
}
selected->session.reset();
selected->topology = topology;
selected->last_used = cuda_session_use_counter;
return &selected->session;
};
auto run_round = [&](int topology, bool depth, const char* phase, int position, int total) {
if (stop_requested.load(std::memory_order_relaxed)) {
return;
@@ -2756,16 +3300,43 @@ int global_search_all(const LocalRepairOptions& options) {
GlobalTopologyState& state = states[topology];
const int round_seed = static_cast<int>(
1 + (static_cast<std::uint64_t>(static_cast<std::uint32_t>(options.seed)) +
static_cast<std::uint64_t>(completed_rounds + 1) * 15485863ULL +
static_cast<std::uint64_t>(state.visits + 1) * 15485863ULL +
static_cast<std::uint64_t>(topology + 1) * 32452843ULL) %
2147483646ULL);
std::cout << phase << " " << position << "/" << total
<< " | topology " << topology
<< " | " << (depth ? "depth" : "breadth") << std::endl;
cuda_search::BatchSession* cuda_session = acquire_cuda_session(topology);
const bool improved = run_global_topology_round(
options, state, depth, worker_count, stop_requested, round_seed);
options,
state,
depth,
worker_count,
stop_requested,
round_seed,
effective_cuda_chains,
cuda_session);
completed_rounds += 1;
const auto checkpoint_now = std::chrono::steady_clock::now();
const bool checkpoint_due = state.last_checkpoint_at.time_since_epoch().count() == 0 ||
checkpoint_now - state.last_checkpoint_at >=
std::chrono::seconds(options.checkpoint_seconds);
if (checkpoint_due) {
if (commit_mergeable_checkpoint(
options,
run_identity,
state,
improved
? szilassi::checkpoint::CheckpointReason::Improvement
: szilassi::checkpoint::CheckpointReason::Periodic)) {
state.last_checkpoint_at = checkpoint_now;
}
}
// Legacy previews follow the durable checkpoint cadence. The current
// in-memory best is always committed on a clean stop below.
if (checkpoint_due) {
save_global_topology_state(options, state, improved, round_seed);
}
write_global_leaderboard(options, states);
const double elapsed_minutes = std::chrono::duration<double>(
@@ -2801,9 +3372,9 @@ int global_search_all(const LocalRepairOptions& options) {
}
};
std::vector<int> breadth_order(NUM_TOPOLOGIES);
std::iota(breadth_order.begin(), breadth_order.end(), 0);
const int rotation = ((options.seed % NUM_TOPOLOGIES) + NUM_TOPOLOGIES) % NUM_TOPOLOGIES;
std::vector<int> breadth_order = active_topologies;
const int active_count = static_cast<int>(breadth_order.size());
const int rotation = ((options.seed % active_count) + active_count) % active_count;
std::rotate(breadth_order.begin(), breadth_order.begin() + rotation, breadth_order.end());
std::vector<int> missing;
for (int topology : breadth_order) {
@@ -2817,8 +3388,7 @@ int global_search_all(const LocalRepairOptions& options) {
int cycle = 0;
while (!stop_requested.load(std::memory_order_relaxed)) {
std::vector<int> ranked(NUM_TOPOLOGIES);
std::iota(ranked.begin(), ranked.end(), 0);
std::vector<int> ranked = active_topologies;
std::sort(ranked.begin(), ranked.end(), [&](int a, int b) {
if (states[a].has_state != states[b].has_state) {
return states[a].has_state;
@@ -2830,7 +3400,7 @@ int global_search_all(const LocalRepairOptions& options) {
});
const bool exploration_cycle = cycle % 5 == 4;
int keep = NUM_TOPOLOGIES;
int keep = active_count;
if (!exploration_cycle) {
keep = cycle == 0 ? 30 : (cycle == 1 ? 16 : 8);
} else {
@@ -2852,14 +3422,25 @@ int global_search_all(const LocalRepairOptions& options) {
watcher_done.store(true, std::memory_order_relaxed);
watcher.join();
for (int topology : active_topologies) {
GlobalTopologyState& state = states[topology];
if (state.run_visits == 0 || !load_global_topology_context(topology)) {
continue;
}
commit_mergeable_checkpoint(
options,
run_identity,
state,
szilassi::checkpoint::CheckpointReason::Stop);
save_global_topology_state(options, state, true, options.seed);
}
if (!options.stop_file_path.empty()) {
std::error_code remove_error;
std::filesystem::remove(options.stop_file_path, remove_error);
}
write_global_leaderboard(options, states);
std::vector<int> ranked(NUM_TOPOLOGIES);
std::iota(ranked.begin(), ranked.end(), 0);
std::vector<int> ranked = active_topologies;
std::sort(ranked.begin(), ranked.end(), [&](int a, int b) {
if (states[a].has_state != states[b].has_state) {
return states[a].has_state;
@@ -3101,6 +3682,21 @@ int main(int argc, char* argv[]) {
repair_options.stop_file_path = argv[++i];
} else if (arg == "--global-dir" && i + 1 < argc) {
repair_options.global_dir = argv[++i];
} else if (arg == "--topology-from" && i + 1 < argc) {
repair_options.topology_from = std::atoi(argv[++i]);
} else if (arg == "--topology-to" && i + 1 < argc) {
repair_options.topology_to = std::atoi(argv[++i]);
} else if (arg == "--cuda") {
repair_options.use_cuda = true;
} else if (arg == "--cuda-chains" && i + 1 < argc) {
repair_options.cuda_chains = std::max(0, std::atoi(argv[++i]));
} else if (arg == "--cuda-iters" && i + 1 < argc) {
repair_options.cuda_iterations = std::clamp(std::atoi(argv[++i]), 1, 64);
} else if (arg == "--checkpoint-seconds" && i + 1 < argc) {
repair_options.checkpoint_seconds = std::clamp(std::atoi(argv[++i]), 5, 3600);
} else if (arg == "--degeneracy-weight" && i + 1 < argc) {
repair_options.degeneracy_weight = std::clamp(
std::atof(argv[++i]), 0.0, 1.0);
} else if (arg == "--restarts" && i + 1 < argc) {
repair_options.restarts = std::atoi(argv[++i]);
} else if (arg == "--stagnation" && i + 1 < argc) {
@@ -3121,6 +3717,14 @@ int main(int argc, char* argv[]) {
return study_shape(options);
}
if (run_global_search) {
if (repair_options.topology_from < 0 ||
repair_options.topology_to >= NUM_TOPOLOGIES ||
repair_options.topology_from > repair_options.topology_to) {
std::cerr << "Invalid topology range: "
<< repair_options.topology_from << ".."
<< repair_options.topology_to << std::endl;
return 2;
}
return global_search_all(repair_options);
}
if (run_batch_hunt) {
@@ -0,0 +1,15 @@
format szilassi-global-search-v2
run_id d27a3577-93be-4570-ae15-6ac4dfb73ac8
node_id LOOKICH
seed 2005138652
topology_from 0
topology_to 58
backend cuda-fp32
cuda_math standard-fp32
cuda_chains_requested 0
cuda_chains_effective 61440
cuda_iterations_per_batch 64
cuda_depth_batches 6
cuda_session_cache 59
cpu_iterations_per_trial 50000
degeneracy_weight 0.02
1 format szilassi-global-search-v2
2 run_id d27a3577-93be-4570-ae15-6ac4dfb73ac8
3 node_id LOOKICH
4 seed 2005138652
5 topology_from 0
6 topology_to 58
7 backend cuda-fp32
8 cuda_math standard-fp32
9 cuda_chains_requested 0
10 cuda_chains_effective 61440
11 cuda_iterations_per_batch 64
12 cuda_depth_batches 6
13 cuda_session_cache 59
14 cpu_iterations_per_trial 50000
15 degeneracy_weight 0.02

Some files were not shown because too many files have changed in this diff Show More