production.py

To meet the demands of its customers, a company manufactures its products in its own factories (inside production) or buys them from other companies (outside production). The inside production is subject to some resource constraints: each product consumes a certain amount of each resource. In contrast, outside production is theoretically unlimited. The problem is to determine how much of each product should be produced inside and outside the company while minimizing the overall production cost, meeting the demand, and satisfying the resource constraints.

The model aims at minimizing the production cost for a number of products while satisfying customer demand. Each product can be produced either inside the company or outside, at a higher cost. The inside production is constrained by the company’s resources, while outside production is considered unlimited. The model first declares the products and the resources. The data consists of the description of the products (the demand, the inside and outside costs, and the resource consumption) and the capacity of the various resources.

The variables for this problem are the inside and outside production for each product.

  1# --------------------------------------------------------------------------
  2# Source file provided under Apache License, Version 2.0, January 2004,
  3# http://www.apache.org/licenses/
  4# (c) Copyright IBM Corp. 2015, 2018
  5# --------------------------------------------------------------------------
  6
  7"""The model aims at minimizing the production cost for a number of products
  8while satisfying customer demand. Each product can be produced either inside
  9the company or outside, at a higher cost.
 10
 11The inside production is constrained by the company's resources, while outside
 12production is considered unlimited.
 13
 14The model first declares the products and the resources.
 15The data consists of the description of the products (the demand, the inside
 16and outside costs, and the resource consumption) and the capacity of the
 17various resources.
 18
 19The variables for this problem are the inside and outside production for each
 20product.
 21"""
 22
 23from docplex.mp.model import Model
 24from docplex.util.environment import get_environment
 25
 26
 27# ----------------------------------------------------------------------------
 28# Initialize the problem data
 29# ----------------------------------------------------------------------------
 30PRODUCTS = [("kluski", 100, 0.6, 0.8),
 31            ("capellini", 200, 0.8, 0.9),
 32            ("fettucine", 300, 0.3, 0.4)]
 33
 34# resources are a list of simple tuples (name, capacity)
 35RESOURCES = [("flour", 20),
 36             ("eggs", 40)]
 37
 38CONSUMPTIONS = {("kluski", "flour"): 0.5,
 39                ("kluski", "eggs"): 0.2,
 40                ("capellini", "flour"): 0.4,
 41                ("capellini", "eggs"): 0.4,
 42                ("fettucine", "flour"): 0.3,
 43                ("fettucine", "eggs"): 0.6}
 44
 45
 46# ----------------------------------------------------------------------------
 47# Build the model
 48# ----------------------------------------------------------------------------
 49def build_production_problem(mdl, products, resources, consumptions, **kwargs):
 50    """ Takes as input:
 51        - a list of product tuples (name, demand, inside, outside)
 52        - a list of resource tuples (name, capacity)
 53        - a list of consumption tuples (product_name, resource_named, consumed)
 54    """
 55      # --- decision variables ---
 56    mdl.inside_vars  = mdl.continuous_var_dict(products, name=lambda p: 'inside_%s' % p[0])
 57    mdl.outside_vars = mdl.continuous_var_dict(products, name=lambda p: 'outside_%s' % p[0])
 58
 59    # --- constraints ---
 60    # demand satisfaction
 61    mdl.add_constraints((mdl.inside_vars[prod] + mdl.outside_vars[prod] >= prod[1], 'ct_demand_%s' % prod[0]) for prod in products)
 62
 63    # --- resource capacity ---
 64    mdl.add_constraints((mdl.sum(mdl.inside_vars[p] * consumptions[p[0], res[0]] for p in products) <= res[1],
 65                         'ct_res_%s' % res[0]) for res in resources)
 66
 67    # --- objective ---
 68    mdl.total_inside_cost = mdl.sum(mdl.inside_vars[p] * p[2] for p in products)
 69    mdl.add_kpi(mdl.total_inside_cost, "inside cost")
 70    mdl.total_outside_cost = mdl.sum(mdl.outside_vars[p] * p[3] for p in products)
 71    mdl.add_kpi(mdl.total_outside_cost, "outside cost")
 72    mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost)
 73    return mdl
 74
 75
 76def print_production_solution(mdl, products):
 77    obj = mdl.objective_value
 78    print("* Production model solved with objective: {:g}".format(obj))
 79    print("* Total inside cost=%g" % mdl.total_inside_cost.solution_value)
 80    for p in products:
 81        print("Inside production of {product}: {ins_var}".format
 82              (product=p[0], ins_var=mdl.inside_vars[p].solution_value))
 83    print("* Total outside cost=%g" % mdl.total_outside_cost.solution_value)
 84    for p in products:
 85        print("Outside production of {product}: {out_var}".format
 86              (product=p[0], out_var=mdl.outside_vars[p].solution_value))
 87
 88def build_default_production_problem(**kwargs):
 89    mdl = Model( **kwargs)
 90    return build_production_problem(mdl, PRODUCTS, RESOURCES, CONSUMPTIONS)
 91# ----------------------------------------------------------------------------
 92# Solve the model and display the result
 93# ----------------------------------------------------------------------------
 94if __name__ == '__main__':
 95    # Build the model
 96    with Model(name='production') as model:
 97        model = build_production_problem(model, PRODUCTS, RESOURCES, CONSUMPTIONS)
 98        model.print_information()
 99        # Solve the model.
100        if model.solve():
101            print_production_solution(model, PRODUCTS)
102            # Save the CPLEX solution as "solution.json" program output
103            with get_environment().get_output_stream("solution.json") as fp:
104                model.solution.export(fp, "json")
105        else:
106            print("Problem has no solution")
107