blog

ナップサック問題

Published:

By nob

Category: Posts

Tags: 数理最適化 Python-MIP Platypus Python

数理最適化問題で目的関数を複数設定したい。

ナップサック問題で実験してみる。

まず目的関数が1つの場合を実験する。

整数ナップサック問題

ナップサックのサイズの範囲で出来るだけ価値が高くなるような組み合わせを求める。

同じ品物を複数個入れてもよい。

データ

ナップサックのサイズ

capacity = 65

品物

import pandas as pd
from IPython.display import display

items = pd.DataFrame(
    [
        ["缶コーヒー", 120, 10],
        ["水入りペットボトル", 130, 12],
        ["バナナ", 80, 7],
        ["りんご", 100, 9],
        ["おにぎり", 250, 21],
        ["パン", 185, 16],
    ],
    columns=["name", "value", "size"],
)

display(items)
name value size
0 缶コーヒー 120 10
1 水入りペットボトル 130 12
2 バナナ 80 7
3 りんご 100 9
4 おにぎり 250 21
5 パン 185 16

データの出典

モデル

from mip import INTEGER, Model, OptimizationStatus, maximize, xsum

mip_model = Model(solver_name="cbc")

mip_items = items.copy()

mip_items["var"] = mip_model.add_var_tensor(
    (len(mip_items),), "var", var_type=INTEGER
)

mip_model += xsum(mip_items["size"] * mip_items["var"]) <= capacity

mip_model.objective = maximize(xsum(mip_items["value"] * mip_items["var"]))

mip_model.optimize()
Welcome to the CBC MILP Solver 
Version: devel 
Build Date: Aug  4 2024
Starting solution of the Linear programming relaxation problem using Primal Simplex

Coin0506I Presolve 0 (-1) rows, 0 (-6) columns and 0 (-6) elements
Clp0000I Optimal - objective value 780
Coin0511I After Postsolve, objective 780, infeasibilities - dual 0 (0), primal 0 (0)
Clp0032I Optimal objective 780 - 0 iterations time 0.002, Presolve 0.00, Idiot 0.00

Starting MIP optimization





<OptimizationStatus.OPTIMAL: 0>

確認

if mip_model.status == OptimizationStatus.OPTIMAL:
    print("total value:", mip_model.objective_value)
    mip_items["val"] = mip_items["var"].astype(float)
    print("total size:", (mip_items["size"] * mip_items["val"]).sum())
    display(mip_items[["name", "value", "size", "val"]])
else:
    print(mip_model.status)
total value: 770.0
total size: 65.0
name value size val
0 缶コーヒー 120 10 3.0
1 水入りペットボトル 130 12 0.0
2 バナナ 80 7 2.0
3 りんご 100 9 0.0
4 おにぎり 250 21 1.0
5 パン 185 16 0.0

0/1ナップサック問題

ナップサックのサイズの範囲で出来るだけ価値が高くなるような組み合わせを求める。

同じ品物を複数個入れることはできない(0個または1個)。

モデル

from mip import BINARY

mip_model = Model(solver_name="cbc")

mip_items = items.copy()

mip_items["var"] = mip_model.add_var_tensor(
    (len(mip_items),), "var", var_type=BINARY
)

mip_model += xsum(mip_items["size"] * mip_items["var"]) <= capacity

mip_model.objective = maximize(xsum(mip_items["value"] * mip_items["var"]))

mip_model.optimize()
maxSavedSolutions was changed from 1 to 10
Continuous objective value is 780 - 3.7e-05 seconds
Cgl0004I processed model has 1 rows, 6 columns (6 integer (0 of which binary)) and 6 elements
Coin3009W Conflict graph built in 0.000 seconds, density: 0.000%
Cgl0015I Clique Strengthening extended 0 cliques, 0 were dominated
Cbc0045I Nauty did not find any useful orbits in time 2.6e-05
Cbc0012I Integer solution of 760 found by DiveCoefficient after 0 iterations and 0 nodes (0.00 seconds)
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 3 columns
Cbc0012I Integer solution of 770 found by RINS after 0 iterations and 0 nodes (0.00 seconds)
Cbc0031I 1 added rows had average density of 3
Cbc0013I At root node, 3 cuts changed objective from 779.52381 to 770 in 2 passes
Cbc0014I Cut generator 0 (Probing) - 2 row cuts average 2.0 elements, 2 column cuts (2 active)  in 0.000 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 2 row cuts average 3.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 4 (OddWheel) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 5 (MixedIntegerRounding2) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 6 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 8 (ZeroHalf) - 1 row cuts average 6.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0001I Search completed - best objective 770, took 2 iterations and 0 nodes (0.00 seconds)
Cbc0035I Maximum depth 0, 1 variables fixed on reduced cost
Cuts at root node changed objective from 779.524 to 770
Probing was tried 2 times and created 4 cuts (5.4e-05 seconds)
Gomory was tried 2 times and created 2 cuts (5.2e-05 seconds)
Knapsack was tried 2 times and created 0 cuts (1e-05 seconds)
Clique was tried 2 times and created 0 cuts (1.1e-05 seconds)
OddWheel was tried 2 times and created 0 cuts (5e-06 seconds)
MixedIntegerRounding2 was tried 2 times and created 0 cuts (1.3e-05 seconds)
FlowCover was tried 2 times and created 0 cuts (7e-06 seconds)
TwoMirCuts was tried 1 times and created 0 cuts (1.9e-05 seconds)
ZeroHalf was tried 1 times and created 1 cuts (3.3e-05 seconds)

