def simplified_bruteForce(R, ax=None, aCap=0.20, beta=1.5, warmup=False, anim=False): """ a simplified algorithm. Still a little bit complex dock, but this is as simple as it gets I think. Does not add any edges, only removal. No stochastic elements are involved. anim=True creates a movie. """ R.beta=beta inf = 1e12 eps=1e-9 lastAdded=None origin=R.origin if not origin: raise Exception('need info about origin') #now, start for real and save away all kind of info about the paths. for node in R.nodes(data=True): p1,p2=get_shortest_and_second(R,node) node[1]['shortest_path']=p1 if len(p1)==0: #origin assert node[0]==origin node[1]['second_shortest']=[] else: node[1]['second_shortest']=p2 for p in p1,p2: #now, update edge info for all visited edges for edge in R.edges_from_path_gen(p): d=R.get_edge_data(*edge) if not node in d['visited_from_node']: d['visited_from_node'].append(node) #in order to later see... if warmup: forcePaths(R) remList=[] for e in R.edges(data=False): #add to remove list and calc. costs e_data=R.get_edge_data(*e) e_data['c']=cost(R, e, storeData=True) remList.append(e) remList=sortRemList(R,remList) #all stuff initialized by now. while len(remList)>0: #the loop where edges are removed.. """ now, choose the edge with the lowest cost. We have a problem since the cost saved is not necessary updated to the correct value. Actually, the only way to update it correctly is to scan through all edges for every removal. One could think that it would be possible to only update the ones affected by the removal, i.e. the ones connected by the shortest roads. The problem is that we also need to account for the ones that would take this road if some other arbitrary road was removed. Storing that variable would be possible but very memory inefficient. It could be tried and developed further, but would only be necessary if we add edges because the below alg. works pretty good. We use the fact that the cost from removing edges can only be bigger, i.e when removing edges it only gets worse. Thus, if the updated cost is still the smallest in the list, we know that this road is cheapest to remove. """ if anim: #movietime R.movieFlush() while True: #two possibilities to break out below.. e=remList[0] e_data=R.get_edge_data(*e) e_data['c']=cost(R,e,storeData=False) if len(remList)==1: break #now, look for the other one.. e2=remList[1] e2_data=R.get_edge_data(*e2) if e_data['c']<=e2_data['c']: break #e is our candidate, we know it's best e2_data['c']=cost(R, e2, storeData=False) #update, can only get worse for e in e,e2: #check for infinite costs, remove in that case. d=R.get_edge_data(*e) #this c has just been updated. if d['c']>=inf: remList.remove(e) remList=sortRemList(R,remList) #sort it, try again.. #found our candidate if e_data['c']>=inf: break #if last in remList and infinite cost.. remList.remove(e) e_data['c']=cost(R,e,storeData=True) #in order to store the new path.. assert e_data['c']<inf #we are outside... will we go over the areaLimit if we remove e? if e_data['c']>eps and R.areaCover-go.singleRoadSegmentCoverage(e, R, remove=True)*R.Ainv<aCap: assert abs(R.areaCover-go.roadAreaCoverage(R))<eps #compare internal and actual. break #we are finished assert R.degree(e[0])>2 and R.degree(e[1])>2 #cost func should have given c=inf. print "removes edge ",e, e_data['c'] remove_edge(e, R) #remove from R. if anim: R.movieFlush(final=True) R.cost=cf.totalCost(R) print "construction finished." print "road area coverage:", R.areaCover print "total area:", R.A print "number of nodes", len(R.nodes()) print "total cost:", R.cost return R
def stochastic(R, ax=None, aCap=0.20, beta=1.5, anim=False, probListGen=None): """ a simplified algorithm. Still a little bit complex dock, but this is as simple as it gets I think. Does not add any edges, only removal. No stochastic elements are involved. anim=True creates a movie. probListGen can be given. That is a class of type ProbListGen that defines a specific distribution that is used by the stochastic parts. """ if probListGen==None: #use default, 0.5^i probListGen=ProbListGen(0.5,15) R.beta=beta inf = 1e15 eps=1e-9 choiceMax=15 #we will not randomly choose something bigger than this. lastAdded=None origin=R.origin for e in R.edges(data=True): assert e[2]['weight']>=0 if not origin: raise Exception('need info about origin') #now, start for real and save away all kind of info about the paths. for node in R.nodes(data=True): p1,p2=get_shortest_and_second(R,node) node[1]['shortest_path']=p1 if len(p1)==0: #origin assert node[0]==origin node[1]['second_shortest']=[] else: node[1]['second_shortest']=p2 for p in p1,p2: #now, update edge info for all visited edges for edge in R.edges_from_path_gen(p): d=R.get_edge_data(*edge) if not node in d['visited_from_node']: d['visited_from_node'].append(node) #in order to later see... remList=[] for e in R.edges(data=False): #add to remove list and calc. costs e_data=R.get_edge_data(*e) e_data['c']=cost(R, e, storeData=True) remList.append(e) remList=sortRemList(R,remList) choices=[0]*15 #for statistics areound the stochastics. while len(remList)>0: #the loop where edges are removed.. """ We have a problem since the cost saved is not necessary updated to the correct value. Actually, the only way to update it correctly is to scan through all edges for every removal. One could think that it would be possible to only update the ones affected by the removal, i.e. the ones connected by the shortest roads. The problem is that we also need to account for the ones that would take this road if some other arbitrary road was removed. Storing that variable would be possible but very memory inefficient. It could be tried and developed further, but would only be necessary if we add edges because the below alg. works pretty good. We use the fact that the cost from removing edges can only be bigger, i.e when removing edges it only gets worse. Thus, if the updated cost is still the smallest in the list, we know that this road is cheapest to remove. """ probList=probListGen.getList(N=len(remList)) if anim: #it's showtime.. R.movieFlush() r=random.uniform(0,1) choice=choiceMax for i,p in enumerate(probList): #time to make the choice.. if r<p: choice=i #usually 0.. 50% prob of that. break updated=[] #store edges that we have updated the cost for.. done=False while not done: #two possibilities to break out below.. done=True for i in range(choice+2): #loop over all necessary edges try: e=remList[i] except IndexError: #remList is too short.. we are done here... done=True break #breaks out of for-loop, not while loop e_data=R.get_edge_data(*e) if not e in updated: #saves us some calculations done=False #have to iterate once more. e_data['c']=cost(R,e,storeData=False) updated.append(e) if e_data['c']>=inf: remList.remove(e) break #otherwise we "jump over" one in the list. new for loop if e_data['c']>=inf: remList.remove(e) remList=sortRemList(R,remList) #sort it.. remList=sortRemList(R,remList) #last time.. may be a double sort but who cares? #sorting remList and updating cost procedure is now done. if len(remList)==0: break #we are done if choice>=len(remList): #may happen if edges have been removed due to inf. cost choice=int(floor(random.uniform(0,len(remList)))) #take a random one.. print "choice:", choice e=remList[choice] e_data=R.get_edge_data(*e) remList.remove(e) e_data['c']=cost(R,e,storeData=True) #in order to store the new path.. assert e_data['c']<inf #following lines just to check, not used... remove later.. if __debug__ and choice != -1 and len(remList)>choice+1: e2=remList[choice+1] e2_data=R.get_edge_data(*e2) assert e_data['c']<=e2_data['c'] #we are outside... will we go over the areaLimit if we remove e? if e_data['c']>eps and R.areaCover-go.singleRoadSegmentCoverage(e, R, remove=True)*R.Ainv<aCap: assert abs(R.areaCover-go.roadAreaCoverage(R))<eps #compare internal and actual. break #we are finished print "removes edge ",e, e_data['c'], cost(R,e) assert R.degree(e[0])>2 and R.degree(e[1])>2 #cost func should have given c=inf. remove_edge(e, R) #remove from R. choices[choice]+=1 if anim: R.movieFlush(final=True) print "construction finished." print "road area coverage:", R.areaCover print "total area:", R.A print "choices:", choices R.cost=cf.totalCost(R) print "total cost:", R.cost return R
def bruteForce(R, G=None, ax=None, aCap=0.25, beta=1.5, add=True): """ works with cycles instead of shortest paths VERY computationally complex. The earlier algorithms could handle much bigger systems. modifies G into R:... this is a strange procedure and should be changed. """ R.beta=beta if not G: G=copy.deepcopy(R) inf = 1e12 eps=1e-9 lastAdded=None origin=G.origin if not origin: raise Exception('need info about origin') #first, modify the weight of the edges a couple of times. Warmup warmUp(R) paths=nx.algorithms.shortest_paths.weighted.single_source_dijkstra(R, origin) #now, start for real and save away all kind of info about the paths. for node in R.nodes(data=True): p1=paths[1][node[0]] p1.reverse() node[1]['shortest_path']=p1 if len (p1)<=1: node[1]['second_shortest']=p1 else: e=[p1[0], p1[1]] #edge closest to point e.append(R.get_edge_data(e[0], e[1])) R.remove_edge(e[0], e[1]) #temporary remove to get loop p2=nx.dijkstra_path(R,origin, node[0]) node[1]['second_shortest']=p2 R.add_edges_from([tuple(e)]) #reset road #ax=testRoads(R, p1, p2, ax) #used for debugging for path in p1,p2: last=None for nTmp in path: if last: d=R.get_edge_data(*(last, nTmp)) #should always exist if designed properly d['visits']+=1 if not node in d['visited_from_node']: d['visited_from_node'].append(node) last=nTmp remList=[] addList=[] for eTmp in R.edges(data=False): e=copy.copy(eTmp) #copy, so we can remove them and then add them and so on. e2=R.get_edge_data(*e) #not a copy, reference to real dict. e=list(e) e.append(e2) e[2]['origin_dist']=distToOrigin(e,R) e[2]['c']=routingCost(R, e, storeData=False) remList.append(e) i=1 #at this point, the visited thing should be updated for edge in R.edges(data=True): modifyEdge(edge,R,reset=True) #reset to real weight. while len(remList)>0: i=i+1 print "start" first=True e1=False assert len([e for e in R.edges(data=True) if e[2]['weight']<0])==0 while first or e[0:2]!=e1[0:2]: e1=remList[0] #takes the last item in the list. e1[2]=R.get_edge_data(e1[0], e1[1]) #edgelist is a copy, this is not. c=routingCost(R, e1, storeData=True) #also updates e[2]['c'] #e1[2]=R.get_edge_data(e1[0], e1[1]) e1[2]['c']=c #-e1[2]['origin_dist']*0.1 #origin dist just to experiment. if c>=inf: remList.remove(remList[0]) #cannot be empty at this time if len(remList)==0: break remList=sorted(remList, key=lambda edge: edge[2]['c'])#+edge[2]['visits'])#-edge[2]['origin_dist']*0.1) #first sort e=remList[0] # could be the same.. if first: first=False e[2]=R.get_edge_data(*e) # Update again, to get "new second shortest" if add and random.uniform(0,1)<0.33: print "adds" added, addList, remList, lastAdded=addListProcedure(addList,remList,R,e[2]['c'],i,lastAdded) if added: continue #go up to while again if len(remList)==0: break #print "will remove:", remList[0][0:2] remList.remove(remList[0]) #we know now that no edge is added this "round" #print "is it still there?" #for r in remList: # print r[0:2] #print "removed, next", remList[0][0:2] print e[2]['c'] if e[2]['c']>eps and aCap and R.areaCover-go.singleRoadSegmentCoverage(e, R, remove=True)*G.Ainv<aCap: print "tries to exit", e[0:2], "ec:", e[2]['c'] if add: added, addList, remList, lastAdded=addListProcedure(addList,remList,R,e[2]['c'],i,lastAdded) if added: remList.append(e) #since we just removed it and didn't remove it from graph continue break #we are finished if R.degree(e[0])>2 and R.degree(e[1])>2 and c<inf: #loop condition, at least degree 3 print "removes edge ",e[0:2] remove_edge(e, R) #remove from R. addList.append(e) #add to lists for potential adding again. e[2]['c']*=-1 #reverse, we now gain c by adding it again. assert e[2]['c']<=0 e[2]['i_added']=i #this procedure can most certainly be speeded up, expensive operations. update_after_mod(e,R) for e in R.edges(data=True): modifyEdge(e, R, reset=True) R.cost=cf.totalCost(R) print "construction finished." print "total number of nodes:", len(R.nodes()) print "road area coverage:", R.areaCover print "total area:", G.A print "total cost:", R.cost return R