2016-12-12 24 views
1

Это вопрос о структуре карты, которая сохраняет память при тяжелых неразрушающих манипуляциях.Пространственная эффективная реализация неизменной карты в Prolog?

Контекст

Я пишу небольшую программу, в результате чего я произвожу «состояния» (которые только термины, содержащий данные) в предикате iterate/2 по какой-то логике, можно пренебречь для целей настоящего обсуждения ,

iterate/2 рекурсивно выступает в хвостовой рекурсивной манере. При каждом вызове iterate/2 генерирует больше состояний и должен эффективно проверять, было ли ранее обнаружено какое-либо состояние.

Число штатов, «ранее замеченных», может быть значительным (несколько десятков тысяч). Тем не менее, нам разрешено время от времени «забывать о» (жирный процент) ранее замеченных записей. Это хорошо, так как мы можем надеяться сохранить общие требования к памяти в пределах границ.

Для эффективного выполнения «ранее увиденного» предиката интерфейс «карты», поддерживаемый соответствующей реализацией, кажется хорошим выбором (потому что можно эффективно реализовать поиск в картах).

Предположим, что у нас есть такая структура данных карты.

  • Для любого вновь сгенерированного состояния вычислите значение хэша (любыми средствами) из указанного состояния и вставьте пару (хеш, состояние) как (ключ, значение) в карту.
  • Чтобы проверить, было ли ранее обнаружено состояние, вычислите его значение хеша и проверьте, существует ли запись, соответствующая этому хеш-значению на карте. (Для этого упражнения мы пренебрегаем возможность хэш столкновений)

Когда-либо другая карта структура данных затем передается между сеансами iterate.

Это логический язык программирования, мы хотим сохранить общую идею работы в вечном математическом пространстве всех возможных структур, не подлежащих определению, где мы переходим от одной структуры к другой, как обезьяна, качающаяся с вино, вместо того, чтобы постоянно мутировать изменяющуюся во времени структуру данных, как и в императивном программировании. Мы просто надеемся, что сборщик мусора быстрее, чем мы!

Картографические связанные предикаты, которые мы предлагаем может быть:

map_new(?Map) 

... унифицировать карту с пустой картой.

map_get(+Map,+Key,?Val) 

... унифицировать Вал со значением, связанным с ключом Key в карте Карте или потерпеть неудачу, если карта не содержит такое ключ (Key, позволяя быть переменным, можно осуществить перечисления через возвраты).

map_put(+Map,+Key,?Val,?OldVal,?NewMap) 

... унифицировать карту NewMap с картой, полученной путем вставки (Key, Val) Пара на карте Карта. Если Map Map уже содержит запись с ключевым ключом, значение указанной записи объединяется с OldVal.

map_rem(+Map,+Key,?OldVal,?NewMap) 

... унифицировать карту NewMap с картой, полученной путем удаления записи с ключом Ключ от карты карты. Значение, связанное с ключом Ключ на карте Карта унифицирован с помощью OldVal. Ошибка, если карта Map не содержит ключевого ключа.

И мы будем использовать выше, как это:

iterate(Solution) :- 
    map_new(Map), 
    iterate(Map,Solution). 

iterate(M,S) :- 
    gen_fresh_states(ListFresh), 
    gen_stale_states(ListStale), 
    add_fresh_states(M,ListFresh,MM), 
    del_stale_states(MM,ListStale,MMM), 
    (termination_check(MMM,S) -> true ; iterate(MMM,S)). 

Где

add_fresh_states(M,ListFresh,MM), 
del_stale_states(MM,ListStale,MMM), 

итерация за списки-оф-состояний ListFresh и ListStale ожидаемым образом, итеративно вызова map_put/5 или map_rem/4 ,

И -> ; - предикат ->/2.

Проблема

На данный момент, мы должны выбрать хорошую реализацию для карты. Мы не хотим, чтобы структура, которая изменяется чрезмерно, когда один элемент удаляется или добавляется, так что базовая реализация может сохранять операции копирования и, как правило, пустое место, ссылаясь на подструктуры (например, поддеревья) карты M, когда MM построен из нее во время map_put/5 или map_rem/4.

(Например, я слышал, что Clojure использует эффективные реализации в этом смысле для некоторых из его 4 [неизменных карты], но я внимательно не смотрел на это.)

В SWI Prolog мы имеем AVL-tree -backed реализация assoc. Это отлично подходит для быстрого поиска. К сожалению, деревья AVL могут сильно измениться всякий раз, когда узел дерева вставлен или удален. Не может быть много общего между фактическим расположением кучи карт M, MM, MMM или любой другой картиной: куча, вероятно, быстро заполнится. Реализация assoc находится в Prolog btw. (/usr/lib64/swipl-7.2.3/library/assoc.pl), в него нет специального соуса.

Я ошибаюсь в мышлении AVL на основе дерева карты не будут соответствовать задаче?

В качестве альтернативы, существуют ли какие-либо реализации карты (не обязательно в SWI Prolog), которые могут эффективно использовать подструктуру?

Я полагаю, что уже можно смягчить использование кучи, используя «!» между подлогами iterate/2. Это покажет время выполнения, что обратное отслеживание не произойдет, и, таким образом, дает ему лицензию на уничтожение любых структур на кучи, которые больше никогда не будут использоваться. Например, "!" после вызова del_state_states/3 потенциально может сделать MM подходящим для сбора мусора (я не знаю, действительно ли это работает).

+0

Где именно, тогда? –

+0

Хорошо, спасибо, ложь. Моя интуиция все еще слаба. –

ответ

2

Я ошибаюсь, думая, что на основе AVL карты не будут соответствовать задаче?

По всей видимости: Да.

По моему опыту, library(assoc) является отличным выбором для множества задач, требующих доступа по мере их описания. Рекомендую вам дать   попробуйте!

На практике логарифмические накладные расходы часто очень важны приемлемым, и вы также можете повторно строить карты с нуля каждый раз, чтобы удалить ненужные элементы.

Отметим также, что многие другие сбалансирован древовидные структуры (Красно-черные деревья и т.д.) также допускают естественное и чисто реализации Пролога, и если AVL   деревья оказываются не хорошо работать для вас, я рекомендую вам проверьте некоторые из чистых альтернатив.

Докторская диссертация Криса Окасаки Purely Functional Data Structures стоит посмотреть в таких ситуациях.

+0

Хорошо, давайте попробуем это, следя за использованием памяти [как в «Проблемы с памятью Prolog»] (http://stackoverflow.com/questions/15811951/prolog-memory-issues). Имела ли когда-либо инструментарий для реализации Prolog (WAM-based или иначе), как это существует для [Oracle JVM] (http://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/monitor_tab.html) ? –

+1

Учитывая, что Prolog предшествует JVM на несколько десятилетий, шансы высоки [вы также найдете такие инструменты для Prolog] (http://eu.swi-prolog.org/profile.html). – mat

+1

@ David: Тем более, что некоторые из создателей JVM раньше работали над Prolog. – false