Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /branches/unlabeled-1.7.1/src/optimiser.c
Parent Directory
|
Revision Log
Revision 14 -
(show annotations)
(download)
(as text)
Tue Jan 6 18:21:54 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 17753 byte(s)
Tue Jan 6 18:21:54 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 17753 byte(s)
Tried to optimise the Queue data type. It was slower than the original.
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/optimiser.c,v 1.7.1.1 2009-01-06 18:21:54 amb Exp $ |
3 | |
4 | Routing optimiser. |
5 | ******************/ /****************** |
6 | Written by Andrew M. Bishop |
7 | |
8 | This file Copyright 2008,2009 Andrew M. Bishop |
9 | It may be distributed under the GNU Public License, version 2, or |
10 | any higher version. See section COPYING of the GNU Public license |
11 | for conditions under which this file may be redistributed. |
12 | ***************************************/ |
13 | |
14 | |
15 | #include <assert.h> |
16 | #include <string.h> |
17 | #include <stdlib.h> |
18 | |
19 | #include "functions.h" |
20 | #include "types.h" |
21 | |
22 | #define INCREMENT 1024 |
23 | #define NBINS 256 |
24 | |
25 | /*+ One part of the result for a node. +*/ |
26 | typedef struct _HalfResult |
27 | { |
28 | Node *Prev; /*+ The previous Node following the shortest path. +*/ |
29 | distance_t distance; /*+ The distance travelled to the node following the shortest path. +*/ |
30 | duration_t duration; /*+ The time taken to the node following the shortest path. +*/ |
31 | } |
32 | HalfResult; |
33 | |
34 | /*+ One complete result for a node. +*/ |
35 | typedef struct _Result |
36 | { |
37 | node_t node; /*+ The end node. +*/ |
38 | Node *Node; /*+ The end Node. +*/ |
39 | HalfResult shortest; /*+ The result for the shortest path. +*/ |
40 | HalfResult quickest; /*+ The result for the quickest path. +*/ |
41 | } |
42 | Result; |
43 | |
44 | /*+ A list of results. +*/ |
45 | typedef struct _Results |
46 | { |
47 | uint32_t alloced; /*+ The amount of space allocated for results in the array. +*/ |
48 | uint32_t number[NBINS]; /*+ The number of occupied results in the array. +*/ |
49 | Result **results[NBINS]; /*+ An array of pointers to arrays of results. +*/ |
50 | } |
51 | Results; |
52 | |
53 | /*+ A queue of results. +*/ |
54 | typedef struct _Queue |
55 | { |
56 | int firstbin; /*+ The distance associated to the first bin. +*/ |
57 | distance_t minimum; /*+ The distance associated to the first bin. +*/ |
58 | uint32_t alloced; /*+ The amount of space allocated for results in the array. +*/ |
59 | uint32_t number[NBINS]; /*+ The number of occupied results in the array. +*/ |
60 | Result **results[NBINS]; /*+ An array of pointers to arrays of results. +*/ |
61 | } |
62 | Queue; |
63 | |
64 | |
65 | /*+ The queue of nodes. +*/ |
66 | Queue *OSMQueue=NULL; |
67 | |
68 | /*+ The list of results. +*/ |
69 | Results *OSMResults=NULL; |
70 | |
71 | /* Functions */ |
72 | |
73 | static void remove_from_queue(Result *result); |
74 | static void insert_in_queue(Result *result); |
75 | static Result *pop_from_queue(void); |
76 | |
77 | static Result *insert_result(node_t node); |
78 | static Result *find_result(node_t node); |
79 | |
80 | |
81 | /*++++++++++++++++++++++++++++++++++++++ |
82 | Find the optimum route between two nodes. |
83 | |
84 | node_t start The start node. |
85 | |
86 | node_t finish The finish node. |
87 | ++++++++++++++++++++++++++++++++++++++*/ |
88 | |
89 | void FindRoute(node_t start,node_t finish) |
90 | { |
91 | Node *Start,*Finish; |
92 | node_t node2; |
93 | Node *Node1,*Node2; |
94 | HalfResult shortest1,quickest1; |
95 | HalfResult shortest2,quickest2; |
96 | HalfResult shortestfinish,quickestfinish; |
97 | distance_t totalcrow,crow; |
98 | Result *result1,*result2; |
99 | Segment *segment; |
100 | int nresults=0; |
101 | |
102 | /* Set up the finish conditions */ |
103 | |
104 | shortestfinish.distance=~0; |
105 | shortestfinish.duration=~0; |
106 | quickestfinish.distance=~0; |
107 | quickestfinish.duration=~0; |
108 | |
109 | /* Work out the distance as the crow flies */ |
110 | |
111 | Start=FindNode(start); |
112 | Finish=FindNode(finish); |
113 | |
114 | totalcrow=Distance(Start,Finish); |
115 | |
116 | /* Insert the first node into the queue */ |
117 | |
118 | result1=insert_result(start); |
119 | |
120 | result1->node=start; |
121 | result1->Node=Start; |
122 | result1->shortest.Prev=NULL; |
123 | result1->shortest.distance=0; |
124 | result1->shortest.duration=0; |
125 | result1->quickest.Prev=NULL; |
126 | result1->quickest.distance=0; |
127 | result1->quickest.duration=0; |
128 | |
129 | insert_in_queue(result1); |
130 | |
131 | /* Loop across all nodes in the queue */ |
132 | |
133 | while((result1=pop_from_queue())) |
134 | { |
135 | Node1=result1->Node; |
136 | shortest1.distance=result1->shortest.distance; |
137 | shortest1.duration=result1->shortest.duration; |
138 | quickest1.distance=result1->quickest.distance; |
139 | quickest1.duration=result1->quickest.duration; |
140 | |
141 | segment=FindFirstSegment(Node1->id); |
142 | |
143 | while(segment) |
144 | { |
145 | node2=segment->node2; |
146 | |
147 | shortest2.distance=shortest1.distance+segment->distance; |
148 | shortest2.duration=shortest1.duration+segment->duration; |
149 | quickest2.distance=quickest1.distance+segment->distance; |
150 | quickest2.duration=quickest1.duration+segment->duration; |
151 | |
152 | result2=find_result(node2); |
153 | if(result2) |
154 | Node2=result2->Node; |
155 | else |
156 | Node2=FindNode(node2); |
157 | |
158 | crow=Distance(Node2,Finish); |
159 | |
160 | if((crow+shortest2.distance)>(km_to_distance(10)+1.4*totalcrow)) |
161 | goto endloop; |
162 | |
163 | if(shortest2.distance>shortestfinish.distance && quickest2.duration>quickestfinish.duration) |
164 | goto endloop; |
165 | |
166 | if(!result2) /* New end node */ |
167 | { |
168 | result2=insert_result(node2); |
169 | result2->node=node2; |
170 | result2->Node=Node2; |
171 | result2->shortest.Prev=Node1; |
172 | result2->shortest.distance=shortest2.distance; |
173 | result2->shortest.duration=shortest2.duration; |
174 | result2->quickest.Prev=Node1; |
175 | result2->quickest.distance=quickest2.distance; |
176 | result2->quickest.duration=quickest2.duration; |
177 | |
178 | nresults++; |
179 | |
180 | if(node2==finish) |
181 | { |
182 | shortestfinish.distance=shortest2.distance; |
183 | shortestfinish.duration=shortest2.duration; |
184 | quickestfinish.distance=quickest2.distance; |
185 | quickestfinish.duration=quickest2.duration; |
186 | } |
187 | else |
188 | insert_in_queue(result2); |
189 | } |
190 | else |
191 | { |
192 | if(shortest2.distance<result2->shortest.distance || |
193 | (shortest2.distance==result2->shortest.distance && |
194 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ |
195 | { |
196 | remove_from_queue(result2); |
197 | |
198 | result2->shortest.Prev=Node1; |
199 | result2->shortest.distance=shortest2.distance; |
200 | result2->shortest.duration=shortest2.duration; |
201 | |
202 | if(node2==finish) |
203 | { |
204 | shortestfinish.distance=shortest2.distance; |
205 | shortestfinish.duration=shortest2.duration; |
206 | } |
207 | else |
208 | insert_in_queue(result2); |
209 | } |
210 | |
211 | if(quickest2.duration<result2->quickest.duration || |
212 | (quickest2.duration==result2->quickest.duration && |
213 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ |
214 | { |
215 | remove_from_queue(result2); |
216 | |
217 | result2->quickest.Prev=Node1; |
218 | result2->quickest.distance=quickest2.distance; |
219 | result2->quickest.duration=quickest2.duration; |
220 | |
221 | if(node2==finish) |
222 | { |
223 | quickestfinish.distance=quickest2.distance; |
224 | quickestfinish.duration=quickest2.duration; |
225 | } |
226 | else |
227 | insert_in_queue(result2); |
228 | } |
229 | } |
230 | |
231 | endloop: |
232 | |
233 | segment=FindNextSegment(segment); |
234 | } |
235 | |
236 | if(!(nresults%1000)) |
237 | { |
238 | printf("\rRouting: End Nodes=%d Queue=%d Journey=%.1fkm,%.0fmin ",nresults,0, |
239 | distance_to_km(shortest2.distance),duration_to_minutes(quickest2.duration)); |
240 | // printf("%3d %d -> %d = %d\n",OSMQueue->number, |
241 | // (int)(10*distance_to_km(OSMQueue->queue[0]->shortest.distance)), |
242 | // (int)(10*distance_to_km(OSMQueue->queue[OSMQueue->number-1]->shortest.distance)), |
243 | // (int)(10*distance_to_km(OSMQueue->queue[0]->shortest.distance))- |
244 | // (int)(10*distance_to_km(OSMQueue->queue[OSMQueue->number-1]->shortest.distance))); |
245 | fflush(stdout); |
246 | } |
247 | } |
248 | |
249 | printf("\rRouted: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin\n",nresults, |
250 | distance_to_km(shortestfinish.distance),duration_to_minutes(shortestfinish.duration), |
251 | distance_to_km(quickestfinish.distance),duration_to_minutes(quickestfinish.duration)); |
252 | fflush(stdout); |
253 | } |
254 | |
255 | |
256 | /*++++++++++++++++++++++++++++++++++++++ |
257 | Print the optimum route between two nodes. |
258 | |
259 | node_t start The start node. |
260 | |
261 | node_t finish The finish node. |
262 | ++++++++++++++++++++++++++++++++++++++*/ |
263 | |
264 | void PrintRoute(node_t start,node_t finish) |
265 | { |
266 | FILE *file; |
267 | Result *result; |
268 | // int i,j; |
269 | |
270 | /* Print the result for the shortest route */ |
271 | |
272 | file=fopen("shortest.txt","w"); |
273 | |
274 | result=find_result(finish); |
275 | |
276 | do |
277 | { |
278 | if(result->shortest.Prev) |
279 | { |
280 | Segment *segment; |
281 | Way *way; |
282 | |
283 | segment=FindFirstSegment(result->shortest.Prev->id); |
284 | while(segment->node2!=result->Node->id) |
285 | segment=FindNextSegment(segment); |
286 | |
287 | way=FindWay(segment->way); |
288 | |
289 | fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node, |
290 | distance_to_km(segment->distance),duration_to_minutes(segment->duration), |
291 | distance_to_km(segment->distance)/duration_to_hours(segment->duration), |
292 | WayName(way)); |
293 | |
294 | result=find_result(result->shortest.Prev->id); |
295 | } |
296 | else |
297 | { |
298 | fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node); |
299 | |
300 | result=NULL; |
301 | } |
302 | } |
303 | while(result); |
304 | |
305 | fclose(file); |
306 | |
307 | /* Print the result for the quickest route */ |
308 | |
309 | file=fopen("quickest.txt","w"); |
310 | |
311 | result=find_result(finish); |
312 | |
313 | do |
314 | { |
315 | if(result->quickest.Prev) |
316 | { |
317 | Segment *segment; |
318 | Way *way; |
319 | |
320 | segment=FindFirstSegment(result->quickest.Prev->id); |
321 | while(segment->node2!=result->Node->id) |
322 | segment=FindNextSegment(segment); |
323 | |
324 | way=FindWay(segment->way); |
325 | |
326 | fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node, |
327 | distance_to_km(segment->distance),duration_to_minutes(segment->duration), |
328 | distance_to_km(segment->distance)/duration_to_hours(segment->duration), |
329 | WayName(way)); |
330 | |
331 | result=find_result(result->quickest.Prev->id); |
332 | } |
333 | else |
334 | { |
335 | fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node); |
336 | |
337 | result=NULL; |
338 | } |
339 | } |
340 | while(result); |
341 | |
342 | /* Print all the distance results. */ |
343 | |
344 | // file=fopen("distance.txt","w"); |
345 | // |
346 | // for(i=0;i<NBINS;i++) |
347 | // for(j=0;j<OSMResults->number[i];j++) |
348 | // { |
349 | // result=OSMResults->results[i][j]; |
350 | // |
351 | // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude, |
352 | // distance_to_km(result->shortest.distance)); |
353 | // } |
354 | // |
355 | // fclose(file); |
356 | |
357 | /* Print all the duration results. */ |
358 | |
359 | // file=fopen("duration.txt","w"); |
360 | // |
361 | // for(i=0;i<NBINS;i++) |
362 | // for(j=0;j<OSMResults->number[i];j++) |
363 | // { |
364 | // result=OSMResults->results[i][j]; |
365 | // |
366 | // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude, |
367 | // duration_to_minutes(result->quickest.duration)); |
368 | // } |
369 | // |
370 | // fclose(file); |
371 | } |
372 | |
373 | |
374 | /*++++++++++++++++++++++++++++++++++++++ |
375 | Insert a result into the queue in the right order. |
376 | |
377 | Result *result The result to insert into the queue. |
378 | ++++++++++++++++++++++++++++++++++++++*/ |
379 | |
380 | static void insert_in_queue(Result *result) |
381 | { |
382 | static int biggest=0; |
383 | int bin; |
384 | |
385 | /* Check that the whole thing is allocated. */ |
386 | |
387 | if(!OSMQueue) |
388 | { |
389 | int i; |
390 | |
391 | OSMQueue=(Queue*)calloc(1,sizeof(Queue)); |
392 | OSMQueue->alloced=(INCREMENT/8); |
393 | |
394 | for(i=0;i<NBINS;i++) |
395 | OSMQueue->results[i]=(Result**)malloc(OSMQueue->alloced*sizeof(Result*)); |
396 | } |
397 | |
398 | /* Choose the bin */ |
399 | |
400 | bin=(int)(result->shortest.distance>>5)-OSMQueue->minimum; |
401 | |
402 | if(bin<0) |
403 | bin=0; |
404 | |
405 | if(bin>=NBINS) |
406 | bin=NBINS-1; |
407 | |
408 | if(bin>biggest) |
409 | {printf("bin=%d\n",bin);biggest=bin;} |
410 | |
411 | bin=(bin+OSMQueue->firstbin)%NBINS; |
412 | |
413 | /* Check that the arrays have enough space. */ |
414 | |
415 | if(OSMQueue->number[bin]==OSMQueue->alloced) |
416 | { |
417 | int i; |
418 | |
419 | OSMQueue->alloced+=(INCREMENT/8); |
420 | |
421 | for(i=0;i<NBINS;i++) |
422 | OSMQueue->results[i]=(Result**)realloc((void*)OSMQueue->results[i],OSMQueue->alloced*sizeof(Result*)); |
423 | } |
424 | |
425 | /* No search - just add result to appropriate bin */ |
426 | |
427 | OSMQueue->results[bin][OSMQueue->number[bin]]=result; |
428 | OSMQueue->number[bin]++; |
429 | } |
430 | |
431 | |
432 | /*++++++++++++++++++++++++++++++++++++++ |
433 | Remove a result from the queue. |
434 | |
435 | Result *result The result to remove from the queue. |
436 | ++++++++++++++++++++++++++++++++++++++*/ |
437 | |
438 | static void remove_from_queue(Result *result) |
439 | { |
440 | int i; |
441 | int bin=(result->shortest.distance>>5)-OSMQueue->minimum; |
442 | |
443 | if(bin<0) |
444 | return; |
445 | |
446 | if(bin>=NBINS) |
447 | bin=NBINS-1; |
448 | |
449 | bin=(bin+OSMQueue->firstbin)%NBINS; |
450 | |
451 | /* Linear search in correct bin */ |
452 | |
453 | for(i=0;i<OSMQueue->number[bin];i++) |
454 | if(OSMQueue->results[bin][i]==result) |
455 | OSMQueue->results[bin][i]=NULL; |
456 | } |
457 | |
458 | |
459 | /*++++++++++++++++++++++++++++++++++++++ |
460 | Pop a result from the queue. |
461 | ++++++++++++++++++++++++++++++++++++++*/ |
462 | |
463 | static Result *pop_from_queue(void) |
464 | { |
465 | int i,j; |
466 | |
467 | /* No search - just take first result in first non-empty bin */ |
468 | |
469 | for(j=0;j<NBINS;j++) |
470 | { |
471 | int bin=OSMQueue->firstbin; |
472 | |
473 | for(i=OSMQueue->number[bin]-1;i>=0;i--) |
474 | if(OSMQueue->results[bin][i]) |
475 | { |
476 | OSMQueue->number[bin]=i; |
477 | return(OSMQueue->results[bin][i]); |
478 | } |
479 | |
480 | OSMQueue->firstbin++; |
481 | OSMQueue->firstbin%=NBINS; |
482 | OSMQueue->minimum++; |
483 | } |
484 | |
485 | return(NULL); |
486 | } |
487 | |
488 | |
489 | /*++++++++++++++++++++++++++++++++++++++ |
490 | Insert a new result into the results data structure in the right order. |
491 | |
492 | node_t node The node that is to be inserted into the results. |
493 | ++++++++++++++++++++++++++++++++++++++*/ |
494 | |
495 | static Result *insert_result(node_t node) |
496 | { |
497 | int start; |
498 | int end; |
499 | int mid; |
500 | int insert=-1; |
501 | int bin=node%NBINS; |
502 | |
503 | /* Check that the whole thing is allocated. */ |
504 | |
505 | if(!OSMResults) |
506 | { |
507 | int i; |
508 | |
509 | OSMResults=(Results*)calloc(1,sizeof(Results)); |
510 | OSMResults->alloced=INCREMENT; |
511 | |
512 | for(i=0;i<NBINS;i++) |
513 | OSMResults->results[i]=(Result**)malloc(OSMResults->alloced*sizeof(Result*)); |
514 | } |
515 | |
516 | /* Check that the arrays have enough space. */ |
517 | |
518 | if(OSMResults->number[bin]==OSMResults->alloced) |
519 | { |
520 | int i; |
521 | |
522 | OSMResults->alloced+=INCREMENT; |
523 | |
524 | for(i=0;i<NBINS;i++) |
525 | OSMResults->results[i]=(Result**)realloc((void*)OSMResults->results[i],OSMResults->alloced*sizeof(Result*)); |
526 | } |
527 | |
528 | /* Binary search - search key may not match, if not then insertion point required |
529 | * |
530 | * # <- start | Check mid and move start or end if it doesn't match |
531 | * # | |
532 | * # | Since there may not be an exact match we must set end=mid |
533 | * # <- mid | or start=mid because we know that mid doesn't match. |
534 | * # | |
535 | * # | Eventually end=start+1 and the insertion point is before |
536 | * # <- end | end (since it cannot be before the initial start or end). |
537 | */ |
538 | |
539 | start=0; |
540 | end=OSMResults->number[bin]-1; |
541 | |
542 | if(OSMResults->number[bin]==0) /* There are no results */ |
543 | insert=start; |
544 | else if(node<OSMResults->results[bin][start]->node) /* Check key is not before start */ |
545 | insert=start; |
546 | else if(node>OSMResults->results[bin][end]->node) /* Check key is not after end */ |
547 | insert=end+1; |
548 | else |
549 | { |
550 | do |
551 | { |
552 | mid=(start+end)/2; /* Choose mid point */ |
553 | |
554 | if(OSMResults->results[bin][mid]->node<node) /* Mid point is too low */ |
555 | start=mid; |
556 | else if(OSMResults->results[bin][mid]->node>node) /* Mid point is too high */ |
557 | end=mid; |
558 | else |
559 | assert(0); |
560 | } |
561 | while((end-start)>1); |
562 | |
563 | insert=end; |
564 | } |
565 | |
566 | /* Shuffle the array up */ |
567 | |
568 | if(insert!=OSMResults->number[bin]) |
569 | memmove(&OSMResults->results[bin][insert+1],&OSMResults->results[bin][insert],(OSMResults->number[bin]-insert)*sizeof(Result*)); |
570 | |
571 | /* Insert the new entry */ |
572 | |
573 | OSMResults->number[bin]++; |
574 | |
575 | OSMResults->results[bin][insert]=(Result*)malloc(sizeof(Result)); |
576 | |
577 | return(OSMResults->results[bin][insert]); |
578 | } |
579 | |
580 | |
581 | /*++++++++++++++++++++++++++++++++++++++ |
582 | Find a result, ordered by node. |
583 | |
584 | node_t node The node that is to be found. |
585 | ++++++++++++++++++++++++++++++++++++++*/ |
586 | |
587 | static Result *find_result(node_t node) |
588 | { |
589 | int start; |
590 | int end; |
591 | int mid; |
592 | int bin=node%NBINS; |
593 | |
594 | /* Binary search - search key exact match only is required. |
595 | * |
596 | * # <- start | Check mid and move start or end if it doesn't match |
597 | * # | |
598 | * # | Since an exact match is wanted we can set end=mid-1 |
599 | * # <- mid | or start=mid+1 because we know that mid doesn't match. |
600 | * # | |
601 | * # | Eventually either end=start or end=start+1 and one of |
602 | * # <- end | start or end is the wanted one. |
603 | */ |
604 | |
605 | start=0; |
606 | end=OSMResults->number[bin]-1; |
607 | |
608 | if(OSMResults->number[bin]==0) /* There are no results */ |
609 | return(NULL); |
610 | else if(node<OSMResults->results[bin][start]->node) /* Check key is not before start */ |
611 | return(NULL); |
612 | else if(node>OSMResults->results[bin][end]->node) /* Check key is not after end */ |
613 | return(NULL); |
614 | else |
615 | { |
616 | do |
617 | { |
618 | mid=(start+end)/2; /* Choose mid point */ |
619 | |
620 | if(OSMResults->results[bin][mid]->node<node) /* Mid point is too low */ |
621 | start=mid+1; |
622 | else if(OSMResults->results[bin][mid]->node>node) /* Mid point is too high */ |
623 | end=mid-1; |
624 | else /* Mid point is correct */ |
625 | return(OSMResults->results[bin][mid]); |
626 | } |
627 | while((end-start)>1); |
628 | |
629 | if(OSMResults->results[bin][start]->node==node) /* Start is correct */ |
630 | return(OSMResults->results[bin][start]); |
631 | |
632 | if(OSMResults->results[bin][end]->node==node) /* End is correct */ |
633 | return(OSMResults->results[bin][end]); |
634 | } |
635 | |
636 | return(NULL); |
637 | } |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |