Loading...
Searching...
No Matches
cutstock.m
1function cutstock(varargin)
2
3 % check workspace info from arguments
4 if nargin > 0
5 wsInfo = gams.control.WorkspaceInfo();
6 wsInfo.systemDirectory = varargin{1};
7 ws = gams.control.Workspace(wsInfo);
8 else
9 ws = gams.control.Workspace();
10 end
11
12 % instantiate Options and define parameters
13 opt = ws.addOptions();
14 cutstockData = ws.addDatabase('csdata');
15 opt.setAllModelTypes('Cplex');
16 opt.optCR = 0; % Solve to optimality
17 maxpattern = 35;
18 opt.defines('pmax', sprintf('%d', maxpattern));
19 opt.defines('solveMasterAs', 'RMIP');
20
21 % define input data
22 d = containers.Map({'i1', 'i2', 'i3', 'i4'}, {97, 610, 395, 211});
23 w = containers.Map({'i1', 'i2', 'i3', 'i4'}, {45, 36, 31, 14});
24 r = 100;
25
26 widths = cutstockData.addSet('i', 1, 'widths');
27 rawWidth = cutstockData.addParameter('r', 0, 'raw width');
28 demand = cutstockData.addParameter('d', 1, 'demand');
29 width = cutstockData.addParameter('w', 1, 'width');
30
31 for key = keys(d)
32 widths.addRecord(key{1});
33 rec = demand.addRecord(key{1});
34 rec.value = d(key{1});
35 end
36 for key = keys(w)
37 rec = width.addRecord(key{1});
38 rec.value = w(key{1});
39 end
40 rec = rawWidth.addRecord();
41 rec.value = 100;
42
43 masterModel = {
44 '$Title Cutting Stock - Master problem '
45 ' '
46 'Set i widths '
47 'Parameter '
48 ' w(i) width '
49 ' d(i) demand '
50 'Scalar '
51 ' r raw width; '
52 '$gdxin csdata '
53 '$load i w d r '
54 ' '
55 '$if not set pmax $set pmax 1000 '
56 'Set p possible patterns /1*%pmax%/ '
57 ' pp(p) dynamic subset of p '
58 'Parameter '
59 ' aip(i,p) number of width i in pattern growing in p;'
60 ' '
61 '* Master model '
62 'Variable xp(p) patterns used '
63 ' z objective variable '
64 'Integer variable xp; xp.up(p) = sum(i, d(i)); '
65 ' '
66 'Equation numpat number of patterns used '
67 ' demand(i) meet demand; '
68 ' '
69 'numpat.. z =e= sum(pp, xp(pp)); '
70 'demand(i).. sum(pp, aip(i,pp)*xp(pp)) =g= d(i); '
71 ' '
72 'model master /numpat, demand/; '
73 ' '};
74 masterModel = sprintf('%s\n', masterModel{:});
75
76 subModel = {
77 '$Title Cutting Stock - Pricing problem is a knapsack model '
78 ' '
79 'Set i widths '
80 'Parameter '
81 ' w(i) width; '
82 'Scalar '
83 ' r raw width; '
84 ' '
85 '$gdxin csdata '
86 '$load i w r '
87 ' '
88 'Parameter '
89 ' demdual(i) duals of master demand constraint /#i eps/; '
90 ' '
91 'Variable z, y(i) new pattern; '
92 'Integer variable y; y.up(i) = ceil(r/w(i)); '
93 ' '
94 'Equation defobj '
95 ' knapsack; '
96 ' '
97 'defobj.. z =e= 1 - sum(i, demdual(i)*y(i)); '
98 'knapsack.. sum(i, w(i)*y(i)) =l= r; '
99 'model pricing /defobj, knapsack/; '
100 ' '};
101 subModel = sprintf('%s\n', subModel{:});
102
103 % create initial checkpoint
104 masterCP = ws.addCheckpoint();
105 masterInitJob = ws.addJobFromString(masterModel);
106 masterInitJob.run(opt, masterCP, cutstockData);
107
108 masterJob = ws.addJobFromString('execute_load ''csdata'', aip, pp; solve master min z using %solveMasterAs%;', masterCP);
109
110 pattern = cutstockData.addSet('pp', 1, 'pattern index');
111 patternData = cutstockData.addParameter('aip', 2, 'pattern data');
112
113 % Initial pattern: pattern i hold width i
114 patternCount = 0;
115 for key = keys(w)
116 patternCount = patternCount + 1;
117 patternCount_str = sprintf('%d', patternCount);
118 pattern.addRecord(patternCount_str);
119 rec = patternData.addRecord(key{1}, patternCount_str);
120 rec.value = floor(r / w(key{1}));
121 end
122
123 % create model instance for sub job
124 subCP = ws.addCheckpoint();
125 ws.addJobFromString(subModel).run(opt, subCP, cutstockData);
126
127 subMI = subCP.addModelInstance();
128
129 % define modifier demdual
130 demandDual = subMI.syncDB.addParameter('demdual', 1, 'dual of demand from master');
131 subMI.instantiate('pricing min z using mip', opt, gams.control.Modifier(demandDual));
132
133 % find new pattern
134 patternAdded = true;
135 while patternAdded
136 masterJob.run(opt, masterCP, cutstockData);
137
138 % Copy duals into gmssubMI.syncDB DB
139 demandDual.clear();
140 for d = masterJob.outDB.getEquation('demand').records
141 rec = demandDual.addRecord(d{1}.key(1));
142 rec.value = d{1}.marginal;
143 end
144
145 subMI.solve();
146
147 z_level = subMI.syncDB.getVariable('z').record.level;
148 if z_level < -0.00001
149 if patternCount == maxpattern
150 fprintf('Out of pattern. Increase maxpattern (currently [%d])\n', maxpattern);
151 patternAdded = false;
152 else
153 fprintf('New pattern Value: %g\n', z_level);
154 patternCount = patternCount + 1;
155 s = pattern.addRecord(sprintf('%d', patternCount));
156 for y = subMI.syncDB.getVariable('y').records
157 if y{1}.level > 0.5
158 rec = patternData.addRecord(y{1}.key(1), s.key(1));
159 rec.value = round(y{1}.level);
160 end
161 end
162 end
163 else
164 patternAdded = false;
165 end
166 end
167
168 % solve final MIP
169 opt.defines("solveMasterAs", "MIP");
170 masterJob.run(opt, cutstockData);
171
172 fprintf("Optimal Solution: %g\n", masterJob.outDB.getVariable("z").record.level);
173 for xp = masterJob.outDB.getVariable("xp").records
174 if xp{1}.level > 0.5
175 fprintf(" pattern [%s] [%g] times: ", xp{1}.key(1), xp{1}.level);
176 for aip = masterJob.outDB.getParameter("aip").records
177 fprintf(" [%s] : [%g]\n", aip{1}.key(1), aip{1}.value);
178 end
179 fprintf("\n");
180 end
181 end
182
183 % clean up of unmanaged resources
184 cutstockData.dispose();
185 subMI.dispose();
186 opt.dispose();
187end