涉及向量(数组)的快速简单约束编程

时间:2013-05-07 23:12:25

标签: c++ c++11 constraints constraint-programming

我有很多很多很多的向量需要用一些非常基本的一阶逻辑来检查数字的重复数。

我可以使用交叉路口,但这证明太慢了。我以为我可以把它变成一个有点问题。完整的整数集是已知的,每个向量/数组可以表示为一个位集,但我只能找到一半的解决方案。

我目前使用循环和矢量交集,但事实证明它对于我需要检查的问题数量来说太慢了。

举个简单的例子,给出:

E: 1 2
F: 2 4
M: 1 3
N: 4 5  
A: 5 6

我想要识别的问题总是更大的格式:

(E || F) && (M || N) && A -> which is proven as possible by selecting F,M,A.

我需要验证上述内容是否可以重复。

有没有办法检查这样的矢量/数组比900万个循环快? 约束库是唯一的选择吗?

努力澄清:

容器是std :: vector。

向量包含任何整数。

我需要通过问题来检查问题以识别整个整数集。

使用指定的条件逻辑来选择整个向量,是否会出现重复? 使用中的条件运算符将始终仅为“AND”和“OR”。我列出的问题是一个简化版本,但实际上就是它的全部内容。它的大小不同。

输出我不太关心..它可能是一个布尔值,另一个潜在重复的矢量等等。我正在努力为工作找到合适的工具而不是打捞。

在我目前的设置中,我会通过分析强制项目(如A)并删除与...相交的任何内容来解决这个问题(在这种情况下,N ...然后我会再次循环,并执行相同的过程M,现在是强制选择,并删除E,留给我F.

1 个答案:

答案 0 :(得分:1)

如果我正确理解了这个问题,这就是一个集合分区问题,其中应该选择某个“Universe”的值(即集合中的所有值),以便一个值只在一个选定的集合中。并且这是一个可能的组合组合的特定条件。

我在MiniZinc实施的规定(简单)的问题(一个非常高的水平约束规划系统,看到我MiniZinc页面获取更多信息,并进一步链接:http://www.hakank.org/minizinc/)。

模型在这里:http://www.hakank.org/minizinc/set_partition_stackoverflow.mzn 并在下面完整复制:

include "globals.mzn";

int: n = 5; % number of sets

array[1..n] of set of int: s = 
  [
   {1,2}, % E
   {2,4}, % F
   {1,3}, % M
   {4,5}, % N 
   {5,6}  % A
  ];

% All values (the "universe")
set of int: values = {j | i in 1..n, j in s[i]};

% decision variables
array[1..n] of var bool: x; % which set (in s) to select
array[1..n] of var set of values: xs; % the selected sets

solve satisfy;
% Minimize the number of selected sets
% solve minimize sum(i in 1..n) (bool2int(card(xs[i]) > 0));

constraint 

  % The condition
  % (E || F) && (M || N) && A
  ((x[1] \/ x[2]) /\ (x[3] \/ x[4]) /\ x[5])
  /\ 
  forall(i in 1..n) (
     % If this set is selected (in x[i]), put s[i] in xs[i]
     (x[i]  xs[i] = s[i])
     /\ % ensure not selected sets are represented as {} in xs
     (not(x[i])  card(xs[i]) = 0)
  )
  /\ % make sure that a value is selected in exactly one set
  partition_set([xs[i] | i in 1..n], values)
;

output
[
  "x: " ++ show(x) ++ "\n" ++ 
  "xs: " ++ show(xs) ++ "\n"
];

此问题有一个解决方案:

x: [false, true, true, false, true]
xs: [{}, {2, 4}, {1, 3}, {}, 5..6]

其中“x”是布尔数组,如果应该选择一个集合,并且“xs”包含所选集合(如果未选择集合则元素为{},即为空)。集合的分区是使用partition_set函数完成的,该函数确保一个值在一个集合中,并且Universe中的所有值(集合“值”)都在某个集合中。

我不确定这款MiniZinc型号是否有用,但你可能会把它看作是一种灵感,如果没有其他的话。此外,在这个模型中对条件的处理进行了硬编码,因此这里没有解决。

在基于C ++的CP系统Gecode(http://www.gecode.org/)具有用于组变量和一个分区约束(称为在Gecode“不相交”),虽然我还没有针对此问题测试它的支持。 下面是一个如何在标准分区问题中使用“不相交”的示例:http://www.hakank.org/gecode/set_partition.cpp