Result - Optimal solution found
Objective value:                770
Enumerated nodes:               0
Total iterations:               2
Time (CPU seconds):             0.002176
Time (Wallclock seconds):       0.00341201
Total time (CPU seconds):       0.002239   (Wallclock seconds):       0.00352001
Starting solution of the Linear programming relaxation problem using Primal Simplex

Coin0506I Presolve 1 (0) rows, 6 (0) columns and 6 (0) elements
Clp1000I sum of infeasibilities 0 - average 0, 6 fixed columns
Coin0506I Presolve 0 (-1) rows, 0 (-6) columns and 0 (-6) elements
Clp0000I Optimal - objective value -0
Clp0000I Optimal - objective value -0
Coin0511I After Postsolve, objective 0, infeasibilities - dual 0 (0), primal 0 (0)
Clp0000I Optimal - objective value 756.66667
Clp0000I Optimal - objective value 756.66667
Clp0000I Optimal - objective value 756.66667
Clp0032I Optimal objective 756.6666667 - 0 iterations time 0.002, Idiot 0.00

Starting MIP optimization
maxSavedSolutions was changed from 1 to 10
Continuous objective value is 756.667 - 4.7e-05 seconds
Cgl0003I 0 fixed, 0 tightened bounds, 1 strengthened rows, 0 substitutions
Cgl0004I processed model has 1 rows, 6 columns (6 integer (6 of which binary)) and 6 elements
Coin3009W Conflict graph built in 0.000 seconds, density: 7.692%
Cgl0015I Clique Strengthening extended 0 cliques, 0 were dominated
Cbc0045I Nauty did not find any useful orbits in time 5.4e-05
Cbc0038I Initial state - 1 integers unsatisfied sum - 0.142857
Cbc0038I Pass   1: suminf.    0.04762 (1) obj. 753.095 iterations 1
Cbc0038I Solution found of 515
Cbc0038I Rounding solution of 615 is better than previous of 515
Cbc0038I Before mini branch and bound, 4 integers at bound fixed and 0 continuous
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 2 columns
Cbc0038I Mini branch and bound improved solution from 615 to 685 (0.00 seconds)
Cbc0038I Round again with cutoff of 696.357
Cbc0038I Pass   2: suminf.    0.04762 (1) obj. 753.095 iterations 0
Cbc0038I Pass   3: suminf.    0.27457 (1) obj. 696.357 iterations 1
Cbc0038I Pass   4: suminf.    0.37104 (1) obj. 696.357 iterations 1
Cbc0038I Pass   5: suminf.    0.11357 (1) obj. 696.357 iterations 2
Cbc0038I Pass   6: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass   7: suminf.    0.14286 (1) obj. 749.286 iterations 2
Cbc0038I Pass   8: suminf.    0.35457 (1) obj. 696.357 iterations 1
Cbc0038I Pass   9: suminf.    0.35457 (1) obj. 696.357 iterations 0
Cbc0038I Pass  10: suminf.    0.47619 (1) obj. 745.952 iterations 2
Cbc0038I Pass  11: suminf.    0.32543 (1) obj. 696.357 iterations 1
Cbc0038I Pass  12: suminf.    0.47619 (1) obj. 745.952 iterations 1
Cbc0038I Pass  13: suminf.    0.14286 (1) obj. 749.286 iterations 1
Cbc0038I Pass  14: suminf.    0.31813 (1) obj. 696.357 iterations 2
Cbc0038I Pass  15: suminf.    0.31813 (1) obj. 696.357 iterations 0
Cbc0038I Pass  16: suminf.    0.31813 (1) obj. 696.357 iterations 0
Cbc0038I Pass  17: suminf.    0.14286 (1) obj. 749.286 iterations 2
Cbc0038I Pass  18: suminf.    0.35457 (1) obj. 696.357 iterations 1
Cbc0038I Pass  19: suminf.    0.47915 (1) obj. 696.357 iterations 1
Cbc0038I Pass  20: suminf.    0.11357 (1) obj. 696.357 iterations 1
Cbc0038I Pass  21: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  22: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  23: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  24: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  25: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  26: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  27: suminf.    0.11357 (1) obj. 696.357 iterations 0
Cbc0038I Pass  28: suminf.    0.08842 (1) obj. 696.357 iterations 2
Cbc0038I Pass  29: suminf.    0.47619 (1) obj. 745.952 iterations 2
Cbc0038I Pass  30: suminf.    0.32543 (1) obj. 696.357 iterations 1
Cbc0038I Pass  31: suminf.    0.31813 (1) obj. 696.357 iterations 2
Cbc0038I Rounding solution of 735 is better than previous of 685
Cbc0038I Before mini branch and bound, 1 integers at bound fixed and 0 continuous
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 4 columns
Cbc0038I Mini branch and bound did not improve solution (0.00 seconds)
Cbc0038I Round again with cutoff of 742.714
Cbc0038I Reduced cost fixing fixed 1 variables on major pass 3
Cbc0038I Pass  31: suminf.    0.04762 (1) obj. 753.095 iterations 0
Cbc0038I Pass  32: suminf.    0.08914 (1) obj. 742.714 iterations 1
Cbc0038I Pass  33: suminf.    0.00914 (1) obj. 742.714 iterations 2
Cbc0038I Solution found of 745
Cbc0038I Before mini branch and bound, 2 integers at bound fixed and 0 continuous
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 4 columns
Cbc0038I Mini branch and bound did not improve solution (0.00 seconds)
Cbc0038I Round again with cutoff of 751.071
Cbc0038I Reduced cost fixing fixed 4 variables on major pass 4
Cbc0038I Pass  34: suminf.    0.06250 (1) obj. 753.438 iterations 1
Cbc0038I Pass  35: suminf.    0.07529 (1) obj. 751.071 iterations 1
Cbc0038I Pass  36: suminf.    0.06250 (1) obj. 753.438 iterations 1
Cbc0038I Pass  37: suminf.    0.07529 (1) obj. 751.071 iterations 1
Cbc0038I Pass  38: suminf.    0.17411 (1) obj. 751.071 iterations 1
Cbc0038I Pass  39: suminf.    0.06250 (1) obj. 753.438 iterations 2
Cbc0038I Pass  40: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  41: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  42: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  43: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  44: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  45: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  46: suminf.    0.17411 (1) obj. 751.071 iterations 2
Cbc0038I Pass  47: suminf.    0.17411 (1) obj. 751.071 iterations 0
Cbc0038I Pass  48: suminf.    0.17411 (1) obj. 751.071 iterations 0
Cbc0038I Pass  49: suminf.    0.17411 (1) obj. 751.071 iterations 0
Cbc0038I Pass  50: suminf.    0.06250 (1) obj. 753.438 iterations 2
Cbc0038I Pass  51: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  52: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  53: suminf.    0.17411 (1) obj. 751.071 iterations 2
Cbc0038I Pass  54: suminf.    0.06250 (1) obj. 753.438 iterations 2
Cbc0038I Pass  55: suminf.    0.06250 (1) obj. 753.438 iterations 0
Cbc0038I Pass  56: suminf.    0.17411 (1) obj. 751.071 iterations 2
Cbc0038I Pass  57: suminf.    0.17411 (1) obj. 751.071 iterations 0
Cbc0038I Pass  58: suminf.    0.17411 (1) obj. 751.071 iterations 0
Cbc0038I Pass  59: suminf.    0.07529 (1) obj. 751.071 iterations 1
Cbc0038I Pass  60: suminf.    0.06250 (1) obj. 753.438 iterations 1
Cbc0038I Pass  61: suminf.    0.17411 (1) obj. 751.071 iterations 2
Cbc0038I Pass  62: suminf.    0.06250 (1) obj. 753.438 iterations 2
Cbc0038I Pass  63: suminf.    0.17411 (1) obj. 751.071 iterations 2
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 4 integers at bound fixed and 0 continuous
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 2 columns
Cbc0038I Mini branch and bound did not improve solution (0.00 seconds)
Cbc0038I After 0.00 seconds - Feasibility pump exiting with objective of 745 - took 0.00 seconds
Cbc0012I Integer solution of 745 found by feasibility pump after 0 iterations and 0 nodes (0.00 seconds)
Cbc0038I Full problem 1 rows 6 columns, reduced to 1 rows 2 columns
Cbc0006I The LP relaxation is infeasible or too expensive
Cbc0013I At root node, 0 cuts changed objective from 753.57143 to 685 in 1 passes
Cbc0014I Cut generator 0 (Probing) - 0 row cuts average 0.0 elements, 1 column cuts (1 active)  in 0.000 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 2 (Knapsack) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 4 (OddWheel) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 5 (MixedIntegerRounding2) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 6 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0014I Cut generator 8 (ZeroHalf) - 0 row cuts average 0.0 elements, 0 column cuts (0 active)  in 0.000 seconds - new frequency is -100
Cbc0001I Search completed - best objective 745, took 0 iterations and 0 nodes (0.01 seconds)
Cbc0035I Maximum depth 0, 3 variables fixed on reduced cost
Cuts at root node changed objective from 753.571 to 685
Probing was tried 1 times and created 1 cuts (2.2e-05 seconds)
Gomory was tried 0 times and created 0 cuts (0 seconds)
Knapsack was tried 0 times and created 0 cuts (0 seconds)
Clique was tried 0 time




