Проверьте, нельзя ли ограничивать кортеж переменных в Mozart / Oz - PullRequest
2 голосов
/ 08 мая 2011

Привет,

Идея может быть лучше всего приведена на примере:

Предположим, у нас есть вектор vec(a:{FD.int 1#100} b:{FD.int 1#100} c:{FD.int 1#100}).Я хочу иметь возможность добавлять ограничения к этому вектору до тех пор, пока каждое добавленное к нему дополнительное ограничение не добавит больше информации, например, не будет больше ограничивать vec.a, vec.b и vec.c.

Возможно ли это сделать в Моцарте / Оз?

Мне бы хотелось так думать.

В цикле:

  1. Доступ к хранилищу ограничений,
  2. Проверить, является лиизменено
  3. Завершить, если нет изменений.

1 Ответ

2 голосов
/ 08 мая 2011

Вы можете проверить состояние конечной доменной переменной с помощью функций в модуле FD.reflect. Функция FD.reflect.dom кажется особенно полезной в этом контексте.

Чтобы получить текущий домен каждого поля в записи, вы можете сопоставить эту функцию с записями:

declare

fun {GetDomains Vec}
   {Record.map Vec FD.reflect.dom}
end

Первоначальный результат в вашем примере будет:

vec(a:[1#100] b:[1#100] c:[1#100])

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

Два ограничения:

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

Если вам нужен пример использования функции GetDomains в цикле, дайте мне знать ...

РЕДАКТИРОВАТЬ: С подсказкой из старого сообщения списка рассылки я пришел к этому общему решению, которое должно работать со всеми типами ограничений. Он работает путем умозрительного выполнения ограничения в подчиненном вычислительном пространстве.

declare

Vec = vec(a:{FD.int 1#100} b:{FD.int 1#100} c:{FD.int 1#100})

%% A number of constraints as a list of procedures
Constraints =
[proc {$} Vec.a <: 50 end
 proc {$} Vec.b =: Vec.a end
 proc {$} Vec.b <: 50 end
 proc {$} Vec.a =: Vec.b end
]


%% Tentatively executes a constraint C (represented as a procedure).
%% If it is already entailed by the current constraint store, returns false.
%% Otherwise merges the space (and thereby finally executes the constraint)
%% and returns true.
fun {ExecuteConstraint C}
   %% create a compuation space which tentatively executes C
   S = {Space.new
        proc {$ Root}
           {C}
           Root = unit
        end
       }
in
   %% check whether the computation space is entailed
   case {Space.askVerbose S}
   of succeeded(entailed) then false
   else
      {Wait {Space.merge S}}
      true
   end
end


for C in Constraints I in 1..4 break:Break do
   {System.showInfo "Trying constraint "#I#" ..."}
   if {Not {ExecuteConstraint C}} then
      {System.showInfo "Constraint "#I#" is already entailed. Stopping."}
      {Break}
   end
   {Show Vec}
end

{Show Vec}
...