MiniZinc如何对数组对应天数的时间步子集进行求和
MiniZinc按天分段求和实现方案
错误原因
你原来的写法报错是因为MiniZinc的范围运算符..要求两侧边界为编译期可确定的常量表达式,你在范围中使用了依赖迭代变量d的动态计算表达式,无法在编译阶段解析出合法范围,因此会抛出语法错误。
解决方案
以下是两种常用的实现方式,第一种优先推荐,可维护性更高:
方式1:预定义每日对应时间步集合
提前将每天对应的时间步范围存储为固定集合数组,求和时直接调用对应天的集合即可,是最稳妥的实现方式:
set of int: Days = 1..3; set of int: Timesteps = 1..36; % 定义单日时间步数量,方便后续修改 int: STEPS_PER_DAY = 12; % 预定义每天对应的时间步集合 array[Days] of set of Timesteps: daily_timesteps = [ (d-1)*STEPS_PER_DAY + 1 .. d*STEPS_PER_DAY | d in Days ]; array[Timesteps] of var -1.0..1.0: X; % 注意:12个X求和的范围是-12~12,原来的-1.0..1.0范围会导致约束冲突 array[Days] of var -12.0..12.0: Y; constraint forall(d in Days)( Y[d] = sum(t in daily_timesteps[d])(X[t]) );
方式2:sum内使用where条件过滤
如果不想额外定义集合变量,可以直接在sum的迭代范围中增加过滤条件,筛选属于当前天的时间步:
set of int: Days = 1..3; set of int: Timesteps = 1..36; int: STEPS_PER_DAY = 12; array[Timesteps] of var -1.0..1.0: X; array[Days] of var -12.0..12.0: Y; constraint forall(d in Days)( Y[d] = sum(t in Timesteps where t > (d-1)*STEPS_PER_DAY /\ t <= d*STEPS_PER_DAY)(X[t]) );
注意事项
- 你原代码中Y变量的取值范围设置有误,12个取值范围为-1~1的变量求和后,取值范围应为
-12.0..12.0,若保留原来的-1.0..1.0会直接触发约束冲突导致模型无解。 - 推荐将单日时间步数量提取为单独的参数变量,后续需要修改时间步配置时只需修改一处即可,避免硬编码带来的维护问题。
内容的提问来源于stack exchange,提问作者dirkvbok
相关产品推荐
相关产品推荐

