File size: 4,862 Bytes
ddc847a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import gradio as gr
import numpy as np
import pulp


def bounded_knapsack_problem_solver(target, df):

    name_ls = []
    for index, item in enumerate(df["name"]):
        if item:
            name_ls.append(item)
        else:
            name_ls.append(f"📦{str(index+1)}")

    if len(name_ls) != len(set(name_ls)):
        return "Please check for duplicate item names and try again."

    items = np.array(name_ls)  # 物品名称
    prices = np.array([int(p) if p else 0 for p in df["value"]])  # 物品单价
    stocks = np.array([int(c) if c else 0 for c in df["count"]])  # 物品数量

    # 创建问题实例,最大化物品总价值
    prob = pulp.LpProblem("Maximize_Value", pulp.LpMaximize)

    # 决策变量,装入背包的物品物品组合,件数必须是整数
    x = pulp.LpVariable.dicts("x", range(len(prices)), lowBound=0, cat="Integer")

    # 遍历,设置决策变量的上界为库存量
    for i in range(len(stocks)):
        x[i].upBound = stocks[i]

    # 目标函数:最大化物品总价值
    prob += pulp.lpSum([prices[i] * x[i] for i in range(len(stocks))])

    # 添加约束条件: 总价值小于等于目标值
    prob += pulp.lpSum([prices[i] * x[i] for i in range(len(stocks))]) <= target

    # 求解问题
    # CBC(Coin-or Branch and Cut)求解器使用分支定界算法来寻找整数规划问题的最优解
    solver = pulp.getSolver("PULP_CBC_CMD")
    prob.solve(solver=solver)

    if pulp.LpStatus[prob.status] == "Optimal":

        value = 0
        solution = []
        for i, v in x.items():
            if v.varValue:
                if v.varValue > 0:
                    solution.append(f"{items[i]}(${prices[i]}): {int(v.varValue)}\n")
                    value += int(v.varValue) * prices[i]
        if value == target:
            return f"Optimal solution found:\n\n{''.join(solution)}\nTotal value: {value}\nGreat! Found a combination of items with a total value equal to the target value(${target}).😃"

        else:
            return f"Optimal solution found:\n\n{''.join(solution)}\nTotal value: {value}\n${target - value} short of the target value(${target}).😂"


# Create a Gradio interface with a column layout
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown(
        """
        <center><font size=8>📦Easy Bounded Knapsack Problem Solver📦</center>

        ### Given

            - A set of items, each with:
                - Value ( v_i )
                - Maximum quantity ( q_i )
            - A target value ( T )

        ### Objective

            Find a combination of items such that the sum of the selected items' values equals ( T ) 
            or maximizes the total value without exceeding ( T ). 
            Each item ( i ) can be selected up to ( q_i ) times.
        """
    )

    with gr.Column():
        # Add a row for the target input
        target = gr.Number(
            label="Target",
            info="number less than 50,000",
            value=0,
            precision=0,
            minimum=0,
            maximum=50000,
            step=100,
        )

        df = gr.Dataframe(
            headers=["name", "value", "count"],
            datatype=["str", "number", "number"],
            row_count=3,
            col_count=(3, "fixed"),
            label="Items",
        )

        # Add a radio selection for the strategy
        # condition = gr.Radio(
        #     [
        #         ("最小化物品数量(优先选择高价物品)", "MinimizeCount"),
        #         ("最大化物品数量(优先选择低价物品)", "MaximizeCount"),
        #     ],
        #     value="MinimizeCount",
        #     label="Condition",
        # )

        # Add a row for the Clear and Calculate buttons
        with gr.Row():
            clear_btn = gr.ClearButton(df, size="sm", value="❌Clear")

            # Add a button to trigger the calculation
            submit_btn = gr.Button(value="🛠Calculate")

        # Add a row for the result textbox
        with gr.Row():
            result = gr.Textbox(label="Output")
    
    examples = gr.Examples(
        examples=[
            [150, [["", 12, 10], ["", 9, 5], ["", 8, 10]]],
            [
                500,
                [
                    ["pencil", 129, 1],
                    ["magic keyboard", 349, 1],
                    ["homepod", 299, 1],
                    ["airpods max", 549, 1],
                ],
            ],
        ],
        inputs=[target, df],
    )    
    
    # Set up the button click event to call the calculator function
    submit_btn.click(
        bounded_knapsack_problem_solver,
        inputs=[target, df],
        outputs=[result],
    )

# Launch the Gradio application
demo.queue(api_open=False)
demo.launch(max_threads=5, share=False)

if __name__ == "__main__":
    demo.launch()