Minizinc 阵列排序
Minizinc array sorting
假设我有一个如下所示的数组声明
array[1..5] of int: temp = [1,0,5,0,3];
有没有办法启动一个看起来与 temp 相同但没有 0 的新数组?结果如下所示
[1,5,3]
或以 0 位于数组开头或结尾的方式对数组进行排序,即
[0,0,1,5,3]
或
[1,5,3,0,0]
谢谢
使用MiniZinc 2
,可以按如下方式完成:
array[1..5] of int: temp = [1,0,5,0,3];
% calculate upper bound of temp index
int: i_max = max(index_set(temp));
% use array comprehension to count non-zero elements
int: temp_non_zero = sum([1 | i in 1..i_max where temp[i] != 0]);
% copy non-zero elements to new array
array[1..temp_non_zero] of int: temp2 = [temp[i] | i in 1..i_max where temp[i] != 0];
% calculate upper bound for temp2 index
int: i2_max = max(index_set(temp2));
solve satisfy;
% show our variables
output
["\ni_max=" ++ show(i_max)]
++ ["\ni2_max=" ++ show(i2_max)]
++ ["\n" ++ show(temp2[i]) | i in 1..i2_max]
;
尽管 Axel 已经回答了这个问题,但我将展示另一种方法——在我的书中更简洁一些。
情况一:数组("temp")是常量数组。
然后可以简单地写
数组[int] of int: temp2 = [temp[i] |我在 index_set(temp) where temp[i] != 0];
MiniZinc 2(对比版本1.*)如果可以计算则不需要声明大小;只需使用 "array[int]" 就足够了。此外,"index_set" 用于更通用一点,例如处理索引从 0..4 开始的情况(参见注释行)。
- 情况 2:数组 ("s") 是一个决策变量数组
如果要处理的数组是决策变量,我们不知道(根据定义)有多少个 0,必须依赖替代变体,即对数组进行排序。然后可以使用 "sort" 函数,如模型所示。
include "globals.mzn";
% constant
array[1..5] of int: temp = [1,0,5,0,3];
% array[0..4] of int: temp = array1d(0..4, [1,0,5,0,3]);
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
% decision variables
array[1..5] of var int: s;
array[1..5] of var int: s2 = sort(s); % NOT CORRECT, see model below
solve satisfy;
constraint
s = [1,0,5,0,3]
;
% show our variables
output
[
"temp: \(temp)\n",
"temp2: \(temp2)\n",
"s: \(s)\n",
"s2: \(s2)\n",
];
更新
对于决策变量的稳定版本,这在我看来是有效的。它根据 "s[i]" 是否为 0 来计算放置此数字的位置。虽然不是很漂亮。
int: n = 5;
array[1..n] of var 0..5: s;
array[1..n] of var lb_array(s)..ub_array(s): s2;
solve satisfy;
constraint
s = [1,0,5,0,3] /\
forall(i in 1..n) (
if s[i] != 0 then
s2[sum([s[j]!=0 | j in 1..i-1])+1] = s[i]
else
s2[sum([s[j]!=0 | j in 1..n]) + sum([s[j]=0 | j in 1..i-1])+1 ] = 0
endif
)
;
output
[
"s: \(s)\n",
"s2: \(s2)\n",
]
;
输出为
s: [1, 0, 5, 0, 3]
s2: [1, 5, 3, 0, 0]
另一种选择:
两个数组之间的1:1映射被建立为唯一索引值(=数组位置)的数组。然后对这些索引进行排序。如果元素指向零,则比较对元素的权重更高。因此,零值被移到后面,同时保持非零元素的顺序不变。
int: n = 5;
int: INF = 99999; % infinity
array[1..n] of var 0..5: s;
array[1..n] of var 1..n: map;
array[1..n] of var 0..5: s2;
solve satisfy;
% set s[]
constraint
s = [1,0,5,0,3]
;
% 1:1 mapping between s[] and s2[]
constraint
forall (i in 1..n) (
exists(j in 1..n) (
map[j] = i
)
)
;
constraint
forall(i in 1..n) (
s2[i] = s[map[i]]
)
;
% sort the map and move zero values to the back
constraint
forall(i in 1..n-1) (
(if s2[i] != 0 then map[i] else INF endif) <=
(if s2[i+1] != 0 then map[i+1] else INF endif)
)
;
output
[
"s: \(s)\n",
"map: \(map)\n",
"s2: \(s2)\n",
]
;
输出:
s: [1, 0, 5, 0, 3]
map: [1, 3, 5, 4, 2]
s2: [1, 5, 3, 0, 0]
假设我有一个如下所示的数组声明
array[1..5] of int: temp = [1,0,5,0,3];
有没有办法启动一个看起来与 temp 相同但没有 0 的新数组?结果如下所示
[1,5,3]
或以 0 位于数组开头或结尾的方式对数组进行排序,即
[0,0,1,5,3]
或
[1,5,3,0,0]
谢谢
使用MiniZinc 2
,可以按如下方式完成:
array[1..5] of int: temp = [1,0,5,0,3];
% calculate upper bound of temp index
int: i_max = max(index_set(temp));
% use array comprehension to count non-zero elements
int: temp_non_zero = sum([1 | i in 1..i_max where temp[i] != 0]);
% copy non-zero elements to new array
array[1..temp_non_zero] of int: temp2 = [temp[i] | i in 1..i_max where temp[i] != 0];
% calculate upper bound for temp2 index
int: i2_max = max(index_set(temp2));
solve satisfy;
% show our variables
output
["\ni_max=" ++ show(i_max)]
++ ["\ni2_max=" ++ show(i2_max)]
++ ["\n" ++ show(temp2[i]) | i in 1..i2_max]
;
尽管 Axel 已经回答了这个问题,但我将展示另一种方法——在我的书中更简洁一些。
情况一:数组("temp")是常量数组。 然后可以简单地写
数组[int] of int: temp2 = [temp[i] |我在 index_set(temp) where temp[i] != 0];
MiniZinc 2(对比版本1.*)如果可以计算则不需要声明大小;只需使用 "array[int]" 就足够了。此外,"index_set" 用于更通用一点,例如处理索引从 0..4 开始的情况(参见注释行)。
- 情况 2:数组 ("s") 是一个决策变量数组
如果要处理的数组是决策变量,我们不知道(根据定义)有多少个 0,必须依赖替代变体,即对数组进行排序。然后可以使用 "sort" 函数,如模型所示。
include "globals.mzn";
% constant
array[1..5] of int: temp = [1,0,5,0,3];
% array[0..4] of int: temp = array1d(0..4, [1,0,5,0,3]);
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
% decision variables
array[1..5] of var int: s;
array[1..5] of var int: s2 = sort(s); % NOT CORRECT, see model below
solve satisfy;
constraint
s = [1,0,5,0,3]
;
% show our variables
output
[
"temp: \(temp)\n",
"temp2: \(temp2)\n",
"s: \(s)\n",
"s2: \(s2)\n",
];
更新
对于决策变量的稳定版本,这在我看来是有效的。它根据 "s[i]" 是否为 0 来计算放置此数字的位置。虽然不是很漂亮。
int: n = 5;
array[1..n] of var 0..5: s;
array[1..n] of var lb_array(s)..ub_array(s): s2;
solve satisfy;
constraint
s = [1,0,5,0,3] /\
forall(i in 1..n) (
if s[i] != 0 then
s2[sum([s[j]!=0 | j in 1..i-1])+1] = s[i]
else
s2[sum([s[j]!=0 | j in 1..n]) + sum([s[j]=0 | j in 1..i-1])+1 ] = 0
endif
)
;
output
[
"s: \(s)\n",
"s2: \(s2)\n",
]
;
输出为
s: [1, 0, 5, 0, 3]
s2: [1, 5, 3, 0, 0]
另一种选择:
两个数组之间的1:1映射被建立为唯一索引值(=数组位置)的数组。然后对这些索引进行排序。如果元素指向零,则比较对元素的权重更高。因此,零值被移到后面,同时保持非零元素的顺序不变。
int: n = 5;
int: INF = 99999; % infinity
array[1..n] of var 0..5: s;
array[1..n] of var 1..n: map;
array[1..n] of var 0..5: s2;
solve satisfy;
% set s[]
constraint
s = [1,0,5,0,3]
;
% 1:1 mapping between s[] and s2[]
constraint
forall (i in 1..n) (
exists(j in 1..n) (
map[j] = i
)
)
;
constraint
forall(i in 1..n) (
s2[i] = s[map[i]]
)
;
% sort the map and move zero values to the back
constraint
forall(i in 1..n-1) (
(if s2[i] != 0 then map[i] else INF endif) <=
(if s2[i+1] != 0 then map[i+1] else INF endif)
)
;
output
[
"s: \(s)\n",
"map: \(map)\n",
"s2: \(s2)\n",
]
;
输出:
s: [1, 0, 5, 0, 3]
map: [1, 3, 5, 4, 2]
s2: [1, 5, 3, 0, 0]