12from gams
import GamsModifier, GamsWorkspace
14GAMS_MASTER_MODEL =
"""
28$
if not set pmax $set pmax 1000
30 p
'possible patterns' / 1*%pmax% /
31 pp(p)
'dynamic subset of p';
34 aip(i,p)
'number of width i in pattern growing in p';
38 z
'objective variable';
41xp.up(p) = sum(i,
d(i));
47 numpat.. z =e= sum(pp, xp(pp));
49 demand(i).. sum(pp,
aip(i,pp)*xp(pp)) =g=
d(i);
51Model master / numpat, demand /;
57Parameter
w(i)
'width';
65 demdual(i)
'duals of master demand constraint' /
71y.up(i) = ceil(r/
w(i));
77defobj.. z =e= 1 - sum(i, demdual(i)*y(i));
79knapsack.. sum(i,
w(i)*y(i)) =l= r;
81Model pricing / defobj, knapsack /;
84if __name__ == "__main__":
85 sys_dir = sys.argv[1] if len(sys.argv) > 1
else None
86 ws = GamsWorkspace(system_directory=sys_dir)
88 opt = ws.add_options()
89 cutstock_data = ws.add_database(
"csdata")
90 opt.all_model_types =
"Cplex"
94 opt.defines[
"pmax"] = str(max_pattern)
95 opt.defines[
"solveMasterAs"] =
"RMIP"
98 raw_width = cutstock_data.add_parameter(
"r", 0,
"raw width")
99 raw_width.add_record().value = 100
101 d = {
"i1": 97,
"i2": 610,
"i3": 395,
"i4": 211}
102 demand = cutstock_data.add_parameter(
"d", 1,
"demand")
103 widths = cutstock_data.add_set(
"i", 1,
"widths")
104 for k, v
in d.items():
106 demand.add_record(k).value = v
108 w = {
"i1": 47,
"i2": 36,
"i3": 31,
"i4": 14}
109 width = cutstock_data.add_parameter(
"w", 1,
"width")
110 for k, v
in w.items():
111 width.add_record(k).value = v
113 cp_master = ws.add_checkpoint()
114 job_master_init = ws.add_job_from_string(GAMS_MASTER_MODEL)
115 job_master_init.run(opt, cp_master, databases=cutstock_data)
116 job_master = ws.add_job_from_string(
117 "execute_load 'csdata', aip, pp; solve master min z using %solveMasterAs%;",
121 pattern = cutstock_data.add_set(
"pp", 1,
"pattern index")
122 pattern_data = cutstock_data.add_parameter(
"aip", 2,
"pattern data")
126 for k, v
in w.items():
128 pattern_data.add_record(
129 (k, pattern.add_record(str(pattern_count)).key(0))
130 ).value = (int)(r / v)
132 cp_sub = ws.add_checkpoint()
133 job_sub = ws.add_job_from_string(GAMS_SUB_MODEL)
134 job_sub.run(opt, cp_sub, databases=cutstock_data)
135 mi_sub = cp_sub.add_modelinstance()
138 demand_dual = mi_sub.sync_db.add_parameter(
139 "demdual", 1,
"dual of demand from master"
141 mi_sub.instantiate(
"pricing min z using mip", GamsModifier(demand_dual), opt)
145 job_master.run(opt, cp_master, databases=cutstock_data)
148 for dem
in job_master.out_db[
"demand"]:
149 demand_dual.add_record(dem.key(0)).value = dem.marginal
151 if mi_sub.sync_db[
"z"].first_record().level < -0.00001:
152 if pattern_count == max_pattern:
154 f
"Out of pattern. Increase max_pattern (currently {max_pattern})."
158 print(f
"New pattern! Value: {mi_sub.sync_db['z'].first_record().level}")
160 s = pattern.add_record(str(pattern_count))
161 for y
in mi_sub.sync_db[
"y"]:
163 pattern_data.add_record((y.key(0), s.key(0))).value = round(
170 opt.defines[
"solveMasterAs"] =
"MIP"
171 job_master.run(opt, databases=cutstock_data)
172 print(f
"Optimal Solution: {job_master.out_db['z'].first_record().level}")
173 for xp
in job_master.out_db[
"xp"]:
175 print(f
" pattern {xp.key(0)} {xp.level} times:")
176 aip = job_master.out_db[
"aip"].first_record((
" ", xp.key(0)))
178 print(f
" {aip.key(0)}: {aip.value}")
179 if not aip.move_next():