<OptimizationStatus.OPTIMAL: 0>

確認

if mip_model.status == OptimizationStatus.OPTIMAL:
    print("total value:", mip_model.objective_value)
    mip_items["val"] = mip_items["var"].astype(float)
    print("total size:", (mip_items["size"] * mip_items["val"]).sum())
    display(mip_items[["name", "value", "size", "val"]])
else:
    print(mip_model.status)
total value: 745.0
total size: 65.0
name value size val
0 缶コーヒー 120 10 0.0
1 水入りペットボトル 130 12 1.0
2 バナナ 80 7 1.0
3 りんご 100 9 1.0
4 おにぎり 250 21 1.0
5 パン 185 16 1.0

次に目的関数を2つにしてみる。

多目的・多制約整数ナップサック問題

ナップサックの価値が最大かつ最軽量となる組み合わせを求める。

同じ品物を複数個入れてもよい。

多目的最適化のために Platypus を使う。

$ poetry add platypus-opt

データ

moo_data = [
    ["缶コーヒー", 120, 10, 350],
    ["水入りペットボトル", 130, 12, 500],
    ["バナナ", 80, 7, 200],
    ["りんご", 100, 9, 350],
    ["おにぎり", 120, 21, 120],
    ["パン", 110, 16, 100],
]

moo_items = pd.DataFrame(
    data=moo_data,
    columns=["name", "value", "volume", "weight"],
)

