简体   繁体   English

示例通道约束ECLiPSe

[英]Example channelling constraints ECLiPSe

Can someone provide a simple example of channelling constraints? 有人可以提供一个简单的渠道约束示例吗?

Channelling constraints are used to combine viewpoints of a constraint problem. 通道约束用于组合约束问题的视点。 Handbook of Constraint Programming gives a good explanation of how it works and why it can be useful: 约束编程手册很好地解释了它是如何工作的以及为什么它有用:

The search variables can be the variables of one of the viewpoints, say X1 (this is discussed further below). 搜索变量可以是其中一个视点的变量,比如X1(这将在下面进一步讨论)。 As search proceeds, propagating the constraints C1 removes values from the domains of the variables in X1. 随着搜索的进行,传播约束C1从X1中的变量的域中移除值。 The channelling constraints may then allow values to be removed from the domains of the variables in X2. 然后,信道约束可以允许从X2中的变量的域中移除值。 Propagating these value deletions using the constraints of the second model, C2, may remove further values from these variables, and again these removals can be translated back into the first viewpoint by the channelling constraints. 使用第二模型C2的约束来传播这些值删除可以从这些变量中移除更多值,并且这些移除可以通过信道约束再次转换回第一视点。 The net result can be that more values are removed within viewpoint V1 than by the constraints C1 alone, leading to reduced search. 最终结果可能是在视点V1内移除的值多于仅由约束C1移除的值,导致搜索减少。

I do not understand how this is implemented. 我不明白这是如何实现的。 What are these constraints exactly, how do they look like in a real problem? 究竟是什么限制,它们在真正的问题中看起来如何? A simple example would be very helpful. 一个简单的例子非常有用。

Channeling constraints are used when, in a model, aspects of a problem are represented in more than one way. 当在模型中,问题的各个方面以多种方式表示时,使用信道约束。 They are then necessary to synchronize these multiple representations, even though they do not themselves model an aspect of the problem. 然后,它们必须同步这些多个表示,即使它们本身并不模拟问题的某个方面。

Typically, when modelling a problem with constraints, you have several ways of choosing your variables. 通常,在使用约束对问题建模时,您可以通过多种方式选择变量。 For example, in a scheduling problem, you could choose to have 例如,在调度问题中,您可以选择拥有

  • an integer variable for each job (indicating which machine does the job) 每个作业的整数变量(指示哪个机器完成作业)
  • an integer variable for each machine (indicating which job it performs) 每台机器的整数变量(表示它执行的作业)
  • a matrix of Booleans (indicating which job runs on which machine) 布尔矩阵(表示哪个作业在哪台机器上运行)
  • or something more exotic 或更具异国情调的东西

In a simple enough problem, you choose the representation that makes it easiest to formulate the constraints of the problem. 在一个足够简单的问题中,您可以选择最简单的表示形式来解决问题的约束。 However, in real life problems with many heterogeneous constraints it is often impossible to find such a single best representation: some constraints are best represented with one type of variable, others with another. 然而,在具有许多异构约束的现实生活问题中,通常不可能找到这样的单一最佳表示:一些约束最好用一种类型的变量表示,而另一些约束用另一种变量表示。

In such cases, you can use multiple sets of variables, and formulate each individual problem constraint over the most convenient variable set. 在这种情况下,您可以使用多组变量,并在最方便的变量集上制定每个单独的问题约束。 Of course, you then end up with multiple independent subproblems, and solving these in isolation will not give you a solution for the whole problem. 当然,您最终会遇到多个独立的子问题,单独解决这些问题并不能为您提供整个问题的解决方案。 But by adding channeling constraints, the variable sets can be synchronized, and the subproblems thus re-connected. 但是通过添加通道约束,可以同步变量集,从而重新连接子问题。 The result is then a valid model for the whole problem. 结果是整个问题的有效模型。

As hinted in the quote from the handbook, in such a formulation is is sufficient to perform search on only one of the variable sets ("viewpoints"), because the values of the others are implied by the channeling constraints. 正如手册中引用的那样,在这样的表述中,只需对一个变量集(“视点”)进行搜索就足够了,因为其他值的值是由信道约束所暗示的。

