16 | | EXAMPLES: |
| 19 | You have already had a knapsack problem, so you should know, but in case you |
| 20 | do not, a knapsack problem is what happens when you have hundred of items to |
| 21 | put into a bag which is too small for all of them. |
| 22 | |
| 23 | When 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 | |
| 28 | You then want to maximize the usefulness of the items you will store into |
| 29 | your bag, while keeping sure the weight of the bag will not go over W |
| 30 | |
| 31 | As a linear program, this problem can be represented this way |
| 32 | ( if you define `b_i` as the binary variable indicating whether |
| 33 | the 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 | |
| 43 | Examples |
| 44 | -------------------- |
| 45 | |
| 46 | If your knapsack problem is composed of three items (weight, value) |
| 47 | defined by (1,2), (1.5,1), (0.5,3), and a bag of maximum weight 2, |
| 48 | you 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 | |
| 54 | Super-increasing sequences : |
| 554 | |
| 555 | def 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] |