def get_shortest_and_second(R,node,debug=False): """ returns the shortest and second shortest paths FROM node. Does NOT store any data. assumes that R has origin info. R is of grid-type NOT tested """ inf=1e15 node=node[0] assert len(node)==2 #otherwise node was not given in the way we wanted if node==R.origin: return [], [] p1=nx.dijkstra_path(R, node, R.origin) w1=go.sumWeights(R,p1) assert len(p1)!=0 #should not happen since origin is handled e=(p1[0],p1[1]) e_data=R.get_edge_data(*e) #need to store away this dictionary of data assert node in e #we always start from node. wstore=e_data['weight'] e_data['weight']=inf #to force a loop.. cycle=go.shortestCycle(R,node, debug) #shortest cycle not including inf. weight edge if cycle: altW=w1+go.sumWeights(R,cycle) alternative=cycle[:-1]+p1 #-1 to avoid double use of node in path.. p2=nx.dijkstra_path(R, node, R.origin) #cannot do this single source w2=go.sumWeights(R,p2) if w2>=inf: #if we are forced to use e in second shortest as well -> no p2 or cycle if cycle: p2=alternative else: p2=None #corresponds to infinite elif cycle and w2>altW: p2=alternative #take the loop instead for second shortest e_data['weight']=wstore return p1,p2
def getRoute(self,road): """ get the routes to origin or to road. If to road, the node furthest away is returned and nextPos is set to the node closest to the origin. returns a list of nodes that should be visited. Does not really follow the turn restrictions, needs improvements. """ if not road: raise Exception('road does not have a value') ls=[] shortest_path=nx.dijkstra_path if road==self.origin: #give path to origin if fun.ListTupleEquals(self.pos, self.origin): return [] elif not self.nextPos: raise Exception('if not located in origin, nextPos must be given') if fun.ListTupleEquals(self.pos, self.nextPos): ls.append(self.nextPos) #also works if we are on a graph node frm=self.nextPos if fun.ListTupleEquals(frm, self.origin): if not frm in ls: ls.append(frm) ls.reverse() return ls #remove last visited road. eTmp=[self.lastRoadPos, frm] eTmp.append(self.roadNet.get_edge_data(eTmp[0], eTmp[1])) self.roadNet.remove_edge(eTmp[0], eTmp[1]) ls+=shortest_path(self.roadNet,frm, self.origin) #dijksta shortest path self.roadNet.add_edges_from([tuple(eTmp)]) self.nextPos=self.origin else: #on our way out in the "road-jungle" if tuple(self.pos) in self.roadNet: frm=self.pos else: print self.pos, self.origin, self.pos in self.roadNet if not self.nextPos: raise Exception('if not located in origin, nextPos must be given', self.pos) ls.append(self.nextPos) frm=self.nextPos #remove road segment from graph, then add it again. road=list(road) road[2]=self.roadNet.get_edge_data(road[0], road[1]) self.roadNet.remove_edge(road[0], road[1]) if frm==road[0]: first=[] else: first=shortest_path(self.roadNet, frm, road[0]) if frm==road[1]: second=[] else: second=shortest_path(self.roadNet, frm, road[1]) self.roadNet.add_edges_from([tuple(road)]) if go.sumWeights(self.roadNet,first)<go.sumWeights(self.roadNet,second): shortest=first no2=second else: shortest=second no2=first ls.extend(no2) if len(shortest)==0: #we are on the other side of road already. self.nextPos=self.pos else: self.nextPos=shortest[-1] #should be road[0] or road[1] self.lastRoadPos=no2[-1] #as above. Used for directions. ls.reverse() #to get a stack from it. nicer to just pop() return ls
def sumPathsDiff(R,e,storeData=False, add=False): """ culculates the difference in the sum of the paths from removing/adding edge e. May store the new paths as well if storeData==True. This function is a freaking mess.. clean up.. """ #if not storeData: R=copy.deepcopy(R) #why was this here? extremely slow. if len(e)<3: raise Exception('sumPathsDiff needs edge data as well. set data=True so e[2] can be reached') beta=R.beta w=R.roadWidth #width of roads C=0 #cost origin=R.origin inf=1e12 eps=1e-8 etpl=tuple(e) if add: #different orders of things, but otherwise the same. action1=R.add_edges_from action2=R.remove_edges_from #we need to reduce the number of nodes checked... if euc. distance #to origin is less than half that from e, remove dtmp=fun.getDistance(e[0], R.origin) lst=[n for n in R.nodes(data=True) if fun.getDistance(n[0], R.origin)>dtmp*0.5]#really slow, but necessary #lst=R.nodes(data=True) #old one, replaced to increase speed a bit.. else: action1=R.remove_edges_from action2=R.add_edges_from lst=e[2]['visited_from_node'] #faster than above. action1([etpl]) if not nx.is_connected(R): #probably remove in this case. Not allowed since graph looses connectivity action2([etpl]) return inf routeAfter=nx.algorithms.shortest_paths.weighted.single_source_dijkstra(R, origin) sumP21={} for n in lst: P21=routeAfter[1][n[0]] P21.reverse() sumP21[n[0]]=go.sumWeights(R, P21) #need to do this before addding/removing edge again action2([etpl]) #print "sumpathdiff, visited from ", len(e[2]['visited_from_node']), " nodes" for nTmp in lst: if nTmp[0]==R.origin: continue #print nTmp[1] P11=nTmp[1]['shortest_path'] P12=nTmp[1]['second_shortest'] old_s1=go.sumWeights(R,P11) #if add and storeData: print "p12:", add, storeData, P12 old_s2=go.sumWeights(R,P12) P21=routeAfter[1][nTmp[0]] #used to be try statement here, be aware of exceptions #P21.reverse() #already reversed above now! #P21=nx.dijkstra_path(R,nTmp[0], origin) #try single source also..may be faster for a lot of n if abs(sumP21[nTmp[0]]- old_s1) > eps: C+=beta*(sumP21[nTmp[0]]-old_s1) action1([etpl]) if C<inf: #road back calculated, now road there. eTmp=[P21[0], P21[1]] #minus, since reveresed. Look above eTmp.append(R.get_edge_data(eTmp[0], eTmp[1])) P21W=go.sumWeights(R,P21) #needs to be calculated before eTmp is removed R.remove_edges_from([tuple(eTmp)]) #temporary remove to get loop cycle=go.shortestCycle(R,nTmp[0],cutoff=10*e[2]['weight']) #the cutoff is taken from nothing. Makes the code slow. Should be modified to similar as graphOperations.pathdiff.. but this code is however not used.. alternative=False altW=inf W22=None if cycle: #if we found one.. altW=P21W+go.sumWeights(R,cycle) tmp=copy.deepcopy(P21) tmp.reverse() #want from origin to point alternative=tmp+cycle try: P22=nx.dijkstra_path(R, origin, nTmp[0]) #cannot do this single source if alternative and go.sumWeights(R,P22)>altW: P22=alternative W22=altW else: W22=go.sumWeights(R,P22) except nx.exception.NetworkXNoPath: if alternative: P22=alternative W22=altW else: C=inf #this exception is thrown if the node is in a local graph separated from OR R.add_edges_from([tuple(eTmp)]) #reset road if C>=inf: break #saves some time, but is ugly if abs(W22-old_s2)>eps: C+=W22-old_s2 #if P22 != old_s2: C+=go.sumWeights(R,P22)-old_s2 #old one. wrong, right? if storeData: nTmp[1]['new_shortest_path']=P21 nTmp[1]['new_second_shortest']=P22 action2([etpl]) #print "C=", C if C>=inf: R.add_edges_from([tuple(e)]) #we broke out without adding again.. return C
def pathsDiff(R,e,storeData=False): """ culculates the difference in the sum of the paths from removing/adding edge e. May store the new paths as well if storeData==True. This function is a freaking mess.. clean up.. """ assert len(e)>=3 beta=R.beta w=R.roadWidth #width of roads C=0 #cost origin=R.origin inf=1e15 eps=1e-8 etpl=tuple(e) for nTmp in e[2]['visited_from_node']: if nTmp[0]==R.origin: continue """ used to use already calc. balues.. P11=nTmp[1]['shortest_path'] P12=nTmp[1]['second_shortest'] #remove!!! """ P11,P12=get_shortest_and_second(R, nTmp) """if t2!=P12: print nTmp print go.sumWeights(R,t2) print go.sumWeights(R,P12) print t2 print P12 ax=R.draw(weight=True) draw_road(t2, ax,'r') draw_road(P12, ax,'b') plt.show() assert t1==P11 assert t2==P12""" if P12 == None or P11==None: #road is forced over e.. cannot be removed.. C=inf break w11=go.sumWeights(R,P11) w12=go.sumWeights(R,P12) assert w12>=w11 wstore=e[2]['weight'] e[2]['weight']=inf #force other ways.. P21,P22=get_shortest_and_second(R, nTmp) if P21==None or P22==None: C=inf break w21=go.sumWeights(R,P21) w22=go.sumWeights(R,P22) assert w22>=w21 #closest one is the one with load #print w22, w21, w22+w21 #print w11, w12, w11+w12 if w22+w21<w11+w12: #new route should be longer or equal print w22+w21, w11+w12 print e[0:2] ax=R.draw() P21.reverse() draw_road(P21+P22, ax, 'r') P11.reverse() draw_road(P11+P12, ax, 'b') plt.show() assert w22+w21>=w11+w12 #new route should be longer or equal C+=(w21+beta*w22)-(w11+beta*w12) if storeData: #store so we don't have to do this all again when/if removing edge assert P21!=None and P22!=None """if nTmp[0]==(135.637, 103.395): p1,p2=get_shortest_and_second(R,nTmp, debug=True) if go.sumWeights(R,p2)>160: ax=R.draw(weight=True) draw_road(p2, ax, 'r') plt.show() raise Exception('remove..')""" nTmp[1]['new_shortest_path']=P21 nTmp[1]['new_second_shortest']=P22 e[2]['weight']=wstore if C>=inf: e[2]['weight']=wstore #we broke out without adding.. return C