MiniZinc:获取集合数组的超集合
MiniZinc: Obtain a super set of array of sets
我正在研究一个约束规划问题,但卡在了某个特定步骤,需要建议。
我的数据有一堆订单,每个订单都有一些 SKU。我想将这些订单分成不同的批次,然后计算 batch/group 中的唯一 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 和 4 分组到第 1 批中,而订单 2 和 3 分组到第 2 批中,那么每批中的 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)'
如何修改代码以获得所需的结果?
如果我没理解错的话,你可以直接用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]);
这是我在另一个论坛上从 MiniZinc 的架构师那里收到的答案,我意识到这种方法可以用于许多其他类似的情况,在这些情况下,我们会因不支持的选项类型而收到错误 -
The expression
skus_in_batch[i] = card(array_union(o in ORDERS where
obatch[o] = i)(oskuids[o]));
Is effectively equivalent to
skus_in_batch[i] = card(array_union([ if obatch[o] = i then oskuids[o] else top endif | o in ORDERS]]);
and hence fails since array_union is not able to handle the array of
optional sets that are created. You can simple rewrite it to below to
avoid option types.
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));
我正在研究一个约束规划问题,但卡在了某个特定步骤,需要建议。
我的数据有一堆订单,每个订单都有一些 SKU。我想将这些订单分成不同的批次,然后计算 batch/group 中的唯一 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 和 4 分组到第 1 批中,而订单 2 和 3 分组到第 2 批中,那么每批中的 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)'
如何修改代码以获得所需的结果?
如果我没理解错的话,你可以直接用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]);
这是我在另一个论坛上从 MiniZinc 的架构师那里收到的答案,我意识到这种方法可以用于许多其他类似的情况,在这些情况下,我们会因不支持的选项类型而收到错误 -
The expression
skus_in_batch[i] = card(array_union(o in ORDERS where obatch[o] = i)(oskuids[o]));
Is effectively equivalent to
skus_in_batch[i] = card(array_union([ if obatch[o] = i then oskuids[o] else top endif | o in ORDERS]]);
and hence fails since array_union is not able to handle the array of optional sets that are created. You can simple rewrite it to below to avoid option types.
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));