Example #1
0
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
Example #2
0
	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
Example #3
0
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
Example #4
0
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