Optimization production list order - math

I have an optimization problem.
The situation is the following:
Imagine many boxes (box 1, box 2, box 3, box 4 …). Each one of these boxes needs to be filled with a different combination of items
Ex:
Box 1 : item B + E
Box 2 : item A + C
Box 3 : item E
Box 4 : item B + C + E + F
….
Each one of these boxes may content up to 6 products. There are around 100 boxes to fill and about 45 different products.
• When an item is treated, all the boxes with this item are filled with it.
• Each item type is treated once only :
• When a box contains one or more items it is “Open”
• When a box contains all of its items, it is “Closed”.
We must find the treatment order that minimizes the average number of open boxes.
Ex:
1. Items B
2. Items D
3. Items A
4. …
Would give 11 open boxes on average.
Sadly, testing all possibilities is not an option. ( 40! = a lot) so we’re looking for a way to formalize the problem and solve it.
Any ideas?
I would like to get a list which show me the item productions order

One option would be to address this problem through constraint programming. Below a simple MiniZinc (https://www.minizinc.org) model with a small data set:
include "globals.mzn";
int: items = 5;
set of int: ITEM = 1..items;
set of int: TIME = 1..items;
int: boxes = 8;
set of int: BOX = 1..boxes;
array[BOX] of set of ITEM: content = [{1}, {1,3}, {1,3,4}, {2,4}, {1,2}, {4}, {1,2,5}, {4,5}];
array[ITEM] of var TIME: time; % which item to treat at which time instant
array[TIME] of var ITEM: item; % which time instant to treat each item
array[BOX] of var TIME: open = [min([time[i] | i in content[b]]) | b in BOX];
array[BOX] of var TIME: close = [max([time[i] | i in content[b]]) | b in BOX];
constraint inverse(time, item);
var int: obj = sum(b in BOX)(close[b] - open[b]);
solve minimize obj;
output ["obj = \(obj)\n"] ++ ["item = \(item)\n"] ++ ["open = \(open)\n"] ++ ["close = \(close)\n"]
This model minimizes the cumulative open time of all the boxes. If you instead want to minimize the maximum time any box is open then change the objective to var int: obj = max(b in BOX)(close[b] - open[b]).
Edit: To minimize the maximum number of boxes open at any time instant use the following:
% number of open boxes after each step
array[TIME] of var int: nopen = [sum(b in BOX)(close[b] > t /\ open[b] <= t) | t in TIME];
var int: obj = max(nopen);
I hope this model can be adapted for you data and that it scales well enough.
Edit:
To scale to larger instances you could use a LNS (Large Neighbourhood Search) configuration with the default Gecode solver.
To do so replace the solve minimize obj; item with:
% Gecode
annotation relax_and_reconstruct(array[int] of var int,int);
solve
:: int_search(item, dom_w_deg, indomain_random, complete)
:: restart_luby(50)
:: relax_and_reconstruct(item, 80)
minimize obj;
Another option would be to try another solver. For this model the or-tools-solver (https://developers.google.com/optimization/) seems to work particularly well, especially if configured with more threads (e.g. 8).
You could also switch to the OsiCbc-solver (provided with the MiniZinc-distribution) and use the following MIP-model:
include "globals.mzn";
int: items;
set of int: ITEM = 1..items;
set of int: TIME = 1..items;
int: boxes;
set of int: BOX = 1..boxes;
array[BOX] of set of ITEM: content;
array[ITEM, TIME] of var 0..1: x;
array[BOX] of var TIME: open;
array[BOX] of var TIME: close;
constraint forall(i in ITEM)
(sum(t in TIME)(x[i,t]) = 1);
constraint forall(t in TIME)
(sum(i in ITEM)(x[i,t]) = 1);
constraint forall(b in BOX, i in content[b])
(open[b] <= sum(t in TIME)(t*x[i,t]) /\ close[b] >= sum(t in TIME)(t*x[i,t]));
array[BOX] of int: v = [card(content[b]) - 1 | b in BOX];
constraint forall(b in BOX) % redundant constraints
(close[b] >= open[b] + v[b]);
var int: obj = sum([close[b] - open[b] | b in BOX]);
solve
minimize obj;
output ["obj = \(obj)\n"] ++ ["item = \([sum(i in ITEM)(i * x[i,t]) | t in TIME])\n"] ++ ["open = \(open)\n"] ++ ["close = \(close)\n"] ++ ["nopen = \([fix(sum(b in BOX)(close[b] > t /\ open[b] <= t)) | t in TIME])\n"];

Related

How to “tripartite” a tree using 0, 1 and 2 and maximize the numbers used?

An interesting problem is to assign labels (0, 1 or 2) for every node in a tree (not necessarily binary), where no parent-child pair can have the same label. In addition, we need to maximize the sum of all labels, i.e., use as little 0 as possible. Return the minimum number of 0 labels used. Some leaf nodes have been pre-labeled. We cannot change those labels. If there are no way to assign labels, for example, one parent node has children pre-labeled with all three labels, return negative infinity.
I am trying dynamic programming on this. One possible recurrence is that OPT(v) returns the number of 0 used to label v’s subtree, and we start at the overall root. When recurse down the tree, try to label each v’s children 0, 1 and 2 (by manipulating v.label field in each node) and see which option returns the minimum number of 0. If we reach bottom and a leaf node has been pre-labeled, we can’t explore all labels but to use the given label. If the leaf node is not pre-labeled, try each label, same as above. The tree itself can be used as my memorization structure where the label is stored in each node’s .label field. But I am not sure how to write the recurrence explicitly, especially for the recursive case when I explore all possible labels for every child of current node. I have no idea to express this combination and get the minimum of it. The base case is fairly simple, perhaps return 1 if the leaf is labeled 0 and return 0 otherwise.
Your idea looks fine. Just one thing to improve: the memoization should concern not just one label value, but possibly all 3 label values (0, 1 and 2). For each label you would (per node) memoize what the minimum number of zeroes is in that node's tree (where it is the root) when that label is assigned to it.
Then, depending on which choice you made for the parent node, you would look at the two possible labels that remain and choose the label which has the least number of zeroes linked to it.
For the below implementation I have used this tree as example:
*
/ \
* * ___
/|\ / \ \
1 * * 2 * *
/ \ \
* 2 2
/|\
2 * 0
The asterisks are nodes that have no label.
So the algorithm would start at the root and temporarily assign it a 0, then see what effect and possibilities that leaves for the children. Then for each child go through the possible values it can have (not zero), ...and recurse deeper into the tree, each time backtracking -- registering the count of 0 labels -- and continuing with the next possible label for the node (and going down the tree again unless memoization is available).
For the above example we can see that an optimal labeling would be:
0
/ \
2 1 ___
/|\ / \ \
1 1 1 2 0 0
/ \ \
1 2 2
/|\
2 2 0
The root and its left child could swap values -- it doesn't matter. The result is 4 zeroes.
Here is the implementation:
// Main algorithm:
function triple(node, parentLabel=-1) {
let choices = node.label !== undefined ? [node.label] : [0,1,2];
let minCount = Infinity;
for (let label of choices) {
if (label === parentLabel) continue; // We cannot use same label as parent has
let count = node.memo[label]; // Already memoized?
if (count === undefined) { // No...
count = 0;
for (let child of node.children) {
count += triple(child, label); // recur
if (count >= minCount) break; // not better...
}
node.memo[label] = count;
}
if (label === 0) count++; // Count the zero
if (count < minCount) minCount = count; // better!
}
// Minimum number of 0-labels if parent has the given parentLabel
return minCount;
}
class Node {
constructor(label, ...children) {
this.label = label;
this.children = children;
this.memo = [undefined, undefined, undefined];
}
}
// Short-cut function for creating a Node instance with or without label
function N(...children) {
let label = undefined;
if (typeof children[0] === "number") { // first argument is a label
label = children.shift(); // extract first argument
}
return new Node(label, ...children);
}
// Demo
let tree = N(
N(
N(1), N(), N()
),
N(
N(2),
N(
N(
N(2), N(), N(0)
),
N(2)
),
N(
N(2)
)
)
)
console.log("input tree:");
console.log(tree);
let count = triple(tree);
console.log("Number of zeroes:", count);
This implementation would return Infinity when there is no valid labelling possible.

Ordered set AMPL

I am trying to program a set, F, which contains subsets of unknown size in AMPL.
An example would be: F1 = {2,3}, F2 = {5}, F3={4}, F4={5}.
The complete set will be of the form {(2,3),(5),(4),(5)}.
I need the set to be organized in this way because I will use this set in a constraint where I will need to iterate for every j contained in the set Fi. So when i=1, j will iterate for j=1,2 and so on.
Is there a way to program this set in AMPL?
I am working programming on assembly line balancing problems and will need this set to program the precedence constraints; ie. task 1 must happen before tasks 2 and 3, task 3 before 4, and task 2 and 4 before 5.
Thanks.
You can represent F as an indexed set in AMPL:
set F{1..4};
data;
set F[1] = 2 3;
set F[2] = 5;
set F[3] = 4;
set F[4] = 5;

Index of string value in MiniZinc array

The question
Given a MiniZinc array of strings:
int: numStats;
set of int: Stats = 1..numStats;
array[Stats] of string: statNames;
... with data loaded from a MiniZinc data file:
numStats = 3;
statNames = ["HEALTH", "ARMOR", "MANA"];
How can one look up the index of a specific string in the array? For example, that ARMOR is located at position 2.
The context
I need to find an optimal selection of items with regard to some constraints on their stats. This information is stored in a 2D array declared as follows:
int: numItems;
set of int: Items = 1..numItems;
array[Items, Stats] of float: itemStats;
So in order to write a constraint on, say, the minimum amount of ARMOR obtained through the selected items, I need to know that ARMOR has index 2 in the inner array.
Since the data file is generated by an external program, and the number and order of stats are dynamic, I cannot hardcode the indices in the constraints.
One solution (that won't work in my case)
The MiniZinc tutorial uses an interesting trick to achieve something similar:
set of int: Colors = 1..3;
int: red = 1;
int: yellow = 2;
int: blue = 3;
array[Colors] of string: name = ["red", "yellow", "blue"];
var Colors: x;
constraint x != red;
output [ name[fix(x)] ];
Unfortunately, as variable declarations are not allowed in MiniZinc data files, this trick won't work in my case.
You can write your own custom function to get the index of a string within a string array:
function int: getIndexOfString(string: str,
array[int] of string: string_array) =
sum( [ if str = string_array[i]
then i
else 0 endif
| i in index_set(string_array) ]
);
In this function I create an array of integers where the integer at position i either equals the index of str if string_array[i]=str and 0 otherwise. For instance, for your sample string array ["HEALTH", "ARMOR", "MANA"] and str ARMOR the resulting int array will be [0,2,0].
This is why I can simply sum over the int array to get the index of the string. If the string does not occur, the return value is 0, which is fine since indices in MiniZinc start with 1 by default.
Here is how you can call the function above for your first example:
int: numStats;
set of int: Stats = 1..numStats;
array[Stats] of string: statNames;
numStats = 3;
statNames = ["HEALTH", "ARMOR", "MANA"];
var int: indexOfArmor;
constraint
indexOfArmor = getIndexOfString("ARMOR",statNames);
solve satisfy;
Note however that the function above is limited and has some flaws. First, if you have multiple occurrences of the string in the array, then you will receive an invalid index (the sum of all indices where str occurred). Also, if you have your own index set for your string array (say (2..6)), then you will need to adapt the function.
Another, cleaner option is to write a function that uses a recursive helper function:
% main function
function int: index_of(string: elem, array[int] of string: elements) =
let {
int: index = length(elements);
} in % calls the helper function with the last index
get_index(elem, elements, index)
;
% recursive helper function
function int: get_index(string: elem, array[int] of string: elements, int: index) =
if index == 0
then -1 % the element was not found (base case of recursion)
elseif elements[index] == elem
then index % the element was found
else
get_index(elem, elements, index - 1) % continue searching
endif
;
The helper function iterates recursively over the array, starting from the last element, and when it finds the element, it returns the index. If the element was not found in the array, then -1 is returned. Alternatively, you can also throw an assertion following the suggestion of Patrick Trentin by replacing then -1 with then assert(false, "unknown element: " + elem).
An example of calling this function:
set of int: Customers = 1..5;
array[Customers] of string: ids = ["a-1", "a-2", "a-3", "a-4", "a-5"];
var int: index = index_of("a-3", ids);
var int: unknown_index = index_of("x-3", ids);
where index will be assigned 3 and unknown_index will be -1.
An alternative approach to that presented by Andrea Rendl-Pitrey, is the following one:
array[int] of string: statNames = array1d(10..12, ["HEALTH", "ARMOR", "MANA"]);
var int: indexOfArmor =
sum([i | i in index_set(statNames) where statNames[i] = "ARMOR"]);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
which outputs:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
note: that var can be dropped from the declaration of indexOfArmor, since the index can be statically computed. I kept it here only for output purposes.
A better solution is to declare a new predicate:
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
assert(
not exists(i in index_set(arr), j in index_set(arr))
(i != j /\ arr[i] = str /\ arr[j] = str),
"input string occurs at multiple locations",
assert(
exists(i in index_set(arr))
(arr[i] = str),
"input string does not occur in the input array",
exists(i in index_set(arr))
(arr[i] = str /\ i = idx)
));
which enforces both of the following conditions:
str occurs at least once in arr
str does not occur multiple times in arr
e.g
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
...
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ATTACK"]);
var int: indexOfArmor;
constraint index_of_str_in_array(indexOfArmor, "ARMOR", statNames);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
outputs
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
If one changes statNames in the following way
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ARMOR"]);
then mzn2fzn detects an assertion violation:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
MiniZinc: evaluation error:
example.mzn:24:
in call 'index_of_str_in_array'
example.mzn:4:
in call 'assert'
Assertion failed: input string occurs at multiple locations
flatzinc:
example.fzn: cannot open input file: No such file
A similar result would be obtained by searching for the index of a string that does not occur in the array. This condition can of course be removed if not necessary.
DISCLAIMER: older versions of mzn2fzn don't seem to check that the declared index-set of an array of strings variable matches the index-set of an array of strings literal that is being assigned to it. This rule is enforced on newer versions, as it is also valid for other data types.
According to this other post on Stackoverflow there is no way of converting strings to integers in MiniZinc, only the other way around. You need to first pre process your data in some other language and turn it into integers. You can however turn those integers into string once you are done in MiniZinc.
You can however load MiniZinc files instead of data files if you would like. Use the include syntax to include any .mzn file.

Minizinc: is this constraint possible?

I'd like to figure out how to write this constraint: I have a list of exams,every exam has a duration; the final output is the display of a real timetable, in the columns there are the available hours, four in the morning and four in the afternoon, with two hours in the middle of lunch which won't be available.So,let me make this perfectly clear,if I have two exams and each exam has an assigned duration, I'd like to show the number of the exam in the timetable linked to their duration,because my variables are the exams.
For example: I have two exams and the first takes one hours,the second three hours
int: Exams;
array[1..Exams] of int: Exams_duration;
int: Slotstime; % number of slots
int: Rooms; % number of rooms
array[1..Slotstime,1..Rooms] of var 0..Exams: Timetable_exams;
%Data
Exams=2;
Exam_duration=[1,3];
Slotstime=4;
I'd like to have this output: [1,2,2,2] and not [0,0,0,4] (in vertical mode)
Is it possible to do in Minizinc?
The code for the second output is:
constraint forall (p in 1..Rooms)
(
sum (s in 1..Slotstime) (Timetable_exams[s,p])
= sum (f in 1..Exams)(Exams_duration[f])
);
Thanks in advance
(Hi, this question is easier to answer than your original question since it is much more to the point.)
Here is a version that use two extra arrays of decision variables: "ExamsRoom" to handle the assignment of the room to an exam, and "ExamsStart" for the start time of the exam. Perhaps these are not really necessary, but they makes it easier to state the exam duration constraint; the assignments of the room and time are more also shown more clearly. They might also be useful for adding further constraints.
I also added the parameter "Rooms = 2" since it was missing from your example.
int: Exams;
array[1..Exams] of int: Exams_duration;
int: Slotstime; % number of slots
int: Rooms; % number of rooms
array[1..Slotstime,1..Rooms] of var 0..Exams: Timetable_exams;
array[1..Exams] of var 1..Rooms: ExamsRoom; % new
array[1..Exams] of var 1..Slotstime: ExamsStart; % new
solve satisfy;
% solve :: int_search(x, first_fail, indomain_min, complete) satisfy;
constraint
% hakank's version
% for each exam
forall(e in 1..Exams) (
% find a room
exists(r in 1..Rooms) (
% assign the room to the exam
ExamsRoom[e] = r /\
% assign the exam to the slot times and room in the timetable
forall(t in 0..Exams_duration[e]-1) (
Timetable_exams[t+ExamsStart[e],r] = e
)
)
)
/\ % ensure that we have the correct number of exam slots
sum(Exams_duration) = sum([bool2int(Timetable_exams[t,r]>0) | t in 1..Slotstime, r in 1..Rooms])
;
output [
if r = 1 then "\n" else " " endif ++
show(Timetable_exams[t,r])
| t in 1..Slotstime, r in 1..Rooms
]
++
[
"\nExamsRoom: ", show(ExamsRoom), "\n",
"ExamsStart: ", show(ExamsStart), "\n",
]
;
%
% Data
%
Exams=2;
Exams_duration=[1,3];
Slotstime=4;
% was not defined
Rooms = 2;
This model have 20 different solutions, the first two (using Gecode as a solver) is
2 0
2 0
2 0
1 0
ExamsRoom: [1, 1]
ExamsStart: [4, 1]
----------
2 1
2 0
2 0
0 0
ExamsRoom: [2, 1]
ExamsStart: [1, 1]
----------
The first solution means that exam 1 starts at time 4 in room 1, and exam 2 starts at time 1, also in room 1. The second solution has the same assignment for exam 2, but set exam 1 to room 2 (at time 1).
Hope this helps you to go further with the model.
/hakank

How to quickly populate a dictionary in Swift

I'm creating a new dictionary, say:
var a: [Int: Int] = []
And, I'd like to set the keys 0...n to 1.
I'm doing this, rather brutishly as:
for i in 0...n {
a[i] = 1
}
n is likely to be around 700000. And, this "initialization" takes hours.
I know I can do this to an array:
var z: [Int] = []
z = Array(0...700000)
and, in a few seconds I get a 700000 element array.
What's the right way to populate my dictionary? Thanks much.
I tried to run your code, slightly modified, like this:
let n = 700000
let start = NSDate()
var a: [Int: Int] = [:] //Dictionary<Int, Int>(minimumCapacity: n)
for i in 0..<n {
a[i] = 1
}
let stop = NSDate()
let dif = stop.timeIntervalSinceDate(start)
println(dif)
This runs for 6.7 seconds. If I replace the
[:]
with
Dictionary<Int, Int>(minimumCapacity: n)
it gets initialized in 3 seconds (debug build, no optimizations). Perhaps you are not on the latest build of Xcode?

Resources