display(moo_items)
name value volume weight
0 缶コーヒー 120 10 350
1 水入りペットボトル 130 12 500
2 バナナ 80 7 200
3 りんご 100 9 350
4 おにぎり 120 21 120
5 パン 110 16 100

モデル

from platypus import NSGAII, Constraint, Integer, Problem


class MultiObjectiveKnapsack(Problem):

    def __init__(self, items, capacity, max_qty_per_item):
        super().__init__(nvars=len(items), nobjs=2, nconstrs=2)
        self.items = items
        self.capacity = capacity
        self.types[:] = Integer(0, max_qty_per_item)
        self.constraints[:] = [Constraint("<=", capacity), Constraint(">", 0)]
        self.directions[:] = [Problem.MAXIMIZE, Problem.MINIMIZE]

    def evaluate(self, solution):
        item_values = self.items["value"].values
        item_volumes = self.items["volume"].values
        item_weights = self.items["weight"].values
        item_qtys = solution.variables
        solution.objectives[0] = sum(
            value * qty for value, qty in zip(item_values, item_qtys)
        )
        solution.objectives[1] = sum(
            weight * qty for weight, qty in zip(item_weights, item_qtys)
        )
        solution.constraints[0] = sum(
            volume * qty for volume, qty in zip(item_volumes, item_qtys)
        )
        solution.constraints[1] = sum(item_qtys)

求解

problem = MultiObjectiveKnapsack(
    moo_items,
    capacity=capacity,
    max_qty_per_item=capacity // moo_items["volume"].min(),
)

algorithm = NSGAII(problem)

algorithm.run(1000)

確認

import matplotlib.pyplot as plt
from platypus import nondominated, unique


