diff --git a/lib/Triangle.py b/lib/Triangle.py index 3b818ba..fff3d05 100644 --- a/lib/Triangle.py +++ b/lib/Triangle.py @@ -19,7 +19,7 @@ def try_reduce_out_degree(a,p): # Reverse as many edges out-edges of p as possible toremove = [] for q in a.edge[p]: - if a.out_degree(q) < 8: + if a.out_degree(q) < 8 and a.edge[p][q]['reversible']: a.add_edge(q,p) a.edge[q][p] = a.edge[p][q] toremove.append(q) @@ -53,7 +53,7 @@ def try_ordered_edge(a,p,q,reversible): p,q = q,p m = a.size() - a.add_edge(p,q,{'order':m,'reversible':reversible,'fields':[]}) + a.add_edge(p,q,{'order':m,'reversible':reversible,'fields':[],'depends':[]}) try: a.edgeStack.append( (p,q) ) @@ -234,10 +234,19 @@ def markEdgesWithFields(self): p,q = edges[lastInd] self.a.edge[p][q]['fields'].append(self.verts) + # the last edge depends on the other two + del edges[lastInd] + self.a.edge[p][q]['depends'].extend(edges) for child in self.children: child.markEdgesWithFields() + # all edges starting from inside this triangle have to be completed before it + for c in self.contents: + self.a.edge[p][q]['depends'].append(c) + + #print("edge %d-%d depends on: %s" % (p, q, self.a.edge[p][q]['depends'])) + def edgesByDepth(self,depth): # Return list of edges of triangles at given depth # 0 means edges of this very triangle diff --git a/lib/agentOrder.py b/lib/agentOrder.py index e604806..822e2a4 100644 --- a/lib/agentOrder.py +++ b/lib/agentOrder.py @@ -237,48 +237,109 @@ def getAgentOrder(a,nagents,orderedEdges): # def improveEdgeOrder(a): ''' - Edges that do not complete any fields can be made earlier - This method alters the graph a such that - The relative order of edges that complete fields is unchanged - Edges that do not complete fields may only be completed earlier - Where possible, non-completing edges are made immediately before another edge with same origin + A greedy algorithm to reduce the path length. + Moves edges earlier or later, if they can be moved (dependencies are + done in the proper order) and the move reduces the total length of the + path. + The algorithm tries to move 1 to 5 edges at the same time as a block + to improve upon certain types of local optima. ''' + m = a.size() # If link i is e then orderedEdges[i]=e orderedEdges = [-1]*m + geo = np.array([ a.node[i]['geo'] for i in xrange(a.order())]) + d = geometry.sphereDist(geo,geo) + + def pathLength(d, edges): + return sum([d[edges[i][0]][edges[i+1][0]] for i in xrange(len(edges)-1)]) + + def dependsOn(subjects, objects): + ''' + Returns True, if an edge inside 'objects' should be made before + one (or more) of the edges inside 'subjects' + ''' + for p,q in subjects: + depends = a.edge[p][q]['depends'] + for u,v in objects: + if depends.count((u,v,)) + depends.count(u) > 0: + return True + + return False + + + def possiblePlaces(j, block): + ''' + A generator returning the possible places of the given + block of edges within the complete edge sequence. + The current position (j) is not returned. + ''' + pos = j + # smaller index means made earlier + while pos > 0 and not dependsOn(block, [orderedEdges[pos-1]]): + pos -= 1 + yield pos + + pos = j + bsize = len(block) + n = len(orderedEdges) - bsize + 1 + # bigger index means made later + while pos < n-1 and not dependsOn([orderedEdges[pos+bsize]], block): + pos += 1 + yield pos + + for p,q in a.edges_iter(): orderedEdges[a.edge[p][q]['order']] = (p,q) - for j in xrange(1,m): - p,q = orderedEdges[j] - # Only move those that don't complete fields - if len(a.edge[p][q]['fields']) > 0: - continue - -# print j,p,q,a.edge[p][q]['fields'] - - origin = orderedEdges[j][0] - # The first time this portal is used as an origin - i = 0 - while orderedEdges[i][0]!=origin: - i+=1 - - if i %d): %s" % (j, best, bestPath)) + orderedEdges = bestPath + cont = True + + length = pathLength(d, orderedEdges) + print("Length reduction: original = %d, improved = %d, change = %d meters" % (origLength, length, length-origLength)) + for i in xrange(m): p,q = orderedEdges[i] -# print p,q,a.edge[p][q]['fields'] a.edge[p][q]['order'] = i -# print + if __name__=='__main__': order = [0,5,5,5,2,2,1,0]