Constraint to select certain items in MiniZinc - constraint-programming

I am trying to create a model to work with a problem derived from the Set Packing problem.
In this case, I have a parameter called nRecipes that represents the number of recipes and another called nIngred that represents the number of ingredients. Each recipe has a specific nutritional value that is represented by the value parameter.
I want to choose a menu with at most numDishes recipes, so that the nutritional value of the menu is maximized. Another restriction is that each chosen dish does not contain any ingredients in the other chosen dishes.
I have tried the following:
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
array[INGREDIENTS] of set of RECIPES: group;
var set of RECIPES: menu;
array[1..numDishes] of var RECIPES: selected_menu;
constraint menu <= selected_menu; % Error
constraint alldifferent(selected_menu);
solve maximize value;
Test example:
nRecipes = 10;
value = [10,8,4,2,6,9,5,3,8,10];
group = [{1,4,6},{1,2,6,7},{1,3,6,8},
{1,2,3},{2,9,10},{5,6,8,10},
{7,8,10},{1,3,5}];
numDishes = 3;
nIngred = 8;
Expected Output:
Value:20
Recipe:{1,10}

Here is one way, where the group variable has been flipped around to hold the ingredients per recipe (also renamed it ingredients). Now you can use all_disjoint to formulate the constraint that the selected dishes may not use the same ingredients.
include "globals.mzn";
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
array[RECIPES] of set of INGREDIENTS: ingredients;
array[1..numDishes] of var RECIPES: selected_menu;
constraint all_disjoint([ingredients[selected_menu[i]] | i in 1..numDishes]);
var int: obj = sum([value[selected_menu[i]] | i in 1..numDishes]);
solve maximize obj;
output ["total value=\(obj)\n"] ++
["selected_menu=\(selected_menu)\n"] ++
["ingredients=\([ingredients[selected_menu[i]] | i in 1..numDishes])\n"];
running with the data:
numDishes = 2;
nIngred = 8;
nRecipes = 10;
value = [10,8,4,2,6,9,5,3,8,10];
ingredients = [{1,2,3,4},{2,4,5},{3,4,8},
{1},{6,8},{1,2,3,6},
{2,7},{3,6,7},{5},{5,6,7}];
gives:
total value=20
selected_menu=[10, 1]
ingredients=[5..7, 1..4]
Edit: A new version that allows choosing less dishes than num_dishes dishes if that gives a better objective value. This is done through the variable dishes that represents the number of actually chosen dishes. Non-used menus will have a value of 0.
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
set of int: RECIPES0 = 0..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
var 1..numDishes: maxDishes;
array[INGREDIENTS] of set of RECIPES: group;
array[1..numDishes] of var RECIPES0: selected_menu;
constraint forall(i in INGREDIENTS)
(sum(m in selected_menu)(m in group[i]) <= 1);
var int: obj = sum([value[selected_menu[i]] | i in 1..maxDishes]);
solve maximize obj;
output["Value: ", show(obj), "\nRecipe: ", show([selected_menu[d] | d in 1..maxDishes])];
Edit: Another version using a set to represent selected_menu.
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
array[INGREDIENTS] of set of RECIPES: group;
var 1..numDishes: dishes;
var set of RECIPES: selected_menu;
% each ingredients may appear in at most one recipe
constraint forall(i in INGREDIENTS)
(card(selected_menu intersect group[i]) <= 1);
constraint card(selected_menu) <= dishes;
var int: obj = sum([value[m] | m in selected_menu]);
solve maximize obj;
output["Value: ", show(obj), "\nRecipe: ", show(selected_menu)];

Related

3D bin packing using OPL in Cplex

