2

I'm trying to minimized the following problem: for the production of laptops, phones and tablets, there are costs for inventory (1$ per item per month) and for overtime hours (10$ per hour). There is a demand scheme to be met, which functions as a constraint for the minimum number of gadgets in a specific month. Besides this there is a maximum of 20000 hours of production, plus 3000 overtime hours per month.

The problem is that the results python/pulp give me are (with one exception) all the upperbound values that are inserted in the LpVariables: not the minimized costs!

from pulp import *


# Define the LP problem: minimize costs
prob = LpProblem("Minimize costs of production and inventory", LpMinimize)


# Demand schemes
demand_laptops = [75, 125, 1000, 1500, 1000, 500, 1250, 1500, 1000, 500, 500, 400, 300]           # Demand laptops
demand_phones = [120, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000]    # Demand phones
demand_tablets = [50, 2000, 3000, 2000, 3000, 4000, 5000, 2000, 3000, 4000, 5000, 4000, 5000]     # Demand tablets


# Defining variables: normal production hours and overtime production hours.
production_laptop = {x: LpVariable("Production hours for laptop in month {}".format(x), 0, 20000)
                     for x in range(1, 13)}
production_phone = {x: LpVariable("Production hours for phone in month {}".format(x), 0, 20000)
                    for x in range(1, 13)}
production_tablet = {x: LpVariable("Production hours for tablet in month {}".format(x), 0, 20000)
                     for x in range(1, 13)}

overtime_laptop = {x: LpVariable("Overtime hours for laptop in month {}".format(x), 0, 3000)
                   for x in range(1, 13)}
overtime_phone = {x: LpVariable("Overtime hours for phone in month {}".format(x), 0, 3000)
                  for x in range(1, 13)}
overtime_tablet = {x: LpVariable("Overtime hours for tablet in month {}".format(x), 0, 3000)
                   for x in range(1, 13)}


# defining a list of names for the inventory of products
inventory_laptops = {x: "inventory of laptops in month {}".format(x)
                     for x in range(1, 13)}
inventory_phones = {x: "inventory of phones in month {}".format(x)
                    for x in range(1, 13)}
inventory_tables = {x: "inventory of tablets in month {}".format(x)
                    for x in range(1, 13)}


# Inventory (to be minimized)
inventory_laptops[1] = demand_laptops[0] + (1 / 5) * production_laptop[1] + (1 / 5) * overtime_laptop[1] - demand_laptops[1]
inventory_laptops[2] = inventory_laptops[1] + (1 / 5) * production_laptop[2] + (1 / 5) * overtime_laptop[2] - demand_laptops[2]
inventory_laptops[3] = inventory_laptops[2] + (1 / 5) * production_laptop[3] + (1 / 5) * overtime_laptop[3] - demand_laptops[3]
inventory_laptops[4] = inventory_laptops[3] + (1 / 5) * production_laptop[4] + (1 / 5) * overtime_laptop[4] - demand_laptops[4]
inventory_laptops[5] = inventory_laptops[4] + (1 / 5) * production_laptop[5] + (1 / 5) * overtime_laptop[5] - demand_laptops[5]
inventory_laptops[6] = inventory_laptops[5] + (1 / 5) * production_laptop[6] + (1 / 5) * overtime_laptop[6] - demand_laptops[6]
inventory_laptops[7] = inventory_laptops[6] + (1 / 5) * production_laptop[7] + (1 / 5) * overtime_laptop[7] - demand_laptops[7]
inventory_laptops[8] = inventory_laptops[7] + (1 / 5) * production_laptop[8] + (1 / 5) * overtime_laptop[8] - demand_laptops[8]
inventory_laptops[9] = inventory_laptops[8] + (1 / 5) * production_laptop[9] + (1 / 5) * overtime_laptop[9] - demand_laptops[9]
inventory_laptops[10] = inventory_laptops[9] + (1 / 5) * production_laptop[10] + (1 / 5) * overtime_laptop[10] - demand_laptops[10]
inventory_laptops[11] = inventory_laptops[10] + (1 / 5) * production_laptop[11] + (1 / 5) * overtime_laptop[11] - demand_laptops[11]
inventory_laptops[12] = inventory_laptops[11] + (1 / 5) * production_laptop[12] + (1 / 5) * overtime_laptop[12] - demand_laptops[12]

