2D bin packing with predefined gaps in container - algorithm

I have a problem with optimal placing of rectangular objects with different size and amount in rectangular container. The problem can be perfectly solved with the one of 2D bin packing algorithms but only on empty container. For me it is almost always not a case. My containers can have a restricted places where no object can be placed.
Packing example
Surely I am not the first one who encountered this kind of problem and I hope someone already developed a good solution for it. Anything is good: book references, articles, code snippets, etc.
Formal algorithms are prefered upon neural networks and this kind of things.

One possible way to solve it is with integer linear programming. There are different models but here is a simple one (with a bit of an issue, but you can improve on this if necessary).
Split the problem into a master problem and sub problems, with the master problem looking like this:
minimize sum(p)
s.t.
for all i: sum[j] p[j]*count[j,i] >= n[i]
p[i] >= 0 (and integer, don't add this constraint)
Where:
p are the decision variables, deciding how many instances to use of a particular "packing" of the available items into the container. There are obviously way too many of these to list in advance, but they can be generated dynamically.
count[j,i] is the number of times that packing j contains item i.
n[i] is the number of times we want item i.
the constraints are >= because packing a couple extra items is OK and it lets us use fewer different packings (otherwise the master problem would need special "deliberately subobtimal" packings to be able to fulfill the constraint).
the integer constraint shouldn't be added explicitly if you're using a solver, because an integer solution may need columns that were not needed yet in the fractional solution.
Start with a couple of dumb packings for each item so that there definitely is some solution, bad as it may be. You can even just place one item in the container which is trivial to do even without using the solver for the sub problem, but the sub problem has to be solved anyway so you may as well reuse it here.
The sub problem is finding out what packing can be made that would improve the current solution that the master problem has. So take the dual costs of the rows of the master problem C (there are as many as there are different kinds of item) and solve
maximize y.C
s.t.
1) for all i: y[i] <= n[i]
2) for all i: y[i] = sum[j] P[j] if j is a placement of item i
3) for all cells (a,b): sum[j] P[j] (if j covers a,b) <= 1
4) for all existing packings e: e.y <= sum(e) - 1
y >= 0 and integer
P boolean
Where,
y are implied variables that follow from a choice for P, y[i] is how many times item i occurs in the packing.
P are the real decision variables, deciding whether or not to use a particular placement of a particular item. There are 62 different item-placements in your example problem, including rotations.
constraint 1 ensures that a packing can actually be used in an integer solution to the master problem (using too many of an item would doom the corresponding variable to be fractional or zero).
constraint 2 links y to P
constraint 3 ensures that the solution is a valid packing, in the sense that items do not overlap each other.
constraint 4 is necessary to avoid re-creating a column that was already added to the master problem.
Re-creating a column wouldn't happen if the master problem was a regular linear program, but it's an integer program and after branching constraint 4 needed to explicitly prevent re-creation. For example, on the "low" branch (recall this means we took some variable k that had a fractional value f and limited it to be <= ⌊f⌋), the first thing the sub problem tries to do is re-create exactly the same packing that corresponds k, so that it can be added to the master problem to "undo the damage". That is exactly the opposite of what we need though. So re-creating a column must be banned.
Constraint 4 is not a great way to do it, because now what the sub problem will try is generating all equivalent packings, thanks to symmetries. For example, after rounding down the variable of this packing:
It generates equivalent packings like these:
etc. There are a lot of these, and they're all pointless because it doesn't matter (for the objective value of the master problem, when the integer constraint is taken into account) where the 1x3 piece goes, it just matters that the packing contains a 1x3 piece and 14 1x1 pieces.
So ideally constraint 4 would be replaced by something more complicated that bans a packing equivalent to any that have come before, but something else that mostly works is first trying the high branch. At least in this example, that works out just fine.
In this example, after adding the columns that allow the master problem to be optimal (but still fractional, before any branching), the objective value is 5.5882352941176467. That already means that we know we'll need at least 6 containers, because this being the optimal fractional value proves that it cannot be done with 5 and a fractional number of containers is not an option.
A solution with 6 containers is found quickly, namely
Three of these:
One each of these:
Which packs all the pieces plus an extra 1x4 piece and 3 extra 1x1 pieces.
This algorithm does not depend the shape of the pieces or the container much, except that they have to be expressible as cells on a grid. The container can have holes all over the place, the pieces can be more like tetris pieces or even have disconnected parts. A downside is that the list of placements that it needs scales badly with the size of the container.

