将微型锌模型分解为用户定义的函数

时间:2018-08-04 05:18:33

标签: optimization minizinc

对于我的更大的minizinc模型,我需要一个基本回答以下问题的函数:“此数组的子集内,其总和是否在$ target的$ tolerance之内”(并返回一个布尔值)。

这本身就很容易用minizinc编写。例如

int: tolerance = 3;
int: target = 200;
int: amountsCount = 7;
array[1..amountsCount] of int: amounts = [23, 345, 230, 100, 25, 28, 25];


array[1..amountsCount] of var bool: includeAmount;

var int: subsetAmount = sum([(if includeAmount[i] then amounts[i] else  0 endif) | i in 1..amountsCount]);


var bool: solvable = abs(subsetAmount - target) < tolerance;
solve maximize bool2int(solvable);

output ["solvable=", show(solvable), " included: ", show(includeAmount), " subset amount:", show(subsetAmount)];

但是如何使它成为用户定义的函数(返回布尔值“可解决”),以便可以在实际模型中使用它?

1 个答案:

答案 0 :(得分:2)

您可以引入一个用户定义的谓词,该谓词在模型中返回solvable的值:

predicate has_subset_within_tolerance(array[1..amountsCount] of int: amounts_array) =
    let {
         var int: subsetAmount = sum([(if includeAmount[i] then amounts[i] else  0 endif) | i in 1..amountsCount]);
    } in 
         abs(subsetAmount - target) < tolerance
    ;

谓词就像函数一样,只是它们返回布尔值。在谓词中,我引入了局部变量subsetAmount并以与初始模型相同的方式对其进行约束。然后,我发布需要保留以使谓词返回true的表达式:abs(subsetAmount - target) < tolerance

然后您可以通过以下方式在模型中使用该谓词,例如在solve语句中:

int: tolerance = 3;
int: target = 200;
int: amountsCount = 7;
array[1..amountsCount] of int: amounts = [23, 345, 230, 100, 25, 28, 25];

array[1..amountsCount] of var bool: includeAmount;

solve maximize bool2int(has_subset_within_tolerance(amounts));

% don't forget to insert the predicate here as well

编辑

您还可以将变量includeAmount作为参数添加到谓词中:

predicate has_subset_within_tolerance(array[1..amountsCount] of int: amounts_array,
                                      array[1..amountsCount] of var bool: includeAmount)=
 let {
     var int: subsetAmount = sum([(if includeAmount[i] then amounts_array[i] else  0 endif) | i in 1..amountsCount]);
  } in 
     abs(subsetAmount - target) < tolerance
 ; 

然后,您可以使用不同的变量来调用谓词,例如includeAmount1includeAmount2

int: tolerance = 3;
int: target = 200;
int: amountsCount = 7;
array[1..amountsCount] of int: amounts1 = [23, 345, 230, 100, 25, 28, 25];
array[1..amountsCount] of int: amounts2 = [20, 35, 10, 400, 65, 19, 69];

array[1..amountsCount] of var bool: includeAmount1;
array[1..amountsCount] of var bool: includeAmount2;

solve maximize 
   bool2int(has_subset_within_tolerance(amounts1, includeAmount1))
 + bool2int(has_subset_within_tolerance(amounts2, includeAmount2));

如果它们还依赖于不同的target变量,还可以将toleranceincludeAmount作为谓词的参数添加。