inventory_phones[1] = demand_phones[0] + (1 / 2) * production_phone[1] + (1 / 2) * overtime_phone[1] - demand_phones[1]
inventory_phones[2] = inventory_phones[1] + (1 / 2) * production_phone[2] + (1 / 2) * overtime_phone[2] - demand_phones[2]
inventory_phones[3] = inventory_phones[2] + (1 / 2) * production_phone[3] + (1 / 2) * overtime_phone[3] - demand_phones[3]
inventory_phones[4] = inventory_phones[3] + (1 / 2) * production_phone[4] + (1 / 2) * overtime_phone[4] - demand_phones[4]
inventory_phones[5] = inventory_phones[4] + (1 / 2) * production_phone[5] + (1 / 2) * overtime_phone[5] - demand_phones[5]
inventory_phones[6] = inventory_phones[5] + (1 / 2) * production_phone[6] + (1 / 2) * overtime_phone[6] - demand_phones[6]
inventory_phones[7] = inventory_phones[6] + (1 / 2) * production_phone[7] + (1 / 2) * overtime_phone[7] - demand_phones[7]
inventory_phones[8] = inventory_phones[7] + (1 / 2) * production_phone[8] + (1 / 2) * overtime_phone[8] - demand_phones[8]
inventory_phones[9] = inventory_phones[8] + (1 / 2) * production_phone[9] + (1 / 2) * overtime_phone[9] - demand_phones[9]
inventory_phones[10] = inventory_phones[9] + (1 / 2) * production_phone[10] + (1 / 2) * overtime_phone[10] - demand_phones[10]
inventory_phones[11] = inventory_phones[10] + (1 / 2) * production_phone[11] + (1 / 2) * overtime_phone[11] - demand_phones[11]
inventory_phones[12] = inventory_phones[11] + (1 / 2) * production_phone[12] + (1 / 2) * overtime_phone[12] - demand_phones[12]

inventory_tables[1] = demand_tablets[0] + (1 / 4) * production_tablet[1] + (1 / 4) * overtime_tablet[1] - demand_tablets[1]
inventory_tables[2] = inventory_tables[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] - demand_tablets[2]
inventory_tables[3] = inventory_tables[2] + (1 / 4) * production_tablet[3] + (1 / 4) * overtime_tablet[3] - demand_tablets[3]
inventory_tables[4] = inventory_tables[3] + (1 / 4) * production_tablet[4] + (1 / 4) * overtime_tablet[4] - demand_tablets[4]
inventory_tables[5] = inventory_tables[4] + (1 / 4) * production_tablet[5] + (1 / 4) * overtime_tablet[5] - demand_tablets[5]
inventory_tables[6] = inventory_tables[5] + (1 / 4) * production_tablet[6] + (1 / 4) * overtime_tablet[6] - demand_tablets[6]
inventory_tables[7] = inventory_tables[6] + (1 / 4) * production_tablet[7] + (1 / 4) * overtime_tablet[7] - demand_tablets[7]
inventory_tables[8] = inventory_tables[7] + (1 / 4) * production_tablet[8] + (1 / 4) * overtime_tablet[8] - demand_tablets[8]
inventory_tables[9] = inventory_tables[8] + (1 / 4) * production_tablet[9] + (1 / 4) * overtime_tablet[9] - demand_tablets[9]
inventory_tables[10] = inventory_tables[9] + (1 / 4) * production_tablet[10] + (1 / 4) * overtime_tablet[10] - demand_tablets[10]
inventory_tables[11] = inventory_tables[10] + (1 / 4) * production_tablet[11] + (1 / 4) * overtime_tablet[11] - demand_tablets[11]
inventory_tables[12] = inventory_tables[11] + (1 / 4) * production_tablet[12] + (1 / 4) * overtime_tablet[12] - demand_tablets[12]


