检查变量元组是否不能进一步约束,以莫扎特/奥兹为单位



>问候,

最好用一个例子来说明这个想法:

假设我们有一个向量vec(a:{FD.int 1#100} b:{FD.int 1#100} c:{FD.int 1#100}).我希望能够向这个向量添加约束,直到我添加的每个附加约束它不会添加更多信息,例如不约束vec.avec.b和进一步vec.c

有可能在莫扎特/奥兹做吗?

我想这样想。

在循环中:

  1. 访问约束存储,
  2. 检查是否更改
  3. 如果没有更改,则终止。
您可以使用

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}

最新更新