Factory Planning 1

Model

import sasoptpy as so
import pandas as pd


def test(cas_conn):

    m = so.Model(name='factory_planning_1', session=cas_conn)

    # Input data
    product_list = ['prod{}'.format(i) for i in range(1, 8)]
    product_data = pd.DataFrame([10, 6, 8, 4, 11, 9, 3],
                                columns=['profit'], index=product_list)
    demand_data = [
        [500, 1000, 300, 300,  800, 200, 100],
        [600,  500, 200,   0,  400, 300, 150],
        [300,  600,   0,   0,  500, 400, 100],
        [200,  300, 400, 500,  200,   0, 100],
        [0,    100, 500, 100, 1000, 300,   0],
        [500,  500, 100, 300, 1100, 500,  60]]
    demand_data = pd.DataFrame(
        demand_data, columns=product_list, index=range(1, 7))
    machine_types_data = [
        ['grinder', 4],
        ['vdrill', 2],
        ['hdrill', 3],
        ['borer', 1],
        ['planer', 1]]
    machine_types_data = pd.DataFrame(machine_types_data, columns=[
        'machine_type', 'num_machines']).set_index(['machine_type'])
    machine_type_period_data = [
        ['grinder', 1, 1],
        ['hdrill',  2, 2],
        ['borer',   3, 1],
        ['vdrill',  4, 1],
        ['grinder', 5, 1],
        ['vdrill',  5, 1],
        ['planer',  6, 1],
        ['hdrill',  6, 1]]
    machine_type_period_data = pd.DataFrame(machine_type_period_data, columns=[
        'machine_type', 'period', 'num_down'])
    machine_type_product_data = [
        ['grinder', 0.5,  0.7,  0,    0,    0.3,  0.2, 0.5],
        ['vdrill',  0.1,  0.2,  0,    0.3,  0,    0.6, 0],
        ['hdrill',  0.2,  0,    0.8,  0,    0,    0,   0.6],
        ['borer',   0.05, 0.03, 0,    0.07, 0.1,  0,   0.08],
        ['planer',  0,    0,    0.01, 0,    0.05, 0,   0.05]]
    machine_type_product_data = \
        pd.DataFrame(machine_type_product_data, columns=['machine_type'] +
                     product_list).set_index(['machine_type'])
    store_ub = 100
    storage_cost_per_unit = 0.5
    final_storage = 50
    num_hours_per_period = 24 * 2 * 8

    # Problem definition
    PRODUCTS = product_list
    PERIODS = range(1, 7)
    MACHINE_TYPES = machine_types_data.index.values

    num_machine_per_period = pd.DataFrame()
    for i in range(1, 7):
        num_machine_per_period[i] = machine_types_data['num_machines']
    for _, row in machine_type_period_data.iterrows():
        num_machine_per_period.at[row['machine_type'],
                                  row['period']] -= row['num_down']

    make = m.add_variables(PRODUCTS, PERIODS, lb=0, name='make')
    sell = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=demand_data.transpose(),
                           name='sell')

    store = m.add_variables(PRODUCTS, PERIODS, lb=0, ub=store_ub, name='store')
    for p in PRODUCTS:
        store[p, 6].set_bounds(lb=final_storage, ub=final_storage+1)

    storageCost = storage_cost_per_unit * store.sum('*', '*')
    revenue = so.expr_sum(product_data.at[p, 'profit'] * sell[p, t]
                           for p in PRODUCTS for t in PERIODS)
    m.set_objective(revenue-storageCost, sense=so.MAX, name='total_profit')

    production_time = machine_type_product_data
    m.add_constraints((
        so.expr_sum(production_time.at[mc, p] * make[p, t] for p in PRODUCTS)
        <= num_hours_per_period * num_machine_per_period.at[mc, t]
        for mc in MACHINE_TYPES for t in PERIODS), name='machine_hours')
    m.add_constraints(((store[p, t-1] if t-1 in PERIODS else 0) + make[p, t] ==
                      sell[p, t] + store[p, t] for p in PRODUCTS
                      for t in PERIODS),
                      name='flow_balance')

    res = m.solve()
    if res is not None:
        print(so.get_solution_table(make, sell, store))

    return m.get_objective_value()

Output

In [1]: import os

In [2]: hostname = os.getenv('CASHOST')

In [3]: port = os.getenv('CASPORT')

In [4]: from swat import CAS

In [5]: cas_conn = CAS(hostname, port)

