Ticket #6749: knapsack.2.patch

File knapsack.2.patch, 6.4 KB (added by ncohen, 11 years ago)
  • sage/numerical/knapsack.py

    diff -r b9b12c1442a4 -r 0965013f5193 sage/numerical/knapsack.py
    a b  
    66following knapsack problems are implemented:
    77
    88- Solving the subset sum problem for super-increasing sequences.
    9 
     9- General case using Linear Programming     
    1010
    1111AUTHORS:
    1212
    1313- Minh Van Nguyen (2009-04): initial version
     14- Nathann Cohen (2009-08) : Linear Programming version         
    1415
     16Definition of Knapsack problems
     17---------------------------------
    1518
    16 EXAMPLES:
     19You have already had a knapsack problem, so you should know, but in case you
     20do not, a knapsack problem is what happens when you have hundred of items to
     21put into a bag which is too small for all of them.
     22
     23When you formally write it, here is your problem :
     24* Your bag can contain a weight of at most W
     25* Each item `i` you have has a weight `w_i`
     26* Each item `i` has a usefulness of `u_i`
     27
     28You then want to maximize the usefulness of the items you will store into
     29your bag, while keeping sure the weight of the bag will not go over W
     30   
     31As a linear program, this problem can be represented this way
     32( if you define `b_i` as the binary variable indicating whether
     33the item `i` is to be included in your bag ) :
     34
     35.. MATH::
     36    \mbox{Maximize : }\sum_ib_iu_i\\
     37    \mbox{Such that : }
     38    \sum_ib_iw_i\leq W\\
     39    \forall i, b_i \mbox{ binary variable}
     40   
     41( for more informations, cf. http://en.wikipedia.org/wiki/Knapsack_problem )
     42
     43Examples
     44--------------------
     45   
     46If your knapsack problem is composed of three items (weight, value)
     47defined by (1,2), (1.5,1), (0.5,3), and a bag of maximum weight 2,
     48you can easily solve it this way ::
     49
     50    sage: from sage.numerical.knapsack import knapsack
     51    sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) # optional - requires Glpk or COIN-OR/CBC
     52    [5.0, [(1, 2), (0.500000000000000, 3)]]
     53
     54Super-increasing sequences :
    1755
    1856We can test for whether or not a sequence is super-increasing::
    1957
     
    3371    sage: L = [1, 2, 5, 21, 69, 189, 376, 919]
    3472    sage: Superincreasing(L).subset_sum(98)
    3573    [69, 21, 5, 2, 1]
     74
     75
     76Functions and methods
     77---------------------
    3678"""
    3779
    3880#*****************************************************************************
     
    509551            return candidates
    510552        else:
    511553            return []
     554
     555def knapsack(seq,binary=True,max=1, value_only=False):
     556    r"""
     557    Solves the knapsack problem
     558
     559
     560    Knapsack problems :
     561
     562    You have already had a knapsack problem, so you should know,
     563    but in case you do not, a knapsack problem is what happens
     564    when you have hundred of items to put into a bag which is
     565    too small for all of them.
     566
     567    When you formally write it, here is your problem :
     568    * Your bag can contain a weight of at most W
     569    * Each item `i` you have has a weight `w_i`
     570    * Each item `i` has a usefulness of `u_i`
     571
     572    You then want to maximize the usefulness of the items you
     573    will store into your bag, while keeping sure the weight of
     574    the bag will not go over W.
     575   
     576    As a linear program, this problem can be represented this way
     577    ( if you define `b_i` as the binary variable indicating whether
     578    the item `i` is to be included in your bag ) :
     579
     580    .. MATH::
     581        \mbox{Maximize : }\sum_ib_iu_i\\
     582        \mbox{Such that : }
     583        \sum_ib_iw_i\leq W\\
     584        \forall i, b_i \mbox{ binary variable}\\
     585   
     586    ( for more informations,
     587    cf. http://en.wikipedia.org/wiki/Knapsack_problem )
     588
     589    EXAMPLE :
     590   
     591    If your knapsack problem is composed of three
     592    items (weight, value) defined by (1,2), (1.5,1), (0.5,3),
     593    and a bag of maximum weight 2, you can easily solve it this way ::
     594
     595        sage: from sage.numerical.knapsack import knapsack
     596        sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) # optional - requires Glpk or COIN-OR/CBC
     597        [5.0, [(1, 2), (0.500000000000000, 3)]]
     598
     599        sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2, value_only=True) # optional - requires Glpk or COIN-OR/CBC
     600        5.0
     601
     602    In the case where all the values (usefulness) of the items
     603    are equal to one, you do not need embarass yourself with
     604    the second values, and you can just type for items
     605    `(1,1), (1.5,1), (0.5,1)` the command ::
     606
     607        sage: from sage.numerical.knapsack import knapsack
     608        sage: knapsack([1,1.5,0.5], max=2, value_only=True) # optional - requires Glpk or COIN-OR/CBC
     609        2.0
     610
     611    INPUT:
     612   
     613    - ``seq`` :  Two different possible types :
     614                  - A sequence of pairs (weight, value)
     615                  - A sequence of reals (a value of 1 is assumed)
     616   
     617    - ``binary`` : When set to True, an item can be taken 0 or 1 time.
     618                   When set to False, an item can be taken any amount of
     619                   times ( while staying integer and positive )
     620
     621    - ``max`` : Maximum admissible weight
     622
     623    - ``value_only`` : When set to True, only the maximum useful
     624                         value is returned
     625                       When set to False, both the maximum useful
     626                         value and an assignment are returned
     627
     628    OUTPUT:
     629   
     630    If value_only is set to True, only the maximum useful value
     631    is returned.
     632    Else ( default ), the function returns a pair ``[value,list]``,
     633    where ``list`` can be of two types according to the type of ``seq`` :
     634
     635        - A list of pairs (w_i, u_i), for each object i occurring
     636            in the solution.
     637        - A list of reals where each real is repeated the number
     638            of times it is taken into the solution.
     639    """
     640    reals=not isinstance(seq[0],tuple)
     641    if reals:
     642        seq=[(x,1) for x in seq]
     643
     644    from sage.numerical.mip import MIP
     645    p=MIP(sense=1)
     646    p.setobj(dict([(i,seq[i][1]) for i in range(len(seq))]))
     647    p.addconstraint(dict([(i,seq[i][0]) for i in range(len(seq))]),max=max)
     648
     649    if binary:
     650        for i in range(len(seq)):
     651            p.setbinary(i)
     652    else:
     653        for i in range(len(seq)):
     654            p.setinteger(i)
     655   
     656    if value_only:
     657        return p.solve(objective_only=True)
     658   
     659    else:
     660        tmp=p.solve()
     661
     662        if reals:
     663            val=[x[0] for c in [ [seq[a]]*int(round(b)) for (a,b) in tmp[1].items() if b>0] for x in c]
     664        else:
     665            val=[x for c in [ [seq[a]]*int(round(b)) for (a,b) in tmp[1].items() if b>0] for x in c]
     666
     667        return [tmp[0],val]