我有一组变量和它们之间的线性约束列表。对于每个变量,我有一个包含有效值的起始列表的集合。使用Minizinc,我如何将这些起始值集减少到只能满足约束条件的那些?
一个简单的例子来展示我想要实现的目标:
array[1..2] of var int: xy;
array[1..2] of set of int: xyvalid = [ {1, 5, 7}, 0..9 ];
constraint forall(i in 1..2)( xy[i] in xyvalid[i] );
constraint xy[1] + xy[2] = 7;
当我使用solve satisfy
项目运行并打印xy
的所有解决方案时,我得到(删除了水平线):
[1, 6]
[5, 2]
[4, 3]
[3, 4]
我想要的是以某种方式得到一个var set数组,称之为xypossible
,在这种情况下它将等于[ {1, 3, 4, 5}, {2, 3, 4, 6} ]
。我想我可以定义一组约束,以某种方式检查xypossible[1]
中的每个可能值,xypossible[2]
中产生有效解决方案的值,反之亦然,然后解决以最大化xypossible
中所有集合的总基数,但是当我的真实数据可能具有几百个变量的规模时,几十个线性约束会变得难以编码和可怕跑。
如果没有一种方法可以作为一个模型,那么有没有办法在解算器识别有效值作为自己工作的一部分时捕获信息?
答案 0 :(得分:1)
我认为你的意思是结果应该是[{1,5,7},{0,2,6}],因为xy [1]的唯一可能值是{1,5,7} " xyvalid"阵列; 0,2和6是唯一在加到1,5和7时产生7的值。否则,我一定错过了一些东西......
这是一个可能按照你想要的方式工作的模型。虽然它需要最大化目标才能找出最佳解决方案。
% the domains of the two variables
array[1..2] of set of int: xyvalid = [ {1, 5, 7}, 0..9 ];
% the result sets
array[1..2] of var set of 0..9: z;
% ensure that the largest solution is picked
solve maximize card(z[1]) + card(z[2]);
constraint
% get the domains of each variable set
forall(i in 1..2)( z[i] subset xyvalid[i] ) /\
% ensure that for all valid values in z[1] are in z[2] given
% that j + k = 7
forall(j in z[1]) (
exists(k in z[2]) (j + k = 7)
)
/\
% and ensure that all valid values in z[2] are in z[1]
forall(k in z[2]) (
exists(j in z[1]) (j + k = 7)
)
;
结果是
z = array1d(1..2 ,[{1,5,7}, {0,2,6}]);
没有最大化目标,就会有8个解决方案:
z = array1d(1..2 ,[{1,5,7}, {0,2,6}]);
----------
z = array1d(1..2 ,[{1,7}, {0,6}]);
----------
z = array1d(1..2 ,[{5,7}, {0,2}]);
----------
z = array1d(1..2 ,[7..7, 0..0]);
----------
z = array1d(1..2 ,[{1,5}, {2,6}]);
----------
z = array1d(1..2 ,[1..1, 6..6]);
----------
z = array1d(1..2 ,[5..5, 2..2]);
----------
z = array1d(1..2 ,[{}, {}]);
----------
==========
(其中一些可能已被一些额外的限制删除)
我个人的方法可能是使用您的变体并通过一些外部程序收集可能的值。
注意:在某些CP系统中,可以在标记之前打印决策变量的域(即尝试查找正确的有效值)。但MiniZinc没有此功能。我想念那个。
注2:我测试了dom()函数,它给出了一个决策变量的域,但是我无法使它起作用。