FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Coco: The Coco productional planning problem

Description
The company Coco has two plants that can produce two types of cocoa powder. The plant capacities are limited. It is possible to store raw materials and finished product from one time period to the next. Raw material prices, sales revenues, and the maximum amount that may be sold depend on the time period. Raw material storage capacity is limited. Storing product between time periods incurs storage costs. Some product is held in stock at the beginning of the planning period. The objective function of maximizing the total profit is to maximize the sales revenues, minus the cost of production, buying raw material, and storing finished products and raw material.

Further explanation of this example: 'Xpress Python Reference Manual'

coco_python.zip[download all files]

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
coco.py[download]





coco.py

'''*******************************************************
  * Python Example Problems                             *
  *                                                     *
  * file coco.py                                        *
  * Example for the use of the Python language          *
  * (Complete Coco Problem.                             *
  *  Specify phase by PHASE parameter.                  *
  *  Data input in the model, not via data files.)      *
  *                                                     *
  * (c) 2018-2024 Fair Isaac Corporation                *
  *******************************************************'''

from __future__ import print_function
import xpress as xp

PHASE = 5

'''* Phase = 3: Multi-period parameterised model; mines always open
   * Phase = 4: Mines may open/closed freely; when closed save 20000 per month
   * Phase = 5: Once closed always closed; larger saving
'''

NT = 4       # Number of time periods
RP = [0, 1]  # Range of products (p)
RF = [0, 1]  # Range of factories (f)
RR = [0, 1]  # Range of raw materials (r)

RT = [i for i in range(NT)]  # time periods (t)

CPSTOCK = 2.0    # Unit cost to store any product p
CRSTOCK = 1.0    # Unit cost to store any raw mat. r
MXRSTOCK = 300   # Max. amount of r that can be stored each f and t

Post = [i for i in range(0, NT+1)]

prob = xp.problem()

# Amount of product p made at factory f
make = prob.addVariables(RP, RF, RT, name='make')

# Amount of product p sold from factory f in period t
sell = prob.addVariables(RP, RF, RT, name='sell')

# Amount of raw material r bought for factory f in period t
buy = prob.addVariables(RR, RF, RT, name='buy')

# Stock level of product p at factory f at start of period t
pstock = prob.addVariables(RP, RF, Post, name='pst')

# Stock level of raw material r at factory f at start of period t
rstock = prob.addVariables(RR, RF, Post, name='rst')

# 1 if factory f is open in period t, else 0
openm = prob.addVariables(RF, RT, name='openm', vartype=xp.binary)

REV = [[400, 380, 405, 350],
       [410, 397, 412, 397]]
CMAKE = [[150, 153],
         [75,  68]]
CBUY = [[100,  98,  97, 100],
        [200, 195, 198, 200]]
COPEN = [50000, 63000]
REQ = [[1.0, 0.5],
       [1.3, 0.4]]
MXSELL = [[650, 600, 500, 400],
          [600, 500, 300, 250]]
MXMAKE = [400, 500]
PSTOCK0 = [[50, 100],
           [50,  50]]
RSTOCK0 = [[100, 150],
           [50, 100]]

# Objective: maximize total profit
MaxProfit = (
    xp.Sum(REV[p][t] * sell[p, f, t] for p in RP
           for f in RF for t in RT) -              # revenue
    xp.Sum(CMAKE[p][f] * make[p, f, t] for p in RP
           for f in RF for t in RT) -            # prod. cost
    xp.Sum(CBUY[r][t] * buy[r, f, t] for r in RR
           for f in RF for t in RT) -              # raw mat. cost
    xp.Sum(CPSTOCK * pstock[p, f, t] for p in RP
           for f in RF for t in range(1, NT+1)) -  # p stor. cost
    xp.Sum(CRSTOCK * rstock[r, f, t] for r in RR
           for f in RF for t in range(1, NT+1)))   # r stor. cost

if PHASE == 4:                 # Factory fixed cost
    MaxProfit -= xp.Sum((COPEN[f] - 20000) * openm[f, t]
                        for f in RF for t in RT)
elif PHASE == 5:
    MaxProfit -= xp.Sum(COPEN[f] * openm[f, t] for f in RF for t in RT)

prob.setObjective(MaxProfit, sense=xp.maximize)

# Product stock balance
prob.addConstraint(pstock[p, f, t+1] == pstock[p, f, t]
                   + make[p, f, t] - sell[p, f, t]
                   for p in RP for f in RF for t in RT)

# Raw material stock balance
prob.addConstraint(rstock[r, f, t+1] == rstock[r, f, t] + buy[r, f, t] -
                   xp.Sum(REQ[p][r]*make[p, f, t] for p in RP)
                   for r in RR for f in RF for t in RT)

# Capacity limit at factory f
prob.addConstraint(xp.Sum(make[p, f, t] for p in RP) <= MXMAKE[f] * openm[f, t]
                   for f in RF for t in RT)

# Limit on the amount of prod. p to be sold
prob.addConstraint(xp.Sum(sell[p, f, t] for f in RF) <= MXSELL[p][t]
                   for p in RP for t in RT)

# Raw material stock limit
prob.addConstraint(xp.Sum(rstock[r, f, t] for r in RR) <= MXRSTOCK
                   for f in RF for t in range(NT))

if PHASE == 5:                 # Once closed, always closed
    prob.addConstraint(openm[f, t+1] <= openm[f, t]
                       for f in RF for t in range(NT - 1))

# Initial product levels
prob.addConstraint(pstock[p, f, 1] == PSTOCK0[p][f] for p in RP for f in RF)
# Initial raw material levels
prob.addConstraint(rstock[r, f, 1] == RSTOCK0[r][f] for r in RR for f in RF)

if PHASE < 4:
    prob.addConstraint(openm[f, t] == 1 for f in RF for t in RT)

prob.optimize()  # Solve the LP or MIP-problem

# Print out the solution
print("Solution:\n Objective: ", prob. getObjVal())

hline = 60*"-"

print("Total profit: ", prob.getObjVal())
print(hline)
print(8*" ", "Period", end='')
for t in range(NT+1):
    print("{:8}".format(t), end='')
print("\n", hline)
print("Finished products\n",
      "=================")

for f in RF:
    print(" Factory", f)
    for p in RP:
        print(3*" ", "P", p, ":  Prod", 12*" ", end='', sep='')
        for t in RT:
            print("{:8.2f}".format(prob.getSolution(make[p, f, t])), end='')
        print('')
        print(8*" ", "Sell", 12*" ", end='', sep='')
        for t in RT:
            print("{:8.2f}".format(prob.getSolution(sell[p, f, t])), end='')
        print('')
        print(7*" ", "(Stock)", end='')
        for t in range(NT+1):
            print("  (", "{:4.1f}".format(prob.getSolution(pstock[p, f, t])),
                  ")", end='', sep='')
        print('')

print(hline)
print("Raw material\n",
      "============")
for f in RF:
    print(" Factory", f)
    for r in RR:
        print(3*" ", "R", r, ":  Buy", 12*" ", end='', sep='')
        for t in RT:
            print("{:8.2f}".format(prob.getSolution(buy[r, f, t])), end='')
        print('')
        print(8*" ", "Use", 12*" ", end='', sep='')
        for t in RT:
            print("{:8.2f}".format(sum(REQ[p][r] *
                                       prob.getSolution(make[p, f, t])
                                       for p in RP)), end='')
        print('')
        print(7*" ", "(Stock)", end='')
        for t in range(NT+1):
            print(" (", "{:4.1f}".format(prob.getSolution(rstock[r, f, t])),
                  ")", end='', sep='')
        print('')

print(hline)

Back to examples browserPrevious exampleNext example