Существует ли парадигма для составления функций «инкрементного обновления» в стиле чистого потока данных?


10

Я не знаю правильной терминологии для того, чтобы задать этот вопрос, поэтому вместо этого я опишу его множеством слов, потерпите меня.

Фон , просто так, что мы находимся на одной странице: программы часто содержат кэши - компромисс между временем и памятью. Распространенная ошибка программиста - забыть обновить кэшированное значение после изменения одного из его исходных источников / прецедентов. Но парадигма потока данных или FRP не застрахована от таких ошибок. Если у нас есть несколько чистых функций, и мы соединяем их вместе в ориентированном графе зависимостей, то узлы могут кэшировать свое выходное значение и использовать его повторно, пока не изменится какой-либо из входов функции. Эта системная архитектура описана в статье Кэширование в средах на основе потоков данных, и на императивном языке она более или менее аналогична запоминанию.

Проблема : Когда один из входных данных функции изменяется, нам все равно приходится выполнять функцию целиком, отбрасывая ее кэшированные выходные данные и пересчитывая заново. Во многих случаях это кажется мне расточительным. Рассмотрим простой пример, который генерирует список «5 лучших». Входные данные представляют собой несортированный список чего угодно. Он передается в качестве входных данных в функцию, которая выводит отсортированный список. Который, в свою очередь, является входом для функции, которая принимает только первые 5 элементов. В псевдокоде:

input = [5, 20, 7, 2, 4, 9, 6, 13, 1, 45]
intermediate = sort(input)
final_output = substring(intermediate, 0, 5)

Сложность функции сортировки составляет O (N log N). Но учтите, что этот поток используется в приложении, в котором входные данные изменяются лишь незначительно, добавляя 1 элемент. Вместо того, чтобы каждый раз заново сортировать с нуля, на самом деле было бы быстрее, фактически O (N), использовать функцию, которая обновляет старый кэшированный отсортированный список, вставляя новый элемент в правильную позицию. Это только один пример - многие функции «с нуля» имеют такие «инкрементные обновления». Кроме того, возможно, новый элемент даже не появится в final_output, потому что он находится после 5-й позиции.

Моя интуиция предполагает, что можно было бы каким-то образом добавить такие функции «инкрементного обновления» в систему потока данных, бок о бок с существующими функциями «с нуля». Конечно, перерасчет всего с нуля всегда должен давать тот же результат, что и набор дополнительных обновлений. Система должна обладать свойством, что если каждая из отдельных примитивных пар FromScratch-Incremental всегда дает один и тот же результат, то большие составные функции, построенные из них, также должны автоматически давать тот же результат.

Вопрос : возможно ли иметь систему / архитектуру / парадигму / мета-алгоритм, которая может поддерживать как функции FromScratch, так и их инкрементные аналоги, сотрудничая для повышения эффективности и объединяясь в большие потоки? Если нет, то почему? Если кто-то уже исследовал эту парадигму и опубликовал ее, как она называется, и могу ли я получить краткое описание того, как она работает?


Кстати, в конкретном случае вашего примера, еще более эффективным решением будет использование кучи . Вставка элемента теперь просто , а генерация обновленного отсортированного списка верхних значений теперь просто . O(logn)kO(klogn)
j_random_hacker

Ответы:


7

Это поле было изобретено много раз и имеет множество имен, таких как:

(И, возможно, больше.) Это не то же самое, но связано.

Перефразируя Cai et al. (1): Есть два основных способа общей реализации онлайн-алгоритмов (т.е. без ссылки на какую-либо конкретную алгоритмическую проблему):

  • Статическая инкрементация. Статические подходы анализируют программу во время компиляции и создают инкрементную версию, которая эффективно обновляет выходные данные исходной программы в соответствии с изменяющимися входными данными. Статические подходы могут быть более эффективными, чем динамические, потому что не требуется никакой бухгалтерии во время выполнения. Кроме того, вычисленные инкрементные версии часто могут быть оптимизированы с использованием стандартных методов компиляции, таких как постоянное свертывание или вставка. Этот подход исследован в (1).

  • Динамическая инкрементация. Динамические подходы создают динамические графы зависимостей во время работы программы и распространяют изменения вдоль этих графиков. Наиболее известный подход - это самонастраивающиеся вычисления Акара., Основная идея проста: программы выполняются на исходном вводе в расширенной среде выполнения, которая отслеживает зависимости между значениями в динамическом графе зависимостей; промежуточные результаты кэшируются. (Как вы можете себе представить, это имеет тенденцию использовать много памяти, и многие исследования в этой области посвящены тому, как ограничить использование памяти.) Позже, изменения во входных данных распространяются через графы зависимостей от измененных входных данных до результатов, обновляя как промежуточные, так и промежуточные данные. окончательные результаты; эта обработка часто более эффективна, чем пересчет. Однако создание графиков динамической зависимости накладывает большие накладные расходы постоянного фактора во время выполнения, варьируясь от 2 до 30 в сообщаемых экспериментах.

Кроме того, всегда можно попробовать «вручную» найти онлайн-версию данного алгоритма. Это может быть сложно.


(1) Y. Cai, PG Giarrusso, T. Rendel, K. Ostermann, Теория изменений для языков высшего порядка: увеличение λ-исчисления статическим дифференцированием .


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.