oh-my-dear-ai's picture
fix: ensure talent_price_bonus defaults to 0 in get_results function
ed2014d
Raw
History Blame Contribute Delete
4.44 kB
from datetime import datetime
import numpy as np
from numpy.typing import NDArray
from pyscipopt import Model, quicksum
from ui.display import format_results
from data_loader import (
DISHES_DF,
LABELS,
PLANTS_DF,
)
def optimize(budget, strategy, stocks, sold_prices):
"""
Calculate the optimal solution of item sales based on the given budget
and inventory constraints.
Args:
- budget (int): The total budget available for purchasing items.
- strategy (str): The strategy to use for optimization, either "MinimizeStock" or "MaximizeStock".
- stocks (NDArray[int]): An array representing the available stock of each item.
- sold_prices (NDArray[int]): An array representing the selling price of each item.
Returns:
- dict: A dictionary containing the solution, total price, total count,
"""
# Initialize the master problem
model = Model("Knapsack")
# Decision variables in master problem
x = [
model.addVar(
vtype="I", name=f"x_{i}", lb=0, ub=int(stocks[i]) if stocks[i] else 0
)
for i in range(len(stocks))
]
obj1 = quicksum(sold_prices[i] * x[i] for i in range(len(stocks)))
obj2 = quicksum(x[i] for i in range(len(stocks)))
# Objective: maximize total value of sold plants
model.setObjective(obj1, "maximize")
model.addCons(obj1 <= budget)
# first optimize
model.hideOutput()
model.optimize()
if model.getStatus() == "optimal":
optimal_total_value = model.getObjVal()
model.freeTransform()
model.setObjective(
obj2, "maximize" if strategy == "MinimizeStock" else "minimize"
)
model.addCons(obj1 == optimal_total_value)
model.optimize()
# Final solution processing
solution = [0] * len(x)
total_value = 0
total_count = 0
if model.getStatus() == "optimal":
for i, var in enumerate(x):
if (n := round(model.getVal(var))) > 0 and sold_prices[i] > 0:
solution[i] = n
total_count += n
total_value += n * sold_prices[i]
return {
"solution": solution,
"total_price": int(total_value),
"total_count": int(total_count),
"remaining": int(budget - total_value),
}
raise ValueError(
f"Optimization failed with status: {model.getStatus()} at {datetime.now()}"
)
def get_results(
language,
currency,
budget,
plants_prices_extra_rate,
dishes_prices_extra_rate,
talent_price_bonus,
strategy,
*inventory,
):
talent_price_bonus = talent_price_bonus or 0
prices: NDArray[np.int16] = np.concat(
[
PLANTS_DF[currency] * (1 + plants_prices_extra_rate),
np.floor(
DISHES_DF[currency]
* (1 + dishes_prices_extra_rate)
* (1 + talent_price_bonus / 100)
).astype(
np.int16
), # Licet(@discord)'s data shows that all values are rounded down: https://docs.google.com/spreadsheets/d/1CWv0VmgfKKWWlqUty9hqGwWt86_G94x5K89DP4b4eRI
],
dtype=np.int16,
)
outputs = optimize(
budget,
strategy,
np.array([n if n else 0 for n in inventory], dtype=np.int16),
prices,
)
plants_solution = outputs["solution"][: len(PLANTS_DF)]
dishes_solution = outputs["solution"][
len(PLANTS_DF) : len(PLANTS_DF) + len(DISHES_DF)
]
results = {}
results["solution"] = {
f"{LABELS[language]['plants'][PLANTS_DF.iloc[i]['name']]} ({LABELS[language]['tiers'][PLANTS_DF.iloc[i]['tier']]}, {int(prices[i])} {currency})": plants_solution[
i
]
for i in range(len(PLANTS_DF))
if plants_solution[i] > 0
}
results["solution"].update({
f"{LABELS[language]['dishes'][DISHES_DF.iloc[i]['name']]} ({LABELS[language]['tiers'][DISHES_DF.iloc[i]['tier']]}, {int(prices[len(PLANTS_DF) + i])} {currency})": dishes_solution[
i
]
for i in range(len(DISHES_DF))
if dishes_solution[i] > 0
})
results["total_price"] = outputs["total_price"]
results["total_count"] = outputs["total_count"]
results["remaining"] = outputs["remaining"]
return format_results(results, language)