Arrays Minizing:压缩列表中的非零元素对

Arrays Minizing:压缩列表中的非零元素对,arrays,minizinc,Arrays,Minizinc,我有这样一种情况:我正在建模一个数组S,它包含一组来自预定义域1..t,加上0,这是“不存在/未使用”的特殊值 现在,我想为列表S'发布一个约束条件,对成本函数求和,表示为2D数组C,将S中的每个非零元素按相同顺序保存,如下所示: constraint x=sum([C[S'[d],S'[d+1]]| d in 1..max-1]) 然而,这并非易事。我尝试过的事情: 使用根的函数形式获得数据为非零的S的索引集。该解决方案的问题是: 结果是一个集合,因此不能压缩成对或轻松转换为列表,即使我

我有这样一种情况:我正在建模一个数组
S
,它包含一组来自预定义域
1..t
,加上
0
,这是“不存在/未使用”的特殊值

现在,我想为列表
S'
发布一个约束条件,对成本函数求和,表示为2D数组
C
,将
S
中的每个非零元素按相同顺序保存,如下所示:

constraint x=sum([C[S'[d],S'[d+1]]| d in 1..max-1])

然而,这并非易事。我尝试过的事情:

  • 使用
    根的函数形式
    获得数据为非零的
    S
    的索引集。该解决方案的问题是:
    • 结果是一个集合,因此不能压缩成对或轻松转换为列表,即使我从提供的实例数据中知道它们的编号
    • 根似乎要求所有值都参与数组,而我只希望拥有除0之外的完整域
  • 使用列表理解(例如,
    [S[i]| i in 1..max其中S[i]!=0]
    )仅选择值非零的元素:这也不起作用,因为列表理解上的
    where
    子句会导致列表的类型为
    opt
    ,并且元素数量错误(我假设其中一些将是
    ),本质上,使用
    :s将过滤零的问题再次减少为相同的问题
  • 将成本函数视为DFA,将0值视为自循环:这不允许(以任何方式我可以识别)计数;只允许验证转换,我不关心

这里我真正想要的是
filter
zip
,这两种方法都可以很容易地解决我的问题,但我认为我缺少某种标准的解决方案。否则,我将不得不重新设计模型。

可以通过使用计算成本的递归函数来解决您的问题通过迭代数组的索引
S
。我在下面的一个小示例中演示了函数
calculate\u cost()

int: t = 10; int: N = 5;

% cost array
array[1..t,1..t] of int: C = array2d(1..t,1..t,[ i | i in 1..t, j in 1..t]);

% variables
array[1..N] of var 0..t: S;
var 0..1000: x;

% constraints
constraint S[1] = 4; % setting some arbitrary values
constraint S[2] = 7;
constraint S[3] = 0;
constraint S[4] = 6;

constraint x =  calculate_cost(1,2);

function var int: calculate_cost(int: index1, int:index2) =
  if index1 > N then 0 
  elseif index2 > N then 0
  else 
    let {
       var bool: value_at_index1_is_zero = S[index1] == 0;
       var bool: value_at_index2_is_zero = S[index2] == 0;
    }
    in 
      if value_at_index1_is_zero 
         then calculate_cost(index1+1, index1+2)
      elseif value_at_index2_is_zero 
         then calculate_cost(index1, index2 + 1) 
      else 
        C[S[index1],S[index2]] + calculate_cost(index2, index2+1)   
      endif
  endif;

solve satisfy;
此示例具有
S=[4,7,0,6,0]
并计算成本
x=C[4,7]+C[7,6]=4+7=11

在函数
calculate_cost()
中,我通过跳过
S
中具有零值的索引来递归计算总和。在前几行中,我检查索引是否超出范围,并在这种情况下返回0(递归的基本情况)。然后,如果
S[index]
处的值对于
index
为零,我创建两个
true
局部变量。然后,如果其中一个情况为true,我将忽略这些索引,并再次递归调用该函数,并在递归调用中增加/调整相应的索引


这是可行的,但可能不是解决这个问题的好方法,因为它在Flatzin模型中引入了很多辅助变量,所以可能还是重新表述这个问题更好。

太好了,谢谢!我将针对修改后的模型运行它,看看这些额外变量相对而言有多糟糕,因为其他孤子可能也引入了一些冗余的决策变量。