# Constraints to meet demand scheme
prob += demand_laptops[0] + (1 / 5) * production_laptop[1] + (1 / 5) * overtime_laptop[1] >= demand_laptops[1]
prob += inventory_laptops[1] + (1 / 5) * production_laptop[2] + (1 / 5) * overtime_laptop[2] >= demand_laptops[2]
prob += inventory_laptops[2] + (1 / 5) * production_laptop[3] + (1 / 5) * overtime_laptop[3] >= demand_laptops[3]
prob += inventory_laptops[3] + (1 / 5) * production_laptop[4] + (1 / 5) * overtime_laptop[4] >= demand_laptops[4]
prob += inventory_laptops[4] + (1 / 5) * production_laptop[5] + (1 / 5) * overtime_laptop[5] >= demand_laptops[5]
prob += inventory_laptops[5] + (1 / 5) * production_laptop[6] + (1 / 5) * overtime_laptop[6] >= demand_laptops[6]
prob += inventory_laptops[6] + (1 / 5) * production_laptop[7] + (1 / 5) * overtime_laptop[7] >= demand_laptops[7]
prob += inventory_laptops[7] + (1 / 5) * production_laptop[8] + (1 / 5) * overtime_laptop[8] >= demand_laptops[8]
prob += inventory_laptops[8] + (1 / 5) * production_laptop[9] + (1 / 5) * overtime_laptop[9] >= demand_laptops[9]
prob += inventory_laptops[9] + (1 / 5) * production_laptop[10] + (1 / 5) * overtime_laptop[10] >= demand_laptops[10]
prob += inventory_laptops[10] + (1 / 5) * production_laptop[11] + (1 / 5) * overtime_laptop[11] >= demand_laptops[11]
prob += inventory_laptops[11] + (1 / 5) * production_laptop[12] + (1 / 5) * overtime_laptop[12] >= demand_laptops[12]

prob += demand_phones[0] + (1 / 2) * production_phone[1] + (1 / 2) * overtime_phone[1] >= demand_phones[1]
prob += inventory_phones[1] + (1 / 2) * production_phone[2] + (1 / 2) * overtime_phone[2] >= demand_phones[2]
prob += inventory_phones[2] + (1 / 2) * production_phone[3] + (1 / 2) * overtime_phone[3] >= demand_phones[3]
prob += inventory_phones[3] + (1 / 2) * production_phone[4] + (1 / 2) * overtime_phone[4] >= demand_phones[4]
prob += inventory_phones[4] + (1 / 2) * production_phone[5] + (1 / 2) * overtime_phone[5] >= demand_phones[5]
prob += inventory_phones[5] + (1 / 2) * production_phone[6] + (1 / 2) * overtime_phone[6] >= demand_phones[6]
prob += inventory_phones[6] + (1 / 2) * production_phone[7] + (1 / 2) * overtime_phone[7] >= demand_phones[7]
prob += inventory_phones[7] + (1 / 2) * production_phone[8] + (1 / 2) * overtime_phone[8] >= demand_phones[8]
prob += inventory_phones[8] + (1 / 2) * production_phone[9] + (1 / 2) * overtime_phone[9] >= demand_phones[9]
prob += inventory_phones[9] + (1 / 2) * production_phone[10] + (1 / 2) * overtime_phone[10] >= demand_phones[10]
prob += inventory_phones[10] + (1 / 2) * production_phone[11] + (1 / 2) * overtime_phone[11] >= demand_phones[11]
prob += inventory_phones[11] + (1 / 2) * production_phone[12] + (1 / 2) * overtime_phone[12] >= demand_phones[12]


prob += demand_tablets[0] + (1 / 4) * production_tablet[1] + (1 / 4) * overtime_tablet[1] >= demand_tablets[1]
prob += inventory_phones[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] >= demand_tablets[2]
prob += inventory_phones[2] + (1 / 4) * production_tablet[3] + (1 / 4) * overtime_tablet[3] >= demand_tablets[3]
prob += inventory_phones[3] + (1 / 4) * production_tablet[4] + (1 / 4) * overtime_tablet[4] >= demand_tablets[4]
prob += inventory_phones[4] + (1 / 4) * production_tablet[5] + (1 / 4) * overtime_tablet[5] >= demand_tablets[5]
prob += inventory_phones[5] + (1 / 4) * production_tablet[6] + (1 / 4) * overtime_tablet[6] >= demand_tablets[6]
prob += inventory_phones[6] + (1 / 4) * production_tablet[7] + (1 / 4) * overtime_tablet[7] >= demand_tablets[7]
prob += inventory_phones[7] + (1 / 4) * production_tablet[8] + (1 / 4) * overtime_tablet[8] >= demand_tablets[8]
prob += inventory_phones[8] + (1 / 4) * production_tablet[9] + (1 / 4) * overtime_tablet[9] >= demand_tablets[9]
prob += inventory_phones[9] + (1 / 4) * production_tablet[10] + (1 / 4) * overtime_tablet[10] >= demand_tablets[10]
prob += inventory_phones[10] + (1 / 4) * production_tablet[11] + (1 / 4) * overtime_tablet[11] >= demand_tablets[11]
prob += inventory_phones[11] + (1 / 4) * production_tablet[12] + (1 / 4) * overtime_tablet[12] >= demand_tablets[12]


