在 minizinc 中使用 forall() 谓词作为没有 'constraint' 的赋值语句
Using forall() predicate in minizinc as assignment statement without 'constraint'
我有一个 Minizinc 程序,可以根据时间间隔给定一组价格,为并网电池生成最佳 charge/discharge 时间表。
我的程序可以运行(有点;有一些注意事项),但我的问题是关于两个 'constraint' 语句,它们实际上只是赋值语句:
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
这些只是意味着能量 SALES
是 MW_SETPOINT
从 t-1
到 1
的增量,而 PROFIT
是 SALE
* PRICE
每个间隔。因此,将它们声明为 'constraints' 对我来说似乎违反直觉。但是我无法在不抛出语法错误的情况下将它们表述为赋值语句。
问题:
- 是否有更惯用的方法来为作为其他 params/variables 函数的数组声明此类赋值语句?或者在
constraint
中为数组赋值是在 Minizinc 中的 recommended/idiomatic 方法吗?
上下文的完整程序:
% PARAMS
int: MW_CAPACITY = 10;
array[int] of float: PRICE;
% DERIVED PARAMS
int: STARTING_MW = MW_CAPACITY div 2; % integer division
int: T = length(PRICE);
% DECISION VARIABLE - MW SETPOINT EACH INTERVAL
array[1..T] of var 0..MW_CAPACITY: MW_SETPOINT;
% DERIVED/INTERMEDIATE VARIABLES
array[1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array[1..T] of var float: PROFIT;
var float: NET_PROFIT = sum(PROFIT);
% CONSTRAINTS
%% If start at 5MW, and sell 5 first interval, setpoint for first interval is 0
constraint MW_SETPOINT[1] = STARTING_MW - SALE[1];
%% End where you started; opt schedule from arbitrage means no net MW over time
constraint MW_SETPOINT[T] = STARTING_MW;
%% these are really justassignment statements for SALE & PROFIT
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
% OBJECTIVE: MAXIMIZE REVENUE
solve maximize NET_PROFIT;
output["DAILY_PROFIT: " ++ show(NET_PROFIT) ++
"\nMW SETPOINTS: " ++ show(MW_SETPOINT) ++
"\nMW SALES: " ++ show(SALE) ++
"\n$/MW PRICES: " ++ show(PRICE)++
"\nPROFITS: " ++ show(PROFIT)
];
可以运行和
minizinc opt_sched_hindsight.mzn --solver org.minizinc.mip.coin-bc -D "PRICE = [29.835, 29.310470000000002, 28.575059999999997, 28.02416, 28.800690000000003, 32.41052, 34.38542, 29.512390000000003, 25.66587, 25.0499, 26.555529999999997, 28.149440000000002, 30.216509999999996, 32.32415, 31.406609999999997, 36.77642, 41.94735, 51.235209999999995, 50.68137, 64.54481, 48.235170000000004, 40.27663, 34.93675, 31.10404];"```
你可以玩Array Comprehensions:(引用自文档)
Array comprehensions have this syntax:
<array-comp> ::= "[" <expr> "|" <comp-tail> "]"
For example (with the literal equivalents on the right):
[2*i | i in 1..5] % [2, 4, 6, 8, 10]
Array comprehensions have more flexible type and inst requirements than set comprehensions (see Set Comprehensions).
Array comprehensions are allowed over a variable set with finite type,
the result is an array of optional type, with length equal to the
cardinality of the upper bound of the variable set. For example:
var set of 1..5: x;
array[int] of var opt int: y = [ i * i | i in x ];
The length of array will be 5.
Array comprehensions are allowed where the where-expression
is a var bool
. Again the resulting array is of optional
type, and of length equal to that given by the generator expressions. For example:
var int x;
array[int] of var opt int: y = [ i | i in 1..10 where i != x ];
The length of the array will be 10.
The indices of an evaluated simple array comprehension are
implicitly 1..n
, where n
is the length of the evaluated
comprehension.
示例:
int: MW_CAPACITY = 10;
int: STARTING_MW = MW_CAPACITY div 2;
array [int] of float: PRICE = [1.0, 2.0, 3.0, 4.0];
int: T = length(PRICE);
array [1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT = let {
int: min_i = min(index_set(PRICE));
} in
[STARTING_MW - sum([SALE[j] | j in min_i..i])
| i in index_set(PRICE)];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in index_set(PRICE)];
solve satisfy;
输出:
~$ minizinc test.mzn
SALE = array1d(1..4, [-10, -5, 0, 0]);
----------
注意 index_set(PRICE)
就是 1..T
而 min(index_set(PRICE))
就是 1
,所以可以写成上面的 数组理解 也为
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT =
[STARTING_MW - sum([SALE[j] | j in 1..i])
| i in 1..T];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in 1..T];
我有一个 Minizinc 程序,可以根据时间间隔给定一组价格,为并网电池生成最佳 charge/discharge 时间表。
我的程序可以运行(有点;有一些注意事项),但我的问题是关于两个 'constraint' 语句,它们实际上只是赋值语句:
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
这些只是意味着能量 SALES
是 MW_SETPOINT
从 t-1
到 1
的增量,而 PROFIT
是 SALE
* PRICE
每个间隔。因此,将它们声明为 'constraints' 对我来说似乎违反直觉。但是我无法在不抛出语法错误的情况下将它们表述为赋值语句。
问题:
- 是否有更惯用的方法来为作为其他 params/variables 函数的数组声明此类赋值语句?或者在
constraint
中为数组赋值是在 Minizinc 中的 recommended/idiomatic 方法吗?
上下文的完整程序:
% PARAMS
int: MW_CAPACITY = 10;
array[int] of float: PRICE;
% DERIVED PARAMS
int: STARTING_MW = MW_CAPACITY div 2; % integer division
int: T = length(PRICE);
% DECISION VARIABLE - MW SETPOINT EACH INTERVAL
array[1..T] of var 0..MW_CAPACITY: MW_SETPOINT;
% DERIVED/INTERMEDIATE VARIABLES
array[1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array[1..T] of var float: PROFIT;
var float: NET_PROFIT = sum(PROFIT);
% CONSTRAINTS
%% If start at 5MW, and sell 5 first interval, setpoint for first interval is 0
constraint MW_SETPOINT[1] = STARTING_MW - SALE[1];
%% End where you started; opt schedule from arbitrage means no net MW over time
constraint MW_SETPOINT[T] = STARTING_MW;
%% these are really justassignment statements for SALE & PROFIT
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
% OBJECTIVE: MAXIMIZE REVENUE
solve maximize NET_PROFIT;
output["DAILY_PROFIT: " ++ show(NET_PROFIT) ++
"\nMW SETPOINTS: " ++ show(MW_SETPOINT) ++
"\nMW SALES: " ++ show(SALE) ++
"\n$/MW PRICES: " ++ show(PRICE)++
"\nPROFITS: " ++ show(PROFIT)
];
可以运行和
minizinc opt_sched_hindsight.mzn --solver org.minizinc.mip.coin-bc -D "PRICE = [29.835, 29.310470000000002, 28.575059999999997, 28.02416, 28.800690000000003, 32.41052, 34.38542, 29.512390000000003, 25.66587, 25.0499, 26.555529999999997, 28.149440000000002, 30.216509999999996, 32.32415, 31.406609999999997, 36.77642, 41.94735, 51.235209999999995, 50.68137, 64.54481, 48.235170000000004, 40.27663, 34.93675, 31.10404];"```
你可以玩Array Comprehensions:(引用自文档)
Array comprehensions have this syntax:
<array-comp> ::= "[" <expr> "|" <comp-tail> "]"
For example (with the literal equivalents on the right):
[2*i | i in 1..5] % [2, 4, 6, 8, 10]
Array comprehensions have more flexible type and inst requirements than set comprehensions (see Set Comprehensions).
Array comprehensions are allowed over a variable set with finite type, the result is an array of optional type, with length equal to the cardinality of the upper bound of the variable set. For example:
var set of 1..5: x; array[int] of var opt int: y = [ i * i | i in x ];
The length of array will be 5.
Array comprehensions are allowed where the where-expression is a
var bool
. Again the resulting array is of optional type, and of length equal to that given by the generator expressions. For example:var int x; array[int] of var opt int: y = [ i | i in 1..10 where i != x ];
The length of the array will be 10.
The indices of an evaluated simple array comprehension are implicitly
1..n
, wheren
is the length of the evaluated comprehension.
示例:
int: MW_CAPACITY = 10;
int: STARTING_MW = MW_CAPACITY div 2;
array [int] of float: PRICE = [1.0, 2.0, 3.0, 4.0];
int: T = length(PRICE);
array [1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT = let {
int: min_i = min(index_set(PRICE));
} in
[STARTING_MW - sum([SALE[j] | j in min_i..i])
| i in index_set(PRICE)];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in index_set(PRICE)];
solve satisfy;
输出:
~$ minizinc test.mzn
SALE = array1d(1..4, [-10, -5, 0, 0]);
----------
注意 index_set(PRICE)
就是 1..T
而 min(index_set(PRICE))
就是 1
,所以可以写成上面的 数组理解 也为
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT =
[STARTING_MW - sum([SALE[j] | j in 1..i])
| i in 1..T];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in 1..T];