Related

Runtime of Dynamic Programming Solution from Previous Post (Balls into Bins)

In the question
Calculating How Many Balls in Bins Over Several Values Using Dynamic Programming
the answer discusses a dynamic programming algorithm for placing balls into bins, and I was attempting to determine the running time, as it is not addressed in the answer.
A quick summary: Given M indistinguishable balls and N distinguishable bins, the entry in the dynamic programming table Entry[i][j] represents the number of unique ways i balls can be placed into j bins.
S[i][j] = sum(x = 0 -> i, S[i-x][j-1])
It is clear that the size of the dynamic programming 2D array is O(MN). However, I am trying to determine the impact the summation has on the running time.
I know a summation of values (1....x) means we must access values from 1 to x. Would this then mean, that for each entry computation, since we must access at most from 1...M other values, the running time is in the realm of O((M^2)N)?
Would appreciate any clarification. Thanks!
You can avoid excessive time for summation if you keep column sums in additional table.
When you calculate S[i][j], also fill Sums[i,j]=Sums[i-1,j] + S[i,j] and later use this value for the cell at right side S[i,j+1]
P.S. Note that you really need to store only two rows or even one row of sum table

Defragmentation with minimum changes

I need to design an algorithm that does a simple defragmentation, but with the "minimum amount of changes" feature. Let's say I have 3 containers with capacity of 10 and following items in them:
Container 1: 2 3 3
Container 2: 4 4
Container 3: 1 5 1 1
All the containers are filled up to 8/10. Now i want to place next item of size 3 - the overall free capacity is 6, but none of the container has free capacity of 3. Although there are multiple possible solutions for doing defragmentation, I need the algorithm, that will find the solution, where item of size 2 from the 1st container will be placed somewhere else, so the new items can be then placed into container 1, since this solution requires only one change (instead of replacing two items from container 3). So the required result is supposed to be:
Container 1: 3 3 3(new item)
Container 2: 4 4 2(moved from Container 1)
Container 3: 1 5 1 1
I did some research already, all I could find was either Knapsack problem, or Buddy algorithm, but i am not sure, whether these are really what I am looking for.
Can anyone of you help me to design this algorithm as simple as possible? I am solving a situation where I will have low amount of large containers and huge amount of items in them, so enumerating all possibilities is not quite optimal.
Thanks a lot!
UPDATE Just to make clear what am I asking - it it no problem to determine whether the situation can be solved by doing one change only. The problem is, how to find the minimum amount of replacements when "one single move" is not possible.
This is not an answer to the question, but it is too long for a comment. The problem as stated here is NP-complete (once we've suitably changed it to a decision problem), reducible from the PARTITION problem.
Let x1, x2, ..., xn be an instance of the PARTITION problem. For the sake of notation, let us take x1 to be the size of the smallest of the x's and let W be the sum of all the x's. Further, for the sake of simplicity let us assume that W is even.
We construct an instance of the given problem to encode our PARTITION instance as follows. We have three containers of sizes W, W/2-x1, and x1. Initially, the first container contains items of sizes x1, x2, ..., xn and the other two are empty. The new item to be inserted is of size W/2. We observe that this new item can be inserted into these containers if and only if the original PARTITION problem has a solution.
EDITED TO ADD (more proof detail)
First, we suppose that we have a solution of the original PARTITION problem, i.e.: a split of the x's into two subsets S1 and S2 such that the sum of the x's in each subset are equal to W/2. Suppose that S1 contains x1, the smallest element. Then, we can move x1 into the third container and all the other elements of S1 into the second container, thus leaving a space of W/2 in the first container for the new item.
Next, suppose that we have some way of inserting the new W/2-sized element into these containers. By inspection, the only way this can happen is by making space for it in the first container; and the only way that can happen is by moving exactly W/2 worth of items out of (and, consequently, leaving exactly W/2 worth of items in) the first container. Clearly, this defines a split of the original set of items into two subsets such that each subset has size W/2.
Now, just because this problem is NP-complete doesn't mean that all is lost. It simply means that if you think you've come up with a solution that solves all instances in polynomial time, then you should probably check your work. The structure of the types of instances you will see (e.g.: "low amount of large containers and huge amount of items in them") may help guide the search for useful heuristics.
If these containers are built up from scratch, you could add state to say which one was least filled, and always put the next item there.
If you can remove the size of the containers from within the container to outside the container, this could become simpler.
Just my 2 cents.

Algorithm on Seating Arrangement

So let me describe the problem of my project Module:
I have a room of capacity 50.
10 rows 5 columns.
I have 6 different flavors available, and an unlimited amount of elements for each flavor.
I need to make a seating Plan so that no one of same flavor sits nearby (front - back - diagonal).
What are the best Sets of algorithm I can use to solve this problem?
And if possible please describe the steps of the algorithm.
Algorithm
For this specific example, you can just use greedy algorithm. Iterate over rows and columns and at each seat set any flavor that doesn't clash with already seated flavors.
Proof
xxxxxxxxxx
xxxxxxxxxx
xxxo......
..........
..........
x - already seated
o - currently seating
. - empty
Lets say we iterate in row by row, left to right fashion. When we are making new seating, this place has at most 4 already seated neighbors (look at the image above). As we have 6 flavors, there will always exist one, which is different to all others. As this is true for every seating we make, we can fill all 50 spaces.
Generalisation
For general values, this problem might be rather tricky, I dare to claim even NP-hard.
A good set of algorithms are graph coloring, specifically vertex coloring algorithms. You need to think of the chairs as vertices with edges to all neighboring chairs.
The given problem is a Constraint Satisfaction Problem. In particular (using the terminology used here):
The set of variables X is made of the seats (in your case we have 50 seats correspond to a set of 50 variables, one for each seat)
The sets of domain values D is a set of 50 domains (1 for each variable), each of which contains a set of 6 values (the 6 different flavours).
The set of constraints is made up like this C1 := (X[0,0] != X[0,1]); C2 := (X[0,0] != X[1,0]); C3 := (X[0,0] != X[1,1]) and so on.
Personally I would suggest to use Forward Checking in order to reduce complexity.
The resulting algorithm (a simplified version without rollback of the assignment as it's unnecessary for this specific problem) would look something like this:
initialize_domains_for_each_variable; // set the 6 available flavours
for(int i = 0; i < 10; i++){
for(int j = 0; j < 5; j++){
seats[i,j].flavour = seats[i,j].possible_flavours[0];
// look ahead and eliminate possible conflicts
remove_this_flavour_from_surrounding_seats_possible_flavours;
}
}
Doing it like this will ensure that no conflict arises because you'll have at least 2 available flavours for each seat. We visit the seats from left to right and from top to bottom so for each seat we have to check which assignment does not conflict with the previously completed assignments. In the general case we will have:
seat[i,j].available_flavours = available_flavours - seat[i-1,j+1].flavour - seat[i-1,j].flavour - seat[i-1,j-1].flavour - seat[i,j-1].flavour
that has 2 items. In the borders of the matrix you will have more available flavours because the items it can conflict with are 2 (in the case of a left border), 3 (in the case of a right border not in the first row), or 1 (in the case of the top right element, the right border of the first row).
Be aware that using the above algorithm will only use 5 flavours (the bare minimum). If you have the necessity of using 6 flavours you will have to adapt the algorithm.

Combinations of binary features (vectors)

The source data for the subject is an m-by-n binary matrix (only 0s and 1s are allowed).
m Rows represent observations, n columns - features. Some observations are marked as targets which need to be separated from the rest.
While it looks like a typical NN, SVM, etc problem, I don't need generalization. What I need is an efficient algorithm to find as many as possible combinations of columns (features) that completely separate targets from other observations, classify, that is.
For example:
f1 f2 f3
o1 1 1 0
t1 1 0 1
o2 0 1 1
Here {f1, f3} is an acceptable combo which separates target t1 from the rest (o1, o2) (btw, {f2} is NOT as by task definition a feature MUST be present in a target). In other words,
t1(f1) & t1(f3) = 1 and o1(f1) & o1(f3) = 0, o2(f1) & o2(f3) = 0
where '&' represents logical conjunction (AND).
The m is about 100,000, n is 1,000. Currently the data is packed into 128bit words along m and the search is optimized with sse4 and whatnot. Yet it takes way too long to obtain those feature combos.
After 2 billion calls to the tree descent routine it has covered about 15% of root nodes. And found about 8,000 combos which is a decent result for my particular application.
I use some empirical criteria to cut off less probable descent paths, not without limited success, but is there something radically better? Im pretty sure there gotta be?.. Any help, in whatever form, reference or suggestion, would be appreciated.
I believe the problem you describe is NP-Hard so you shouldn't expect to find the optimum solution in a reasonable time. I do not understand your current algorithm, but here are some suggestions on the top of my head:
1) Construct a decision tree. Label targets as A and non-targets as B and let the decision tree learn the categorization. At each node select the feature such that a function of P(target | feature) and P(target' | feature') is maximum. (i.e. as many targets as possible fall to positive side and as many non-targets as possible fall to negative side)
2) Use a greedy algorithm. Start from the empty set and at each time step add the feauture that kills the most non-target rows.
3) Use a randomized algorithm. Start from a small subset of positive features of some target, use the set as the seed for the greedy algorithm. Repeat many times. Pick the best solution. Greedy algorithm will be fast so it will be ok.
4) Use a genetic algorithm. Generate random seeds for the greedy algorithm as in 3 to generate good solutions and cross-product them (bitwise-and probably) to generate new candidates seeds. Remember the best solution. Keep good solutions as the current population. Repeat for many generations.
You will need to find the answer "how many of the given rows have the given feature f" fast so probably you'll need specialized data structures, perhaps using a BitArray for each feature.

