#include "pch.h" static __declspec(noalias) __for...
Erstellt am: 18. September 2025
Erstellt am: 18. September 2025
#include "pch.h"
static __declspec(noalias) __forceinline float LCG_rand(double& __restrict state) noexcept
{
if (!state) {
state = GetTickCount();
}
state = std::fma(state, 1.618033988749895, state * 0.5772156649);
state -= std::floor(state);
state = std::fma(state, state + 1.0, 0.0);
state -= std::floor(state);
return state;
}
static __declspec(noalias) __forceinline float ShekelFunc(const float x, const double seed) noexcept
{
uint64_t i = 0u;
double current_state = seed;
float res = 0.0f;
textwhile (i < 10u) { const float x_part = fmaf(-LCG_rand(current_state), 10.0f, x); float delimiter = fmaf(fmaf(LCG_rand(current_state), 20.0f, 5.0f), x_part * x_part, fmaf(LCG_rand(current_state), 0.2f, 1.0f)); delimiter = copysignf(fmaxf(fabsf(delimiter), FLT_MIN), delimiter); res -= 1.0f / delimiter; ++i; } return res;
}
static __declspec(noalias) __forceinline float RastriginFunc(const float x1, const float x2) noexcept
{
const float term1 = fmaf(x1, x1, x2 * x2);
return (term1 - fmaf(
fabe13_cos(6.28318530717958647692f * x1) +
fabe13_cos(6.28318530717958647692f * x2),
10.0f,
-14.6f)) *
fmaf(-term1, 0.25f, 18.42f);
}
static __declspec(noalias) __forceinline float Shag(const float _m, const float x1, const float x2, const float y1,
const float y2, const uint64_t _N, const float _r) noexcept
{
const float diff = y2 - y1;
return _N == 1u
? fmaf(-(1.0f / _m), diff, x1 + x2) * 0.5f
: _N == 2u
? diff > 0.0f
? fmaf(-(1.0f / (_m * _m)), (diff) * (diff)_r, x1 + x2) * 0.5f
: fmaf(1.0f / (_m * _m), (diff) * (diff)_r, x1 + x2) * 0.5f
: diff > 0.0f
? fmaf(-(1.0f / powf(_m, _N)), powf(diff, _N) * _r, x1 + x2) * 0.5f
: fmaf(1.0f / powf(_m, _N), powf(diff, _N) * _r, x1 + x2) * 0.5f;
}
__declspec(align(16u)) struct Interval final {
public:
float M;
float R;
std::pair<float, float> start;
std::pair<float, float> end;
text__declspec(noalias) __forceinline Interval(const std::pair<float, float> _start, const std::pair<float, float> _end, const uint64_t _N) noexcept : start(_start) , end(_end) , M(_N == 1u ? fabsf(_end.second - _start.second) * (1.0f / (_end.first - _start.first)) : _N == 2u ? fabsf(_end.second - _start.second) * (1.0f / sqrtf(_end.first - _start.first)) : fabsf(_end.second - _start.second) * (1.0f / powf(_end.first - _start.first, 1.0f / _N))) { } __declspec(noalias) __forceinline void ChangeCharacteristic(const float _m, const uint64_t _N) noexcept { const float delta_x = end.first - start.first; const float delta_y = end.second - start.second; switch (_N) { case 1u: R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, delta_x, (delta_y * delta_y) * (1.0f / (_m * delta_x)))); return; case 2u: const float sqrt_dx = sqrtf(delta_x); R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, sqrt_dx, (delta_y * delta_y) * (1.0f / (_m * sqrt_dx)))); return; } const float pow_dx = powf(delta_x, 1.0f / _N); R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, pow_dx, (delta_y * delta_y) * (1.0f / (_m * pow_dx)))); }
};
static __forceinline bool Compare(const Interval& a, const Interval& b) noexcept
{
return a.R < b.R;
}
const enum List : uint8_t {
Top = 0b00,
Down = 0b01,
Left = 0b10,
Right = 0b11
};
__declspec(align(64u)) struct PeanoCurve_2D final {
public:
const List Type;
const uint64_t razvertka;
const float a;
const float b;
const float c;
const float d;
const float x1;
const float x2;
std::unique_ptr<PeanoCurve_2D> DownLeft;
std::unique_ptr<PeanoCurve_2D> TopLeft;
std::unique_ptr<PeanoCurve_2D> TopRight;
std::unique_ptr<PeanoCurve_2D> DownRight;
text__declspec(noalias) __forceinline PeanoCurve_2D( const List _Type, uint64_t _razvertka, const float _a, const float _b, const float _c, const float _d) noexcept : Type(_Type), razvertka(_razvertka), a(_a), b(_b), c(_c), d(_d), x1(fmaf(0.5f, _a, 0.5f * _b)), x2(fmaf(0.5f, _c, 0.5f * _d)) { if (_razvertka-- != 0u) { if (_razvertka > 8u) { switch (_Type) { case Top: tbb::parallel_invoke( [&]() { DownLeft = std::make_unique<PeanoCurve_2D>(Right, _razvertka, _a, x1, _c, x2); }, [&]() { TopLeft = std::make_unique<PeanoCurve_2D>(Top, _razvertka, _a, x1, x2, _d); }, [&]() { TopRight = std::make_unique<PeanoCurve_2D>(Top, _razvertka, x1, _b, x2, _d); }, [&]() { DownRight = std::make_unique<PeanoCurve_2D>(Left, _razvertka, x1, _b, _c, x2); } ); break; case Down: tbb::parallel_invoke( [&]() { TopRight = std::make_unique<PeanoCurve_2D>(Left, _razvertka, x1, _b, x2, _d); }, [&]() { DownRight = std::make_unique<PeanoCurve_2D>(Down, _razvertka, x1, _b, _c, x2); }, [&]() { DownLeft = std::make_unique<PeanoCurve_2D>(Down, _razvertka, _a, x1, _c, x2); }, [&]() { TopLeft = std::make_unique<PeanoCurve_2D>(Right, _razvertka, _a, x1, x2, _d); } ); break; case Right: tbb::parallel_invoke( [&]() { DownLeft = std::make_unique<PeanoCurve_2D>(Top, _razvertka, _a, x1, _c, x2); }, [&]() { DownRight = std::make_unique<PeanoCurve_2D>(Right, _razvertka, x1, _b, _c, x2); }, [&]() { TopRight = std::make_unique<PeanoCurve_2D>(Right, _razvertka, x1, _b, x2, _d); }, [&]() { TopLeft = std::make_unique<PeanoCurve_2D>(Down, _razvertka, _a, x1, x2, _d); } ); break; case Left: tbb::parallel_invoke( [&]() { TopRight = std::make_unique<PeanoCurve_2D>(Down, _razvertka, x1, _b, x2, _d); }, [&]() { TopLeft = std::make_unique<PeanoCurve_2D>(Left, _razvertka, _a, x1, x2, _d); }, [&]() { DownLeft = std::make_unique<PeanoCurve_2D>(Left, _razvertka, _a, x1, _c, x2); }, [&]() { DownRight = std::make_unique<PeanoCurve_2D>(Top, _razvertka, x1, _b, _c, x2); } ); } } else { switch (_Type) { case Top: DownLeft = std::make_unique<PeanoCurve_2D>(Right, _razvertka, _a, x1, _c, x2); TopLeft = std::make_unique<PeanoCurve_2D>(Top, _razvertka, _a, x1, x2, _d); TopRight = std::make_unique<PeanoCurve_2D>(Top, _razvertka, x1, _b, x2, _d); DownRight = std::make_unique<PeanoCurve_2D>(Left, _razvertka, x1, _b, _c, x2); break; case Down: TopRight = std::make_unique<PeanoCurve_2D>(Left, _razvertka, x1, _b, x2, _d); DownRight = std::make_unique<PeanoCurve_2D>(Down, _razvertka, x1, _b, _c, x2); DownLeft = std::make_unique<PeanoCurve_2D>(Down, _razvertka, _a, x1, _c, x2); TopLeft = std::make_unique<PeanoCurve_2D>(Right, _razvertka, _a, x1, x2, _d); break; case Right: DownLeft = std::make_unique<PeanoCurve_2D>(Top, _razvertka, _a, x1, _c, x2); DownRight = std::make_unique<PeanoCurve_2D>(Right, _razvertka, x1, _b, _c, x2); TopRight = std::make_unique<PeanoCurve_2D>(Right, _razvertka, x1, _b, x2, _d); TopLeft = std::make_unique<PeanoCurve_2D>(Down, _razvertka, _a, x1, x2, _d); break; case Left: TopRight = std::make_unique<PeanoCurve_2D>(Down, _razvertka, x1, _b, x2, _d); TopLeft = std::make_unique<PeanoCurve_2D>(Left, _razvertka, _a, x1, x2, _d); DownLeft = std::make_unique<PeanoCurve_2D>(Left, _razvertka, _a, x1, _c, x2); DownRight = std::make_unique<PeanoCurve_2D>(Top, _razvertka, x1, _b, _c, x2); } } } }
const __declspec(noalias) __forceinline PeanoCurve_2D* PeanoCurve_2D::HitTest_2D(float x) const noexcept
{
uint64_t i = 0u;
const uint64_t _razvertka = this->razvertka;
uint64_t num;
const float this_a = this->a;
x -= this_a;
const float b_minus_a = this->b - this_a;
const float inv_b_minus_a = 1.0f / b_minus_a;
const PeanoCurve_2D* Curr = this;
textwhile (i != _razvertka) { const uint64_t shift = 1u << ++i + i; num = shift * x * inv_b_minus_a; x = fmaf(-ldexp(1.0f, -(i << 1)) * num, b_minus_a, x); const List currType = Curr->Type; switch (num) { case 0u: Curr = (currType == Top || currType == Right) ? Curr->DownLeft.get() : Curr->TopRight.get(); break; case 1u: Curr = (currType == Top || currType == Left) ? Curr->TopLeft.get() : Curr->DownRight.get(); break; case 2u: Curr = (currType == Top || currType == Right) ? Curr->TopRight.get() : Curr->DownLeft.get(); break; default: Curr = (currType == Top || currType == Left) ? Curr->DownRight.get() : Curr->TopLeft.get(); } } return Curr;
}
const __declspec(noalias) __forceinline float PeanoCurve_2D::FindX_2D(const float target_x1, const float target_x2) const noexcept
{
uint64_t _razvertka = this->razvertka;
uint64_t _razvertka1 = _razvertka;
float x1, x2, x = this->a;
const float b_minus_a = this->b - x;
const PeanoCurve_2D* Curr = this;
textwhile (_razvertka != 0u) { const uint64_t exponent = _razvertka1 - _razvertka-- << 1u; x1 = Curr->x1; x2 = Curr->x2; const List currType = Curr->Type; if (target_x1 > x1 && target_x2 > x2) { Curr = Curr->TopRight.get(); if (currType == Top || currType == Right) { x = fmaf(ldexp(1.0f, -exponent) * 0.5f, b_minus_a, x); } } else if (target_x1 < x1 && target_x2 > x2) { Curr = Curr->TopLeft.get(); if (currType == Top || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.25f, b_minus_a, x); } else { x = fmaf(ldexp(1.0f, -exponent) * 0.75f, b_minus_a, x); } } else if (target_x1 < x1 && target_x2 < x2) { Curr = Curr->DownLeft.get(); if (currType == Down || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.5f, b_minus_a, x); } } else { Curr = Curr->DownRight.get(); if (currType == Top || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.75f, b_minus_a, x); } else { x = fmaf(ldexp(1.0f, -exponent) * 0.25f, b_minus_a, x); } } } return x;
}
extern const boost::mpi::communicator world;
extern std::unique_ptr<PeanoCurve_2D> Curve;
extern std::unique_ptr<PeanoCurve_2D> Curve_Inverted;
__declspec(align(16u)) struct CrossMsg final {
float s_x1, s_x2;
float e_x1, e_x2;
float Rtop;
template <typename Archive>
__declspec(noalias) __forceinline void serialize(Archive& __restrict ar, const uint64_t) noexcept { ar& s_x1& s_x2& e_x1& e_x2& Rtop; }
};
static __declspec(noalias) __forceinline bool ComparePtr(const std::unique_ptr<Interval>& __restrict a, const std::unique_ptr<Interval>& __restrict b) noexcept
{
return a->R < b->R;
}
extern "C" __declspec(dllexport) __declspec(noalias) void Base_LNA_1_2_Mer_AGP(
const float N, const float global_iterations, const float a, const float b, const float c, const float d, const float r,
const bool mode, const float epsilon, const double seed,
float** out_data, uint64_t* out_len) noexcept
{
if (N == 1.0f) {
const float initial_length = b - a;
float dmax = initial_length;
const float start_val = ShekelFunc(a, seed);
float best_f = ShekelFunc(b, seed);
float schetchick = 0.0f;
textstd::pair<float, float> x_Rmax{ a, b }; std::pair<float, float> y_Rmax{ start_val, best_f }; std::vector<float> Extr; Extr.reserve(global_iterations * 4u); std::vector<std::unique_ptr<Interval>> R; R.reserve(global_iterations * 2u); // Создаем начальный интервал R.emplace_back(std::make_unique<Interval>(std::make_pair(a, start_val), std::make_pair(b, best_f), N)); float Mmax = R.front()->M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_length; const float inv_threshold_03 = 1.0f / threshold_03; while (true) { const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, N, r); const float new_value = ShekelFunc(new_point, seed); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } // Извлекаем максимальный интервал std::pop_heap(R.begin(), R.end(), ComparePtr); const std::unique_ptr<Interval> promejutochny_otrezok = std::move(R.back()); R.pop_back(); const size_t r_size = R.size(); const float len2 = promejutochny_otrezok->end.first - new_point; const float len1 = new_point - promejutochny_otrezok->start.first; const float dmin = len1 < len2 ? len1 : len2; // Условие завершения if (++schetchick == global_iterations || dmin < epsilon) { Extr.emplace_back(schetchick); Extr.emplace_back(dmin); // Копируем данные в выходной буфер *out_len = Extr.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, Extr.data(), sizeof(float) * (*out_len)); return; } // Создаем новые интервалы std::unique_ptr<Interval> curr = std::make_unique<Interval>(promejutochny_otrezok->start, promejutochnaya_tochka, N); std::unique_ptr<Interval> curr1 = std::make_unique<Interval>(promejutochnaya_tochka, promejutochny_otrezok->end, N); const float currM = curr->M > curr1->M ? curr->M : curr1->M; if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i]->end.first - R[i]->start.first;
if (len > dmax) {
dmax = len;
}
}
}
textif (mode) { if (threshold_03 > dmax && fmodf(schetchick, 3.0f) == 0.0f || 10.0f * dmax < initial_length) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr->M * alpha), N); curr1->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1->M * alpha), N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i]->end.first - R[i]->start.first;
R[i]->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i]->M * alpha), N);
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr->ChangeCharacteristic(m, N);
curr1->ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i]->ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
curr->ChangeCharacteristic(m, N);
curr1->ChangeCharacteristic(m, N);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr->ChangeCharacteristic(m, N);
curr1->ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i]->ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
curr->ChangeCharacteristic(m, N);
curr1->ChangeCharacteristic(m, N);
}
}
text// Добавляем новые интервалы R.emplace_back(std::move(curr)); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), ComparePtr); // Обновляем x_Rmax и y_Rmax const std::unique_ptr<Interval>& top = R.front(); x_Rmax = { top->start.first, top->end.first }; y_Rmax = { top->start.second, top->end.second }; } } // Для случая N != 1.0f *out_len = 0; *out_data = nullptr; return;
}
extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p) {
CoTaskMemFree(p); - это код основного .cpp файла моей чисто нативной c++ dll библиотеки, #include "pch.h"
const boost::mpi::environment mpi_env;
extern const boost::mpi::communicator world;
const boost::mpi::communicator world;
std::unique_ptr<PeanoCurve_2D> Curve;
std::unique_ptr<PeanoCurve_2D> Curve_Inverted;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
const int32_t rank = world.rank();
if (rank == 0u) {
Curve = std::make_unique<PeanoCurve_2D>(List::Top, 12u, -2.2f, 1.8f, -2.2f, 1.8f);
}
else if (rank == 1u) {
Curve_Inverted = std::make_unique<PeanoCurve_2D>(List::Down, 12u, -2.2f, 1.8f, -2.2f, 1.8f);
}
}
return TRUE;
} - это код файла dllmain.cpp, раньше основная функция не была экспортируемой а возвращала вектор и экспортировалась через c обёртку, раньше код основной функции был таким: static __declspec(noalias)std::vector<float> Base_LNA_1_2_Mer_AGP(const uint32_t N,
const uint32_t global_iterations, const float a, const float b, const float c, const float d, const float r,
const bool mode, const float epsilon, const float seed) noexcept
{
textif (N == 1u) { const float initial_length = b - a; float dmax = initial_length; const float start_val = ShekelFunc(a, seed); float best_f = ShekelFunc(b, seed); uint32_t schetchick = 0u; std::pair<float, float> x_Rmax = std::make_pair(a, b); std::pair<float, float> y_Rmax = std::make_pair(start_val, best_f); std::vector<float> Extr; Extr.reserve((global_iterations << 1u) + 4u); std::vector<Interval> R; R.reserve(global_iterations + 1u); Interval start_interval = Interval(std::make_pair(a, start_val), std::make_pair(b, best_f), N); R.push_back(start_interval); std::push_heap(R.begin(), R.end(), Compare); float Mmax = R.front().M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_length; const float inv_threshold_03 = 1.0f / threshold_03; while (true) { const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, N, r); const float new_value = ShekelFunc(new_point, seed); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } std::pop_heap(R.begin(), R.end(), Compare); Interval promejutochny_otrezok = R.back(); R.pop_back(); const size_t r_size = R.size(); const float len2 = promejutochny_otrezok.end.first - new_point; const float len1 = new_point - promejutochny_otrezok.start.first; const float dmin = len1 < len2 ? len1 : len2; if (++schetchick == global_iterations || dmin < epsilon) { Extr.emplace_back(dmin); Extr.emplace_back(schetchick); return Extr; } Interval curr(promejutochny_otrezok.start, promejutochnaya_tochka, N); Interval curr1(promejutochnaya_tochka, promejutochny_otrezok.end, N); const float currM = curr.M > curr1.M ? curr.M : curr1.M; if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i].end.first - R[i].start.first;
if (len > dmax) {
dmax = len;
}
}
}
textif (mode) { if (threshold_03 > dmax && schetchick % 3u == 0u || 10.0f * dmax < initial_length) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr.M * alpha), N); curr1.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1.M * alpha), N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i].end.first - R[i].start.first;
R[i].ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i].M * alpha), N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
textR.push_back(curr); std::push_heap(R.begin(), R.end(), Compare); R.push_back(curr1); std::push_heap(R.begin(), R.end(), Compare); const Interval& top = R.front(); x_Rmax = std::make_pair(top.start.first, top.end.first); y_Rmax = std::make_pair(top.start.second, top.end.second); } } else { const float divider = 1u << (2u * Curve_Inverted->razvertka + 1u); const float inv_divider = 1.0f / divider; const float x_addition = (b - a) * inv_divider; const float y_addition = (d - c) * inv_divider; const float true_start = a + x_addition; const float true_end = b - x_addition; const float initial_length = true_end - true_start; float dmax = initial_length; const int rank = world.rank(); const int partner = rank ^ 1; const PeanoCurve_2D* __restrict LocCurve = rank ? Curve_Inverted.get() : Curve.get(); const float end_val = rank ? RastriginFunc(true_end, d - y_addition) : RastriginFunc(true_start, c + y_addition); float best_f = rank ? RastriginFunc(true_start, d - y_addition) : RastriginFunc(true_end, c + y_addition); uint32_t schetchick = 0u; uint32_t mcQueenSpeed = 1u; std::pair<float, float> x_Rmax = std::make_pair(true_start, true_end); std::pair<float, float> y_Rmax = std::make_pair(end_val, best_f); std::vector<float> Extr; Extr.reserve(global_iterations * 3u + 4u); std::vector<Interval> R; R.reserve(global_iterations + 1u); R.emplace_back(std::make_pair(true_start, end_val), std::make_pair(true_end, best_f), N); float Mmax = R.front().M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_length; const float inv_threshold_03 = 1.0f / threshold_03; while (true) { boost::optional<boost::mpi::status> status = world.iprobe(partner, boost::mpi::any_tag); if (status) { int tag = status->tag(); if (tag == 0) { world.recv(partner, 0, mcQueenSpeed); } else if (tag == 2) { uint32_t received_flag = 0u; world.recv(partner, 2, received_flag); if (received_flag) break; } } if (++schetchick == global_iterations) { const Interval& front = R.front(); Extr.emplace_back(front.end.first - front.start.first); Extr.emplace_back(global_iterations); world.send(partner, 2, 1u); break; } float cooling = ldexp(1.0f, -schetchick * (1.0f / 138.63f)); const uint32_t T = fmaf(20.0f, cooling, 10.0f); const float k = fmaf(0.2f, cooling, 0.7f); if (!(schetchick % T) == mcQueenSpeed) { const Interval& topL = R.front(); const PeanoCurve_2D* __restrict p1L = LocCurve->HitTest_2D(topL.start.first); const PeanoCurve_2D* __restrict p2L = LocCurve->HitTest_2D(topL.end.first); const CrossMsg outbound{ p1L->x1, p1L->x2, p2L->x1, p2L->x2, topL.R }; CrossMsg inbound{}; if (mcQueenSpeed) { world.send(partner, 0, uint32_t{ 0u }); } else { mcQueenSpeed = 1u; } world.sendrecv(partner, 1, outbound, partner, 1, inbound); const float newParam1_remote = LocCurve->FindX_2D(inbound.s_x1, inbound.s_x2); const float newParam2_remote = LocCurve->FindX_2D(inbound.e_x1, inbound.e_x2); const std::pair<float, float> newStart_remote(newParam1_remote, RastriginFunc(inbound.s_x1, inbound.s_x2)); const std::pair<float, float> newEnd_remote(newParam2_remote, RastriginFunc(inbound.e_x1, inbound.e_x2)); Interval injected(newStart_remote, newEnd_remote, N); injected.R = inbound.Rtop * k; R.emplace_back(std::move(injected)); std::push_heap(R.begin(), R.end(), Compare); } const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, N, r); const PeanoCurve_2D* pc = LocCurve->HitTest_2D(new_point); const float new_x1 = pc->x1; const float new_x2 = pc->x2; const float new_value = RastriginFunc(new_x1, new_x2); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_x1); Extr.emplace_back(new_x2); } std::pop_heap(R.begin(), R.end(), Compare); Interval promejutochny_otrezok = std::move(R.back()); R.pop_back(); Interval curr(promejutochny_otrezok.start, promejutochnaya_tochka, N); Interval curr1(promejutochnaya_tochka, promejutochny_otrezok.end, N); const float currM = curr.M > curr1.M ? curr.M : curr1.M; const float len2 = promejutochny_otrezok.end.first - new_point; const float len1 = new_point - promejutochny_otrezok.start.first; const size_t r_size = R.size(); if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i].end.first - R[i].start.first;
if (len > dmax) {
dmax = len;
}
}
}
textif (mode) { if (threshold_03 > dmax && schetchick % 3u == 0u || 10.0f * dmax < initial_length) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr.M * alpha), N); curr1.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1.M * alpha), N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i].end.first - R[i].start.first;
R[i].ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i].M * alpha), N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
textR.emplace_back(std::move(curr)); std::push_heap(R.begin(), R.end(), Compare); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), Compare); const Interval& top = R.front(); const float interval_length = top.end.first - top.start.first; if (interval_length < epsilon) { Extr.emplace_back(interval_length); Extr.emplace_back(schetchick); world.send(partner, 2, 1u); break; } x_Rmax = std::make_pair(top.start.first, top.end.first); y_Rmax = std::make_pair(top.start.second, top.end.second); } return Extr; }
}
} - обрати внимание на двумерную ветку, сейчас она удалена в актуальном коде, а здесь последняя оптимальная версия, но заметь что многие вещи изменились - теперь целые параметры принимаются как float, теперь используется вектор не интервалов а умных указателей на интервалы, теперь при выходе из главной функции происходит копирование в буфер - твоя задача - подогнать двумерную ветку под изменённую сигнатуру - чтобы теперь двумерная ветка удовлетворяла тем же основным правилам что и одномерная, причём заметь что код двумерной ветки уже довольно оптимальный - тебе не нужно сильно менять его - нужно лишь сделать чтобы он работал в новой сигнатуре основной функции - актуальную одномерную ветку менять запрещено. Полученный код двумерной ветки проанализируй на предмет возможных оптимизаций по скорости и напиши что ещё можно улучшить по скорости с примерами кода, также в двумерной ветке используй оптимизации из одномерной - например такие как перестроение кучи после того как положены два финальных curr, curr1, а не перестраивать кучу после каждого emplace_back, использование константной ссылки в одном месте чтобы избежать лишнего копирования, использование прямой инициализации для создания пар, const std::unique_ptr<Interval> promejutochny_otrezok = std::move(R.back()); - перемещение в этом месте и.т.д., в целом ты должен использовать подход уже оптимизированной одномерной ветки но для двумерного случая
ниже — готовая «двумерная» ветка, подогнанная под вашу новую сигнатуру экспортируемой функции (типы-параметры float
, контейнер std::vector<std::unique_ptr<Interval>>
, сбор результатов в Extr
и копирование в буфер через CoTaskMemAlloc
). Я сохранил алгоритм и обмен MPI из вашей “последней оптимальной” 2D-версии, но привёл стиль и микроприёмы к уже оптимизированной 1D-ветке: отложенная перестройка кучи, константные ссылки, прямые инициализации, аккуратные std::move
, единообразное завершение и упаковка результатов.
Вставьте этот фрагмент вместо заглушки
// Для случая N != 1.0f
внутриBase_LNA_1_2_Mer_AGP(...)
(веткаelse
после 1D-кода). Одномерную ветку не трогаем.
cppelse { // ===== Параметры и подготовка ===== // Приводим «счётчики» к целым локально, но внешняя сигнатура остаётся float const uint64_t raz = Curve_Inverted ? Curve_Inverted->razvertka : Curve->razvertka; // Делители для отступов по Пеано (как в исходнике, но всё в float) const float divider = float(1u << (2u * raz + 1u)); const float inv_divider = 1.0f / divider; const float x_addition = (b - a) * inv_divider; const float y_addition = (d - c) * inv_divider; const float true_start = a + x_addition; const float true_end = b - x_addition; const float initial_len = true_end - true_start; float dmax = initial_len; // MPI окружение const int rank = world.rank(); const int partner = rank ^ 1; // Выбор локальной кривой (как в исходнике) const PeanoCurve_2D* __restrict LocCurve = rank ? Curve_Inverted.get() : Curve.get(); // Граничные значения целевой функции (Rastrigin) в соответствии с исходником const float end_val = rank ? RastriginFunc(true_end, d - y_addition) : RastriginFunc(true_start, c + y_addition); float best_f = rank ? RastriginFunc(true_start, d - y_addition) : RastriginFunc(true_end, c + y_addition); // Счётчики — как в новой 1D-ветке: float (для fmodf) + отдельные целочисленные локальные float schetchick = 0.0f; uint32_t mcQueenSpeed = 1u; std::pair<float, float> x_Rmax{ true_start, true_end }; std::pair<float, float> y_Rmax{ end_val, best_f }; std::vector<float> Extr; Extr.reserve(size_t(global_iterations) * 3u + 4u); // ===== Куча интервалов (умные указатели, как в 1D-ветке) ===== std::vector<std::unique_ptr<Interval>> R; R.reserve(size_t(global_iterations) + 2u); // Прямые инициализации пар (избегаем лишних копий) R.emplace_back(std::make_unique<Interval>( std::make_pair(true_start, end_val), std::make_pair(true_end, best_f), /*_N*/ 2u // двумерная ветка )); float Mmax = R.front()->M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_len; const float inv_threshold_03 = 1.0f / threshold_03; // ===== Основной цикл ===== while (true) { // Неблокирующая проверка входящих MPI if (auto status = world.iprobe(partner, boost::mpi::any_tag)) { const int tag = status->tag(); if (tag == 0) { world.recv(partner, 0, mcQueenSpeed); } else if (tag == 2) { uint32_t received_flag = 0u; world.recv(partner, 2, received_flag); if (received_flag) { // Партнёр попросил завершиться: упакуем финальное состояние const std::unique_ptr<Interval>& front = R.front(); const float interval_len = front->end.first - front->start.first; Extr.emplace_back(schetchick); // как в новой 1D-ветке: сначала счётчик Extr.emplace_back(interval_len); // затем «текущая минимальная длина» *out_len = Extr.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, Extr.data(), sizeof(float) * (*out_len)); return; } } } // Порог по итерациям (единый стиль с 1D-веткой) if (++schetchick == global_iterations) { const std::unique_ptr<Interval>& front = R.front(); const float interval_len = front->end.first - front->start.first; Extr.emplace_back(schetchick); Extr.emplace_back(interval_len); // Сигналим партнёру о завершении world.send(partner, 2, 1u); *out_len = Extr.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, Extr.data(), sizeof(float) * (*out_len)); return; } // «Охлаждение» и период T (как в вашей 2D-версии) const float cooling = ldexpf(1.0f, int(-schetchick * (1.0f / 138.63f))); const uint32_t T = uint32_t(fmaf(20.0f, cooling, 10.0f)); const float k = fmaf(0.2f, cooling, 0.7f); // Условие «тика» через float-остаток (эквивалент !(schetchick % T) == mcQueenSpeed) const float Tf = float(T); const bool tick = (fmodf(schetchick, Tf) == 0.0f); if ((tick ? 1u : 0u) == mcQueenSpeed) { // Берём top без копирования (константная ссылка на уникальный указатель) const std::unique_ptr<Interval>& topL = R.front(); // HitTest для концов лучшего интервала const PeanoCurve_2D* __restrict p1L = LocCurve->HitTest_2D(topL->start.first); const PeanoCurve_2D* __restrict p2L = LocCurve->HitTest_2D(topL->end.first); const CrossMsg outbound{ p1L->x1, p1L->x2, p2L->x1, p2L->x2, topL->R }; CrossMsg inbound{}; if (mcQueenSpeed) { world.send(partner, 0, uint32_t{ 0u }); } else { mcQueenSpeed = 1u; } world.sendrecv(partner, 1, outbound, partner, 1, inbound); // Проекция удалённых точек обратно в параметр x по локальной кривой const float newParam1_remote = LocCurve->FindX_2D(inbound.s_x1, inbound.s_x2); const float newParam2_remote = LocCurve->FindX_2D(inbound.e_x1, inbound.e_x2); // Прямая инициализация пар, без лишних временных const std::pair<float,float> newStart_remote { newParam1_remote, RastriginFunc(inbound.s_x1, inbound.s_x2) }; const std::pair<float,float> newEnd_remote { newParam2_remote, RastriginFunc(inbound.e_x1, inbound.e_x2) }; // Вставляем «инъекцию» с пониженной характеристикой auto injected = std::make_unique<Interval>(newStart_remote, newEnd_remote, /*_N*/ 2u); injected->R = inbound.Rtop * k; R.emplace_back(std::move(injected)); std::push_heap(R.begin(), R.end(), ComparePtr); } // ===== Локальный шаг LNA в параметре кривой ===== const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, /*_N*/ 2u, r); // Координаты по кривой Пеано const PeanoCurve_2D* pc = LocCurve->HitTest_2D(new_point); const float new_x1 = pc->x1; const float new_x2 = pc->x2; const float new_value = RastriginFunc(new_x1, new_x2); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; // Обновление экстремумов (формат записи — как решено в 2D-ветке) if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_x1); Extr.emplace_back(new_x2); } // ===== Разбиение лучшего интервала ===== std::pop_heap(R.begin(), R.end(), ComparePtr); const std::unique_ptr<Interval> promejutochny_otrezok = std::move(R.back()); R.pop_back(); // Создаём подынтервалы с прямой инициализацией auto curr = std::make_unique<Interval>(promejutochny_otrezok->start, promejutochnaya_tochka, /*_N*/ 2u); auto curr1 = std::make_unique<Interval>(promejutochnaya_tochka, promejutochny_otrezok->end, /*_N*/ 2u); const float currM = (curr->M > curr1->M ? curr->M : curr1->M); const float len2 = promejutochny_otrezok->end.first - new_point; const float len1 = new_point - promejutochny_otrezok->start.first; const size_t r_size = R.size(); // Обновление dmax — один проход без лишних вызовов if (len2 + len1 == dmax) { dmax = (len2 > len1 ? len2 : len1); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { const float len = R[i]->end.first - R[i]->start.first; if (len > dmax) dmax = len; } } // ===== Перенастройка характеристик R (как в 1D-ветке, но для N=2) ===== if (mode) { if ((threshold_03 > dmax && fmodf(schetchick, 3.0f) == 0.0f) || (10.0f * dmax < initial_len)) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr ->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr ->M * alpha), /*_N*/ 2u); curr1->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1->M * alpha), /*_N*/ 2u); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { const float len_item = R[i]->end.first - R[i]->start.first; R[i]->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i]->M * alpha), /*_N*/ 2u); } std::make_heap(R.begin(), R.end(), ComparePtr); } else { if (currM > Mmax) { Mmax = currM; m = r * Mmax; curr ->ChangeCharacteristic(m, /*_N*/ 2u); curr1->ChangeCharacteristic(m, /*_N*/ 2u); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { R[i]->ChangeCharacteristic(m, /*_N*/ 2u); } std::make_heap(R.begin(), R.end(), ComparePtr); } else { curr ->ChangeCharacteristic(m, /*_N*/ 2u); curr1->ChangeCharacteristic(m, /*_N*/ 2u); } } } else { if (currM > Mmax) { Mmax = currM; m = r * Mmax; curr ->ChangeCharacteristic(m, /*_N*/ 2u); curr1->ChangeCharacteristic(m, /*_N*/ 2u); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { R[i]->ChangeCharacteristic(m, /*_N*/ 2u); } std::make_heap(R.begin(), R.end(), ComparePtr); } else { curr ->ChangeCharacteristic(m, /*_N*/ 2u); curr1->ChangeCharacteristic(m, /*_N*/ 2u); } } // ===== Добавление подынтервалов и единоразовая перестройка кучи ===== R.emplace_back(std::move(curr)); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), ComparePtr); // достаточно одного push_heap после двух вставок // Проверка критерия сходимости по «лучшему» интервалу const std::unique_ptr<Interval>& top = R.front(); const float interval_len = top->end.first - top->start.first; if (interval_len < epsilon) { Extr.emplace_back(schetchick); Extr.emplace_back(interval_len); world.send(partner, 2, 1u); *out_len = Extr.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, Extr.data(), sizeof(float) * (*out_len)); return; } // Обновляем x_Rmax и y_Rmax (константная ссылка на top, чтобы избежать копии) x_Rmax = { top->start.first, top->end.first }; y_Rmax = { top->start.second, top->end.second }; } }
Контейнер кучи — std::vector<std::unique_ptr<Interval>>
+ ComparePtr
• Вставки/изъятия сделаны через emplace_back
/std::move
, std::pop_heap
→ локальный const std::unique_ptr<Interval> promejutochny_otrezok = std::move(R.back());
→ R.pop_back();
без лишних копий.
• Отложенная перестройка: после изменения R[i]
вызываем std::make_heap
один раз; после добавления двух подынтервалов — один std::push_heap
. Это повторяет паттерн 1D-ветки и уменьшает ребалансировки.
Константные ссылки на top
• const std::unique_ptr<Interval>& top = R.front();
и topL
— избавляет от копий уникальных указателей и повторных обращений.
Прямая инициализация пар/структур
• std::pair<float,float>{...}
и агрегатная инициализация CrossMsg
— без временных и присваиваний.
Единообразие завершения/упаковки результата
• Как в новой 1D-ветке: сначала schetchick
, потом текущая «мелкость» интервала; затем CoTaskMemAlloc
+memcpy
и return
.
Меньше ветвлений на горячем пути
• Быстрые локальные вычисления len1/len2/r_size
до итераций по куче.
• Обновление dmax
одним проходом с минимальной логикой.
Плавающий счётчик + fmodf
(совместимость со стилем 1D)
• Условие «тика» переписано на fmodf
, чтобы без %
по float, при этом полностью повторяет логику (!(schetchick % T) == mcQueenSpeed)
.
Interval::ChangeCharacteristic
Сейчас каждый вызов для N=2
вычисляет sqrtf(delta_x)
. Это ок, но можно вынести из цикла один раз и передавать внутрь уже «готовый» масштаб — особенно когда вызывается для множества элементов:
cpp// Перед циклом: const float sqrt_dx_len1 = sqrtf(len1); const float sqrt_dx_len2 = sqrtf(len2); // Пример использования: curr ->ChangeCharacteristic_precomputed(m, /*inv_scale=*/1.0f/(m * sqrt_dx_len1), /*scale=*/m * sqrt_dx_len1); curr1->ChangeCharacteristic_precomputed(m, /*inv_scale=*/1.0f/(m * sqrt_dx_len2), /*scale=*/m * sqrt_dx_len2);
Где ChangeCharacteristic_precomputed(...)
— лёгкий inlined-вариант без повторного sqrtf
. Для элементов R[i]
можно заодно вычислять sqrtf
на лету один раз и переиспользовать, если хранить длину интервала внутри Interval
(обновляя её только при создании).
Interval
Часто считаем end.first - start.first
. Добавьте поле dx
и инициализируйте в конструкторе, обновляя только при создании:
cppstruct Interval { float M, R, dx, dy; std::pair<float,float> start, end; /* ... */ Interval(...): start(_start), end(_end), dx(_end.first - _start.first), dy(_end.second - _start.second), M( /* формула через dx */ ) {} void ChangeCharacteristic(float m, uint64_t N) noexcept { const float delta_x = dx; const float delta_y = dy; /* ... */ } };
Это убирает десятки обращений к памяти на hot-path.
std::make_heap
при «глобальной подстройке»Сейчас, как и в 1D, вы перестраиваете кучу после массового изменения R[i]
. Можно сделать «ленивую отметку» (флаг dirty) и перестраивать кучу лишь перед тем местом, где критично правильное R.front()
(например, сразу перед следующим pop_heap
). Это экономит перестройки, если «подстройки» встречаются пачками.
Вместо разового iprobe
в каждой итерации можно делать батч: если нет трафика — пропускать несколько итераций (например, через счётчик локальных шагов). Простая версия:
cppif ((uint32_t)schetchick % 4u == 0u) { if (auto s = world.iprobe(partner, boost::mpi::any_tag)) { /* ... */ } }
Это снижает накладные расходы MPI на плотных вычислениях.
Вы активно используете fmaf
— это хорошо. Для fabsf/max/min
на массиве интервалов можно попробовать SIMD-путь (например, AVX2) при массовой «подстройке» R[i]->ChangeCharacteristic(...)
. Но это уже более тяжёлая рефакторизация (структура-SOA и т.д.), поэтому оставляю как опциональное.
Если несколько итераций подряд best_f
не улучшается и interval_len
падает медленно, можно вводить адаптивное увеличение периода «тиков» (переменная T
) чуть агрессивнее, что снижает межпроцессные синхронизации. Например, линейно увеличить T до минимума/максимума, исходя из progress
.
если хотите, могу сделать аккуратный дифф-патч под ваш текущий файл, чтобы было удобно применить правки к ветке N != 1.0f
и не задеть 1D-код.