Some common examples for channeling between two representations are: 在两个表示之间进行通道的一些常见示例是:

Integer variable and Array of Booleans : Consider an integer variable T indicating the time slot 1..N when an event takes place, and an array of Booleans Bs[N] such that Bs[T] = 1 iff an event takes place in time slot T . 整数变量布尔数组 :考虑一个整数变量T表示发生事件时的时隙1..N ,以及一个布尔值Bs[N]数组,如果事件发生在时间上,则Bs[T] = 1T In ECLiPSe: 在ECLiPSe中:

    T #:: 1..N,
    dim(Bs, [N]), Bs #:: 0..1,

Channeling between the two representations can then be set up with 然后可以设置两个表示之间的通道

    ( for(I,1,N), param(T,Bs) do Bs[I] #= (T#=I) )

which will propagate information both ways between T and Bs . 它将在TBs之间传播信息。 Another way of implementing this channeling is the special purpose bool_channeling/3 constraint. 实现此通道的另一种方法是特殊用途bool_channeling / 3约束。

Start/End integer variables and Array of Booleans (timetable): We have integer variables S,E indicating the start and end time of an activity. 开始/结束整数变量布尔数组 (时间表):我们有整数变量S,E表示活动的开始和结束时间。 On the other side an array of Booleans Bs[N] such that Bs[T] = 1 iff the activity takes place at time T . 另一方面,布尔运算Bs[N]的阵列使得如果活动在时间T发生,则Bs[T] = 1 In ECLiPSe: 在ECLiPSe中:

    [S,E] #:: 1..N,
    dim(Bs, [N]), Bs #:: 0..1,

Channeling can be achieved via 通道可以通过实现

    ( for(I,1,N), param(S,E,Bs) do Bs[I] #= (S#=<I and I#=<E) ).

Dual representation Job/Machine integer variables : Here, Js[J] = M means that job J is executed on machine M , while the dual formulation Ms[M] = J means that machine M executes job J 双重表示作业/机器整数变量 :这里, Js[J] = M表示作业J在机器M上执行,而双重公式Ms[M] = J表示机器M执行作业J

    dim(Js, [NJobs]), Js #:: 0..NMach,
    dim(Ms, [NMach]), Ms #:: 1..NJobs,

And channeling is achieved via 通过渠道实现渠道化

    ( multifor([J,M],1,[NJobs,NMach]), param(Js,Ms) do
        (Js[J] #= M) #= (Ms[M] #= J)
    ).

Set variable and Array of Booleans : If you use a solver (such as library(ic_sets) ) that can directly handle set-variables, these can be reflected into an array of booleans indicating membership of elements in the set. 设置变量布尔数组 :如果使用可以直接处理集变量的求解器(例如库(ic_sets) ),这些可以反映到布尔数组中,表示集合中元素的成员资格。 The library provides a dedicated constraint membership_booleans/2 for this purpose. 为此目的,库提供了一个专用约束membership _booleans / 2

As stated in Dual Viewpoint Heuristics for Binary Constraint Satisfaction Problems (PA Geelen) : 正如二元约束满足问题的双视点启发式(PA Geelen)中所述

Channelling constraints of two different models allows for the expression of a relationship between two sets of variables, one of each model. 两个不同模型的通道约束允许表达两组变量之间的关系,每个模型之一。

This implies assignments in one of the viewpoints can be translated into assignments in the other and vice versa, as well as, when search initiates, excluded values from one model can be excluded from the other as well. 这意味着其中一个视点中的分配可以转换为另一个视图中的分配,反之亦然,以及当搜索启动时,一个模型中的排除值也可以从另一个模型中排除。

Let me throw in an example I implemented a while ago while writing a Sudoku solver. 让我举一个我在编写数独求解器时实现的示例。

Classic viewpoint 经典观点

Here we interpret the problem in the same way a human would: using the integers between 1 and 9 and a definition that all rows, columns and blocks must contain every integer exactly once. 在这里,我们以与人类相同的方式解释问题:使用1到9之间的整数以及所有行,列和块必须包含每个整数一次的定义。

We can easily state this in ECLiPSe using something like: 我们可以使用以下内容在ECLiPSe中轻松说明这一点:

% Domain
dim(Sudoku,[N,N]),
Sudoku[1..N,1..N] :: 1..N

% For X = rows, cols, blocks
alldifferent(X)

And this is yet sufficient to solve the Sudoku puzzle. 这足以解决数独谜题。

Binary boolean viewpoint 二进制布尔观点

One could however choose to represent integers by their binary boolean arrays (shown in the answer by @jschimpf). 然而,可以选择通过其二进制布尔数组表示整数(在@jschimpf的答案中显示)。 In case it's not clear what this does, consider the small example below (this is built-in functionality!): 如果不清楚这是做什么的,请考虑下面的小例子(这是内置功能!):

?­ ic_global:bool_channeling(Digit, [0,0,0,1,0], 1).
    Digit = 4
    Yes (0.00s cpu)
?­ ic_global:bool_channeling(Digit, [A,B,C,D], 1), C = 1.
    Digit = 3
    A = 0
    B = 0
    C = 1
    D = 0
    Yes (0.00s cpu)

If we use this model to represent a Sudoku, every number will be replaced by its binary boolean array and corresponding constraints can be written. 如果我们使用此模型来表示数独,则每个数字将被其二进制布尔数组替换,并且可以写入相应的约束。 Being trivial for this answer, I will not include all the code for the constraints, but a single sum constraint is yet enough to solve a Sudoku puzzle in its binary boolean representation. 这个答案很简单,我不会包含约束的所有代码,但单个和约束足以解决其二进制布尔表示中的数独谜题。

Channelling

Having these two viewpoints with corresponding constrained models now gives the opportunity to channel between them and see if any improvements were made. 现在,将这两个视点与相应的约束模型相结合,可以在它们之间进行通道,并查看是否进行了任何改进。

Since both models are still just an NxN board, no difference in dimension of representation exists and channelling becomes real easy. 由于两个模型仍然只是一个NxN板,因此表示的维度不存在差异,并且通道变得非常简单。

Let me first give you a last example of what a block filled with integers 1..9 would look like in both of our models: 让我先给你一个最后一个例子,说明在我们的两个模型中填充整数1..9的块是什么样的:

% Classic viewpoint
1 2 3
4 5 6
7 8 9

% Binary Boolean Viewpoint
[](1,0,0,0,0,0,0,0,0)  [](0,1,0,0,0,0,0,0,0)  [](0,0,1,0,0,0,0,0,0) 
[](0,0,0,1,0,0,0,0,0)  [](0,0,0,0,1,0,0,0,0)  [](0,0,0,0,0,1,0,0,0) 
[](0,0,0,0,0,0,1,0,0)  [](0,0,0,0,0,0,0,1,0)  [](0,0,0,0,0,0,0,0,1)

We now clearly see the link between the models and simply write the code to channel our decision variables. 我们现在清楚地看到模型之间的联系,只需编写代码来引导我们的决策变量。 Using Sudoku and BinBools as our boards, the code would look something like: 使用SudokuBinBools作为我们的板,代码看起来像:

( multifor([Row,Col],1,N), param(Sudoku,BinBools,N) 
do
  Value is Sudoku[Row,Col], 
  ValueBools is BinBools[Row,Col,1..N], 
  ic_global:bool_channeling(Value,ValueBools,1) 
).

At this point, we have a channelled model where, during search, if values are pruned in one of the models, its impact will also occur in the other model. 此时,我们有一个通道模型,在搜索过程中,如果在其中一个模型中修剪了值,其影响也会发生在另一个模型中。 This can then of course lead to further overall constraint propagation. 这当然可以导致进一步的整体约束传播。

Reasoning 推理

To explain the usefulness of the binary boolean model for the Sudoku puzzle, we must first differentiate between some provided alldifferent/1 implementations by ECLiPSe: 为了解释二元布尔模型对数独谜题的有用性,我们必须首先区分alldifferent/1提供的一些不同的alldifferent/1实现:

推理不同/ 1

What this means in practice can be shown as following: 这在实践中意味着如下所示:

?­ [A, B, C] :: [0..1], ic:alldifferent([A, B, C]). 
  A = A{[0, 1]} 
  B = B{[0, 1]} 
  C = C{[0, 1]} 
  There are 3 delayed goals. 
  Yes (0.00s cpu) 

?­ [A, B, C] :: [0..1], ic_global:alldifferent([A, B, C]). 
  No (0.00s cpu)

As there has not yet occurred any assignment using the Forward Checking (ic library), the invalidity of the query is not yet detected, whereas the Bounds Consistent version immediately notices this. 由于尚未使用正向检查(ic库)进行任何分配,因此尚未检测到查询的无效性,而Bounds Consistent版本会立即注意到此情况。 This behaviour can lead to considerable differences in constraint propagation while searching and backtracking through highly constrained models. 在通过高度约束的模型进行搜索和回溯时,此行为可能导致约束传播存在相当大的差异。

On top of these two libraries there is the ic_global_gac library intended for global constraints for which generalized arc consistency (also called hyper arc consistency or domain consistency) is maintained. 在这两个库的顶部有ic_global_gac库,用于全局约束,其中维护了广义弧一致性(也称为超弧一致性或域一致性)。 This alldifferent/1 constraint provides even more pruning opportunities than the bounds consistent one, but preserving full domain consistency has its cost and using this library in highly constrained models generally leads to a loss in running performance. 这种不同的/ 1约束提供了比边界一致的更多修剪机会, 保留完整域一致性有其成本,并且在高度约束模型中使用该库通常会导致运行性能的损失。

Because of this, I found it interesting for the Sudoku puzzle to try and work with the bounds consistent (ic_global) implementation of alldifferent to maximise performance and subsequently try to approach domain consistency myself by channelling the binary boolean model. 正因为如此,我发现Sudoku难题尝试使用不同的边界一致(ic_global)实现以最大化性能并随后尝试通过引用二进制布尔模型来自己接近域一致性。

Experiment results 实验结果

Below are the backtrack results for the 'platinumblonde' Sudoku puzzle (referenced as being the hardest, most chaotic Sudoku puzzle to solve in The Chaos Within Sudoku , M. ErcseyRavasz and Z. Toroczkai) using respectively forward checking, bounds consistency, domain consistency, standalone binary boolean model and finally, the channelled model: 下面是'platinumblonde'数独谜题的回溯结果(被称为最难,最混乱的数独谜题, 在数独的混乱中解决,M。ErcseyRavasz和Z.Toroczkai)分别使用前向检查,边界一致性,域一致性,独立的二进制布尔模型,最后是通道模型:

      (ic)   (ic_global)  (ic_global_gac)  (bin_bools)  (channelled)
BT    6 582      43             29             143           30

As we can see, our channelled model (using bounds consistency (ic_global)) still needs one backtrack more than the domain consistent implementation, but it definitely performs better than the standalone bounds consistent version. 正如我们所看到的,我们的通道模型(使用边界一致性(ic_global))仍然需要一个回溯而不是域一致的实现,但它肯定比独立边界一致版本更好。

When we now take a look at the running times (results are the product of calculating an average over multiple executions, this to avoid extremes) excluding the forward checking implementation as it's proven to no longer be interesting for solving Sudoku puzzles: 当我们现在看一下运行时间(结果是计算多次执行的平均值的结果,这是为了避免极端情况),不包括前向检查实现,因为它已被证明不再有趣解决数独谜题:

          (ic_global)  (ic_global_gac)  (bin_bools)  (channelled)
Time(ms)     180ms          510ms           100ms        220ms

Looking at these results, I think we can successfully conclude the experiment (these results were confirmed by 20+ other Sudoku puzzle instances): 看看这些结果,我认为我们可以成功地完成实验(这些结果得到了20多个其他数独谜题实例的证实):

Channelling the binary boolean viewpoint to the bounds consistent standalone implementation produces a slightly less strong constraint propagation behaviour than that of the domain consistent standalone implementation, but with running times ranging from just as long to notably faster. 将二进制布尔视点引导到边界一致的独立实现会产生比域一致的独立实现稍微强一些的约束传播行为,但是运行时间范围从长到明显更快。

EDIT: attempt to clarify 编辑:尝试澄清

Imagine some domain variable representing a cell on a Sudoku board has a remaining domain of 4..9. 想象一下,代表Sudoku板上一个单元的某个域变量的剩余域为4..9。 Using bounds consistency, it is guaranteed that for both value 4 and 9 other domain values can be found which satisfy all constraints and thus provides consistency. 使用边界一致性,可以保证对于值4和9,可以找到满足所有约束的其他域值,从而提供一致性。 However, no consistency is explicitly guaranteed for other values in the domain (this is what 'domain consistency' is). 但是,没有明确保证域中其他值的一致性(这就是“域一致性”)。

Using a binary boolean model, we define the following two sum constraints: 使用二进制布尔模型,我们定义以下两个求和约束:

  • The sum of every binary boolean array is always equal to 1 每个二进制布尔数组的总和始终等于1
  • The sum of every N'th element of every array in every row/col/block is always equal to 1 每行/列/块中每个数组的每个第N个元素的总和始终等于1

The extra constraint strength is enforced by the second constraint which, apart from constraining row, columns and blocks, also implicitly says: "every cell can only contain every digit once". 额外约束强度由第二个约束强制执行,第二个约束除了约束行,列和块之外,还隐含地说:“每个单元格只能包含每个数字一次”。 This behaviour is not actively expressed when using just the bounds consistent alldifferent/1 constraint! 当仅使用bounds一致的alldifferent / 1约束时,不会主动表达此行为!

Conclusion 结论

It is clear that channelling can be very useful to improve a standalone constrained model, however if the new model's constraint strengthness is weaker than that of the current model, obviously, no improvements will be made. 显然,引导对于改进独立约束模型非常有用, 但是如果新模型的约束强度弱于当前模型的约束强度,显然,不会进行任何改进。 Also note that having a more constrained model doesn't necesarilly also mean an overall better performance! 另请注意,拥有更具约束力的模型并不意味着总体上更好的性能! Adding more constraints will in fact decrease amounts of backtracks required to solve a problem, but it might also increase the running times of your program if more constraint checks have to occur. 实际上,添加更多约束将减少解决问题所需的回溯量,但如果必须进行更多约束检查,则可能还会增加程序的运行时间。

Here is a simple example, works in SWI-Prolog, but should also work in ECLiPSe Prolog (in the later you have to use (::)/2 instead of (in)/2): 这是一个简单的例子,适用于SWI-Prolog,但也应该在ECLiPSe Prolog中工作(在后面你必须使用(::)/ 2而不是(in)/ 2):

Constraint C1: 约束C1:

 ?- Y in 0..100.
 Y in 0..100.

Constraint C2: 约束C2:

 ?- X in 0..100.
 X in 0..100.

Channelling Constraint: 引导约束:

 ?- 2*X #= 3*Y+5.
 2*X#=3*Y+5.

All together: 全部一起:

?- Y in 0..100, X in 0..100, 2*X #= 3*Y+5.
Y in 1..65,
2*X#=3*Y+5,
X in 4..100.

So the channel constraint works in both directions, it reduces the domain of C1 as well as the domain of C2. 因此,信道约束在两个方向上都起作用,它减少了C1的域以及C2的域。

Some systems use iterative methods, with the result that this channelling can take quite some time, here is an example which needs around 1 minute to compute in SWI-Prolog: 有些系统使用迭代方法,结果是这个通道可能需要相当长的时间,这里有一个例子,需要大约1分钟来计算SWI-Prolog:

?- time(([U,V] ins 0..1_000_000_000, 36_641*U-24 #= 394_479_375*V)).
% 9,883,559 inferences, 53.616 CPU in 53.721 seconds 
(100% CPU, 184341 Lips)
U in 346688814..741168189,
36641*U#=394479375*V+24,
V in 32202..68843.

On the other hand ECLiPSe Prolog does it in a blink: 另一方面,ECLiPSe Prolog眨眼间就做了:

[eclipse]: U::0..1000000000, V::0..1000000000, 
              36641*U-24 #= 394479375*V.
U = U{346688814 .. 741168189}
V = V{32202 .. 68843}
Delayed goals:
     -394479375 * V{32202 .. 68843} + 
     36641 * U{346688814 .. 741168189} #= 24
Yes (0.11s cpu)

Bye 再见

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM