Minizinc:根据与第二个数组的匹配来计算数组中的出现次数,输出为二维数组

问题描述

我遇到的下一个问题是尝试计算数组中出现的次数,条件是它们与另一个数组中的值匹配。

我想结合以下模型

set of int: OPTS = 1..4;
set of int: ASSIGN = 1..12;

array[ASSIGN] of var OPTS: result;

有这些声明

enum CONDS = {A,B,C,D};
array[ASSIGN] of CONDS : const = [A,A,D,D];

array[OPTS,CONDS] of var int: result2;

output ["\(result) \(show2d(result2))"]

生成一个输出,记录每个 OPTS 出现的次数,类似于

CONDS

也就是说,[ 1,2,1,3,4,4 ] [|2,0|1,2|0,0|0,1] 有 2 A OPTS[1],0 B CONDS 和 2 C CONDS 和 0 D CONDS,而 CONDS 有1 A OPTS[2]、0 B CONDS、0 C CONDS 和 2 D CONDS,依此类推。

我不知道我经历了多少以下组合,但没有一个产生预期的结果,尽管我认为应该是合乎逻辑的。

CONDS

解决方法

这是一个模型,它为 OPTS 中的每个值计算 CONDS 中出现的次数。棘手的部分是 count 构造,其中必须检查 result 中的值是否为 OPTSo。这是通过 count 约束完成的,其中 (result[i]==0) 是条件 result[i] 中的这个值是我们想要的 o,然后我们检查它是什么 COND属于 (const[i])。

include "globals.mzn";

set of int: OPTS = 1..4;
set of int: ASSIGN = 1..12;

% Note: hard coded with the example from the question.
array[ASSIGN] of var OPTS: result = [ 1,2,1,3,4,4 ];

enum CONDS = {A,B,C,D};
array[ASSIGN] of CONDS : const = [A,A,D,D];

% count the number of occurences in each chunk
array[OPTS,CONDS] of var 0..max(ASSIGN): result2;

constraint 
   % for each integer in OPTS
   %     count the number of occurrences of each c in CONDS
   forall(o in OPTS) (
       forall(c in CONDS) (
           result2[o,c] = count([const[i]*(result[i] == o) | i in ASSIGN],c)
       )
   )
;

solve satisfy;

output [
    "const: \(const)\n","result: \(result)\n","result2: ",show2d(result2),"\n",];

带有硬编码 result 的模型的输出是:

const: [A,D]
result: [1,4]
result2: [| 2,0 |
   1,2 |
   0,0 |
   0,1 |]

编辑: 除了计数循环,我们还可以使用全局约束,这应该更有效一点global_cardinality。它使用与 count 版本相同的想法,但包含在单个 forall 循环中:

constraint 
   forall(o in OPTS) (
       global_cardinality([const[i]*(result[i] == o) | i in ASSIGN],OPTS,result2[o,..])
   )
;