In [6]: import sasoptpy
In [7]: from examples.client_side.factory_planning_1 import test

In [8]: test(cas_conn)
NOTE: Initialized model factory_planning_1.
NOTE: Added action set 'optimization'.
NOTE: Converting model factory_planning_1 to OPTMODEL.
NOTE: Submitting OPTMODEL code to CAS server.
NOTE: Problem generation will use 8 threads.
NOTE: The problem has 126 variables (0 free, 6 fixed).
NOTE: The problem has 72 linear constraints (30 LE, 42 EQ, 0 GE, 0 range).
NOTE: The problem has 281 linear constraint coefficients.
NOTE: The problem has 0 nonlinear constraints (0 LE, 0 EQ, 0 GE, 0 range).
NOTE: The OPTMODEL presolver is disabled for linear problems.
NOTE: The LP presolver value AUTOMATIC is applied.
NOTE: The LP presolver time is 0.01 seconds.
NOTE: The LP presolver removed 60 variables and 46 constraints.
NOTE: The LP presolver removed 178 constraint coefficients.
NOTE: The presolved problem has 66 variables, 26 constraints, and 103 constraint coefficients.
NOTE: The LP solver is called.
NOTE: The Dual Simplex algorithm is used.
                              Objective
         Phase Iteration        Value         Time
          D 2          1    9.478510E+04         0
          P 2         21    9.371518E+04         0
NOTE: Optimal.
NOTE: Objective = 93715.178571.
NOTE: The Dual Simplex solve time is 0.01 seconds.
NOTE: The output table 'SOLUTION' in caslib 'CASUSER(casuser)' has 126 rows and 6 columns.
NOTE: The output table 'DUAL' in caslib 'CASUSER(casuser)' has 72 rows and 4 columns.
NOTE: The CAS table 'solutionSummary' in caslib 'CASUSER(casuser)' has 13 rows and 4 columns.
NOTE: The CAS table 'problemSummary' in caslib 'CASUSER(casuser)' has 18 rows and 4 columns.
                   make         sell  store
(prod1, 1)   500.000000   500.000000    0.0
(prod1, 2)   700.000000   600.000000  100.0
(prod1, 3)     0.000000   100.000000    0.0
(prod1, 4)   200.000000   200.000000    0.0
(prod1, 5)     0.000000     0.000000    0.0
(prod1, 6)   550.000000   500.000000   50.0
(prod2, 1)   888.571429   888.571429    0.0
(prod2, 2)   600.000000   500.000000  100.0
(prod2, 3)     0.000000   100.000000    0.0
(prod2, 4)   300.000000   300.000000    0.0
(prod2, 5)   100.000000   100.000000    0.0
(prod2, 6)   550.000000   500.000000   50.0
(prod3, 1)   382.500000   300.000000   82.5
(prod3, 2)   117.500000   200.000000    0.0
(prod3, 3)     0.000000     0.000000    0.0
(prod3, 4)   400.000000   400.000000    0.0
(prod3, 5)   600.000000   500.000000  100.0
(prod3, 6)     0.000000    50.000000   50.0
(prod4, 1)   300.000000   300.000000    0.0
(prod4, 2)     0.000000     0.000000    0.0
(prod4, 3)     0.000000     0.000000    0.0
(prod4, 4)   500.000000   500.000000    0.0
(prod4, 5)   100.000000   100.000000    0.0
(prod4, 6)   350.000000   300.000000   50.0
(prod5, 1)   800.000000   800.000000    0.0
(prod5, 2)   500.000000   400.000000  100.0
(prod5, 3)     0.000000   100.000000    0.0
(prod5, 4)   200.000000   200.000000    0.0
(prod5, 5)  1100.000000  1000.000000  100.0
(prod5, 6)     0.000000    50.000000   50.0
(prod6, 1)   200.000000   200.000000    0.0
(prod6, 2)   300.000000   300.000000    0.0
(prod6, 3)   400.000000   400.000000    0.0
(prod6, 4)     0.000000     0.000000    0.0
(prod6, 5)   300.000000   300.000000    0.0
(prod6, 6)   550.000000   500.000000   50.0
(prod7, 1)     0.000000     0.000000    0.0
(prod7, 2)   250.000000   150.000000  100.0
(prod7, 3)     0.000000   100.000000    0.0
(prod7, 4)   100.000000   100.000000    0.0
(prod7, 5)   100.000000     0.000000  100.0
(prod7, 6)     0.000000    50.000000   50.0
Out[8]: 93715.17857142858