I have a 3D bin packing problem that I need to code in an OPL project in Cplex. I have to use item dimensions such as length, width and height in my constraints to ensure the items fit into the bins. The bins are all of the same dimensions. The information is all read from and Excel spreadsheet. I have incorporated the item dimensions, but I am struggling to include that multiple items of an item type can be ordered and must fit into the bin for example:
item 1 : 2 - two items of item 1 must be packed
item 2 : 8 - eight items of item 2 must be packed
etc...
the code I have is as follows:
//parameters
int n = ...;
range Item = 1..n;
range Bin = 1..n;
float binvolume = ...;
float itemvolume[Item] = ...;
float item_l[Item]=...;
float item_w[Item]=...;
float item_h[Item]=...;
float bin_h=...;
float bin_l=...;
float bin_w=...;
range QTY = 1..n;
int iq[QTY]=...;
//decision variables
dvar boolean x[Bin][Item];
dvar boolean y[Bin];
dvar boolean l[Bin][Item];
dvar boolean w[Bin][Item];
dvar boolean h[Bin][Item];
//objective
minimize sum(i in Bin)y[i];
//constraints
subject to {
forall( q in QTY){
forall(i in Bin)
constraint_1:
sum(j in Item) itemvolume[j]*x[i][j] <= binvolume*y[i];
forall(i in Bin)
constraint_2:
sum(j in Item)item_l[j]*l[i][j] <= bin_l*y[i];
forall(i in Bin)
constraint_3:
sum(j in Item) item_w[j]*w[i][j] <= bin_w*y[i];
}
forall(j in Item)
constraint_5:
sum(i in Bin) x[i][j] == 1;
forall(j in Item)
constraint_6:
sum(i in Bin) l[i][j] == 1;
forall(j in Item)
constraint_7:
sum(i in Bin) w[i][j] == 1;
forall(j in Item)
constraint_8:
sum(i in Bin) h[i][j] == 1;
}
execute{
if(cplex.getCplexStatus() == 1){
writeln("Items are placed in bins as : ", x.solutionValue);
}
else{
writeln("Error, solution not found");
}
}

An internal unit of company XYZ provides services to other departments