def plot_solutions(solutions):
    # 実現可能解
    feasible_solutions = unique(
        [solution for solution in solutions if solution.feasible]
    )
    feasible_values = []
    feasible_weights = []
    for solution in feasible_solutions:
        feasible_values.append(solution.objectives[0])
        feasible_weights.append(solution.objectives[1])

    # パレート解
    pareto_solutions = unique(nondominated(solutions))
    pareto_values = []
    pareto_weights = []
    for solution in pareto_solutions:
        pareto_values.append(solution.objectives[0])
        pareto_weights.append(solution.objectives[1])

    fig = plt.figure(figsize=(5, 5))
    ax = fig.add_subplot()
    ax.scatter(feasible_values, feasible_weights, alpha=0.5, label="feasible")
    ax.scatter(
        pareto_values,
        pareto_weights,
        color="yellow",
        edgecolor="black",
        label="pareto",
    )
    ax.set(xlabel="total value", ylabel="total weight")
    ax.legend()
    plt.minorticks_on()
    plt.grid(which="major", color="black", alpha=0.4)
    plt.grid(which="minor", color="gray", linestyle=":")
    plt.show()

解の候補を表示する。

plot_solutions(algorithm.result)

fig-1

from platypus import bin2int, gray2bin


def display_solutions(items, solutions):
    pareto_solutions = unique(nondominated(solutions))
    moo_result = []
    for solution in sorted(
        pareto_solutions, key=lambda x: x.objectives[0], reverse=True
    )[0:10]:
        item_qtys = [bin2int(gray2bin(bits)) for bits in solution.variables]
        moo_result.append(
            [*item_qtys, *solution.objectives, solution.constraints[0]]
        )
    result = pd.DataFrame(
        moo_result,
        columns=[
            *moo_items["name"].values,
            "total value",
            "total weight",
            "total volume",
        ],
    )
    display(result)

求めた解を価値の高い順に10件表示する。

display_solutions(moo_items, algorithm.result)
缶コーヒー 水入りペットボトル バナナ りんご おにぎり パン total value total weight total volume
0 1 0 5 2 0 0 720 2050 63
1 1 0 3 3 0 0 660 2000 58
2 2 1 2 0 0 1 640 1700 62
3 0 0 5 1 1 0 620 1470 65
4 0 0 6 0 1 0 600 1320 63
5 0 0 4 1 1 0 540 1270 58
6 0 0 4 1 0 1 530 1250 53
7 0 0 5 0 1 0 520 1120 56
8 0 0 2 1 2 0 500 990 65
9 0 0 2 1 1 1 490 970 60

多目的・多制約0/1ナップサック問題

ナップサックの価値が最大かつ最軽量となる組み合わせを求める。

同じ品物を複数個入れることはできない(0個または1個)。

モデル

problem = MultiObjectiveKnapsack(
    moo_items,
    capacity=capacity,
    max_qty_per_item=1,
)

algorithm = NSGAII(problem)

algorithm.run(100)

確認

解の候補を表示する。

plot_solutions(algorithm.result)

fig-2

求めた解を価値の高い順に10件表示する。

display_solutions(moo_items, algorithm.result)
缶コーヒー 水入りペットボトル バナナ りんご おにぎり パン total value total weight total volume
0 1 1 1 1 1 0 550 1520 59
1 1 1 1 1 0 1 540 1500 54
2 1 0 1 1 1 1 530 1120 63
3 1 1 0 0 1 1 480 1070 59
4 1 0 0 1 1 1 450 920 56
5 1 0 1 0 1 1 430 770 54
6 1 0 0 0 1 1 350 570 47
7 0 0 1 0 1 1 310 420 44
8 0 0 0 0 1 1 230 220 37
9 0 0 0 0 0 1 110 100 16

試行回数を増やす

試行回数を増やしてみる。

problem = MultiObjectiveKnapsack(
    moo_items,
    capacity=capacity,
    max_qty_per_item=1,
)

algorithm = NSGAII(problem)

algorithm.run(10000)
plot_solutions(algorithm.result)

fig-3

display_solutions(moo_items, algorithm.result)
缶コーヒー 水入りペットボトル バナナ りんご おにぎり パン total value total weight total volume
0 1 1 1 1 1 0 550 1520 59
1 0 1 1 1 1 1 540 1270 65
2 1 0 1 1 1 1 530 1120 63
3 1 1 0 0 1 1 480 1070 59
4 1 0 0 1 1 1 450 920 56
5 1 0 1 0 1 1 430 770 54
6 0 1 0 0 1 1 360 720 49
7 1 0 0 0 1 1 350 570 47
8 0 0 1 0 1 1 310 420 44
9 0 0 0 0 1 1 230 220 37