Loading...
Searching...
No Matches
CutstockClass.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.IO;
6using GAMS;
7
8namespace Cutstock
9{
10 class Cutstock
11 {
12 #region private fields
13 private GAMSSet fWidths;
14 private GAMSParameter fRawWidth;
15 private GAMSParameter fDemand;
16 private GAMSParameter fWidth;
17 private GAMSParameter fPatRep;
18
19 private GAMSWorkspace fws;
20 private GAMSDatabase fCutstockData, fDbOut;
21
22 private GAMSOptions fopt;
23
24 private GAMSJob job;
25 #endregion
26
27 public Cutstock(GAMSWorkspace ws)
28 {
29 fws = ws;
30 fopt = ws.AddOptions();
31
32 fCutstockData = ws.AddDatabase(inModelName: "gdxincname");
33
34 fopt.SolveLink = GAMSOptions.ESolveLink.LoadLibrary;
35 fopt.Defines.Add("dbOut1", "dbOut1");
36
37 fWidths = fCutstockData.AddSet("i", "widths");
38 fRawWidth = fCutstockData.AddParameter("r", "raw width");
39 fDemand = fCutstockData.AddParameter("d", "demand", fWidths);
40 fWidth = fCutstockData.AddParameter("w", "width", fWidths);
41
42 job = ws.AddJobFromString(GetModelSource());
43 }
44
45 public void Run(TextWriter output = null)
46 {
47 if (!fCutstockData.CheckDomains())
48 throw new GAMSException("Domain Errors in Cutstock Database");
49 job.Run(fopt, null, output, false, fCutstockData);
50 fDbOut = fws.AddDatabaseFromGDX(fopt.Defines["dbOut1"] + ".gdx");
51 fPatRep = fDbOut.GetParameter("patrep");
52 }
53
54 #region Input Symbols
55 public GAMSSet Widths
56 { get { return fWidths; } }
57
58 public GAMSParameter RawWidth
59 { get { return fRawWidth; } }
60
61 public GAMSParameter Demand
62 { get { return fDemand; } }
63
64 public GAMSParameter Width
65 { get { return fWidth; } }
66 #endregion
67
68 #region Output Symbols
69 public GAMSParameter PatRep
70 { get { return fPatRep; } }
71 #endregion
72
73 public GAMSOptions Opt
74 { get { return fopt; } }
75
76 public string GetModelSource()
77 {
78 return @"
79$Title Cutting Stock - A Column Generation Approach (CUTSTOCK,SEQ=294)
80
81$ontext
82 The task is to cut out some paper products of different sizes from a
83 large raw paper roll, in order to meet a customer's order. The objective
84 is to minimize the required number of paper rolls.
85
86
87P. C. Gilmore and R. E. Gomory, A linear programming approach to the
88cutting stock problem, Part I, Operations Research 9 (1961), 849-859.
89
90P. C. Gilmore and R. E. Gomory, A linear programming approach to the
91cutting stock problem, Part II, Operations Research 11 (1963), 863-888.
92$offtext
93
94Set i widths
95Parameter
96 r raw width
97 w(i) width
98 d(i) demand ;
99
100$if not set gdxincname $abort 'no include file name for data file provided'
101$gdxin %gdxincname%
102$load r i w d
103$gdxin
104
105* Gilmore-Gomory column generation algorithm
106
107Set p possible patterns /p1*p1000/
108 pp(p) dynamic subset of p
109Parameter
110 aip(i,p) number of width i in pattern growing in p;
111
112
113* Master model
114Variable xp(p) patterns used
115 z objective variable
116Integer variable xp; xp.up(p) = sum(i, d(i));
117
118Equation numpat number of patterns used
119 demand(i) meet demand;
120
121numpat.. z =e= sum(pp, xp(pp));
122demand(i).. sum(pp, aip(i,pp)*xp(pp)) =g= d(i);
123
124model master /numpat, demand/;
125
126* Pricing problem - Knapsack model
127Variable y(i) new pattern;
128Integer variable y; y.up(i) = ceil(r/w(i));
129
130Equation defobj
131 knapsack knapsack constraint;
132
133defobj.. z =e= 1 - sum(i, demand.m(i)*y(i));
134knapsack.. sum(i, w(i)*y(i)) =l= r;
135
136model pricing /defobj, knapsack/;
137
138* Initialization - the initial patterns have a single width
139pp(p) = ord(p)<=card(i);
140aip(i,pp(p))$(ord(i)=ord(p)) = floor(r/w(i));
141*display aip;
142
143Scalar done loop indicator /0/
144Set pi(p) set of the last pattern; pi(p) = ord(p)=card(pp)+1;
145
146option optcr=0,limrow=0,limcol=0,solprint=off;
147
148While(not done and card(pp)<card(p),
149 solve master using rmip minimizing z;
150 solve pricing using mip minimizing z;
151
152* pattern that might improve the master model found?
153 if(z.l < -0.001,
154 aip(i,pi) = round(y.l(i));
155 pp(pi) = yes; pi(p) = pi(p-1);
156 else
157 done = 1;
158 );
159);
160display 'lower bound for number of rolls', master.objval;
161
162option solprint=on;
163solve master using mip minimizing z;
164
165Parameter patrep Solution pattern report
166 demrep Solution demand supply report;
167
168patrep('# produced',p) = round(xp.l(p));
169patrep(i,p)$patrep('# produced',p) = aip(i,p);
170patrep(i,'total') = sum(p, patrep(i,p));
171patrep('# produced','total') = sum(p, patrep('# produced',p));
172
173demrep(i,'produced') = sum(p,patrep(i,p)*patrep('# produced',p));
174demrep(i,'demand') = d(i);
175demrep(i,'over') = demrep(i,'produced') - demrep(i,'demand');
176
177display patrep, demrep;
178
179$if not set dbOut1 $abort 'no file name for out-database 1 file provided'
180execute_unload '%dbOut1%', patrep;
181";
182 }
183 }
184}
GAMSSet AddSet(string identifier, int dimension, string explanatoryText="", SetType setType=SetType.multi)
GAMSParameter GetParameter(string parameterIdentifier)
GAMSParameter AddParameter(string identifier, int dimension, string explanatoryText="")
void Run(GAMSOptions gamsOptions=null, GAMSCheckpoint checkpoint=null, TextWriter output=null, Boolean createOutDB=true)
Dictionary< string, string > Defines
GAMSJob AddJobFromString(string gamsSource, GAMSCheckpoint checkpoint=null, string jobName=null)
GAMSDatabase AddDatabaseFromGDX(string gdxFileName, string databaseName=null, string inModelName=null)
GAMSDatabase AddDatabase(string databaseName=null, string inModelName=null)
GAMSOptions AddOptions(GAMSOptions optFrom=null)