13from itertools
import product
16from gams
import GamsWorkspace, GamsModifier, SymbolUpdateType
19$if not set tspdata $abort 'tspdata not set'
23 i(ii) 'subset of cities';
25Alias (ii,jj), (i,j,k);
27Parameter c(ii,jj) 'distance matrix';
33$if not set nrCities $set nrCities 20
34i(ii)$(ord(ii) < %nrCities%) = yes;
37 x(ii,jj) 'decision variables - leg of trip'
38 z 'objective variable';
44 objective 'total cost'
45 rowsum(ii) 'leave each city only once'
46 colsum(jj) 'arrive at each city only once';
48* the assignment problem is a relaxation of the TSP
49objective.. z =e= sum((i,j), c(i,j)*x(i,j));
51rowsum(i).. sum(j, x(i,j)) =e= 1;
53colsum(j).. sum(i, x(i,j)) =e= 1;
55$if not set cmax $set cmax 2
59 acut(cut,ii,jj) 'cut constraint matrix'
60 rhscut(cut) 'cut constraint rhs';
62Equation sscut(cut) 'sub_tour elimination cut';
63sscut(cut).. sum((i,j), acut(cut,i,j)*x(i,j)) =l= rhscut(cut);
65set cc(cut) 'previous cuts';
68$if set cutdata execute_load '%cutdata%', cc, acut, rhscut;
70acut(cut,i,j)$(not cc(cut)) = eps;
72rhscut(cut)$(not cc(cut)) = card(ii);
79if __name__ ==
"__main__":
80 sys_dir = sys.argv[1]
if len(sys.argv) > 1
else None
81 work_dir = sys.argv[2]
if len(sys.argv) > 2
else None
82 ws = GamsWorkspace(system_directory=sys_dir, working_directory=work_dir)
94 cut_data = ws.add_database()
95 cc = cut_data.add_set(
"cc", 1)
96 acut = cut_data.add_parameter(
"acut", 3)
97 rhscut = cut_data.add_parameter(
"rhscut", 1)
103 cmax = cur_cut + cuts_per_round
107 job = ws.add_job_from_string(GAMS_MODEL)
108 cp = ws.add_checkpoint()
109 opt = ws.add_options()
110 opt.defines[
"nrcities"] =
"20"
111 opt.defines[
"cmax"] = str(cmax - 1)
112 opt.defines[
"cutdata"] = cut_data.name
113 opt.defines[
"tspdata"] = (
115 + os.path.join(ws.system_directory,
"apifiles",
"Data",
"tsp.gdx")
118 job.run(gams_options=opt, checkpoint=cp)
122 for i
in job.out_db[
"i"]:
126 mi = cp.add_modelinstance()
127 mi_acut = mi.sync_db.add_parameter(
"acut", 3)
128 mi_rhscut = mi.sync_db.add_parameter(
"rhscut", 1)
130 "assign use mip min z", [GamsModifier(mi_acut), GamsModifier(mi_rhscut)]
134 mi.solve(SymbolUpdateType.Accumulate)
135 mi.sync_db[
"acut"].clear()
136 mi.sync_db[
"rhscut"].clear()
140 for i, j
in product(n, n):
141 if mi.sync_db[
"x"].find_record([i, j]).level > 0.5:
145 not_visited = list(n)
149 while graph[i] != not_visited[0]:
152 not_visited = list(filter(
lambda x: x
not in sub_tour, not_visited))
155 for i, j
in product(sub_tour, sub_tour):
156 acut.add_record([f
"c{cur_cut}", i, j]).value = 1
157 mi_acut.add_record([f
"c{cur_cut}", i, j]).value = 1
158 rhscut.add_record(f
"c{cur_cut}").value = len(sub_tour) - 0.5
159 mi_rhscut.add_record([f
"c{cur_cut}"]).value = len(sub_tour) - 0.5
160 cc.add_record(f
"c{cur_cut}")
164 if len(sub_tour) == len(n):
165 print(f
"z={mi.sync_db['z'].first_record().level}")
168 print(f
"{i} -> ", end=
"")