Example 1:
``
Given S="300.01" and B-["300.00", "200.00*,*100.00"].
R[0]="150.00" (=300.01 300.00/600.00) R[1]="100.00" (=150.01* 200.00/300.00)
R[2]="50.01" (=50.01*100.00/100.00)
Example 2 (Pay careful attention to this one).
Given S="1.00" and B=["0.05","1.00"]. 1. First we consider 1.00 because it is the largest,
a. 1.00*1.00/1.05~0.95238...
b. Round 0.95238... to "0.95". Rounding down to carry pennies to smaller departments. c. Set R[1]=0.95. Notice, this is in the same place as 1.00. It is the 2nd value in the result! 2. Now we have 0.05 left
Next we look at the smaller B[0]=0.05 department
a. 0.05 0.05/0.05 = 0.05 b. No rounding required
c. Set R[0]=0.05. R=["0.05", "0.95"]
`
Write a function:
class Solution { public String[] solution(String 5, String[] B); }
that, given a string S representing the total excess billables and an array B consisting of K strings representing the undiscounted bills for each customer. The return value should be an array of strings R (length M) in the same order as B representing the amount of the discount to each customer.
Notes:
The total S should be completely refunded. Neither more nor less than S should be
returned. Don't lose or gain a penny!
Be careful with the types you choose to represent currencies. Floating points numbers are notoriously error prone for precise calculations with currencies.
Test Output
Amounts should be rounded down to the nearest $0.01. By design, fractional pennies are pushed to groups with smaller unadjusted invoices.
Results should be represented with 2 decimal places of precision as strings, even if these are both zeroes. ex. "100.00" 5. You may assume sensible inputs. The total to be discounted will never exceed the total of the
unadjusted invoices.
Please do pay attention to returning the discounts in the same order as the incoming invoices.
Answer:::
def solution(A):
answer = 0
current_sum = 0
#Currently there is one empty subarray with sum 0
prefixSumCount = {0:1}
for list_element in A:
current_sum = current_sum + list_element
if current_sum in prefixSumCount:
answer = answer + prefixSumCount[current_sum]
if current_sum not in prefixSumCount:
prefixSumCount[current_sum] = 1
else:
prefixSumCount[current_sum] = prefixSumCount[current_sum] + 1
if answer > 1000000000:
return -1
else:
return answer
#Sample run
A = [2,-2,3,0,4,-7]
print(solution(A))
strong text
Find my solution for JavaScript
You can avoid function sumArray and use the sum funciton with reducer within solution function.
enter code here
function solution(S, B) {
// write your code in JavaScript (Node.js 8.9.4)
let copyArray=[...B];
let solutionObj={};
//ordered array to consider last first
copyArray.sort();
//calculating sum of values within array
let sumArray=B.reduce((acc,value)=> acc+Number(value),0);
//calculating values of array
//loop for ading on to solvin array
let initial=S;
for(i=copyArray.length-1;i>=0;i--){
//obtaining index of value addded to solution array
let index=B.indexOf(copyArray[i]);
let value=initial*copyArray[i]/sumArray;
value=i==0?Math.ceil(value*100)/100:Math.floor(value*100)/100;
solutionObj[index]=value.toFixed(2);
}
return Object.values(solutionObj) ;
}
console.log(solution(300.01,["300.00","200.00","100.00"]))
console.log(solution(1.00,["0.05","1.00"]))
These are the resulting entries
Solution in java for the same coding exercise
public String[] solution(String S, String[] B) {
List<Double> list = Arrays.stream(B).sorted(Comparator.comparingDouble(v->Double.valueOf((String) v)).reversed()).map(Double::parseDouble).collect(Collectors.toList());
Double S1 = Double.valueOf(S);
String R[] = new String[B.length];
Double total = 0.00;
for (int i = 0; i< list.size(); i++){
Double individualValue = list.get(i);
Double sumTotal = 0.0;
for(int j = i+1;j < list.size(); j++){
sumTotal+=list.get(j);
}
BigDecimal data = new BigDecimal(S1 * (individualValue / (individualValue + sumTotal)));
data = data.setScale(2, RoundingMode.FLOOR);
total+=data.doubleValue();
R[i] = String.valueOf(data);
S1 = S1 - Double.valueOf(R[i]);
}
Double diff = new BigDecimal(Double.valueOf(S) - total).setScale(2, RoundingMode.HALF_DOWN).doubleValue();
if (diff > 0) {
R[B.length - 1] = String.valueOf(Double.valueOf(R[B.length - 1]) + diff);
}
return R;
}

CPLEX execute block is not being run from VBA

I have a model written in OPL, that is called from VBA.
Afterwards an execute block is made, but when the call from VBA is made, the execute block does not run.
// Create Parameters:
{string} G1 = ...; // Set of teams in first group
{string} G2 = ...; // Set of teams in second group
{string} G3 = ...; // Set of teams in third group
{string} G4 = ...; // Set of teams in fourth group
{string} Teams = G1 union G2 union G3 union G4;
tuple Match {string team1; string team2;}
{Match} Matches_G1 = {<t1,t2>| ordered t1,t2 in G1};
{Match} Matches_G2 = {<t1,t2>| ordered t1,t2 in G2};
{Match} Matches_G3 = {<t1,t2>| ordered t1,t2 in G3};
{Match} Matches_G4 = {<t1,t2>| ordered t1,t2 in G4};
{Match} MD2 = ...;
{Match} MD6 = ...;
{Match} MD10 = ...;
{Match} MD4 = ...;
{Match} MD8 = ...;
{Match} MD12 = ...;
{Match} M_G12 = Matches_G1 union Matches_G2; //All matches for the first two groups
{Match} M_G34 = Matches_G3 union Matches_G4; //All matches for the second two groups
{Match} M = M_G12 union M_G34;
{Match} matchForTeam[t in Teams] = {m| m in M : m.team1 == t || m.team2 == t}; //List of all teams
{string} S =...; //Set of stadiums
{string} T = ...; //Set of kick off times
{string} D = ...; //Set of kick off days
int K[D][S][T] = ...; //Predetermined schedule between stadium and kickoff time
float VT[M][T] = ...; //Value of match M is played at Time T according to TV distribution
float VH[M][S] = ...; //Value of match M is played at stadium S according to Hospitality
int V[M] = ...;
int Treshold = ...;
//float W = 4;
//float Q = 1000;
// Decision Variables:
dvar int X[M][S][T] in 0..1; // if match M is played at stadium S at time T
dvar int Dist; //Object function for distribution
dvar int Hosp; //Object function for Hopsitality
dvar int Village[M][S] in 0..1; //If village build at stadium S
//////////// OBJECTIVE FUNCTION ///////////////
maximize
1000*Dist+0.1*Hosp;
//////////// CONSTRAINTS ///////////////
subject to{
Dist == sum(m in M, s in S, t in T) VT[m][t]*X[m][s][t];
Hosp == sum(m in M, s in S, t in T) VH[m][s]*X[m][s][t];
Block of code...
}
execute {
var cd = new IloOplOutputFile("resbi2.txt");
for(var m in M)
for(var s in S)
for(var t in T)
cd.writeln(thisOplModel.X[m][s][t]);
cd.close();
writeln("schedule: ", X);
}
If I run it directly in CPLEX then it is not a problem, the file is created. But this is not happening when the call from VBA is made. Any ideas how to solve this? Thanks in advance.
can you change
var cd = new IloOplOutputFile("resbi2.txt");
into an absolute path like
var cd = new IloOplOutputFile("c:\\resbi2.txt");
?

Why does this two-line change break this minizinc set-cover program?

The program below (adapted from http://www.hakank.org/minizinc/set_covering4b.mzn ) is a solution to the set-cover problem (example data provided at end of question). This runs correctly.
int: num_alternatives;
int: num_objects;
par set of int: ALTERNATIVES = 1..num_alternatives;
% costs for the alternatives
array[ALTERNATIVES] of int: costs;
% objects covered by the alternatives
array[ALTERNATIVES] of var set of 1..num_objects: a;
% decision variable: which alternative to choose
array[ALTERNATIVES] of var bool: x;
% the objective to minimize
var int: z = sum(i in 1..num_alternatives) (x[i]*costs[i]);
solve minimize z;
constraint
forall(j in 1..num_objects) (
sum(i in 1..num_alternatives) (x[i] * bool2int(j in a[i])) >= 1
)
;
output
[
"x: " ++ show(x) ++ "\n" ++
"a: " ++ show(a) ++ "\n"
];
However, if I replace the a definition above:
array[ALTERNATIVES] of var set of 1..num_objects: a;
with these two lines that seem to me to be equivalent:
var set of int: OBJECTS = 1..num_objects;
array[ALTERNATIVES] of OBJECTS: a;
...suddenly I get the following error:
MiniZinc: type error: type-inst must be par set but is `var set of
int'
This confuses me. What did I even change? In each case a is an array of sets of ints. The type-instance is a var set of int in each case, but the second one throws an error and the first one doesn't for some reason?
Here's some data which can be dropped in the bottom of the .mzn code file to produce a self-contained, runnable example:
% data
num_alternatives = 10;
costs = [ 19, 16, 18, 13, 15, 19, 15, 17, 16, 15];
num_objects = 8;
% the alternatives and the objects they contain
a = [
{1,6},
{2,6,8},
{1,4,7},
{2,3,5},
{2,5},
{2,3},
{2,3,4},
{4,5,8},
{3,6,8},
{1,6,7}
];
You could write it as follows:
int: num_alternatives;
int: num_objects;
set of int: ALTERNATIVES = 1..num_alternatives;
set of int: OBJECTS = 1..num_objects;
% costs for the alternatives
array[ALTERNATIVES] of int: costs;
% objects covered by the alternatives
array[ALTERNATIVES] of var set of OBJECTS: a;
% decision variable: which alternative to choose
array[ALTERNATIVES] of var bool: x;
% the objective to minimize
var int: z = sum(i in ALTERNATIVES) (x[i]*costs[i]);
solve minimize z;
constraint
forall(j in OBJECTS) (
sum(i in ALTERNATIVES) (x[i] * (j in a[i])) >= 1
)
;
output
[
"x: " ++ show(x) ++ "\n" ++
"a: " ++ show(a) ++ "\n"
];
In your experiment
var set of int: OBJECTS = 1..num_objects;
array[ALTERNATIVES] of OBJECTS: a;
a is an array of integers in the range 1..num_objects.
But you intended an array of sets of integers in that range.

