MiniZinc:获得一组超级数组

时间:2018-08-22 21:09:30

标签: constraint-programming minizinc

我正在研究约束编程问题,但停留在特定步骤,需要建议。

我的数据有一堆订单,每个订单都有一些SKU。我想将这些订单分为不同的批次,然后在一个批次/组中​​计算唯一的SKU。例如。

Order 1 - SKUs 1, 2, 3 
Order 2 - SKUs 2, 5 
Order 3 - SKUs 1, 3, 7
Order 4 - SKUs 3, 4, 6

现在,如果我将批次1中的订单1和4分组,而批次2中的订单2和3,则每个批次中的唯一SKU计数如下:

Batch 1 - SKUs 1, 2, 3, 4, 6 = 5 SKUs
Batch 2 - SKUs 1, 2, 3, 5, 7 = 5 SKUs

我的代码如下

include "globals.mzn"; 

int: N_Orders = 14; % Number of orders
set of int: ORDERS = 1..N_Orders;
set of int: skuids = {1,2,3,4,5}; % Distinct sku ids across all orders
array[ORDERS] of set of skuids: oskuids = [{1,2,3},{1,3},{4},{4,5},{1},{1,4},{3,4},{5},{1,4,5},{1,2,3},{1,3},{4,5},{1},{1,4}]; % Distinct SKU ids in each order

% Orders per batch
ORDERS: x = 2; 

% Batches needed
int: N_Batches = 7;


% Define array that contains batch for each order
array[ORDERS] of var 1..N_Batches: obatch;
constraint global_cardinality(obatch, [i | i in (1..N_Batches-1)], [x | i in 1..(N_Batches-1)]); % Total orders in batch set to 'x'

% Distinct skus in each batch
array[1..N_Batches] of var int: skus_in_batch;
constraint forall(i in 1..N_Batches)(
             skus_in_batch[i] = card(array_union(o in ORDERS where obatch[o] = i)(oskuids[o]))
           );

solve satisfy;

在运行此代码时,出现以下错误:

MiniZinc: type error: no function or predicate with this signature found: `array_union(array[int] of var opt set of int)'

如何修改代码以提供所需的结果?

2 个答案:

答案 0 :(得分:0)

如果我理解正确,则可以直接使用sum

constraint forall(i in 1..N_Batches)(
   skus_in_batch[i] = sum([obatch[o] = i | o in ORDERS])
);

然后是第一个解决方案

obatch = array1d(1..14 ,[7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1]);
skus_in_batch = array1d(1..7 ,[2, 2, 2, 2, 2, 2, 2]);

答案 1 :(得分:0)

这是我在另一个论坛上从MiniZinc的架构师那里得到的答案,并意识到该方法可以用于许多其他类似情况,这些情况由于选件类型不受支持而导致出现错误-

  

表达式

skus_in_batch[i] = card(array_union(o in ORDERS where   
                   obatch[o] = i)(oskuids[o]));
     

实际上等效于

skus_in_batch[i] = card(array_union([ if obatch[o] = i then oskuids[o] else top endif | o in ORDERS]]);
     

,因此失败,因为array_union无法处理以下数组   创建的可选集。您可以将其简单地重写为以下内容   避免使用选项类型。

skus_in_batch[i] = card(array_union([ if obatch[o] = i then oskuids[o] else {} endif | o in ORDERS]]);

or equivalently

skus_in_batch[i] = card(array_union(o in ORDERS)
                   (if obatch[o] = i then oskuids[o] else {} endif));