Initial commit

This commit is contained in:
Efim Beshmenev
2026-07-10 19:16:42 +03:00
commit 7f9dc067a1
3620 changed files with 516098 additions and 0 deletions
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>18.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{8c3af236-14fc-4b0a-81aa-fc9952837f4a}</ProjectGuid>
<RootNamespace>PolyhedronGui</RootNamespace>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<RepositoryRoot>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\'))</RepositoryRoot>
<OutDir>$(RepositoryRoot)build\msbuild\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(RepositoryRoot)build\msbuild\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LocalDebuggerWorkingDirectory>$(RepositoryRoot)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;UNICODE;_UNICODE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;UNICODE;_UNICODE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UNICODE;_UNICODE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;UNICODE;_UNICODE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="launcher_gui.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{0b5020e1-85b0-4901-88da-9009487f268a}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="launcher_gui.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+861
View File
@@ -0,0 +1,861 @@
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <shellapi.h>
#include <algorithm>
#include <atomic>
#include <filesystem>
#include <limits>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
namespace fs = std::filesystem;
namespace {
constexpr UINT WM_APPEND_LOG = WM_APP + 1;
constexpr UINT WM_PROCESS_DONE = WM_APP + 2;
constexpr int LOG_TEXT_LIMIT = 8 * 1024 * 1024;
constexpr int LOG_TRIM_KEEP = 6 * 1024 * 1024;
constexpr int LOG_APPEND_MARGIN = 32768;
constexpr int ID_SEED = 1001;
constexpr int ID_ITERS = 1002;
constexpr int ID_SIGMA = 1003;
constexpr int ID_BETA = 1004;
constexpr int ID_TEMP = 1005;
constexpr int ID_CLUSTERS = 1006;
constexpr int ID_MINUTES = 1007;
constexpr int ID_THREADS = 1008;
constexpr int ID_VERIFY_BASELINE = 2001;
constexpr int ID_REPAIR_LOCAL = 2002;
constexpr int ID_STUDY = 2003;
constexpr int ID_VERIFY_LAST = 2004;
constexpr int ID_STOP = 2005;
constexpr int ID_OPEN_CANDIDATES = 2006;
constexpr int ID_OPEN_REPORTS = 2007;
constexpr int ID_OPEN_BASELINE = 2008;
constexpr int ID_CLEAR_LOG = 2009;
constexpr int ID_CONTINUE_BEST = 2010;
constexpr int ID_GLOBAL_SEARCH = 2011;
constexpr int ID_OPEN_GLOBAL = 2012;
HWND g_main_window = nullptr;
HWND g_log = nullptr;
HWND g_status = nullptr;
HWND g_seed = nullptr;
HWND g_iters = nullptr;
HWND g_sigma = nullptr;
HWND g_beta = nullptr;
HWND g_temp = nullptr;
HWND g_clusters = nullptr;
HWND g_minutes = nullptr;
HWND g_threads = nullptr;
HWND g_stop = nullptr;
HFONT g_ui_font = nullptr;
HFONT g_title_font = nullptr;
HFONT g_mono_font = nullptr;
fs::path g_root;
fs::path g_stop_file;
PROCESS_INFORMATION g_process{};
std::atomic<bool> g_running{false};
std::wstring quote_arg(const std::wstring& value) {
if (value.find_first_of(L" \t\"") == std::wstring::npos) {
return value;
}
std::wstring quoted = L"\"";
for (wchar_t ch : value) {
if (ch == L'"') {
quoted += L"\\\"";
} else {
quoted += ch;
}
}
quoted += L"\"";
return quoted;
}
std::wstring join_args(const std::vector<std::wstring>& args) {
std::wstring result;
for (const std::wstring& arg : args) {
if (!result.empty()) {
result += L" ";
}
result += quote_arg(arg);
}
return result;
}
std::wstring get_text(HWND hwnd) {
const int length = GetWindowTextLengthW(hwnd);
std::vector<wchar_t> buffer(static_cast<size_t>(length) + 1, L'\0');
GetWindowTextW(hwnd, buffer.data(), static_cast<int>(buffer.size()));
return std::wstring(buffer.data());
}
std::wstring now_time() {
SYSTEMTIME st{};
GetLocalTime(&st);
wchar_t buffer[32]{};
swprintf_s(buffer, L"%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
return buffer;
}
void post_log(const std::wstring& text) {
PostMessageW(g_main_window, WM_APPEND_LOG, 0, reinterpret_cast<LPARAM>(new std::wstring(text)));
}
std::wstring ansi_to_wide(const char* data, int length) {
if (length <= 0) {
return L"";
}
int needed = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, data, length, nullptr, 0);
UINT codepage = CP_UTF8;
DWORD flags = MB_ERR_INVALID_CHARS;
if (needed <= 0) {
codepage = CP_ACP;
flags = 0;
needed = MultiByteToWideChar(codepage, flags, data, length, nullptr, 0);
}
if (needed <= 0) {
return L"";
}
std::wstring result(needed, L'\0');
MultiByteToWideChar(codepage, flags, data, length, result.data(), needed);
return result;
}
void append_log_direct(const std::wstring& text) {
const std::wstring line = L"[" + now_time() + L"] " + text + L"\r\n";
const int length = GetWindowTextLengthW(g_log);
if (length + static_cast<int>(line.size()) > LOG_TEXT_LIMIT - LOG_APPEND_MARGIN) {
const int remove_until = std::max(0, length - LOG_TRIM_KEEP);
if (remove_until > 0) {
SendMessageW(g_log, WM_SETREDRAW, FALSE, 0);
SendMessageW(g_log, EM_SETSEL, 0, remove_until);
SendMessageW(g_log, EM_REPLACESEL, FALSE, reinterpret_cast<LPARAM>(L"[... old log trimmed ...]\r\n"));
SendMessageW(g_log, WM_SETREDRAW, TRUE, 0);
InvalidateRect(g_log, nullptr, TRUE);
}
}
const int end = GetWindowTextLengthW(g_log);
SendMessageW(g_log, EM_SETSEL, end, end);
SendMessageW(g_log, EM_REPLACESEL, FALSE, reinterpret_cast<LPARAM>(line.c_str()));
SendMessageW(g_log, EM_SCROLLCARET, 0, 0);
}
void set_running_state(bool running, const std::wstring& status) {
g_running = running;
EnableWindow(g_stop, running ? TRUE : FALSE);
SetWindowTextW(g_status, status.c_str());
}
fs::path find_root() {
wchar_t buffer[MAX_PATH]{};
GetModuleFileNameW(nullptr, buffer, MAX_PATH);
fs::path candidate = fs::path(buffer).parent_path();
while (!candidate.empty()) {
if (fs::exists(candidate / L"Szilassi.slnx") &&
fs::exists(candidate / L"data" / L"shape_c2_i0_0.obj")) {
return candidate;
}
const fs::path parent = candidate.parent_path();
if (parent == candidate) {
break;
}
candidate = parent;
}
return fs::path(buffer).parent_path();
}
fs::path main_exe() {
const fs::path local = g_root / L"build" / L"msbuild" / L"bin" / L"x64" / L"Release" / L"Szilassi.exe";
if (fs::exists(local)) {
return local;
}
return g_root / L"build" / L"vs2026" / L"Release" / L"neighborly_main.exe";
}
fs::path verify_exe() {
const fs::path local = g_root / L"build" / L"msbuild" / L"bin" / L"x64" / L"Release" / L"VerifyCpp.exe";
if (fs::exists(local)) {
return local;
}
return g_root / L"build" / L"vs2026" / L"Release" / L"verify_cpp.exe";
}
void open_path(const fs::path& path) {
if (!fs::exists(path)) {
fs::create_directories(path);
}
ShellExecuteW(nullptr, L"open", path.c_str(), nullptr, g_root.c_str(), SW_SHOWNORMAL);
}
void open_file(const fs::path& path) {
if (!fs::exists(path)) {
MessageBoxW(g_main_window, (L"Файл пока не создан:\n" + path.wstring()).c_str(), L"Нет файла", MB_OK | MB_ICONINFORMATION);
return;
}
ShellExecuteW(nullptr, L"open", path.c_str(), nullptr, g_root.c_str(), SW_SHOWNORMAL);
}
fs::path latest_candidate() {
const fs::path dir = g_root / L"runtime" / L"candidates";
fs::path best;
fs::file_time_type best_time{};
if (!fs::exists(dir)) {
return best;
}
for (const fs::directory_entry& entry : fs::directory_iterator(dir)) {
if (!entry.is_regular_file() || entry.path().extension() != L".obj") {
continue;
}
const auto time = entry.last_write_time();
if (best.empty() || time > best_time) {
best = entry.path();
best_time = time;
}
}
return best;
}
bool parse_candidate_score(const fs::path& path, int& crossings, int& intersections, bool& strict) {
const std::wstring name = path.stem().wstring();
strict = name.find(L"_strict_c") != std::wstring::npos;
const size_t c_pos = name.rfind(L"_c");
if (c_pos == std::wstring::npos) {
return false;
}
const size_t i_pos = name.find(L"_i", c_pos + 2);
if (i_pos == std::wstring::npos) {
return false;
}
const size_t end_pos = name.find(L"_", i_pos + 2);
try {
crossings = std::stoi(name.substr(c_pos + 2, i_pos - (c_pos + 2)));
intersections = std::stoi(name.substr(i_pos + 2, end_pos == std::wstring::npos ? end_pos : end_pos - (i_pos + 2)));
} catch (...) {
return false;
}
return crossings >= 0 && intersections >= 0;
}
fs::path best_scored_candidate() {
const fs::path dir = g_root / L"runtime" / L"candidates";
fs::path best;
fs::file_time_type best_time{};
int best_crossings = std::numeric_limits<int>::max();
int best_intersections = std::numeric_limits<int>::max();
if (!fs::exists(dir)) {
return best;
}
for (const fs::directory_entry& entry : fs::directory_iterator(dir)) {
if (!entry.is_regular_file() || entry.path().extension() != L".obj") {
continue;
}
const std::wstring stem = entry.path().stem().wstring();
if (stem.rfind(L"smoke_", 0) == 0 || stem.rfind(L"audit_", 0) == 0) {
continue;
}
int crossings = 0;
int intersections = 0;
bool strict = false;
if (!parse_candidate_score(entry.path(), crossings, intersections, strict)) {
continue;
}
if (!strict) {
continue;
}
fs::path state_path = entry.path();
state_path.replace_extension(L".planes");
if (!fs::exists(state_path)) {
continue;
}
const auto time = entry.last_write_time();
const int defects = crossings + intersections;
const int best_defects = best.empty()
? std::numeric_limits<int>::max()
: best_crossings + best_intersections;
const int peak = std::max(crossings, intersections);
const int best_peak = best.empty()
? std::numeric_limits<int>::max()
: std::max(best_crossings, best_intersections);
const bool better =
best.empty() ||
defects < best_defects ||
(defects == best_defects && peak < best_peak) ||
(defects == best_defects && peak == best_peak && crossings < best_crossings) ||
(defects == best_defects && peak == best_peak && crossings == best_crossings && time > best_time);
if (better) {
best = entry.path();
best_time = time;
best_crossings = crossings;
best_intersections = intersections;
}
}
return best;
}
bool better_candidate_score(
int crossings,
int intersections,
const fs::file_time_type& time,
int best_crossings,
int best_intersections,
const fs::file_time_type& best_time
) {
const int defects = crossings + intersections;
const int best_defects = best_crossings + best_intersections;
const int peak = std::max(crossings, intersections);
const int best_peak = std::max(best_crossings, best_intersections);
return defects < best_defects ||
(defects == best_defects && peak < best_peak) ||
(defects == best_defects && peak == best_peak && crossings < best_crossings) ||
(defects == best_defects && peak == best_peak &&
crossings == best_crossings && time > best_time);
}
fs::path best_global_candidate() {
const fs::path root = g_root / L"runtime" / L"global_search";
if (!fs::exists(root)) {
return {};
}
fs::path best;
fs::file_time_type best_time{};
int best_crossings = std::numeric_limits<int>::max() / 4;
int best_intersections = std::numeric_limits<int>::max() / 4;
for (const fs::directory_entry& entry : fs::recursive_directory_iterator(root)) {
if (!entry.is_regular_file() || entry.path().extension() != L".obj") {
continue;
}
int crossings = 0;
int intersections = 0;
bool strict = false;
if (!parse_candidate_score(entry.path(), crossings, intersections, strict) || !strict) {
continue;
}
fs::path state_path = entry.path();
state_path.replace_extension(L".planes");
if (!fs::exists(state_path)) {
continue;
}
const auto time = entry.last_write_time();
if (best.empty() || better_candidate_score(
crossings,
intersections,
time,
best_crossings,
best_intersections,
best_time)) {
best = entry.path();
best_time = time;
best_crossings = crossings;
best_intersections = intersections;
}
}
return best;
}
fs::path best_any_candidate() {
const fs::path local = best_scored_candidate();
const fs::path global = best_global_candidate();
if (local.empty()) {
return global;
}
if (global.empty()) {
return local;
}
int local_c = 0;
int local_i = 0;
int global_c = 0;
int global_i = 0;
bool local_strict = false;
bool global_strict = false;
parse_candidate_score(local, local_c, local_i, local_strict);
parse_candidate_score(global, global_c, global_i, global_strict);
return better_candidate_score(
global_c,
global_i,
fs::last_write_time(global),
local_c,
local_i,
fs::last_write_time(local)) ? global : local;
}
int candidate_topology(const fs::path& candidate) {
const std::wstring parent = candidate.parent_path().filename().wstring();
if (parent.rfind(L"topology_", 0) == 0) {
try {
return std::stoi(parent.substr(9));
} catch (...) {
}
}
return 4;
}
void close_process_handles() {
if (g_process.hProcess) {
CloseHandle(g_process.hProcess);
g_process.hProcess = nullptr;
}
if (g_process.hThread) {
CloseHandle(g_process.hThread);
g_process.hThread = nullptr;
}
}
void start_process(
const std::wstring& title,
const fs::path& exe,
const std::vector<std::wstring>& args,
const fs::path& stop_file = {}
) {
if (g_running) {
MessageBoxW(g_main_window, L"Сначала останови текущий процесс.", L"Уже запущено", MB_OK | MB_ICONINFORMATION);
return;
}
if (!fs::exists(exe)) {
MessageBoxW(g_main_window, (L"Не найден exe:\n" + exe.wstring()).c_str(), L"Файл не найден", MB_OK | MB_ICONWARNING);
return;
}
fs::create_directories(g_root / L"runtime" / L"candidates");
fs::create_directories(g_root / L"runtime" / L"reports");
SECURITY_ATTRIBUTES sa{};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
HANDLE read_pipe = nullptr;
HANDLE write_pipe = nullptr;
if (!CreatePipe(&read_pipe, &write_pipe, &sa, 0)) {
MessageBoxW(g_main_window, L"Не удалось создать pipe для вывода.", L"Ошибка", MB_OK | MB_ICONERROR);
return;
}
SetHandleInformation(read_pipe, HANDLE_FLAG_INHERIT, 0);
std::wstring command = quote_arg(exe.wstring());
const std::wstring argument_string = join_args(args);
if (!argument_string.empty()) {
command += L" " + argument_string;
}
STARTUPINFOW si{};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = write_pipe;
si.hStdError = write_pipe;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
close_process_handles();
PROCESS_INFORMATION pi{};
std::vector<wchar_t> mutable_command(command.begin(), command.end());
mutable_command.push_back(L'\0');
post_log(L"=== " + title + L" ===");
post_log(command);
const BOOL ok = CreateProcessW(
nullptr,
mutable_command.data(),
nullptr,
nullptr,
TRUE,
CREATE_NO_WINDOW,
nullptr,
g_root.c_str(),
&si,
&pi
);
CloseHandle(write_pipe);
if (!ok) {
CloseHandle(read_pipe);
g_stop_file.clear();
MessageBoxW(g_main_window, L"Не удалось запустить процесс.", L"Ошибка", MB_OK | MB_ICONERROR);
return;
}
g_process = pi;
g_stop_file = stop_file;
set_running_state(true, L"Выполняется: " + title);
std::thread([read_pipe, pi]() {
char buffer[4096];
DWORD read = 0;
while (ReadFile(read_pipe, buffer, sizeof(buffer), &read, nullptr) && read > 0) {
post_log(ansi_to_wide(buffer, static_cast<int>(read)));
}
CloseHandle(read_pipe);
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exit_code = 0;
GetExitCodeProcess(pi.hProcess, &exit_code);
PostMessageW(g_main_window, WM_PROCESS_DONE, static_cast<WPARAM>(exit_code), 0);
}).detach();
}
HWND make_label(HWND parent, const std::wstring& text, int x, int y, int w, int h) {
HWND hwnd = CreateWindowExW(0, L"STATIC", text.c_str(), WS_CHILD | WS_VISIBLE, x, y, w, h, parent, nullptr, nullptr, nullptr);
SendMessageW(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(g_ui_font), TRUE);
return hwnd;
}
HWND make_edit(HWND parent, int id, const std::wstring& text, int x, int y, int w, int h) {
HWND hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, x, y, w, h, parent, reinterpret_cast<HMENU>(static_cast<INT_PTR>(id)), nullptr, nullptr);
SendMessageW(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(g_ui_font), TRUE);
return hwnd;
}
HWND make_button(HWND parent, int id, const std::wstring& text, int x, int y, int w, int h) {
HWND hwnd = CreateWindowExW(0, L"BUTTON", text.c_str(), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, x, y, w, h, parent, reinterpret_cast<HMENU>(static_cast<INT_PTR>(id)), nullptr, nullptr);
SendMessageW(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(g_ui_font), TRUE);
return hwnd;
}
void create_controls(HWND hwnd) {
g_title_font = CreateFontW(24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI");
g_ui_font = CreateFontW(17, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI");
g_mono_font = CreateFontW(15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, FIXED_PITCH, L"Consolas");
HWND title = make_label(hwnd, L"K12 Neighborly Polyhedron", 18, 14, 430, 32);
SendMessageW(title, WM_SETFONT, reinterpret_cast<WPARAM>(g_title_font), TRUE);
make_label(hwnd, L"Папка проекта: " + g_root.wstring(), 20, 50, 900, 24);
make_label(hwnd, L"Seed", 22, 90, 95, 22);
g_seed = make_edit(hwnd, ID_SEED, L"30000157", 22, 114, 95, 26);
make_label(hwnd, L"Итераций", 139, 90, 95, 22);
g_iters = make_edit(hwnd, ID_ITERS, L"30000", 139, 114, 95, 26);
make_label(hwnd, L"Попыток t4", 256, 90, 95, 22);
g_clusters = make_edit(hwnd, ID_CLUSTERS, L"100000", 256, 114, 95, 26);
make_label(hwnd, L"Минут", 373, 90, 95, 22);
g_minutes = make_edit(hwnd, ID_MINUTES, L"480", 373, 114, 95, 26);
make_label(hwnd, L"Потоков", 490, 90, 95, 22);
g_threads = make_edit(hwnd, ID_THREADS, L"0", 490, 114, 95, 26);
make_label(hwnd, L"Шаг", 607, 90, 95, 22);
g_sigma = make_edit(hwnd, ID_SIGMA, L"0.25", 607, 114, 95, 26);
make_label(hwnd, L"Temp", 724, 90, 95, 22);
g_temp = make_edit(hwnd, ID_TEMP, L"0.02", 724, 114, 95, 26);
make_label(hwnd, L"Beta", 841, 90, 95, 22);
g_beta = make_edit(hwnd, ID_BETA, L"0.9995", 841, 114, 95, 26);
make_button(hwnd, ID_GLOBAL_SEARCH, L"Глобальный поиск 59", 22, 164, 220, 36);
make_button(hwnd, ID_CONTINUE_BEST, L"Продолжить topology 4", 254, 164, 210, 36);
make_button(hwnd, ID_REPAIR_LOCAL, L"Начать t4 заново", 476, 164, 180, 36);
make_button(hwnd, ID_VERIFY_LAST, L"Проверить лучший", 668, 164, 170, 36);
g_stop = make_button(hwnd, ID_STOP, L"Остановить", 850, 164, 110, 36);
EnableWindow(g_stop, FALSE);
make_button(hwnd, ID_VERIFY_BASELINE, L"Проверить baseline", 22, 212, 180, 34);
make_button(hwnd, ID_OPEN_GLOBAL, L"Открыть global", 214, 212, 160, 34);
make_button(hwnd, ID_OPEN_CANDIDATES, L"Открыть candidates", 386, 212, 180, 34);
make_button(hwnd, ID_OPEN_REPORTS, L"Открыть reports", 578, 212, 160, 34);
make_button(hwnd, ID_CLEAR_LOG, L"Очистить лог", 750, 212, 140, 34);
g_status = make_label(hwnd, L"Готово", 22, 260, 900, 24);
g_log = CreateWindowExW(
WS_EX_CLIENTEDGE,
L"EDIT",
L"",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
18,
290,
942,
360,
hwnd,
nullptr,
nullptr,
nullptr
);
SendMessageW(g_log, EM_SETLIMITTEXT, static_cast<WPARAM>(LOG_TEXT_LIMIT), 0);
SendMessageW(g_log, WM_SETFONT, reinterpret_cast<WPARAM>(g_mono_font), TRUE);
append_log_direct(L"GUI готов. Двойной клик: build\\msbuild\\bin\\x64\\Release\\PolyhedronGui.exe");
append_log_direct(L"Основной exe: " + main_exe().wstring());
append_log_direct(L"Verifier exe: " + verify_exe().wstring());
}
void resize_controls(HWND hwnd) {
RECT rc{};
GetClientRect(hwnd, &rc);
const int width = rc.right - rc.left;
const int height = rc.bottom - rc.top;
MoveWindow(g_log, 18, 290, std::max(300, width - 36), std::max(120, height - 310), TRUE);
}
void handle_command(int id) {
switch (id) {
case ID_GLOBAL_SEARCH: {
SYSTEMTIME st{};
GetLocalTime(&st);
wchar_t stamp[64]{};
swprintf_s(stamp, L"%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
const fs::path stop_path = g_root / L"runtime" / L"reports" / (std::wstring(L"global_stop_") + stamp + L".flag");
start_process(L"Глобальный поиск по 59 топологиям", main_exe(), {
L"--global-search",
L"--seed", get_text(g_seed),
L"--iters", get_text(g_iters),
L"--threads", get_text(g_threads),
L"--minutes", get_text(g_minutes),
L"--stop-file", stop_path.wstring(),
L"--sigma", get_text(g_sigma),
L"--beta", get_text(g_beta),
L"--temperature", get_text(g_temp),
L"--restarts", L"512",
L"--stagnation", L"1500",
L"--jump-chance", L"0.12",
L"--global-dir", L"runtime\\global_search"
}, stop_path);
break;
}
case ID_VERIFY_BASELINE:
start_process(L"Проверка near-miss", verify_exe(), {
L"--obj", L"data\\shape_c2_i0_0.obj",
L"--topology", L"4",
L"--report", L"runtime\\reports\\00_baseline.md",
L"--json", L"runtime\\reports\\baseline.json"
});
break;
case ID_REPAIR_LOCAL: {
SYSTEMTIME st{};
GetLocalTime(&st);
wchar_t stamp[64]{};
swprintf_s(stamp, L"%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
const fs::path stop_path = g_root / L"runtime" / L"reports" / (std::wstring(L"gui_stop_") + stamp + L".flag");
start_process(L"Поиск с baseline", main_exe(), {
L"--batch-hunt", L"data\\shape_c2_i0_0.obj",
L"--topology", L"4",
L"--seed", get_text(g_seed),
L"--iters", get_text(g_iters),
L"--trials", get_text(g_clusters),
L"--threads", get_text(g_threads),
L"--minutes", get_text(g_minutes),
L"--stop-file", stop_path.wstring(),
L"--sigma", get_text(g_sigma),
L"--beta", get_text(g_beta),
L"--temperature", get_text(g_temp),
L"--report-every", L"100",
L"--restarts", L"512",
L"--stagnation", L"1500",
L"--jump-chance", L"0.12",
L"--out", std::wstring(L"runtime\\candidates\\gui_batch_") + stamp,
L"--report", L"runtime\\reports\\gui_batch_hunt.md"
}, stop_path);
break;
}
case ID_CONTINUE_BEST: {
const fs::path candidate = best_scored_candidate();
if (candidate.empty()) {
append_log_direct(L"Сохранённого состояния пока нет; начинаю с baseline.");
handle_command(ID_REPAIR_LOCAL);
return;
}
fs::path state_path = candidate;
state_path.replace_extension(L".planes");
SYSTEMTIME st{};
GetLocalTime(&st);
wchar_t stamp[64]{};
swprintf_s(stamp, L"%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
const fs::path stop_path = g_root / L"runtime" / L"reports" / (std::wstring(L"gui_stop_") + stamp + L".flag");
append_log_direct(L"Продолжаю от лучшего OBJ: " + candidate.wstring());
start_process(L"Поиск от лучшего", main_exe(), {
L"--batch-hunt", candidate.wstring(),
L"--topology", L"4",
L"--seed", get_text(g_seed),
L"--iters", get_text(g_iters),
L"--trials", get_text(g_clusters),
L"--threads", get_text(g_threads),
L"--minutes", get_text(g_minutes),
L"--stop-file", stop_path.wstring(),
L"--sigma", get_text(g_sigma),
L"--beta", get_text(g_beta),
L"--temperature", get_text(g_temp),
L"--report-every", L"100",
L"--restarts", L"512",
L"--stagnation", L"1500",
L"--jump-chance", L"0.12",
L"--out", std::wstring(L"runtime\\candidates\\gui_continue_") + stamp,
L"--report", L"runtime\\reports\\gui_continue_hunt.md",
L"--start-planes", state_path.wstring()
}, stop_path);
break;
}
case ID_STUDY: {
SYSTEMTIME st{};
GetLocalTime(&st);
wchar_t stamp[64]{};
swprintf_s(stamp, L"%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
start_process(L"study", main_exe(), {
L"--study", L"data\\shape_c2_i0_0.obj",
L"--topology", L"4",
L"--seed", get_text(g_seed),
L"--iters", get_text(g_iters),
L"--clusters", get_text(g_clusters),
L"--sigma", get_text(g_sigma),
L"--objective", L"cross-zint",
L"--out", std::wstring(L"runtime\\candidates\\gui_study_") + stamp,
L"--report", L"runtime\\reports\\gui_study.md"
});
break;
}
case ID_VERIFY_LAST: {
const fs::path candidate = best_any_candidate();
if (candidate.empty()) {
MessageBoxW(g_main_window, L"Сохранённого strict-кандидата пока нет.", L"Нет кандидатов", MB_OK | MB_ICONINFORMATION);
return;
}
const std::wstring topology = std::to_wstring(candidate_topology(candidate));
start_process(L"Проверка лучшего OBJ", verify_exe(), {
L"--obj", candidate.wstring(),
L"--topology", topology,
L"--report", L"runtime\\reports\\last_candidate_verify.md",
L"--json", L"runtime\\reports\\last_candidate_verify.json"
});
break;
}
case ID_STOP:
if (g_running && g_process.hProcess) {
if (!g_stop_file.empty()) {
append_log_direct(L"Запрошена штатная остановка; сохраняю результат...");
HANDLE stop_file = CreateFileW(
g_stop_file.c_str(),
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr);
if (stop_file != INVALID_HANDLE_VALUE) {
CloseHandle(stop_file);
EnableWindow(g_stop, FALSE);
SetWindowTextW(g_status, L"Останавливается и сохраняет...");
} else {
TerminateProcess(g_process.hProcess, 1);
}
} else {
append_log_direct(L"Остановка процесса...");
TerminateProcess(g_process.hProcess, 1);
}
}
break;
case ID_OPEN_CANDIDATES:
open_path(g_root / L"runtime" / L"candidates");
break;
case ID_OPEN_GLOBAL:
open_path(g_root / L"runtime" / L"global_search");
break;
case ID_OPEN_REPORTS:
open_path(g_root / L"runtime" / L"reports");
break;
case ID_OPEN_BASELINE:
open_file(g_root / L"runtime" / L"reports" / L"00_baseline.md");
break;
case ID_CLEAR_LOG:
SetWindowTextW(g_log, L"");
break;
}
}
LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_CREATE:
g_main_window = hwnd;
create_controls(hwnd);
return 0;
case WM_SIZE:
resize_controls(hwnd);
return 0;
case WM_COMMAND:
handle_command(LOWORD(wparam));
return 0;
case WM_APPEND_LOG: {
std::wstring* text = reinterpret_cast<std::wstring*>(lparam);
append_log_direct(*text);
delete text;
return 0;
}
case WM_PROCESS_DONE: {
append_log_direct(L"Завершено: exit code " + std::to_wstring(static_cast<DWORD>(wparam)));
set_running_state(false, L"Готово");
close_process_handles();
if (!g_stop_file.empty()) {
std::error_code remove_error;
fs::remove(g_stop_file, remove_error);
g_stop_file.clear();
}
return 0;
}
case WM_CLOSE:
if (g_running) {
const int answer = MessageBoxW(hwnd, L"Процесс еще работает. Остановить и закрыть окно?", L"Процесс работает", MB_YESNO | MB_ICONQUESTION);
if (answer != IDYES) {
return 0;
}
if (g_process.hProcess) {
TerminateProcess(g_process.hProcess, 1);
}
}
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
close_process_handles();
DeleteObject(g_ui_font);
DeleteObject(g_title_font);
DeleteObject(g_mono_font);
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
} // namespace
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show_command) {
g_root = find_root();
WNDCLASSW wc{};
wc.lpfnWndProc = window_proc;
wc.hInstance = instance;
wc.lpszClassName = L"PolyhedronGuiWindow";
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
RegisterClassW(&wc);
HWND hwnd = CreateWindowExW(
0,
wc.lpszClassName,
L"Polyhedron Control",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1000,
720,
nullptr,
nullptr,
instance,
nullptr
);
ShowWindow(hwnd, show_command);
UpdateWindow(hwnd);
MSG msg{};
while (GetMessageW(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return static_cast<int>(msg.wParam);
}
+182
View File
@@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>18.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{35967190-b8ae-4e08-8c3a-94ee61bd0d46}</ProjectGuid>
<RootNamespace>Szilassi</RootNamespace>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<RepositoryRoot>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\'))</RepositoryRoot>
<OutDir>$(RepositoryRoot)build\msbuild\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(RepositoryRoot)build\msbuild\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LocalDebuggerWorkingDirectory>$(RepositoryRoot)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<BufferSecurityCheck>false</BufferSecurityCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<Profile>true</Profile>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<BufferSecurityCheck>false</BufferSecurityCheck>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<Profile>true</Profile>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="solver.cpp" />
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\NeighborlyCore\plane.h" />
<ClInclude Include="..\..\src\NeighborlyCore\precise_geometry.h" />
<ClInclude Include="solver.h" />
<ClInclude Include="..\..\src\NeighborlyCore\util.h" />
<ClInclude Include="..\..\src\NeighborlyCore\wide_real.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="solver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="solver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\plane.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\precise_geometry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\wide_real.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
File diff suppressed because it is too large Load Diff
+246
View File
@@ -0,0 +1,246 @@
#include "solver.h"
#include <algorithm>
#include <iostream>
#define SYMMETRY make_symmetric_o4
//#define SYMMETRY make_symmetric_o2
//#define SYMMETRY make_symmetric_d2
RNG eng;
struct Sample {
VectorXd x;
double score;
int time;
bool operator<(const Sample& rhs) const {
return this->score < rhs.score;
}
};
void set_rand_seed(int seed) {
eng.seed(seed);
}
void add_random_noise(const VectorXd& x, double sigma, VectorXd& result) {
std::normal_distribution<double> rand_normal(0.0, sigma);
for (int i = 0; i < x.size(); ++i) {
result[i] = x[i] + rand_normal(eng);
}
}
void set_random_mags(VectorXd& x, double sigma) {
std::normal_distribution<double> rand_normal(0.0, sigma);
for (int i = 0; i < x.size(); i += 3) {
Eigen::Map<Vector3d> sub_x(x.data() + i);
sub_x.normalize();
sub_x *= rand_normal(eng);
}
}
void initialize_random_noise(VectorXd& x, double sigma, size_t size) {
std::normal_distribution<double> rand_normal(0.0, sigma);
x.resize(size);
for (int i = 0; i < x.size(); ++i) {
x[i] = rand_normal(eng);
}
}
void initialize_random_noise(std::vector<std::pair<double, VectorXd>>& xvec, double sigma, bool dual_problem) {
size_t size = (dual_problem ? g_tris.size() : g_polys.size()) * 3;
for (auto& x : xvec) {
initialize_random_noise(x.second, sigma, size);
}
}
void initialize_random_noise(std::vector<std::pair<double, VectorXd>>& xvec, const VectorXd& guess, double sigma) {
for (auto& x : xvec) {
initialize_random_noise(x.second, sigma, guess.size());
x.second += guess;
}
}
void initialize_random_mag(std::vector<VectorXd>& yvec, const VectorXd& n, double sigma) {
std::normal_distribution<double> rand_normal(0.0, sigma);
for (VectorXd& y : yvec) {
y.resize(g_polys.size());
for (int i = 0; i < y.size(); ++i) {
y[i] = rand_normal(eng);
}
}
}
VectorXd shuffle_x(const VectorXd& x) {
VectorXd result(x);
const size_t num = x.size() / 3;
for (size_t i = 0; i < num; ++i) {
const size_t ix = std::uniform_int_distribution<size_t>(i, num - 1)(eng);
std::swap(result[ix*3 + 0], result[i*3 + 0]);
std::swap(result[ix*3 + 1], result[i*3 + 1]);
std::swap(result[ix*3 + 2], result[i*3 + 2]);
}
return result;
}
VectorXd random_plane_shift(const VectorXd& x) {
std::uniform_real_distribution<double> rand_uniform(0.8, 1.2);
VectorXd result(x);
const size_t num = x.size() / 3;
const size_t ix = std::uniform_int_distribution<size_t>(0, num - 1)(eng);
const double scale = rand_uniform(eng);
result[ix * 3 + 0] *= scale;
result[ix * 3 + 1] *= scale;
result[ix * 3 + 2] *= scale;
return result;
}
void z_symmetric(VectorXd& x, size_t i, size_t j) {
x[j*3 + 0] = -x[i*3 + 0];
x[j*3 + 1] = -x[i*3 + 1];
x[j*3 + 2] = x[i*3 + 2];
}
void z_rotate_inv(VectorXd& x, size_t i, size_t j) {
x[j * 3 + 0] = x[i * 3 + 1];
x[j * 3 + 1] = -x[i * 3 + 0];
x[j * 3 + 2] = -x[i * 3 + 2];
}
void make_symmetric_d2(VectorXd& x) {
z_symmetric(x, 0, 1);
z_symmetric(x, 2, 3);
z_symmetric(x, 4, 5);
z_symmetric(x, 6, 7);
z_symmetric(x, 8, 9);
z_symmetric(x, 10, 11);
}
void make_symmetric_o2(VectorXd& x) {
z_symmetric(x, 0, 2);
z_symmetric(x, 5, 7);
z_symmetric(x, 8, 10);
z_symmetric(x, 1, 3);
z_symmetric(x, 4, 6);
z_symmetric(x, 9, 11);
}
void make_symmetric_o4(VectorXd& x) {
z_symmetric(x, 0, 2);
z_symmetric(x, 5, 7);
z_symmetric(x, 8, 10);
z_rotate_inv(x, 5, 4);
z_rotate_inv(x, 7, 6);
z_rotate_inv(x, 0, 3);
z_rotate_inv(x, 2, 1);
z_rotate_inv(x, 8, 11);
z_rotate_inv(x, 10, 9);
}
bool v_pred(const std::pair<double, VectorXd>& left, const std::pair<double, VectorXd>& right) {
return left.first < right.first;
}
double my_optimizer(double (*objective_function)(const VectorXd&), VectorXd& result, int max_iters,
double sigma, double beta, int clusters, bool use_symmetry, bool dual_problem) {
static const int extra_tries = 10;
std::vector<std::pair<double, VectorXd>> xv(clusters * extra_tries);
VectorXd new_pt;
initialize_random_noise(xv, 1.0, dual_problem);
for (auto& x : xv) {
if (use_symmetry) { SYMMETRY(x.second); }
x.first = objective_function(x.second);
}
std::sort(xv.begin(), xv.end(), v_pred);
xv.resize(clusters);
int iter = 0;
double best_cost = 99999;
const size_t x_size = xv[0].second.size();
new_pt.resize(x_size);
while (true) {
const size_t min_ix = std::min_element(xv.begin(), xv.end(), v_pred) - xv.begin();
const double min_cost = xv[min_ix].first;
iter += 1;
if (min_cost < best_cost) {
std::cout << min_cost << " " << iter << std::endl;
best_cost = min_cost;
result = xv[min_ix].second;
}
#if 0
if (best_cost > 500 && iter > max_iters) { break; }
if (best_cost > 300 && iter > max_iters * 2) { break; }
if (best_cost > 200 && iter > max_iters * 3) { break; }
if (best_cost > 100 && iter > max_iters * 4) { break; }
#elif 0
if (best_cost > 22 && iter > max_iters) { break; }
if (best_cost > 18 && iter > max_iters * 2) { break; }
if (best_cost > 15 && iter > max_iters * 3) { break; }
if (best_cost > 12 && iter > max_iters * 4) { break; }
#else
if (best_cost > 11 && iter > max_iters) { break; }
if (best_cost > 9 && iter > max_iters * 2) { break; }
if (best_cost > 7 && iter > max_iters * 3) { break; }
if (best_cost > 5 && iter > max_iters * 4) { break; }
#endif
if (iter > max_iters * 10) { break; }
if (best_cost == 0.0) { break; }
for (size_t i = 0; i < clusters; ++i) {
size_t ix = i;
if (xv[i].first > best_cost * 1.25) {
ix = std::uniform_int_distribution<size_t>(0, clusters-1)(eng);
}
add_random_noise(xv[ix].second, sigma, new_pt);
if (use_symmetry) { SYMMETRY(new_pt); }
new_pt *= beta;
const double new_cost = objective_function(new_pt);
const double cost_mult = (i == min_ix ? 1.0 : 1.25);
if (new_cost <= best_cost * cost_mult || new_cost < xv[i].first) {
xv[i].first = new_cost;
xv[i].second = new_pt;
}
}
}
return best_cost;
}
void study_sample(double (*objective_function)(const VectorXd&), VectorXd& result, int max_iters, int clusters, double sigma, double beta, bool use_symmetry) {
const size_t x_size = result.size();
if (use_symmetry) { SYMMETRY(result); }
double min_score = objective_function(result);
std::vector<VectorXd> xv(clusters, result);
std::vector<double> scores(clusters, min_score);
VectorXd new_x(x_size);
for(int iter = 0; iter < max_iters; ++iter) {
int num_updated = 0;
for (int i = 0; i < clusters; ++i) {
add_random_noise(xv[i], sigma, new_x);
if (use_symmetry) { SYMMETRY(new_x); }
new_x.normalize();
const double new_cost = objective_function(new_x);
if (new_cost < scores[i]) {
if (new_cost < min_score) {
std::cout << "==== New Best! ==== (" << new_cost << ")" << std::endl;
result = new_x;
if (int(new_cost) < int(min_score)) {
std::fill(xv.begin(), xv.end(), new_x);
}
min_score = new_cost;
}
xv[i] = new_x;
scores[i] = new_cost;
num_updated += 1;
}
}
std::cout << "Updated: " << num_updated << "/" << clusters << " " << sigma << std::endl;
if (num_updated < clusters / 100) {
sigma *= beta;
} else if (num_updated > clusters / 10) {
sigma *= 1.01;
}
if (sigma < 1e-7) { break; }
}
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "util.h"
#include <random>
//using RNG = std::mt19937;
using RNG = std::minstd_rand;
extern RNG eng;
void set_rand_seed(int seed);
void add_random_noise(const VectorXd& x, double sigma, VectorXd& result);
void set_random_mags(VectorXd& x, double sigma);
void initialize_random_noise(VectorXd& x, double sigma, size_t size);
void initialize_random_noise(std::vector<std::pair<double, VectorXd>>& xvec, double sigma, bool dual_problem);
void initialize_random_noise(std::vector<std::pair<double, VectorXd>>& xvec, const VectorXd& guess, double sigma);
VectorXd shuffle_x(const VectorXd& x);
void make_symmetric_o4(VectorXd& x);
double my_optimizer(double (*objective_function)(const VectorXd&), VectorXd& result, int max_iters,
double sigma, double beta, int clusters, bool use_symmetry, bool dual_problem);
void study_sample(double (*objective_function)(const VectorXd&), VectorXd& result, int max_iters,
int clusters, double sigma, double beta, bool use_symmetry);
+152
View File
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>18.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{edbc9fb5-7482-46d2-bc85-915e34fb1e97}</ProjectGuid>
<RootNamespace>VerifyCpp</RootNamespace>
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<RepositoryRoot>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\'))</RepositoryRoot>
<OutDir>$(RepositoryRoot)build\msbuild\bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(RepositoryRoot)build\msbuild\obj\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LocalDebuggerWorkingDirectory>$(RepositoryRoot)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\src\NeighborlyCore;$(ProjectDir)..\..\external\eigen-3.4.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="verify_cpp.cpp" />
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\NeighborlyCore\plane.h" />
<ClInclude Include="..\..\src\NeighborlyCore\precise_geometry.h" />
<ClInclude Include="..\..\src\NeighborlyCore\util.h" />
<ClInclude Include="..\..\src\NeighborlyCore\wide_real.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{ace0167e-2ac0-47cd-a825-5f520d30f8aa}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{bc3bd4ce-bb85-4b5d-bc63-a16e38f8c04f}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="verify_cpp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\NeighborlyCore\util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\NeighborlyCore\plane.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\precise_geometry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\NeighborlyCore\wide_real.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+496
View File
@@ -0,0 +1,496 @@
#include "util.h"
#include "precise_geometry.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
namespace {
struct Crossing {
int face = -1;
Edge edge_a;
Edge edge_b;
double t = 0.0;
double u = 0.0;
};
struct EdgeFaceIntersection {
Edge edge;
int face = -1;
double t = 0.0;
bool on_boundary = false;
};
struct PlanarityResidual {
int face = -1;
double max_abs = 0.0;
double rms = 0.0;
};
struct Verification {
std::string obj_path;
double eps = 1e-12;
int topology = 4;
size_t vertices = 0;
size_t faces = 0;
size_t edges = 0;
int euler = 0;
int genus = 0;
std::vector<size_t> face_sizes;
std::vector<Edge> unique_edges;
std::vector<Edge> bad_edge_incidence;
std::vector<std::pair<int, int>> bad_face_pairs;
std::vector<Crossing> crossings;
std::vector<EdgeFaceIntersection> intersections;
std::vector<PlanarityResidual> planarity;
int original_crossings = 0;
int original_intersections = 0;
bool finite = false;
double geometry_scale = 0.0;
double min_edge_length = 0.0;
double max_planarity_residual = 0.0;
};
Edge canonical_edge(int a, int b) {
return a < b ? Edge(a, b) : Edge(b, a);
}
std::string edge_obj_string(const Edge& edge) {
std::ostringstream out;
out << "[" << edge.first + 1 << "," << edge.second + 1 << "]";
return out.str();
}
bool segment_intersection_2d(
const Vector2d& a,
const Vector2d& b,
const Vector2d& c,
const Vector2d& d,
double eps,
double& t,
double& u
) {
return precise_segment_intersection_2d(a, b, c, d, eps, &t, &u);
}
std::map<Edge, std::vector<int>> make_edge_to_faces(const Faces& faces) {
std::map<Edge, std::vector<int>> result;
for (size_t face_ix = 0; face_ix < faces.size(); ++face_ix) {
const Face& face = faces[face_ix];
for (size_t i = 0; i < face.size(); ++i) {
result[canonical_edge(face[i], face[(i + 1) % face.size()])].push_back((int)face_ix);
}
}
return result;
}
std::vector<Crossing> find_self_crossings(const Verts3D& verts, const Faces& faces, const Planes& planes, double eps) {
std::vector<Crossing> result;
for (size_t face_ix = 0; face_ix < faces.size(); ++face_ix) {
const Face& face = faces[face_ix];
Verts2D projected;
make_2d_projection(verts, face, planes[face_ix], projected);
const size_t n = face.size();
for (size_t i = 0; i < n; ++i) {
const size_t i_next = (i + 1) % n;
for (size_t j = i + 1; j < n; ++j) {
const size_t j_next = (j + 1) % n;
if (i_next == j || j_next == i) {
continue;
}
std::set<int> vertices = {face[i], face[i_next], face[j], face[j_next]};
if (vertices.size() < 4) {
continue;
}
double t = 0.0;
double u = 0.0;
if (segment_intersection_2d(projected[i], projected[i_next], projected[j], projected[j_next], eps, t, u)) {
Crossing crossing;
crossing.face = (int)face_ix;
crossing.edge_a = Edge(face[i], face[i_next]);
crossing.edge_b = Edge(face[j], face[j_next]);
crossing.t = t;
crossing.u = u;
result.push_back(crossing);
}
}
}
}
return result;
}
std::vector<EdgeFaceIntersection> find_edge_face_intersections(
const Verts3D& verts,
const Faces& faces,
const Planes& planes,
const std::vector<Edge>& edges,
double eps
) {
std::vector<EdgeFaceIntersection> result;
std::vector<std::set<int>> face_vertices;
face_vertices.reserve(faces.size());
for (const Face& face : faces) {
face_vertices.emplace_back(face.begin(), face.end());
}
for (const Edge& edge : edges) {
const int a_ix = edge.first;
const int b_ix = edge.second;
const Vector3d a = verts[a_ix];
const Vector3d b = verts[b_ix];
for (size_t face_ix = 0; face_ix < faces.size(); ++face_ix) {
if (face_vertices[face_ix].count(a_ix) || face_vertices[face_ix].count(b_ix)) {
continue;
}
const Plane& plane = planes[face_ix];
WideReal precise_t;
if (!precise_edge_plane_parameter(a, b, plane, eps, precise_t)) {
continue;
}
const double t = precise_t.to_double();
Matrix3d basis;
Vector3d origin;
Verts2D projected;
make_2d_projection(verts, faces[face_ix], plane, projected, basis, origin);
const WidePoint2 hit2 = precise_projected_edge_hit(a, b, precise_t, basis, origin);
bool on_boundary = false;
if (precise_point_in_polygon_2d(hit2, projected, eps, &on_boundary)) {
EdgeFaceIntersection hit;
hit.edge = edge;
hit.face = (int)face_ix;
hit.t = t;
hit.on_boundary = on_boundary;
result.push_back(hit);
}
}
}
return result;
}
std::vector<PlanarityResidual> measure_planarity(const Verts3D& verts, const Faces& faces, const Planes& planes) {
std::vector<PlanarityResidual> result;
for (size_t face_ix = 0; face_ix < faces.size(); ++face_ix) {
const Face& face = faces[face_ix];
double max_abs = 0.0;
double sum_sq = 0.0;
for (int vertex_ix : face) {
const double distance = planes[face_ix].signed_distance(verts[vertex_ix]);
max_abs = std::max(max_abs, std::abs(distance));
sum_sq += double(distance) * double(distance);
}
PlanarityResidual item;
item.face = (int)face_ix;
item.max_abs = max_abs;
item.rms = (double)std::sqrt(sum_sq / double(face.size()));
result.push_back(item);
}
std::sort(result.begin(), result.end(), [](const PlanarityResidual& a, const PlanarityResidual& b) {
return a.max_abs > b.max_abs;
});
return result;
}
Verification verify_obj(const std::string& obj_path, int topology, double eps) {
Verification verification;
verification.obj_path = obj_path;
verification.topology = topology;
verification.eps = eps;
g_topology = topology;
Verts3D verts;
Planes planes;
import_obj(obj_path.c_str(), verts, g_polys);
verification.finite = is_finite(verts);
if (verts.empty() || g_polys.empty()) {
verification.finite = false;
return verification;
}
make_edges(g_polys, g_edges);
v3ds_to_planes(verts, g_polys, planes);
const std::map<Edge, std::vector<int>> edge_to_faces = make_edge_to_faces(g_polys);
for (const auto& item : edge_to_faces) {
verification.unique_edges.push_back(item.first);
if (item.second.size() != 2) {
verification.bad_edge_incidence.push_back(item.first);
}
}
std::vector<std::set<Edge>> face_edge_sets;
for (const Face& face : g_polys) {
std::set<Edge> face_edges;
for (size_t i = 0; i < face.size(); ++i) {
face_edges.insert(canonical_edge(face[i], face[(i + 1) % face.size()]));
}
face_edge_sets.push_back(face_edges);
}
for (size_t i = 0; i < face_edge_sets.size(); ++i) {
for (size_t j = i + 1; j < face_edge_sets.size(); ++j) {
std::vector<Edge> shared;
std::set_intersection(
face_edge_sets[i].begin(),
face_edge_sets[i].end(),
face_edge_sets[j].begin(),
face_edge_sets[j].end(),
std::back_inserter(shared)
);
if (shared.size() != 1) {
verification.bad_face_pairs.emplace_back((int)i, (int)j);
}
}
}
verification.vertices = verts.size();
verification.faces = g_polys.size();
verification.edges = verification.unique_edges.size();
verification.euler = (int)verification.vertices - (int)verification.edges + (int)verification.faces;
verification.genus = 1 - verification.euler / 2;
for (const Face& face : g_polys) {
verification.face_sizes.push_back(face.size());
}
verification.crossings = find_self_crossings(verts, g_polys, planes, eps);
verification.intersections = find_edge_face_intersections(verts, g_polys, planes, verification.unique_edges, eps);
verification.planarity = measure_planarity(verts, g_polys, planes);
std::vector<double> edge_lengths;
edge_lengths.reserve(verification.unique_edges.size());
for (const Edge& edge : verification.unique_edges) {
edge_lengths.push_back((verts[edge.first] - verts[edge.second]).norm());
}
if (!edge_lengths.empty()) {
std::sort(edge_lengths.begin(), edge_lengths.end());
verification.min_edge_length = edge_lengths.front();
verification.geometry_scale = edge_lengths[edge_lengths.size() / 2];
}
if (!verification.planarity.empty()) {
verification.max_planarity_residual = verification.planarity.front().max_abs;
}
verification.original_crossings = count_crossings(verts, planes);
verification.original_intersections = count_intersections(verts, planes);
return verification;
}
bool has_all_11_gons(const Verification& verification) {
return std::all_of(verification.face_sizes.begin(), verification.face_sizes.end(), [](size_t size) {
return size == 11;
});
}
bool is_ok(const Verification& verification) {
return verification.vertices == 44
&& verification.faces == 12
&& verification.edges == 66
&& has_all_11_gons(verification)
&& verification.bad_face_pairs.empty()
&& verification.bad_edge_incidence.empty()
&& verification.genus == 6
&& verification.finite
&& verification.geometry_scale > 0.0
&& verification.min_edge_length > verification.geometry_scale * 1e-8
&& verification.max_planarity_residual <= verification.geometry_scale * 1e-4
&& verification.crossings.empty()
&& verification.intersections.empty();
}
std::string render_markdown(const Verification& verification) {
std::ostringstream out;
out << "# C++ high-precision verification\n\n";
out << "- Source: `" << verification.obj_path << "`\n";
out << "- Topology: `" << verification.topology << "`\n";
out << "- Epsilon: `" << std::scientific << std::setprecision(17)
<< verification.eps << std::defaultfloat << "`\n";
out << "- Predicate arithmetic: double-double (`~" << WideReal::decimal_digits << " decimal digits`)\n";
out << "- Overall: **" << (is_ok(verification) ? "OK" : "FAIL") << "**\n\n";
out << "## Combinatorics\n\n";
out << "- V/E/F: `" << verification.vertices << "/" << verification.edges << "/" << verification.faces << "`\n";
out << "- Euler characteristic: `" << verification.euler << "`\n";
out << "- Genus: `" << verification.genus << "`\n";
out << "- All faces are 11-gons: `" << (has_all_11_gons(verification) ? "yes" : "no") << "`\n";
out << "- Face-pair failures: `" << verification.bad_face_pairs.size() << "`\n";
out << "- Edge incidence failures: `" << verification.bad_edge_incidence.size() << "`\n\n";
out << "## Geometry\n\n";
out << "- Finite coordinates: `" << (verification.finite ? "yes" : "no") << "`\n";
out << "- Median/min edge length: `" << verification.geometry_scale << "/"
<< verification.min_edge_length << "`\n";
out << "- Max planarity residual: `" << verification.max_planarity_residual << "`\n";
out << "- Strict C++ self-crossings: `" << verification.crossings.size() << "`\n";
out << "- Strict C++ edge-face intersections: `" << verification.intersections.size() << "`\n";
out << "- Original count_crossings: `" << verification.original_crossings << "`\n";
out << "- Original count_intersections: `" << verification.original_intersections << "`\n\n";
out << "## Self-crossings\n\n";
if (verification.crossings.empty()) {
out << "- None\n";
} else {
for (const Crossing& crossing : verification.crossings) {
out << "- Face " << crossing.face << " (OBJ face " << crossing.face + 1 << "): edge "
<< edge_obj_string(crossing.edge_a) << " crosses edge " << edge_obj_string(crossing.edge_b)
<< " (t=" << std::setprecision(17) << crossing.t << ", u=" << crossing.u << ")\n";
}
}
out << "\n## Edge-face intersections\n\n";
if (verification.intersections.empty()) {
out << "- None\n";
} else {
for (const EdgeFaceIntersection& hit : verification.intersections) {
out << "- Edge " << edge_obj_string(hit.edge) << " intersects OBJ face " << hit.face + 1
<< " (t=" << std::setprecision(17) << hit.t
<< ", " << (hit.on_boundary ? "boundary" : "interior") << ")\n";
}
}
out << "\n## Worst face planarity residuals\n\n";
const size_t residual_count = std::min<size_t>(5, verification.planarity.size());
for (size_t i = 0; i < residual_count; ++i) {
const PlanarityResidual& residual = verification.planarity[i];
out << "- Face " << residual.face << " (OBJ face " << residual.face + 1 << "): max `"
<< std::setprecision(17) << residual.max_abs << "`, rms `" << residual.rms << "`\n";
}
return out.str();
}
std::string json_escape(const std::string& value) {
std::ostringstream out;
for (const char ch : value) {
switch (ch) {
case '\\':
out << "\\\\";
break;
case '"':
out << "\\\"";
break;
case '\n':
out << "\\n";
break;
case '\r':
out << "\\r";
break;
case '\t':
out << "\\t";
break;
default:
out << ch;
break;
}
}
return out.str();
}
std::string render_json(const Verification& verification) {
std::ostringstream out;
out << "{\n";
out << " \"source\": \"" << json_escape(verification.obj_path) << "\",\n";
out << " \"topology\": " << verification.topology << ",\n";
out << " \"eps\": " << std::setprecision(17) << verification.eps << ",\n";
out << " \"predicate_decimal_digits\": " << WideReal::decimal_digits << ",\n";
out << " \"vertices\": " << verification.vertices << ",\n";
out << " \"edges\": " << verification.edges << ",\n";
out << " \"faces\": " << verification.faces << ",\n";
out << " \"euler\": " << verification.euler << ",\n";
out << " \"genus\": " << verification.genus << ",\n";
out << " \"finite\": " << (verification.finite ? "true" : "false") << ",\n";
out << " \"geometry_scale\": " << verification.geometry_scale << ",\n";
out << " \"min_edge_length\": " << verification.min_edge_length << ",\n";
out << " \"max_planarity_residual\": " << verification.max_planarity_residual << ",\n";
out << " \"strict_self_crossings\": " << verification.crossings.size() << ",\n";
out << " \"strict_edge_face_intersections\": " << verification.intersections.size() << ",\n";
out << " \"original_count_crossings\": " << verification.original_crossings << ",\n";
out << " \"original_count_intersections\": " << verification.original_intersections << ",\n";
out << " \"ok\": " << (is_ok(verification) ? "true" : "false") << ",\n";
out << " \"self_crossings\": [\n";
for (size_t i = 0; i < verification.crossings.size(); ++i) {
const Crossing& crossing = verification.crossings[i];
out << " {\"face0\": " << crossing.face
<< ", \"face1\": " << crossing.face + 1
<< ", \"edge_a_obj\": [" << crossing.edge_a.first + 1 << ", " << crossing.edge_a.second + 1 << "]"
<< ", \"edge_b_obj\": [" << crossing.edge_b.first + 1 << ", " << crossing.edge_b.second + 1 << "]"
<< ", \"t\": " << crossing.t
<< ", \"u\": " << crossing.u << "}";
out << (i + 1 == verification.crossings.size() ? "\n" : ",\n");
}
out << " ],\n";
out << " \"edge_face_intersections\": [\n";
for (size_t i = 0; i < verification.intersections.size(); ++i) {
const EdgeFaceIntersection& hit = verification.intersections[i];
out << " {\"edge_obj\": [" << hit.edge.first + 1 << ", " << hit.edge.second + 1 << "]"
<< ", \"face0\": " << hit.face
<< ", \"face1\": " << hit.face + 1
<< ", \"t\": " << hit.t
<< ", \"on_boundary\": " << (hit.on_boundary ? "true" : "false") << "}";
out << (i + 1 == verification.intersections.size() ? "\n" : ",\n");
}
out << " ]\n";
out << "}\n";
return out.str();
}
void write_text_file(const std::string& path, const std::string& contents) {
if (path.empty()) {
return;
}
const std::filesystem::path output_path(path);
if (output_path.has_parent_path()) {
std::filesystem::create_directories(output_path.parent_path());
}
std::ofstream out(path);
out << contents;
}
} // namespace
int main(int argc, char** argv) {
if (!wide_real_self_test()) {
std::cerr << "WideReal self-test failed.\n";
return 3;
}
std::string obj_path = "data/shape_c2_i0_0.obj";
std::string report_path = "runtime/reports/00_baseline.md";
std::string json_path = "runtime/reports/baseline.json";
int topology = 4;
double eps = 1e-12;
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
if ((arg == "--obj" || arg == "-o") && i + 1 < argc) {
obj_path = argv[++i];
} else if ((arg == "--topology" || arg == "-t") && i + 1 < argc) {
topology = std::atoi(argv[++i]);
} else if (arg == "--eps" && i + 1 < argc) {
eps = (double)std::atof(argv[++i]);
} else if (arg == "--report" && i + 1 < argc) {
report_path = argv[++i];
} else if (arg == "--json" && i + 1 < argc) {
json_path = argv[++i];
} else {
std::cerr << "Usage: verify_cpp [--obj path] [--topology n] [--eps value] [--report path] [--json path]\n";
return 2;
}
}
const Verification verification = verify_obj(obj_path, topology, eps);
const std::string markdown = render_markdown(verification);
const std::string json = render_json(verification);
write_text_file(report_path, markdown);
write_text_file(json_path, json);
std::cout << markdown;
return is_ok(verification) ? 0 : 1;
}