Efficient predicate for palindrome in Minizinc

To help me learning Minizinc, I am trying to solve an easy problem. My code finds an answer but I am surprised that it takes about 10 seconds to run for such an easy problem.
The problem is "What is the smallest palindromic integer > 10, so that the sum of its digits is > 10 and palindromic too ?".
And I want the code to do large assumptions only: answer has 8 digits at most.
My code is (the toNum predicate comes from hakank website):
predicate toNum(array[int] of var int: a, var int: n, int: base) =
let { int: len = length(a) }
in
n = sum(i in 1..len) (
ceil(pow(int2float(base), int2float(len-i))) * a[i]
)
/\ forall(i in 1..len) (a[i] >= 0 /\ a[i] < base)
;
predicate toNum10(array[int] of var 0..9: a, var int: n) = toNum(a, n, 10);
predicate palindrome_array(array[int] of var int: t) =
let { int: l = length(t), var 1..l: d } in (
forall(j in 1..d-1) (t[j] = 0) /\
t[d] != 0 /\
forall(j in d..(l+d-1) div 2) (t[j] = t[l+d-j])
)
;
predicate palindrome_int(var int: n) =
let { int: size = ceil(log10(int2float(ub(n))))+1,
array[1..size] of var 0..9: digits } in (
toNum10(digits, n) /\
palindrome_array(digits)
)
;
var int: n;
array[1..8] of var 0..9: t;
constraint toNum10(t, n);
constraint palindrome_int(n);
constraint n>10;
var int: s = sum(t);
constraint palindrome_int(s);
constraint s>10;
constraint alldifferent([n, s]);
solve minimize n;
The complete version has the following additional constraints:
var int: s2 = sum(i in 1..8) (t[i]*t[i]);
constraint palindrome_int(s2);
constraint s2 > 10;
var int: s3 = sum(i in 1..8) (t[i]*t[i]*t[i]);
constraint palindrome_int(s3);
constraint s3 > 10;
constraint alldifferent([n, s, s2, s3]);
What's wrong/slow with my code ?
Try to replace "solve minimize n;" with the following labeling strategy:
solve :: int_search(t, first_fail, indomain_min, complete) minimize n;
On my machine, it then takes < 0.1s.

Resources