# Objective function: inventory costs and overtime costs (10 per hour)
prob += sum(inventory_laptops) + sum(inventory_phones) + sum(inventory_tables) + (10 * (sum(overtime_laptop) + sum(overtime_phone) + sum(overtime_tablet)))

# Solve the problem
prob.solve()

print("Status:", LpStatus[prob.status])

for v in prob.variables():
    print(v.name, "=", v.varValue)

print("total costs:", value(prob.objective))

This gives me the following results:

Status: Optimal
Overtime_hours_for_laptop_in_month_1 = 3000.0
Overtime_hours_for_laptop_in_month_10 = 3000.0
Overtime_hours_for_laptop_in_month_11 = 3000.0
Overtime_hours_for_laptop_in_month_12 = 3000.0
Overtime_hours_for_laptop_in_month_2 = 3000.0
Overtime_hours_for_laptop_in_month_3 = 3000.0
Overtime_hours_for_laptop_in_month_4 = 3000.0
Overtime_hours_for_laptop_in_month_5 = 3000.0
Overtime_hours_for_laptop_in_month_6 = 3000.0
Overtime_hours_for_laptop_in_month_7 = 3000.0
Overtime_hours_for_laptop_in_month_8 = 3000.0
Overtime_hours_for_laptop_in_month_9 = 3000.0
Overtime_hours_for_phone_in_month_1 = 3000.0
Overtime_hours_for_phone_in_month_10 = 3000.0
Overtime_hours_for_phone_in_month_11 = 3000.0
Overtime_hours_for_phone_in_month_12 = 3000.0
Overtime_hours_for_phone_in_month_2 = 3000.0
Overtime_hours_for_phone_in_month_3 = 3000.0
Overtime_hours_for_phone_in_month_4 = 3000.0
Overtime_hours_for_phone_in_month_5 = 3000.0
Overtime_hours_for_phone_in_month_6 = 3000.0
Overtime_hours_for_phone_in_month_7 = 3000.0
Overtime_hours_for_phone_in_month_8 = 3000.0
Overtime_hours_for_phone_in_month_9 = 3000.0
Overtime_hours_for_tablet_in_month_1 = 0.0
Overtime_hours_for_tablet_in_month_10 = 3000.0
Overtime_hours_for_tablet_in_month_11 = 3000.0
Overtime_hours_for_tablet_in_month_12 = 3000.0
Overtime_hours_for_tablet_in_month_2 = 3000.0
Overtime_hours_for_tablet_in_month_3 = 3000.0
Overtime_hours_for_tablet_in_month_4 = 3000.0
Overtime_hours_for_tablet_in_month_5 = 3000.0
Overtime_hours_for_tablet_in_month_6 = 3000.0
Overtime_hours_for_tablet_in_month_7 = 3000.0
Overtime_hours_for_tablet_in_month_8 = 3000.0
Overtime_hours_for_tablet_in_month_9 = 3000.0
Production_hours_for_laptop_in_month_1 = 20000.0
Production_hours_for_laptop_in_month_10 = 20000.0
Production_hours_for_laptop_in_month_11 = 20000.0
Production_hours_for_laptop_in_month_12 = 20000.0
Production_hours_for_laptop_in_month_2 = 20000.0
Production_hours_for_laptop_in_month_3 = 20000.0
Production_hours_for_laptop_in_month_4 = 20000.0
Production_hours_for_laptop_in_month_5 = 20000.0
Production_hours_for_laptop_in_month_6 = 20000.0
Production_hours_for_laptop_in_month_7 = 20000.0
Production_hours_for_laptop_in_month_8 = 20000.0
Production_hours_for_laptop_in_month_9 = 20000.0
Production_hours_for_phone_in_month_1 = 20000.0
Production_hours_for_phone_in_month_10 = 20000.0
Production_hours_for_phone_in_month_11 = 20000.0
Production_hours_for_phone_in_month_12 = 20000.0
Production_hours_for_phone_in_month_2 = 20000.0
Production_hours_for_phone_in_month_3 = 20000.0
Production_hours_for_phone_in_month_4 = 20000.0
Production_hours_for_phone_in_month_5 = 20000.0
Production_hours_for_phone_in_month_6 = 20000.0
Production_hours_for_phone_in_month_7 = 20000.0
Production_hours_for_phone_in_month_8 = 20000.0
Production_hours_for_phone_in_month_9 = 20000.0
Production_hours_for_tablet_in_month_1 = 7800.0
Production_hours_for_tablet_in_month_10 = 20000.0
Production_hours_for_tablet_in_month_11 = 20000.0
Production_hours_for_tablet_in_month_12 = 20000.0
Production_hours_for_tablet_in_month_2 = 20000.0
Production_hours_for_tablet_in_month_3 = 20000.0
Production_hours_for_tablet_in_month_4 = 20000.0
Production_hours_for_tablet_in_month_5 = 20000.0
Production_hours_for_tablet_in_month_6 = 20000.0
Production_hours_for_tablet_in_month_7 = 20000.0
Production_hours_for_tablet_in_month_8 = 20000.0
Production_hours_for_tablet_in_month_9 = 20000.0
__dummy = None
total costs: None

