Ticket #6763: binpacking.patch

File binpacking.patch, 4.0 KB (added by ncohen, 11 years ago)
  • sage/numerical/optimize.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1250439244 25200
    # Node ID af750e0cdbe1a0cef08b7163f25612284866ec5a
    # Parent  091e4a425d4653794dfc356c1ca2d34c8e6ebc0c
    Bin packing, and a bit of docstrings...
    
    diff -r 091e4a425d46 -r af750e0cdbe1 sage/numerical/optimize.py
    a b  
    44AUTHOR:
    55
    66- William Stein (2007): initial version
     7- Nathann Cohen (2008) : Bin Packing
     8
     9
     10Functions and Methods
     11----------------------
    712"""
    813from sage.modules.free_module_element import vector
    914from sage.rings.real_double import RDF
     
    646651       return dict
    647652
    648653    return [item[0] == item[1] for item in zip(parameters, estimated_params)]
     654
     655def 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