File: SpongeRollProblem4.py

package info (click to toggle)
python-pulp 1.6.0%2Bdfsg1-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 14,596 kB
  • sloc: python: 6,006; sh: 12; makefile: 5
file content (137 lines) | stat: -rw-r--r-- 4,688 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""
The Full Sponge Roll Problem using Classes for the PuLP Modeller

Authors: Antony Phillips, Dr Stuart Mitchell    2007
"""

def calculatePatterns(totalRollLength,lenOpts,head):
    """
     Recursively calculates the list of options lists for a cutting stock problem. The input
     'tlist' is a pointer, and will be the output of the function call.

     The inputs are:
     totalRollLength - the length of the roll
     lenOpts - a list of the sizes of remaining cutting options
     head - the current list that has been passed down though the recusion

     Returns the list of patterns

     Authors: Bojan Blazevic, Dr Stuart Mitchell    2007
    """
    if lenOpts:
        patterns =[]
        #take the first option off lenOpts
        opt = lenOpts[0]
        for rep in range(int(totalRollLength/opt)+1):
            #reduce the length
            l = totalRollLength - rep*opt
            h = head[:]
            h.append(rep)

            patterns.extend(calculatePatterns(l, lenOpts[1:], h))
    else:
        #end of the recursion
        patterns = [head]
    return patterns

def makePatterns(totalRollLength,lenOpts):
    """
     Makes the different cutting patterns for a cutting stock problem.

     The inputs are:
     totalRollLength : the length of the roll
     lenOpts: a list of the sizes of cutting options as strings

     Authors: Antony Phillips, Dr Stuart Mitchell    2007
    """

    # calculatePatterns is called to create a list of the feasible cutting options in 'tlist'
    patternslist = calculatePatterns(totalRollLength,lenOpts,[])

    # The list 'PatternNames' is created
    PatternNames = []
    for i in range(len(patternslist)):
        PatternNames += ["P"+str(i)]

    #Patterns = [0 for i in range(len(PatternNames))]
    Patterns = []

    for i,j in enumerate(PatternNames):
        Patterns += [Pattern(j, patternslist[i])]

    # The different cutting lengths are printed, and the number of each roll of that length in each
    # pattern is printed below. This is so the user can see what each pattern contains.
    print("Lens: %s" %lenOpts)
    for i in Patterns:
        print(i, " = %s"%[i.lengthsdict[j] for j in lenOpts])

    return Patterns


class Pattern:
    """
    Information on a specific pattern in the SpongeRoll Problem
    """
    cost = 1
    trimValue = 0.04
    totalRollLength = 20
    lenOpts = [5, 7, 9]

    def __init__(self,name,lengths = None):
        self.name = name
        self.lengthsdict = dict(zip(self.lenOpts,lengths))

    def __str__(self):
        return self.name

    def trim(self):
        return Pattern.totalRollLength - sum([int(i)*self.lengthsdict[i] for i in self.lengthsdict])


# Import PuLP modeler functions
from pulp import *

rollData = {#Length Demand SalePrice
              5:   [150,   0.25],
              7:   [200,   0.33],
              9:   [300,   0.40]}

# The pattern names and the patterns are created as lists, and the associated trim with each pattern
# is created as a dictionary. The inputs are the total roll length and the list (as integers) of
# cutting options.
Patterns = makePatterns(Pattern.totalRollLength,Pattern.lenOpts)

# The rollData is made into separate dictionaries
(rollDemand,surplusPrice) = splitDict(rollData)

# The variable 'prob' is created
prob = LpProblem("Cutting Stock Problem",LpMinimize)

# The problem variables of the number of each pattern to make are created
pattVars = LpVariable.dicts("Patt",Patterns,0,None,LpInteger)

# The problem variables of the number of surplus rolls for each length are created
surplusVars = LpVariable.dicts("Surp",Pattern.lenOpts,0,None,LpInteger)

# The objective function is entered: (the total number of large rolls used * the cost of each) - (the value of the surplus stock) - (the value of the trim)
prob += lpSum([pattVars[i]*Pattern.cost for i in Patterns]) - lpSum([surplusVars[i]*surplusPrice[i] for i in Pattern.lenOpts]) - lpSum([pattVars[i]*i.trim()*Pattern.trimValue for i in Patterns]),"Net Production Cost"

# The demand minimum constraint is entered
for j in Pattern.lenOpts:
    prob += lpSum([pattVars[i]*i.lengthsdict[j] for i in Patterns]) - surplusVars[j] >= rollDemand[j],"Ensuring enough %s cm rolls"%j

# The problem data is written to an .lp file
prob.writeLP("SpongeRollProblem.lp")

# The problem is solved
prob.solve()

# The status of the solution is printed to the screen
print("Status:", LpStatus[prob.status])

# Each of the variables is printed with it's resolved optimum value
for v in prob.variables():
    print(v.name, "=", v.varValue)

# The optimised objective function value is printed to the screen
print("Production Costs = ", value(prob.objective))