| 654 | |
| 655 | def binpacking(items,max=1,k=None): |
| 656 | r""" |
| 657 | Solves the bin packing problem. |
| 658 | |
| 659 | The Bin Packing problem is the following : |
| 660 | |
| 661 | Given a list of items of weights `p_i` and a real value `K`, what is |
| 662 | the least number of bins such that all the items can be put in the |
| 663 | bins, while keeping sure that each bin contains a weight of at most `K` ? |
| 664 | |
| 665 | For more informations : http://en.wikipedia.org/wiki/Bin_packing_problem |
| 666 | |
| 667 | Two version of this problem are solved by this algorithm : |
| 668 | * Is it possible to put the given items in `L` bins ? |
| 669 | * What is the assignment of items using the |
| 670 | least number of bins with the given list of items ? |
| 671 | |
| 672 | INPUT: |
| 673 | |
| 674 | - ``items`` -- A list of real values (the items' weight) |
| 675 | |
| 676 | - ``max`` -- The maximal size of a bin |
| 677 | |
| 678 | - ``k`` -- Number of bins |
| 679 | |
| 680 | - When set to an integer value, the function returns a partition |
| 681 | of the items into `k` bins if possible, and ``False`` otherwise. |
| 682 | |
| 683 | - When set to ``None``, the function returns a partition of the items |
| 684 | using the least number possible of bins. |
| 685 | |
| 686 | OUTPUT: |
| 687 | |
| 688 | A list of lists, each member corresponding to a box and containing |
| 689 | the list of the weights inside it. If there is no solution, an |
| 690 | exception is returned (this can only happen when ``k`` is specified) |
| 691 | |
| 692 | EXAMPLES: |
| 693 | |
| 694 | Trying to find the minimum amount of boxes for 5 items of weights |
| 695 | `1/5, 1/4, 2/3, 3/4, 5/7`:: |
| 696 | |
| 697 | sage: from sage.numerical.optimize import binpacking |
| 698 | sage: print sorted(binpacking([1/5,1/4,2/3,3/4, 5/7])) # optional - requires GLPK or CBC |
| 699 | [[1/5, 2/3], [1/4, 5/7], [3/4]] |
| 700 | |
| 701 | One way to use only three boxes (which is best possible) is to put |
| 702 | `1/5 + 2/3` together in a box, `1/4+5/7` in another, and `3/4` |
| 703 | by itself in the third one. |
| 704 | |
| 705 | Of course, we can also check that there is no solution using only two boxes :: |
| 706 | |
| 707 | sage: from sage.numerical.optimize import binpacking |
| 708 | sage: binpacking([0.2,0.3,0.8,0.9], k=2) # optional - requires GLPK or CBC |
| 709 | Traceback (most recent call last): |
| 710 | ... |
| 711 | Exception: This problem has no solution ! |
| 712 | """ |
| 713 | if k==None: |
| 714 | k=1 |
| 715 | while True: |
| 716 | try: |
| 717 | return binpacking(items,k=k,max=max) |
| 718 | except Exception: |
| 719 | k = k + 1 |
| 720 | |
| 721 | from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException |
| 722 | p=MixedIntegerLinearProgram() |
| 723 | |
| 724 | # Boolean variable indicating whether |
| 725 | # the i th element belongs to box b |
| 726 | box=p.new_variable(dim=2) |
| 727 | |
| 728 | # Each bin contains at most max |
| 729 | [p.add_constraint(sum([items[i]*box[i][b] for i in range(len(items))]),max=max) for b in range(k)] |
| 730 | |
| 731 | # Each item is assigned exactly one bin |
| 732 | [p.add_constraint(sum([box[i][b] for b in range(k)]),min=1,max=1) for i in range(len(items))] |
| 733 | |
| 734 | p.set_objective(None) |
| 735 | p.set_binary(box) |
| 736 | |
| 737 | try: |
| 738 | p.solve() |
| 739 | except MIPSolverException: |
| 740 | raise Exception("This problem has no solution !") |
| 741 | |
| 742 | box=p.get_values(box) |
| 743 | |
| 744 | |
| 745 | boxes=[[] for i in range(k)] |
| 746 | |
| 747 | [boxes[b].extend([items[i] for i in range(len(items)) if box[i][b]==1]) for b in range(k)] |
| 748 | return boxes |
| 749 | |
| 750 | |
| 751 | |