3 % check workspace info from arguments
5 wsInfo = gams.control.WorkspaceInfo();
6 wsInfo.systemDirectory = varargin{1};
7 ws = gams.control.Workspace(wsInfo);
9 ws = gams.control.Workspace();
13 '$Title Traveling Salesman Problem '
16 'The sub_tour elimination constraints are generated by a Python '
17 'script. The MIP is solved over and over, but GAMS have to '
18 'generate the model only after n cuts have been added. '
22 '$if not set tspdata $abort ''tspdata not set'' '
25 ' i(ii) subset of cities '
26 'alias (ii,jj),(i,j,k); '
28 'parameter c(ii,jj) distance matrix; '
33 '$if not set nrCities $set nrCities 20 '
34 'i(ii)$(ord(ii) < %nrCities%) = yes; '
36 'variables x(ii,jj) decision variables - leg of trip '
37 ' z objective variable; '
38 'binary variable x; x.fx(ii,ii) = 0; '
40 'equations objective total cost '
41 ' rowsum(ii) leave each city only once '
42 ' colsum(jj) arrive at each city only once; '
44 '* the assignment problem is a relaxation of the TSP '
45 'objective.. z =e= sum((i,j), c(i,j)*x(i,j)); '
46 'rowsum(i).. sum(j, x(i,j)) =e= 1; '
47 'colsum(j).. sum(i, x(i,j)) =e= 1; '
49 '$if not set cmax $set cmax 2 '
50 'set cut /c0*c%cmax%/; '
52 ' acut(cut,ii,jj) cut constraint matrix '
53 ' rhscut(cut) cut constraint rhs; '
55 'equation sscut(cut) sub_tour elimination cut; '
56 'sscut(cut).. sum((i,j), Acut(cut,i,j)*x(i,j)) =l= RHScut(cut); '
58 'set cc(cut) previous cuts; cc(cut) = no; '
59 '$if set cutdata execute_load ''%cutdata%'', cc, Acut, RHScut; '
61 'Acut(cut,i,j)$(not cc(cut)) = eps; '
62 'RHScut(cut)$(not cc(cut)) = card(ii); '
64 'model assign /all/; '
67 model = sprintf(
'%s\n', model{:});
69 % number of cuts that can be added to a model instance
73 % cut limit
for current model instance (cmax = curCut + cutsPerRound)
76 % database used to collect all generated cuts
77 cutData = ws.addDatabase();
78 cc = cutData.addSet(
'cc', 1,
'');
79 acut = cutData.addParameter(
'acut', 3,
'');
80 rhscut = cutData.addParameter(
'rhscut', 1,
'');
82 % list of cities (i1, i2, i3, ...)
87 % create a
new model instance when the cut limit is reached
90 cMax = curCut + cutsPerRound;
93 % create the checkpoint
94 tspJob = ws.addJobFromString(model);
95 cp = ws.addCheckpoint();
96 opt = ws.addOptions();
97 opt.defines(
'nrcities',
'20');
98 opt.defines(
'cmax', int2str(cMax - 1));
99 opt.defines(
'cutdata', cutData.name);
101 % read input data from
'tsp.gdx'
102 opt.defines(
'tspdata', [
'"', fullfile(ws.systemDirectory,
'apifiles',
'Data',
'tsp.gdx'),
'"']);
105 % fill the n list only once
107 for i = tspJob.outDB.getSet(
'i').records
108 n{end+1} = i{1}.key(1);
112 % instantiate the model instance with modifiers miAcut and miRhscut
113 mi = cp.addModelInstance();
114 miAcut = mi.syncDB.addParameter(
'acut', 3,
'');
115 miRhscut = mi.syncDB.addParameter(
'rhscut', 1,
'');
116 modifiers = {gams.control.Modifier(miAcut), gams.control.Modifier(miRhscut)};
117 mi.instantiate(
'assign use mip min z', modifiers);
122 % solve model instance
using update type accumulate and clear acut and rhscut afterwards
123 mi.solve(gams.control.globals.SymbolUpdateType.ACCUMULATE);
124 mi.syncDB.getParameter(
'acut').clear();
125 mi.syncDB.getParameter(
'rhscut').clear();
127 % collect graph information from the solution
128 graph = containers.Map();
132 if mi.syncDB.getVariable(
'x').findRecord({i{1},j{1}}).level > 0.5
138 % find all subtours and add the required cuts by modifying acut and rhscut
139 while numel(notVisited) ~= 0
142 while ~strcmp(graph(ii), notVisited{1})
147 for i = numel(notVisited):-1:1
148 for j = 1:numel(subTour)
149 if strcmp(notVisited{i}, subTour{j})
156 % add the cuts to both databases (cutData, mi.SyncDB)
159 keys = {['c', int2str(curCut)], i{1}, j{1}};
160 rec = acut.addRecord(keys);
162 rec = miAcut.addRecord(keys);
167 key = ['c', int2str(curCut)];
168 rec = rhscut.addRecord(key);
169 rec.value = numel(subTour) - 0.5;
170 rec = miRhscut.addRecord(key);
171 rec.value = numel(subTour) - 0.5;
176 if numel(subTour) >= numel(n)
181 fprintf(
'\nz=%g\n', mi.syncDB.getVariable(
'z').record.level);
182 fprintf(
'sub_tour: ');
184 fprintf(
'%s -> ', i{1});
186 fprintf(
'%s\n', subTour{1});