Can somebody tell me what I am doing wrong?

Jeroen
  • 857
  • 10
  • 18

1 Answers1

6

There are a few syntactic glitches that result in the solver getting a different model than what you would expect. In addition, I would like to point some syntactic suggestions as well.

What is wrong?

First, the production variables are defined as dictionaries, whose values are LpVariables. I would suggest that you use the pulp data structure designed for this job, LpVariable.dicts. The definition would then be like this:

production_laptop = LpVariable.dicts(
    "Production hours for laptop in month ", range(1, 13), 
    lowBound = 0, upBound = 20000)

Note that I explicitly denote lower and upper bounds: this is a good habit, which helps a lot if you have to reuse the code after a few months (or even weeks).

Later on, you define dictionaries that represent variable names: the inventory_ variables. Then, you redefine the values of these dictionaries to point to a combination of variables and constraints. I would define these variables as the previous ones:

inventory_laptops = LpVariable.dicts(
    "inventory of laptops in month  ", range(1,13), lowBound = 0)

If there exist relationships among the variables, you can represent them in the constraints, so we do not need to worry about this during the variable definition stage.

Note that after the variable are defined, the objective function should be defined. Its definition is not correct, because instead of sum(inventory_laptops) one has to sum(inventory_laptops[i] for i in range(1,13)), otherwise we try to sum over a dictionary, and in particular over the keys of the dictionary.

Syntax

DRY: You write a lot of repetitive code, which could easily fit into loops. Try to not repeat yourself, because the code is unnecessarily lengthy and complex and prone to errors. In fact, there is an error in your code which might be because of copy-pasting code you already had: the last block of constraints mixes phones and tablets, like this:

prob += inventory_phones[1] + (1 / 4) * production_tablet[2] + (1 / 4) * overtime_tablet[2] >= demand_tablets[2]

probably because you were copy pasting and replacing phones with tablets. You can easily write these lines as

for i in range(1,13):
    prob += (demand_tablets[i - 1] if i == 1 else inventory_tables[i - 1]) + \
        (1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] >= \
        demand_tablets[i], "demand tablets {}".format(i)

which also has the added benefit that you give your constraint a name, so that you can trace it later if you want to.

Comments: Try to use helpful comments. These are the comments that describe what you intent, not what you actually do. Why comment # Demand laptops when your variable is called demand_laptops?

Consistency: This is a big one. It takes a bit of time to work with your code, mostly because variable names are not consistent: demand_tablets, inventory_tables, overtime_tablet and production_tablet are all very similar and easy to confuse. Try to stick to a more consistent notation.

Line length: Although not necessary, Python developers do not use arbitrary line lengths. Try to use a good IDE (I use Pycharm, sometimes Sublime Text), which is going to steer you to use the regular Python conventions (also in naming variables, functions, etc). This makes the code looking more like Python.

Debugging Math Optimization Models: A very useful habit for small problems, is to print out the formulation you are passing to the solver. This can help you catch many bugs and issues. It would be apparent for example, that you have defined a variable called _dummy, which was done accidentally. This is done with prob.writeLP("DebugThis.lp"). I would also use shorter length variables, so that I can understand what is going on in the constraints and objective function. As a final word, try to avoid hard numbers in your models. The inventory cost might be 10 for the instance you have now, but in the future this might change (it will change in a non-assignment environment). Thus, it is better to define a list of inventory costs (one for each product, and/or period) and update that list only. This is helpful in case you want to add more products, as the constraints and variables will be generated automatically.

Revised Code

I implemented a working version of your code hereby. To keep it close to the original, so that it is easier to understand (for yourself) I did not implement everything I suggest. As a further improvement on my lines below, try to have a list of products and generate the product-month pairs automatically. There are a few ways to do this, and perhaps this example will help.

