Ticket #6763: trac_6763.patch

File trac_6763.patch, 4.4 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 742143928f3a2adbb577351753c1f579b02bdc93
    # Parent  263f1caae32dd7ac94a108e8b279a9872b56f260
    trac 6763 - Bin packing, and a bit of docstrings...
    
    diff -r 263f1caae32d -r 742143928f3a 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,maximum=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    - ``maximum``   -- 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 raises an
     682        exception otherwise.
     683
     684      - When set to ``None``, the function returns a partition of the items
     685        using the least number possible of bins.
     686
     687    OUTPUT:
     688
     689    A list of lists, each member corresponding to a box and containing
     690    the list of the weights inside it. If there is no solution, an
     691    exception is raised (this can only happen when ``k`` is specified
     692    or if ``maximum`` is less that the size of one item).
     693
     694    EXAMPLES:
     695
     696    Trying to find the minimum amount of boxes for 5 items of weights
     697    `1/5, 1/4, 2/3, 3/4, 5/7`::
     698
     699        sage: from sage.numerical.optimize import binpacking
     700        sage: print sorted(binpacking([1/5,1/3,2/3,3/4, 5/7])) # optional - requires GLPK CPLEX or CBC
     701        [[1/5, 3/4], [1/3, 2/3], [5/7]]
     702
     703    One way to use only three boxes (which is best possible) is to put
     704    `1/5 + 3/4` together in a box, `1/3+2/3` in another, and `5/7`
     705    by itself in the third one.
     706
     707    Of course, we can also check that there is no solution using only two boxes ::
     708
     709        sage: from sage.numerical.optimize import binpacking
     710        sage: binpacking([0.2,0.3,0.8,0.9], k=2)              # optional - requires GLPK CPLEX or CBC
     711        Traceback (most recent call last):
     712        ...
     713        ValueError: This problem has no solution !
     714    """
     715
     716    if max(items) > maximum:
     717        raise ValueError("This problem has no solution !")
     718   
     719    if k==None:
     720        from sage.functions.other import ceil
     721        k=ceil(sum(items)/maximum)
     722        while True:
     723            from sage.numerical.mip import MIPSolverException
     724            try:
     725                return binpacking(items,k=k,maximum=maximum)
     726            except MIPSolverException:
     727                k = k + 1
     728
     729    from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
     730    p=MixedIntegerLinearProgram()
     731   
     732    # Boolean variable indicating whether
     733    # the i th element belongs to box b
     734    box=p.new_variable(dim=2)
     735
     736    # Each bin contains at most max
     737    for b in range(k):
     738        p.add_constraint(sum([items[i]*box[i][b] for i in range(len(items))]),max=maximum)
     739
     740    # Each item is assigned exactly one bin
     741    for i in range(len(items)):
     742        p.add_constraint(sum([box[i][b] for b in range(k)]),min=1,max=1)
     743       
     744    p.set_objective(None)
     745    p.set_binary(box)
     746
     747    try:
     748        p.solve()
     749    except MIPSolverException:
     750        raise ValueError("This problem has no solution !")
     751
     752    box=p.get_values(box)
     753   
     754    boxes=[[] for i in range(k)]
     755
     756    for b in range(k):
     757        boxes[b].extend([items[i] for i in range(len(items)) if box[i][b]==1])
     758
     759    return boxes
     760
     761
     762