@@ -70,27 +70,12 @@ def get_neighbors(self, state):
7070
7171 for i , j in self ._neighbours :
7272 try :
73- if state .x + i > 0 and state .y + j > 0 :
73+ if state .x + i >= 0 and state .y + j >= 0 :
7474 state_list .append (self .map [state .y + j ][state .x + i ])
7575 except IndexError :
7676 pass
7777 return state_list
7878
79-
80- # def set_cost(self, region, cost, modify=None):
81-
82- # xmin = max(0, region[0])
83- # xmax = min(self.col, region[1])
84- # ymin = max(0, region[2])
85- # ymax = min(self.row, region[3])
86-
87- # self.costmap[ymin:ymax, xmin:xmax] = cost
88-
89- # if modify is not None:
90- # for x in range(xmin, xmax):
91- # for y in range(ymin, ymax):
92- # modify.modify_cost(self.map[y][x])
93-
9479 _root2 = np .sqrt (2 )
9580
9681 def cost (self , state1 , state2 ):
@@ -127,11 +112,12 @@ def show_h(self):
127112# - replace equality tests with math.isclose() which is faster than np.isclose()
128113# - add an offset to inequality tests, X > Y becomes X > Y + tol
129114class Dstar :
130- def __init__ (self , map ):
115+ def __init__ (self , map , tol = 1e-6 ):
131116 self .map = map
132117 # self.open_list = set()
133118 self .open_list = []
134119 self .nexpand = 0
120+ self .tol = tol
135121
136122 def process_state (self , verbose = False ):
137123 if verbose :
@@ -150,25 +136,27 @@ def process_state(self, verbose=False):
150136 if verbose :
151137 print (f"EXPAND { x } , { k_old :.1f} " )
152138
153- if x .h > k_old + 1e-6 :
139+ if x .h > k_old + self . tol :
154140 # RAISE state
155141 if verbose :
156142 print (' raise' )
157143 for y in self .map .get_neighbors (x ):
158- if y .t is not Tag .NEW and y .h <= k_old and x .h > y .h + self .map .cost (x , y ) + 1e-6 :
144+ if (y .t is not Tag .NEW and
145+ y .h <= k_old - self .tol and
146+ x .h > y .h + self .map .cost (x , y ) + self .tol ):
159147 if verbose :
160148 print (f" { x } cost from { x .h :.1f} to { y .h + self .map .cost (x , y ):.1f} ; parent from { x .parent } to { y } " )
161149 x .parent = y
162150 x .h = y .h + self .map .cost (x , y )
163151
164- if math .isclose (x .h , k_old , rel_tol = 0 , abs_tol = 1e-6 ):
152+ if math .isclose (x .h , k_old , rel_tol = 0 , abs_tol = self . tol ):
165153 # normal state
166154 if verbose :
167155 print (' normal' )
168156 for y in self .map .get_neighbors (x ):
169157 if y .t is Tag .NEW \
170- or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = 1e-6 )) \
171- or (y .parent != x and y .h > x .h + self .map .cost (x , y ) + 1e-6 ):
158+ or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = self . tol )) \
159+ or (y .parent != x and y .h > x .h + self .map .cost (x , y ) + self . tol ):
172160 if verbose :
173161 print (f" reparent { y } from { y .parent } to { x } " )
174162 y .parent = x
@@ -178,19 +166,19 @@ def process_state(self, verbose=False):
178166 if verbose :
179167 print (' raise/lower' )
180168 for y in self .map .get_neighbors (x ):
181- if y .t is Tag .NEW or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = 1e-6 )):
169+ if y .t is Tag .NEW or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = self . tol )):
182170 if verbose :
183171 print (f" { y } cost from { y .h :.1f} to { y .h + self .map .cost (x , y ):.1f} ; parent from { y .parent } to { x } ; add to frontier" )
184172 y .parent = x
185173 self .insert (y , x .h + self .map .cost (x , y ))
186174 else :
187- if y .parent != x and y .h > x .h + self .map .cost (x , y ) + 1e-6 and x .t is Tag .CLOSED :
175+ if y .parent != x and y .h > x .h + self .map .cost (x , y ) + self . tol and x .t is Tag .CLOSED :
188176 self .insert (x , x .h )
189177 if verbose :
190178 print (f" { x } , { x .h :.1f} add to frontier" )
191179 else :
192- if y .parent != x and x .h > y .h + self .map .cost (y , x ) + 1e-6 \
193- and y .t is Tag .CLOSED and y .h > k_old + 1e-6 :
180+ if y .parent != x and x .h > y .h + self .map .cost (y , x ) + self . tol \
181+ and y .t is Tag .CLOSED and y .h > k_old + self . tol :
194182 self .insert (y , y .h )
195183 if verbose :
196184 print (f" { y } , { y .h :.1f} add to frontier" )
@@ -212,28 +200,32 @@ def insert(self, state, h_new):
212200 state .k = h_new
213201
214202 elif state .t is Tag .OPEN :
215- # k_new = min(state.k, h_new)
216- # if state.k == k_new:
217- # # k hasn't changed, leave vertex in frontier
218- # return
219- # else:
220- # state.k = k_new
221- # # remove the item from the open list
222- # # print('node already in open list, remove it first')
223- # #TODO use bisect on old state.k to find the entry
224- # for i, item in enumerate(self.open_list):
225- # if item[1] is state:
226- # del self.open_list[i]
227- # break
228-
229- state .k = min (state .k , h_new )
230- # remove the item from the open list
231- # print('node already in open list, remove it first')
232- #TODO use bisect on old state.k to find the entry
233- for i , item in enumerate (self .open_list ):
234- if item [1 ] is state :
235- del self .open_list [i ]
236- break
203+ k_new = min (state .k , h_new )
204+ if state .k == k_new :
205+ # k hasn't changed, and vertex already in frontier
206+ # just update h and be done
207+ state .h = h_new
208+ return
209+ else :
210+ # k has changed, we need to remove the vertex from the list
211+ # and re-insert it
212+ state .k = k_new
213+
214+ # scan the list to find vertex, then remove it
215+ # this is quite slow
216+ for i , item in enumerate (self .open_list ):
217+ if item [1 ] is state :
218+ del self .open_list [i ]
219+ break
220+
221+ # state.k = min(state.k, h_new)
222+ # # remove the item from the open list
223+ # # print('node already in open list, remove it first')
224+ # #TODO use bisect on old state.k to find the entry
225+ # for i, item in enumerate(self.open_list):
226+ # if item[1] is state:
227+ # del self.open_list[i]
228+ # break
237229
238230 elif state .t is Tag .CLOSED :
239231 state .k = min (state .h , h_new )
@@ -244,50 +236,33 @@ def insert(self, state, h_new):
244236 # self.open_list.add(state)
245237 heapq .heappush (self .open_list , (state .k , state ))
246238
247- # def remove(self, state):
248- # if state.t is Tag.OPEN:
249- # state.t = Tag.CLOSED
250- # else:
251- # state.t = Tag.CLOSED
252- # print('removing non open state')
253- # self.open_list.remove(state)
254-
255239 def modify_cost (self , x , newcost ):
256240 self .map .costmap [x .y , x .x ] = newcost
257241 if x .t is Tag .CLOSED :
258242 self .insert (x , x .parent .h + self .map .cost (x , x .parent ))
259- # return self.get_kmin()
260243 if len (self .open_list ) == 0 :
261244 return - 1
262245 else :
263246 # lowest priority item is always at index 0 according to docs
264247 return self .open_list [0 ][0 ]
265248
266- # def modify(self, state):
267- # self.modify_cost(state)
268- # while True:
269- # k_min = self.process_state()
270- # if k_min == -1 or k_min >= state.h:
271- # break
272-
273- # def showparents(self):
274- # return
275- # for y in range(self.map.row):
276- # if y == 0:
277- # print(" ", end='')
278- # for x in range(self.map.col):
279- # print(f" {x} ", end='')
280- # print()
281- # print(f"{y}: ", end='')
282- # for x in range(self.map.col):
283- # x = self.map.map[y][x]
284- # par = x.parent
285- # if par is None:
286- # print(' G ', end='')
287- # else:
288- # print(f"({par.x},{par.y}) ", end='')
289- # print()
290- # print()
249+ def showparents (self ):
250+ for y in range (self .map .row - 1 , - 1 , - 1 ):
251+ if y == self .map .row - 1 :
252+ print (" " , end = '' )
253+ for x in range (self .map .col ):
254+ print (f" { x } " , end = '' )
255+ print ()
256+ print (f"{ y } : " , end = '' )
257+ for x in range (self .map .col ):
258+ x = self .map .map [y ][x ]
259+ par = x .parent
260+ if par is None :
261+ print (' G ' , end = '' )
262+ else :
263+ print (f"({ par .x } ,{ par .y } ) " , end = '' )
264+ print ()
265+ print ()
291266class DstarPlanner (PlannerBase ):
292267 r"""
293268 D* path planner
@@ -322,7 +297,7 @@ def __init__(self, occ_grid=None,
322297 self .costmap = np .where (self .occgrid .grid > 0 , np .inf , 1 )
323298 self .map = Map (self .costmap .shape [0 ], self .costmap .shape [1 ])
324299 self .map .costmap = self .costmap
325- self .dstar = Dstar (self .map )
300+ self .dstar = Dstar (self .map ) #, tol=0)
326301
327302
328303 def plan (self , goal , animate = False , progress = True ):
@@ -356,6 +331,9 @@ def plan(self, goal, animate=False, progress=True):
356331 print (self .dstar .ninsert , self .dstar .nin )
357332
358333
334+ @property
335+ def nexpand (self ):
336+ return self .dstar .nexpand
359337
360338 def query (self , start , sensor = None , animate = False , verbose = False ):
361339 self .start = start
@@ -385,16 +363,18 @@ def query(self, start, sensor=None, animate=False, verbose=False):
385363 val = self .dstar .modify_cost (X , newcost )
386364 # propagate the changes to plan
387365 print ('propagate' )
366+ # self.dstar.showparents()
388367 while val != - 1 and val < tmp .h :
389368 val = self .dstar .process_state (verbose = verbose )
390369 # print('open set', len(self.dstar.open_list))
370+ # self.dstar.showparents()
391371
392372 tmp = tmp .parent
393373 # print('move to ', tmp)
394374
395375 status = namedtuple ('DstarStatus' , ['cost' ,])
396376
397- return np .array (path ). T , status (cost )
377+ return np .array (path ), status (cost )
398378
399379 # # Just feed self._h into plot function from parent as p
400380
@@ -439,7 +419,7 @@ def sensorfunc(pos):
439419 changes = []
440420 for x in range (3 , 6 ):
441421 for y in range (0 , 4 ):
442- changes .append ((x , y , 5 ))
422+ changes .append ((x , y , 100 ))
443423 return changes
444424
445425 path2 , status2 = ds .query (start = start , sensor = sensorfunc , verbose = False )
0 commit comments