from pulp import * # I would not import the entire workspace - you might end up shadowing variables names that you need

# Problem formulation starts here
prob = LpProblem("Minimize costs of production and inventory", LpMinimize)

# Problem data: Product Demands
demand_laptops = [75, 125, 1000, 1500, 1000, 500, 1250, 1500, 1000, 500, 500, 400, 300]
demand_phones = [120, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000]   
demand_tablets = [50, 2000, 3000, 2000, 3000, 4000, 5000, 2000, 3000, 4000, 5000, 4000, 5000]    


# Defining variables: normal production, overtime, and inventories
production_laptop = LpVariable.dicts(
    "Production hours for laptop in month ", range(1, 13), 
    lowBound = 0, upBound = 20000)
production_phone = LpVariable.dicts(
    "Production hours for phone in month ", range(1, 13),
    lowBound = 0, upBound = 20000)
production_tablet = LpVariable.dicts(
    "Production hours for tablet in month ", range(1, 13),
    lowBound = 0, upBound = 20000)

overtime_laptop = LpVariable.dicts(
    "Overtime hours for laptop in month ", range(1, 13), 
    lowBound = 0, upBound = 3000)
overtime_phone = LpVariable.dicts(
    "Overtime hours for phone in month ", range(1, 13),
    lowBound = 0, upBound = 3000)
overtime_tablet = LpVariable.dicts(
    "Overtime hours for tablet in month ", range(1, 13),
    lowBound = 0, upBound = 3000)

inventory_laptops = LpVariable.dicts(
    "inventory of laptops in month  ", range(1,13), lowBound = 0)
inventory_phones = LpVariable.dicts(
    "inventory of phones in month  ", range(1,13), lowBound = 0)
inventory_tables = LpVariable.dicts(
    "inventory of tables in month  ", range(1,13), lowBound = 0)

# Objective function: inventory costs and overtime costs
prob += (sum(
    inventory_laptops[i] + inventory_phones[i] + inventory_tables[i] 
        for i in range(1,13)) + \
    10 * sum(overtime_laptop[i] + overtime_phone[i] + overtime_tablet[i] 
        for i in range(1,13)))

# Constraint definition part
for i in range(1,13):

    # Inventory definition for laptops, phones and tablets
    prob += inventory_laptops[i] == (demand_laptops[i - 1] if i == 1  else \
    inventory_laptops[i - 1]) + \
     (1 / 5) * production_laptop[i] + (1 / 5) * overtime_laptop[i] - \
    demand_laptops[i], "inventory_laptops definition {}".format(i)

    prob += inventory_phones[i] == (demand_phones[i - 1] if i == 1  else \
    inventory_phones[i - 1]) + \
    (1 / 2) * production_phone[i] + (1 / 2) * overtime_phone[i] - \
    demand_phones[i], "inventory_phones definition {}".format(i)

    prob += inventory_tables[i] == (demand_tablets[i - 1] if i == 1  else \
    inventory_tables[i - 1]) + \
    (1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] - \
    demand_tablets[i], "inventory_tables definition {}".format(i)

    # Demand-covering constraints for laptops, phones, tablets
    prob += (demand_laptops[i - 1] if i == 1 else inventory_laptops[i - 1]) + \
    (1 / 5) * production_laptop[i] + (1 / 5) * overtime_laptop[i] >= \
    demand_laptops[i], "demand laptops {}".format(i)

    prob += (demand_phones[i - 1] if i == 1 else inventory_phones[i - 1]) + \
    (1 / 2) * production_phone[i] + (1 / 2) * overtime_phone[i] >= \
    demand_phones[i], "demand phones {}".format(i)

    prob += (demand_tablets[i - 1] if i == 1 else inventory_tables[i - 1]) + \
    (1 / 4) * production_tablet[i] + (1 / 4) * overtime_tablet[i] >= \
    demand_tablets[i], "demand tablets {}".format(i)

# Solve the problem
prob.solve()

# Take a look at what was solved
prob.writeLP("SO40113557.lp")

print("Status:", LpStatus[prob.status])

for v in prob.variables():
    print(v.name, "=", v.varValue)

print("total costs:", value(prob.objective))

Output (without printing out the variable names/values):

('Status:', 'Optimal')
('total costs:', 0.0)

I hope this helps!

Community
  • 1
  • 1
Ioannis
  • 5,238
  • 2
  • 19
  • 31