def knapsack(seq, binary=True, max=1, value_only=False): r""" Solves the knapsack problem Knapsack problems: You have already had a knapsack problem, so you should know, but in case you do not, a knapsack problem is what happens when you have hundred of items to put into a bag which is too small for all of them. When you formally write it, here is your problem: * Your bag can contain a weight of at most `W`. * Each item `i` you have has a weight `w_i`. * Each item `i` has a usefulness of `u_i`. You then want to maximize the usefulness of the items you will store into your bag, while keeping sure the weight of the bag will not go over `W`. As a linear program, this problem can be represented this way (if you define `b_i` as the binary variable indicating whether the item `i` is to be included in your bag): .. MATH:: \mbox{Maximize: }\sum_i b_i u_i \\ \mbox{Such that: } \sum_i b_i w_i \leq W \\ \forall i, b_i \mbox{ binary variable} \\ (For more information, cf. http://en.wikipedia.org/wiki/Knapsack_problem.) EXAMPLE: If your knapsack problem is composed of three items (weight, value) defined by (1,2), (1.5,1), (0.5,3), and a bag of maximum weight 2, you can easily solve it this way:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) [5.0, [(1, 2), (0.500000000000000, 3)]] sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2, value_only=True) 5.0 In the case where all the values (usefulness) of the items are equal to one, you do not need embarrass yourself with the second values, and you can just type for items `(1,1), (1.5,1), (0.5,1)` the command:: sage: from sage.numerical.knapsack import knapsack sage: knapsack([1,1.5,0.5], max=2, value_only=True) 2.0 INPUT: - ``seq`` -- Two different possible types: - A sequence of pairs (weight, value). - A sequence of reals (a value of 1 is assumed). - ``binary`` -- When set to True, an item can be taken 0 or 1 time. When set to False, an item can be taken any amount of times (while staying integer and positive). - ``max`` -- Maximum admissible weight. - ``value_only`` -- When set to True, only the maximum useful value is returned. When set to False, both the maximum useful value and an assignment are returned. OUTPUT: If ``value_only`` is set to True, only the maximum useful value is returned. Else (the default), the function returns a pair ``[value,list]``, where ``list`` can be of two types according to the type of ``seq``: - A list of pairs `(w_i, u_i)` for each object `i` occurring in the solution. - A list of reals where each real is repeated the number of times it is taken into the solution. """ reals = not isinstance(seq[0], tuple) if reals: seq = [(x, 1) for x in seq] from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=True) present = p.new_variable() p.set_objective(p.sum([present[i] * seq[i][1] for i in range(len(seq))])) p.add_constraint(p.sum([present[i] * seq[i][0] for i in range(len(seq))]), max=max) if binary: p.set_binary(present) else: p.set_integer(present) if value_only: return p.solve(objective_only=True) else: objective = p.solve() present = p.get_values(present) val = [] if reals: [val.extend([seq[i][0]] * int(present[i])) for i in range(len(seq))] else: [val.extend([seq[i]] * int(present[i])) for i in range(len(seq))] return [objective, val]
def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0): r""" Solves the knapsack problem For more information on the knapsack problem, see the documentation of the :mod:`knapsack module <sage.numerical.knapsack>` or the :wikipedia:`Knapsack_problem`. INPUT: - ``seq`` -- Two different possible types: - A sequence of tuples ``(weight, value, something1, something2, ...)``. Note that only the first two coordinates (``weight`` and ``values``) will be taken into account. The rest (if any) will be ignored. This can be useful if you need to attach some information to the items. - A sequence of reals (a value of 1 is assumed). - ``binary`` -- When set to ``True``, an item can be taken 0 or 1 time. When set to ``False``, an item can be taken any amount of times (while staying integer and positive). - ``max`` -- Maximum admissible weight. - ``value_only`` -- When set to ``True``, only the maximum useful value is returned. When set to ``False``, both the maximum useful value and an assignment are returned. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to be used. If set to ``None``, the default one is used. For more information on LP solvers and which default solver is used, see the documentation of class :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`. - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity. Set to 0 by default, which means quiet. OUTPUT: If ``value_only`` is set to ``True``, only the maximum useful value is returned. Else (the default), the function returns a pair ``[value,list]``, where ``list`` can be of two types according to the type of ``seq``: - The list of tuples `(w_i, u_i, ...)` occurring in the solution. - A list of reals where each real is repeated the number of times it is taken into the solution. EXAMPLES: If your knapsack problem is composed of three items ``(weight, value)`` defined by ``(1,2), (1.5,1), (0.5,3)``, and a bag of maximum weight `2`, you can easily solve it this way:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) [5.0, [(1, 2), (0.500000000000000, 3)]] sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2, value_only=True) 5.0 Besides weight and value, you may attach any data to the items:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1, 2, 'spam'), (0.5, 3, 'a', 'lot')]) [3.0, [(0.500000000000000, 3, 'a', 'lot')]] In the case where all the values (usefulness) of the items are equal to one, you do not need embarrass yourself with the second values, and you can just type for items `(1,1), (1.5,1), (0.5,1)` the command:: sage: from sage.numerical.knapsack import knapsack sage: knapsack([1,1.5,0.5], max=2, value_only=True) 2.0 """ reals = not isinstance(seq[0], tuple) if reals: seq = [(x, 1) for x in seq] from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=True, solver=solver) present = p.new_variable() p.set_objective(p.sum([present[i] * seq[i][1] for i in range(len(seq))])) p.add_constraint(p.sum([present[i] * seq[i][0] for i in range(len(seq))]), max=max) if binary: p.set_binary(present) else: p.set_integer(present) if value_only: return p.solve(objective_only=True, log=verbose) else: objective = p.solve(log=verbose) present = p.get_values(present) val = [] if reals: [ val.extend([seq[i][0]] * int(present[i])) for i in range(len(seq)) ] else: [val.extend([seq[i]] * int(present[i])) for i in range(len(seq))] return [objective, val]
def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0): r""" Solves the knapsack problem For more information on the knapsack problem, see the documentation of the :mod:`knapsack module <sage.numerical.knapsack>` or the :wikipedia:`Knapsack_problem`. INPUT: - ``seq`` -- Two different possible types: - A sequence of tuples ``(weight, value, something1, something2, ...)``. Note that only the first two coordinates (``weight`` and ``values``) will be taken into account. The rest (if any) will be ignored. This can be useful if you need to attach some information to the items. - A sequence of reals (a value of 1 is assumed). - ``binary`` -- When set to ``True``, an item can be taken 0 or 1 time. When set to ``False``, an item can be taken any amount of times (while staying integer and positive). - ``max`` -- Maximum admissible weight. - ``value_only`` -- When set to ``True``, only the maximum useful value is returned. When set to ``False``, both the maximum useful value and an assignment are returned. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to be used. If set to ``None``, the default one is used. For more information on LP solvers and which default solver is used, see the documentation of class :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`. - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity. Set to 0 by default, which means quiet. OUTPUT: If ``value_only`` is set to ``True``, only the maximum useful value is returned. Else (the default), the function returns a pair ``[value,list]``, where ``list`` can be of two types according to the type of ``seq``: - The list of tuples `(w_i, u_i, ...)` occurring in the solution. - A list of reals where each real is repeated the number of times it is taken into the solution. EXAMPLES: If your knapsack problem is composed of three items ``(weight, value)`` defined by ``(1,2), (1.5,1), (0.5,3)``, and a bag of maximum weight `2`, you can easily solve it this way:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) [5.0, [(1, 2), (0.500000000000000, 3)]] sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2, value_only=True) 5.0 Besides weight and value, you may attach any data to the items:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1, 2, 'spam'), (0.5, 3, 'a', 'lot')]) [3.0, [(0.500000000000000, 3, 'a', 'lot')]] In the case where all the values (usefulness) of the items are equal to one, you do not need embarrass yourself with the second values, and you can just type for items `(1,1), (1.5,1), (0.5,1)` the command:: sage: from sage.numerical.knapsack import knapsack sage: knapsack([1,1.5,0.5], max=2, value_only=True) 2.0 """ reals = not isinstance(seq[0], tuple) if reals: seq = [(x,1) for x in seq] from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=True, solver=solver) present = p.new_variable() p.set_objective(p.sum([present[i] * seq[i][1] for i in range(len(seq))])) p.add_constraint(p.sum([present[i] * seq[i][0] for i in range(len(seq))]), max=max) if binary: p.set_binary(present) else: p.set_integer(present) if value_only: return p.solve(objective_only=True, log=verbose) else: objective = p.solve(log=verbose) present = p.get_values(present) val = [] if reals: [val.extend([seq[i][0]] * int(present[i])) for i in range(len(seq))] else: [val.extend([seq[i]] * int(present[i])) for i in range(len(seq))] return [objective,val]
def knapsack(seq, binary=True, max=1, value_only=False): r""" Solves the knapsack problem Knapsack problems: You have already had a knapsack problem, so you should know, but in case you do not, a knapsack problem is what happens when you have hundred of items to put into a bag which is too small for all of them. When you formally write it, here is your problem: * Your bag can contain a weight of at most `W`. * Each item `i` you have has a weight `w_i`. * Each item `i` has a usefulness of `u_i`. You then want to maximize the usefulness of the items you will store into your bag, while keeping sure the weight of the bag will not go over `W`. As a linear program, this problem can be represented this way (if you define `b_i` as the binary variable indicating whether the item `i` is to be included in your bag): .. MATH:: \mbox{Maximize: }\sum_i b_i u_i \\ \mbox{Such that: } \sum_i b_i w_i \leq W \\ \forall i, b_i \mbox{ binary variable} \\ (For more information, cf. http://en.wikipedia.org/wiki/Knapsack_problem.) EXAMPLE: If your knapsack problem is composed of three items (weight, value) defined by (1,2), (1.5,1), (0.5,3), and a bag of maximum weight 2, you can easily solve it this way:: sage: from sage.numerical.knapsack import knapsack sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2) [5.0, [(1, 2), (0.500000000000000, 3)]] sage: knapsack( [(1,2), (1.5,1), (0.5,3)], max=2, value_only=True) 5.0 In the case where all the values (usefulness) of the items are equal to one, you do not need embarrass yourself with the second values, and you can just type for items `(1,1), (1.5,1), (0.5,1)` the command:: sage: from sage.numerical.knapsack import knapsack sage: knapsack([1,1.5,0.5], max=2, value_only=True) 2.0 INPUT: - ``seq`` -- Two different possible types: - A sequence of pairs (weight, value). - A sequence of reals (a value of 1 is assumed). - ``binary`` -- When set to True, an item can be taken 0 or 1 time. When set to False, an item can be taken any amount of times (while staying integer and positive). - ``max`` -- Maximum admissible weight. - ``value_only`` -- When set to True, only the maximum useful value is returned. When set to False, both the maximum useful value and an assignment are returned. OUTPUT: If ``value_only`` is set to True, only the maximum useful value is returned. Else (the default), the function returns a pair ``[value,list]``, where ``list`` can be of two types according to the type of ``seq``: - A list of pairs `(w_i, u_i)` for each object `i` occurring in the solution. - A list of reals where each real is repeated the number of times it is taken into the solution. """ reals = not isinstance(seq[0], tuple) if reals: seq = [(x, 1) for x in seq] from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=True) present = p.new_variable() p.set_objective(p.sum([present[i] * seq[i][1] for i in range(len(seq))])) p.add_constraint(p.sum([present[i] * seq[i][0] for i in range(len(seq))]), max=max) if binary: p.set_binary(present) else: p.set_integer(present) if value_only: return p.solve(objective_only=True) else: objective = p.solve() present = p.get_values(present) val = [] if reals: [ val.extend([seq[i][0]] * int(present[i])) for i in range(len(seq)) ] else: [val.extend([seq[i]] * int(present[i])) for i in range(len(seq))] return [objective, val]