2121from __future__ import annotations
2222
2323from pathlib import Path
24+ import networkx as nx
2425
2526import gamspy .math as gams_math
2627from gamspy import (
@@ -167,9 +168,6 @@ def main():
167168 # Parameter
168169 cutcoeff = Parameter (m , name = "cutcoeff" , domain = [cc , i , j ])
169170 rhs = Parameter (m , name = "rhs" , domain = cc )
170- nosubtours = Parameter (
171- m , name = "nosubtours" , description = "number of subtours"
172- )
173171
174172 # Equation
175173 cut = Equation (m , name = "cut" , domain = cc , description = "dynamic cuts" )
@@ -190,51 +188,22 @@ def main():
190188 curcut [cc ].where [Ord (cc ) == 1 ] = True
191189
192190 for ccc_loop in ccc .toList ():
193- # initialize
194- fromi [i ].where [Ord (i ) == 1 ] = True # turn first element on
195- tt [t ].where [Ord (t ) == 1 ] = True # turn first element on
196- tour [i , j , t ] = False
197- visited [i ] = False
198-
199- for _ in i .toList ():
200- nextj [j ].where [x .l [fromi , j ] > 0.5 ] = (
201- True # check x.l(fromi,j) = 1 would be dangerous
202- )
203- tour [fromi , nextj , tt ] = True # store in table
204- visited [fromi ] = True # mark city 'fromi' as visited
205- fromi [j ] = nextj [j ]
206-
207- if nextj .toList ()[0 ] in visited .toList (): # if already visited...
208- tt [t ] = tt [t - 1 ]
209- for ix_loop in ix .toList ():
210- if (
211- ix_loop in visited .toList ()
212- ): # find starting point of new subtour
213- continue
214- fromi [ix_loop ] = True
215-
216- nosubtours [...] = Sum (t , gams_math .Max (0 , Smax (tour [i , j , t ], 1 )))
217-
218- if nosubtours .toValue () == 1 : # done: no subtours
191+ G = nx .DiGraph ()
192+ G .add_nodes_from (i .getUELs ())
193+ x_filtered = x .records [x .records ['level' ] > 0.5 ].loc [:, :"level" ]
194+ edges = list (zip (x_filtered ['ii' ], x_filtered ['jj' ]))
195+ G .add_edges_from (edges )
196+ S = [G .subgraph (c ).copy () for c in nx .strongly_connected_components (G )]
197+
198+ nosubtours = len (S )
199+ if nosubtours == 1 : # done: no subtours
219200 break
220201
221- # introduce cut
222- for idx , t_loop in enumerate (t .toList ()):
223- if idx + 1 > nosubtours .toValue ():
224- continue
202+ for s in S :
225203 rhs [curcut ] = - 1
226-
227- for i_loop , j_loop , t_loop2 , _ in tour .records .itertuples (
228- index = False
229- ):
230- if t_loop2 != t_loop :
231- continue
232-
233- cutcoeff [curcut , i_loop , j_loop ].where [
234- x .l [i_loop , j_loop ] > 0.5
235- ] = 1
236- # not needed due to nature of assignment constraints
237- # cutcoeff(curcut, i, j)$(x.l[i,j] < 0.5) = -1
204+ for u , v in s .edges ():
205+ if x .l [u , v ].records > 0.5 :
206+ cutcoeff [curcut , i , j ].where [i .sameAs (u ) & j .sameAs (v )] = 1
238207 rhs [curcut ] = rhs [curcut ] + 1
239208 allcuts [curcut ] = True # include this cut in set
240209 curcut [cc ] = curcut [cc - 1 ]
@@ -244,10 +213,10 @@ def main():
244213 "Cut: " ,
245214 ccc_loop ,
246215 "\t \t # of subtours remaining: " ,
247- nosubtours . toValue () - 1 ,
216+ nosubtours - 1 ,
248217 )
249218
250- if nosubtours . toValue () != 1 :
219+ if nosubtours != 1 :
251220 raise GamspyException ("Too many cuts needed" )
252221
253222 print ("No subtours remaining. Solution found!!\n " )
0 commit comments