#include "pch.h" static __declspec(noalias) __for...

Created on: September 18, 2025

Answered using GPT-5 by Chat01

Question

#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;

text
while (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;

text
while (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;

text
while (_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;

text
std::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;
}
}
}

text
if (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
{

text
if (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;
}
}
}

text
if (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);
}
}

text
R.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;
}
}
}

text
if (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);
}
}

text
R.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()); - перемещение в этом месте и.т.д., в целом ты должен использовать подход уже оптимизированной одномерной ветки но для двумерного случая

Thought

Updating the 2D branch

We need to adapt the 2D branch code to align with the new signature of Base_LNA_1_2_Mer_AGP. It'll involve using floats instead of uint32_t, unique_ptr<Interval> vectors for R, and storing results in a vector of floats. We also need to integrate heap optimization strategies like move semantics, and make changes to handle interactions with MPI communicator and existing 2D functions like PeanoCurve_2D.

Ensuring Type Alignment in 2D

We need to make sure that types match up with earlier code—previously, uint32_t counters were used, but now we’re relying on floats for things like N, global_iterations, and epsilon. For the 2D branch, we’ll also adjust how the result is returned, ensuring that things like schetchick and dmin are handled in the same order as the 1D case.

Harmonizing Exit Logic for 2D

To mirror the 1D branch, we should push schetchick first, then interval_length or dmin at termination. In the old 2D, they pushed the interval_length or length in different cases, but we will aim to follow 1D style for consistency. We'll also adjust the type of global_iterations to a float, handle float comparisons properly, and switch to unique_ptr<Interval> R to match new code practices. We’ll modify heap operations accordingly.

Emulating 1D Logic in 2D

We need to mirror the 1D approach with std::pop_heap and the way it uses unique_ptr<Interval>. After processing, we’ll track schetchick as a float and handle float increments, even though it's not ideal—it keeps consistency with the new 1D style. Additionally, we’ll optimize with things like direct initialization and const refs.

Thought for 50s

Answer

ниже — готовая «двумерная» ветка, подогнанная под вашу новую сигнатуру экспортируемой функции (типы-параметры 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-кода). Одномерную ветку не трогаем.

cpp
else { // ===== Параметры и подготовка ===== // Приводим «счётчики» к целым локально, но внешняя сигнатура остаётся 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 }; } }

Что я улучшил по стилю и скоростям (и почему это ближе к 1D-ветке)

  1. Контейнер кучи — 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-ветки и уменьшает ребалансировки.

  2. Константные ссылки на top
    const std::unique_ptr<Interval>& top = R.front(); и topL — избавляет от копий уникальных указателей и повторных обращений.

  3. Прямая инициализация пар/структур
    std::pair<float,float>{...} и агрегатная инициализация CrossMsg — без временных и присваиваний.

  4. Единообразие завершения/упаковки результата
    • Как в новой 1D-ветке: сначала schetchick, потом текущая «мелкость» интервала; затем CoTaskMemAlloc+memcpy и return.

  5. Меньше ветвлений на горячем пути
    • Быстрые локальные вычисления len1/len2/r_size до итераций по куче.
    • Обновление dmax одним проходом с минимальной логикой.

  6. Плавающий счётчик + fmodf (совместимость со стилем 1D)
    • Условие «тика» переписано на fmodf, чтобы без % по float, при этом полностью повторяет логику (!(schetchick % T) == mcQueenSpeed).


Ещё идеи для ускорения (точечные, без изменения интерфейса)

1) Кэширование степени и корня в 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 (обновляя её только при создании).

2) Хранить «длину по x» прямо в Interval

Часто считаем end.first - start.first. Добавьте поле dx и инициализируйте в конструкторе, обновляя только при создании:

cpp
struct 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.

3) Уменьшить частоту std::make_heap при «глобальной подстройке»

Сейчас, как и в 1D, вы перестраиваете кучу после массового изменения R[i]. Можно сделать «ленивую отметку» (флаг dirty) и перестраивать кучу лишь перед тем местом, где критично правильное R.front() (например, сразу перед следующим pop_heap). Это экономит перестройки, если «подстройки» встречаются пачками.

4) Схема приёма MPI: батчинг

Вместо разового iprobe в каждой итерации можно делать батч: если нет трафика — пропускать несколько итераций (например, через счётчик локальных шагов). Простая версия:

cpp
if ((uint32_t)schetchick % 4u == 0u) { if (auto s = world.iprobe(partner, boost::mpi::any_tag)) { /* ... */ } }

Это снижает накладные расходы MPI на плотных вычислениях.

5) Интринсики для «мелкой математики»

Вы активно используете fmaf — это хорошо. Для fabsf/max/min на массиве интервалов можно попробовать SIMD-путь (например, AVX2) при массовой «подстройке» R[i]->ChangeCharacteristic(...). Но это уже более тяжёлая рефакторизация (структура-SOA и т.д.), поэтому оставляю как опциональное.

6) Быстрый выход при «стабильности» экстремума

Если несколько итераций подряд best_f не улучшается и interval_len падает медленно, можно вводить адаптивное увеличение периода «тиков» (переменная T) чуть агрессивнее, что снижает межпроцессные синхронизации. Например, линейно увеличить T до минимума/максимума, исходя из progress.


если хотите, могу сделать аккуратный дифф-патч под ваш текущий файл, чтобы было удобно применить правки к ветке N != 1.0f и не задеть 1D-код.

Share this Q&A