Я пытаюсь реализовать алгоритм преобразования расстояния Мейстера в Halide. Я уже переписал этот код на C ++ (с использованием openCV), и он работает нормально. Статья об этом алгоритме Вот. Прямо сейчас мой галоидный код выполнен на 50% — первая фаза работает нормально, теперь у меня проблема с фазой 2 (сканирование 3 в связанном коде), которая (упрощенно) выглядит следующим образом:
//g is 2 dimensional cv::Mat (something like array) - result of previous stage
// m is g.width and n is g.height
int(*functionF)(int x, int i, int g_i) = EDT_f;
int(*functionSep)(int i, int u, int g_i, int g_u, int max_value) = EDT_Sep;
cv::Mat dt = cv::Mat(n, m, CV_32SC1);
int* s = new int[m];
int* t = new int[m];
int q = 0, w;
for (int y = 0; y<n; y++)
{
q = 0;
s[0] = 0;
t[0] = 0;
// Scan 3
for (int u = 1; u<m; u++)
{
//how can i replace this loop:
while (q >= 0 && functionF(t[q], s[q], g.at<int>(y, s[q])) > functionF(t[q], u, g.at<int>(y, u)))
q--;
//some operations which might change value of q, s[] and t[]
}
// Scan 4 - not important here
}
Есть ли галогенид-дружеский способ заменить это время цикла? Прямо сейчас единственное решение, к которому я пришел, это что-то вроде этого (еще не проверено):
Expr calculateQ(Expr currentQValue, Expr y, Func t, Func s, Func g)
{
//while (q >= 0 && functionF(t[q], s[q], g.at<int>(y, s[q])) > functionF(t[q], u, g.at<int>(y, u)))
//q--;
return select(currentQValue >= 0 && functionF(t[q], s[q], g[s[q], y]) > functionF(t[q], u, g[u, y]), calculateQ(currentQValue - 1, y, t, s, g), currentQValue);
}
но даже если это сработает, скорее всего, halide попытается оценить оба значения select, прежде чем проверять условие, и рекурсия сделает его очень медленным.
Если нет способа реализовать цикл while в Halide, есть ли способ просто использовать некоторую часть вашего кода внутри Halide? Есть другие идеи?
Вы правы, заметив, что не совсем понятно, как выразить динамически завершающийся (while) цикл — их сейчас невозможно выразить в чистом Halide! Это может измениться в (неопределенном, долгосрочном) будущем, но добавление их сделает цикл программ Halide Turing-complete; без них мы всегда можем проанализировать границы ваших циклов, но мы их, мы столкнемся с проблемой остановки.
Впрочем, для такого рода вещей существует аварийный люк: вы можете вызывать внешние функции (реализованные в C или как угодно) из конвейера Halide. Интерфейс к функции extern выглядит так же, как интерфейс к скомпилированному конвейеру (он принимает скалярные и буферные аргументы, при этом конечный буфер является выходным, и при вызове с нулевыми буферами он должен вычислять границы, требуемые для его входных данных, с учетом границ запрашивается его вывод). Проверьте extern_*
тестовые программы для некоторых примеров, например, https://github.com/halide/Halide/blob/master/test/correctness/extern_stage.cpp. Быстро взглянув на ваш код, я считаю, что он должен быть легко реализован на внешнем этапе с использованием уже имеющегося кода на языке Си
Других решений пока нет …