Parabolic knapsack

Lets say I have a parabola. Now I also have a bunch of sticks that are all of the same width (yes my drawing skills are amazing!). How can I stack these sticks within the parabola such that I am minimizing the space it uses as much as possible? I believe that this falls under the category of Knapsack problems, but this Wikipedia page doesn't appear to bring me closer to a real world solution. Is this a NP-Hard problem?
In this problem we are trying to minimize the amount of area consumed (eg: Integral), which includes vertical area.
I cooked up a solution in JavaScript using processing.js and HTML5 canvas.
This project should be a good starting point if you want to create your own solution. I added two algorithms. One that sorts the input blocks from largest to smallest and another that shuffles the list randomly. Each item is then attempted to be placed in the bucket starting from the bottom (smallest bucket) and moving up until it has enough space to fit.
Depending on the type of input the sort algorithm can give good results in O(n^2). Here's an example of the sorted output.
Here's the insert in order algorithm.
function solve(buckets, input) {
var buckets_length = buckets.length,
results = [];
for (var b = 0; b < buckets_length; b++) {
results[b] = [];
}
input.sort(function(a, b) {return b - a});
input.forEach(function(blockSize) {
var b = buckets_length - 1;
while (b > 0) {
if (blockSize <= buckets[b]) {
results[b].push(blockSize);
buckets[b] -= blockSize;
break;
}
b--;
}
});
return results;
}
Project on github - https://github.com/gradbot/Parabolic-Knapsack
It's a public repo so feel free to branch and add other algorithms. I'll probably add more in the future as it's an interesting problem.
Simplifying
First I want to simplify the problem, to do that:
I switch the axes and add them to each other, this results in x2 growth
I assume it is parabola on a closed interval [a, b], where a = 0 and for this example b = 3
Lets say you are given b (second part of interval) and w (width of a segment), then you can find total number of segments by n=Floor[b/w]. In this case there exists a trivial case to maximize Riemann sum and function to get i'th segment height is: f(b-(b*i)/(n+1))). Actually it is an assumption and I'm not 100% sure.
Max'ed example for 17 segments on closed interval [0, 3] for function Sqrt[x] real values:
And the segment heights function in this case is Re[Sqrt[3-3*Range[1,17]/18]], and values are:
Exact form:
{Sqrt[17/6], 2 Sqrt[2/3], Sqrt[5/2],
Sqrt[7/3], Sqrt[13/6], Sqrt[2],
Sqrt[11/6], Sqrt[5/3], Sqrt[3/2],
2/Sqrt[3], Sqrt[7/6], 1, Sqrt[5/6],
Sqrt[2/3], 1/Sqrt[2], 1/Sqrt[3],
1/Sqrt[6]}
Approximated form:
{1.6832508230603465,
1.632993161855452, 1.5811388300841898, 1.5275252316519468, 1.4719601443879744, 1.4142135623730951, 1.35400640077266, 1.2909944487358056, 1.224744871391589, 1.1547005383792517, 1.0801234497346435, 1, 0.9128709291752769, 0.816496580927726, 0.7071067811865475, 0.5773502691896258, 0.4082482904638631}
What you have archived is a Bin-Packing problem, with partially filled bin.
Finding b
If b is unknown or our task is to find smallest possible b under what all sticks form the initial bunch fit. Then we can limit at least b values to:
lower limit : if sum of segment heights = sum of stick heights
upper limit : number of segments = number of sticks longest stick < longest segment height
One of the simplest way to find b is to take a pivot at (higher limit-lower limit)/2 find if solution exists. Then it becomes new higher or lower limit and you repeat the process until required precision is met.
When you are looking for b you do not need exact result, but suboptimal and it would be much faster if you use efficient algorithm to find relatively close pivot point to actual b.
For example:
sort the stick by length: largest to smallest
start 'putting largest items' into first bin thy fit
This is equivalent to having multiple knapsacks (assuming these blocks are the same 'height', this means there's one knapsack for each 'line'), and is thus an instance of the bin packing problem.
See http://en.wikipedia.org/wiki/Bin_packing
How can I stack these sticks within the parabola such that I am minimizing the (vertical) space it uses as much as possible?
Just deal with it like any other Bin Packing problem. I'd throw meta-heuristics on it (such as tabu search, simulated annealing, ...) since those algorithms aren't problem specific.
For example, if I'd start from my Cloud Balance problem (= a form of Bin Packing) in Drools Planner. If all the sticks have the same height and there's no vertical space between 2 sticks on top of each other, there's not much I'd have to change:
Rename Computer to ParabolicRow. Remove it's properties (cpu, memory, bandwith). Give it a unique level (where 0 is the lowest row). Create a number of ParabolicRows.
Rename Process to Stick
Rename ProcessAssignement to StickAssignment
Rewrite the hard constraints so it checks if there's enough room for the sum of all Sticks assigned to a ParabolicRow.
Rewrite the soft constraints to minimize the highest level of all ParabolicRows.
I'm very sure it is equivalent to bin-packing:
informal reduction
Be x the width of the widest row, make the bins 2x big and create for every row a placeholder element which is 2x-rowWidth big. So two placeholder elements cannot be packed into one bin.
To reduce bin-packing on parabolic knapsack you just create placeholder elements for all rows that are bigger than the needed binsize with size width-binsize. Furthermore add placeholders for all rows that are smaller than binsize which fill the whole row.
This would obviously mean your problem is NP-hard.
For other ideas look here maybe: http://en.wikipedia.org/wiki/Cutting_stock_problem
Most likely this is the 1-0 Knapsack or a bin-packing problem. This is a NP hard problem and most likely this problem I don't understand and I can't explain to you but you can optimize with greedy algorithms. Here is a useful article about it http://www.developerfusion.com/article/5540/bin-packing that I use to make my php class bin-packing at phpclasses.org.
Props to those who mentioned the fact that the levels could be at varying heights (ex: assuming the sticks are 1 'thick' level 1 goes from 0.1 unit to 1.1 units, or it could go from 0.2 to 1.2 units instead)
You could of course expand the "multiple bin packing" methodology and test arbitrarily small increments. (Ex: run the multiple binpacking methodology with levels starting at 0.0, 0.1, 0.2, ... 0.9) and then choose the best result, but it seems like you would get stuck calulating for an infinite amount of time unless you had some methodlogy to verify that you had gotten it 'right' (or more precisely, that you had all the 'rows' correct as to what they contained, at which point you could shift them down until they met the edge of the parabola)
Also, the OP did not specify that the sticks had to be laid horizontally - although perhaps the OP implied it with those sweet drawings.
I have no idea how to optimally solve such an issue, but i bet there are certain cases where you could randomly place sticks and then test if they are 'inside' the parabola, and it would beat out any of the methodologies relying only on horizontal rows.
(Consider the case of a narrow parabola that we are trying to fill with 1 long stick.)
I say just throw them all in there and shake them ;)

Resources