valhalla / valhalla

Open Source Routing Engine for OpenStreetMap
https://valhalla.github.io/valhalla/
Other
4.44k stars 677 forks source link

Adjust trade-off of distance/time cost through REST API #2902

Open ecotner opened 3 years ago

ecotner commented 3 years ago

Hey, awesome project! I think Valhalla's flexibility to use dynamic costing is an incredible advantage over other routing frameworks! However, one feature that I would love to have is the ability to set the trade-off cost between distance and time of a route, and do this on-the-fly with each API call to the web server. I have been scouring the documentation and code, and so far have been unable to find anything in the costing options that appears to allow this to be set/adjusted. I was looking through the sif module and found some code/comments that suggested it was possible for the user to set the preference for one vs the other, but it is not clear how to do so (or even if it is possible through the web API). Ideally I would like to be able to pass along a float value that would specify how much weight to give the distance costs relative to time (with the understanding that they do not share units, of course; I see that there is some conversion done to make them comparable). Does anyone know if this is possible, and if so, how to do it?

kevinkreiser commented 3 years ago

Yeah I recently added that feature but for the moment its only implemented in auto costing. You can see how to use it by studing the unit tests for it: https://github.com/valhalla/valhalla/blob/master/test/gurka/test_shortest.cc#L117

basically your request needs costing options:

{...,
  "costing_options":{
    "auto":{
      "use_distance":0.5
    }
  }
}
ecotner commented 3 years ago

Thanks! Sorry if this is long-winded, but I just want to make sure I understand how this translates into actual costing so I can go in reverse and figure out what use_distance should be starting from some other criteria: if I understand correctly, this use_distance parameter is what gets returned from costing_options.use_distance() in this line? And so that means that if you pass in say "use_distance": x, with the default value of kInvMedianSpeed = 1.f / 16.f (that's 16 m/s?), then the calculations

distance_factor_ = costing_options.use_distance() * kInvMedianSpeed;
inv_distance_factor_ = 1.f - costing_options.use_distance();

imply that the distance-based cost is C_d = x*k*d (where k is short for kInvMedianSpeed), the time-based cost is C_t = (1-x)*t and so plugging in d=1 meter, t=1 sec, and x=0.5, we have that the distance cost is C_d/C_t=1/16 of the time cost, i.e. moving 16 meters costs as much as waiting one second.

So now to do this in reverse, let's say e.g. gas costs ~$0.10/mile, and paying a driver costs $15/hr, so using the standard 16 m/s conversion factor, the distance cost rate is equivalent to ($0.10/mile)*(1 mile/1609.34 m)*(16 m/s) = 0.0009941 $/sec, and the time cost rate is equivalent to ($15/hr)*(1 hr/3600 s) = 0.004166 $/sec, meaning that the ratio of distance/time cost rates is 0.0009941/0.004166=0.2386, and so solving 0.2386=x/(1-x), we get that the value of use_distance should be x=0.1926 in order to appropriately minimize my objective (dollar cost of the route) given the original cost rates. Is my logic right here?

kevinkreiser commented 3 years ago

the math you laid out there makes sense to me but as you pointed out it is all based on my assertion that we can kind of compare distance and time by holding speed constant to make distances into times. intuitively, i would guess that this assertion would make it so that routes that spend a significant time with access to high speed roads will over estimate the importance of distance and do the opposite in places where most roads are slower than the median speed. i was hoping the value i picked would be a happy middle but in practice i dont know how true that is!

ecotner commented 3 years ago

If this is the right way to do the conversions, I think it is actually independent of the speed! If you have two routes that are identical in terms of total distance and time traveled, they should have the exact same cost (as long as the cost is only a function of total distance/time), regardless of how the velocity changes during the journey. E.g. if you drive at a constant speed vs. driving in a very bursty stop-and-go manner. Sure, your choice of 16 m/s is pretty arbitrary, but if you had chosen another one the only change that would need to be made is in the value of the use_distance parameter. Like if you had chosen 32 m/s instead, you could still get the same distance/time tradeoff by solving the same C_d/C_t = x/(1-x) equation; only difference is C_d is twice as large, but you just correct for that by choosing the appropriate value for x.