Building steel coils

This tutorial includes everything you need to set up decision optimization engines, build constraint programming models.

When you finish this tutorial, you'll have a foundational knowledge of Prescriptive Analytics.

This notebook is part of Prescriptive Analytics for Python

It requires either an installation of CPLEX Optimizers or it can be run on IBM Watson Studio Cloud (Sign up for a free IBM Cloud account and you can start using Watson Studio Cloud right away).

Table of contents:


Describe the business problem

  • The problem is to build steel coils from slabs that are available in a work-in-process inventory of semi-finished products. There is no limitation in the number of slabs that can be requested, but only a finite number of slab sizes is available (sizes 11, 13, 16, 17, 19, 20, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 40, 43, 45).
  • The problem is to select a number of slabs to build the coil orders, and to satisfy the following constraints:
    • A coil order can be built from only one slab.
    • Each coil order requires a specific process to build it from a slab. This process is encoded by a color.
    • Several coil orders can be built from the same slab. But a slab can be used to produce at most two different "colors" of coils.
    • The sum of the sizes of each coil order built from a slab must not exceed the slab size.
  • Finally, the production plan should minimize the unused capacity of the selected slabs.
  • This problem is based on "prob038: Steel mill slab design problem" from CSPLib (www.csplib.org). It is a simplification of an industrial problem described in J. R. Kalagnanam, M. W. Dawande, M. Trumbo, H. S. Lee. "Inventory Matching Problems in the Steel Industry," IBM Research Report RC 21171, 1998.

  • Please refer to documentation for appropriate setup of solving configuration.


How decision optimization can help

  • Prescriptive analytics technology recommends actions based on desired outcomes, taking into account specific scenarios, resources, and knowledge of past and current events. This insight can help your organization make better decisions and have greater control of business outcomes.

  • Prescriptive analytics is the next step on the path to insight-based actions. It creates value through synergy with predictive analytics, which analyzes data to predict future outcomes.

  • Prescriptive analytics takes that insight to the next level by suggesting the optimal way to handle that future situation. Organizations that can act fast in dynamic conditions and make superior decisions in uncertain environments gain a strong competitive advantage.

  • For example:

    • Automate complex decisions and trade-offs to better manage limited resources.
    • Take advantage of a future opportunity or mitigate a future risk.
    • Proactively update recommendations based on changing events.
    • Meet operational goals, increase customer loyalty, prevent threats and fraud, and optimize business processes.

Use decision optimization

Step 1: Download the library

Run the following code to install Decision Optimization CPLEX Modeling library. The DOcplex library contains the two modeling packages, Mathematical Programming and Constraint Programming, referred to earlier.


In [ ]:
import sys
try:
    import docplex.cp
except:
    if hasattr(sys, 'real_prefix'):
        #we are in a virtual env.
        !pip install docplex
    else:
        !pip install --user docplex

Note that the more global package docplex contains another subpackage docplex.mp that is dedicated to Mathematical Programming, another branch of optimization.

Step 2: Model the data


In [ ]:
from docplex.cp.model import *

Set model parameter


In [ ]:
from collections import namedtuple

##############################################################################
# Model configuration
##############################################################################

# The number of coils to produce
TUPLE_ORDER = namedtuple("TUPLE_ORDER", ["index", "weight", "color"])
orders = [ TUPLE_ORDER(1, 22, 5),
           TUPLE_ORDER(2,  9, 3),
           TUPLE_ORDER(3,  9, 4),
           TUPLE_ORDER(4,  8, 5),
           TUPLE_ORDER(5,  8, 7),
           TUPLE_ORDER(6,  6, 3),
           TUPLE_ORDER(7,  5, 6),
           TUPLE_ORDER(8,  3, 0),
           TUPLE_ORDER(9,  3, 2),
           TUPLE_ORDER(10, 3, 3),
           TUPLE_ORDER(11, 2, 1),
           TUPLE_ORDER(12, 2, 5)
           ]

NB_SLABS = 12
MAX_COLOR_PER_SLAB = 2

# The total number of slabs available.  In theory this can be unlimited,
# but we impose a reasonable upper bound in order to produce a practical
# optimization model.

# The different slab weights available.
slab_weights = [ 0, 11, 13, 16, 17, 19, 20, 23, 24, 25,
                 26, 27, 28, 29, 30, 33, 34, 40, 43, 45 ]

In [ ]:
nb_orders = len(orders)
slabs = range(NB_SLABS)
allcolors = set([ o.color for o in orders ])

# CPO needs lists for pack constraint
order_weights = [ o.weight for o in orders ]

# The heaviest slab
max_slab_weight = max(slab_weights)

# The amount of loss incurred for different amounts of slab use
# The loss will depend on how much less steel is used than the slab
# just large enough to produce the coils.
loss = [ min([sw-use for sw in slab_weights if sw >= use]) for use in range(max_slab_weight+1)]

Step 3: Set up the prescriptive model

Create CPO model


In [ ]:
mdl = CpoModel(name="trucks")

Define the decision variables


In [ ]:
# Which slab is used to produce each coil
production_slab = integer_var_dict(orders, 0, NB_SLABS-1, "production_slab")

# How much of each slab is used
slab_use = integer_var_list(NB_SLABS, 0, max_slab_weight, "slab_use")

Express the business constraints


In [ ]:
# The total loss is
total_loss = sum([element(slab_use[s], loss) for s in slabs])

# The orders are allocated to the slabs with capacity
mdl.add(pack(slab_use, [production_slab[o] for o in orders], order_weights))

# At most MAX_COLOR_PER_SLAB colors per slab
for s in slabs:
   su = 0
   for c in allcolors:
       lo = False
       for o in orders:
           if o.color==c:
               lo = (production_slab[o] == s) | lo
       su += lo
   mdl.add(su <= MAX_COLOR_PER_SLAB)

Express the objective


In [ ]:
# Add minimization objective
mdl.add(minimize(total_loss))

Solve the model


In [ ]:
print("\nSolving model....")
# Search strategy
mdl.set_search_phases([search_phase([production_slab[o] for o in orders])])

msol = mdl.solve(FailLimit=100000, TimeLimit=10)

Step 4: Investigate the solution and then run an example analysis


In [ ]:
# Print solution
if msol:
    print("Solution: ")
    from_slabs = [set([o.index for o in orders if msol[production_slab[o]]== s])for s in slabs]
    slab_colors = [set([o.color for o in orders if o.index in from_slabs[s]])for s in slabs]
    for s in slabs:
        if len(from_slabs[s]) > 0:
            print("Slab = " + str(s))
            print("\tLoss = " + str(loss[msol[slab_use[s]]]))
            print("\tcolors = " + str(slab_colors[s]))
            print("\tOrders = " + str(from_slabs[s]) + "\n")
else:
    print("No solution found")

Summary

You learned how to set up and use the IBM Decision Optimization CPLEX Modeling for Python to formulate and solve a Constraint Programming model.

References

Copyright © 2017, 2018 IBM. IPLA licensed Sample Materials.