VROOM-Project / pyvroom

Vehicle Routing Open-source Optimization Machine
BSD 2-Clause "Simplified" License
69 stars 14 forks source link

Route step is missing distance #103

Closed drutkoowski closed 7 months ago

drutkoowski commented 7 months ago

Hello.

This is standard result for route steps after calling solution.solve(..) and it looks like it doesn't have "distance" field:

'steps': [{'type': 'start', 'location': [15.65782, 58.407549], 'setup': 0, 'service': 0, 'waiting_time': 0, 'load': [0, 0], 'arrival': 1712642400, 'duration': 0, 'violations': []}, {'type': 'pickup', 'description': '36', 'location': [15.65782, 58.407549], 'id': 139934561833, 'setup': 0, 'service': 600, 'waiting_time': 0, 'job': 139934561833, 'load': [23, 0], 'arrival': 1712642400, 'duration': 0, 'violations': []}, {'type': 'delivery', 'description': 'customer1', 'location': [15.5770785, 58.3996545], 'id': 776538017840, 'setup': 0, 'service': 600, 'waiting_time': 0, 'job': 776538017840, 'load': [0, 0], 'arrival': 1712644090, 'duration': 1090, 'violations': []}, {'type': 'end', 'location': [15.65782, 58.407549], 'setup': 0, 'service': 0, 'waiting_time': 0, 'load': [0, 0], 'arrival': 1712645777, 'duration': 2177, 'violations': []}]

Minimal example:

import vroom

ROUTING_PROFILE_CAR = "driving-car"
ROUTING_PROFILE_HGV = "driving-hgv"

problem_instance: vroom.Input = vroom.Input(
    servers={
        ROUTING_PROFILE_CAR: "ors:8080",
        ROUTING_PROFILE_HGV: "ors:8080",
    },
    router=vroom._vroom.ROUTER.ORS,
)
...
[problem_instance.add_job(shipment) for shipment in shipments]
problem_instance.add_vehicle([vehicle for vehicle in vehicles])

solution = problem_instance.solve(
    exploration_level=5, nb_threads=4
).to_dict()
print(solution)

I have tried similar payload with standard ORS + VROOM and it returns distances.

EDIT: How is that possible to pass -g flag to problem_instance options? image

jonathf commented 7 months ago

Good question. I am looking through the code and I can see I set geometry flag to false during json export. I don't remember why that was the case.

I'll investigate a little and perhaps expose the flag to the user in to_json and to_dict if that makes sense.

drutkoowski commented 7 months ago

Thank you for your feedback! Please keep me up to date.

drutkoowski commented 7 months ago

However, is that possible to pass options to vroom.Input instance? To have equivalent of standard vroom:

"options": {
    "c": True,
    "g": False,
},
jonathf commented 7 months ago

Setting geometry on input is passed to the vroom engine correctly, so this should be the way to go. When pybind11 picks up the solution on the other end though, the extra fields are ignored. So neither dict, json nor pandas export will include distance values that you can view as a user until we make a fix.

drutkoowski commented 7 months ago

okay I see, when is it expected to happen approximately?

jonathf commented 7 months ago

I've made a developer release 1.13.5-dev0. It is hardcoded with geometry set to true, and can be used right away. Please let me know if it works as expected. Also this only affects the json output. The pandas output will not have this output.

For a permanent solution that follow input: probably sometime next week, when I have a little time to fiddle with it.

jonathf commented 7 months ago

Install with pip install pyvroom==1.13.5.dev0.

drutkoowski commented 7 months ago

Great! Thank you so much for your quick response and fix. Well done!

I will test it today or tomorrow so I can let you know

drutkoowski commented 7 months ago

@jonathf It looks like it now returns distances, but they are not seem valid Response: https://pastebin.com/BitLnmq8

jonathf commented 7 months ago

Does vroom input know that you want geometry? From code: input.set_geometry(). From JSON: "options": {"g": true}

jcoupey commented 7 months ago

Just a nitpicking note: from the upstream vroom point of view, deciding of requiring geometry does not happen in the json with an "options" key. It is done by running with the -g flag.

The "options": {"c": True, "g": False} part is just a convenient way to pass flags when using the vroom-express node server. Just pointing this out to maybe avoid different behaviors between vroom and pyvroom in term of parsing.

drutkoowski commented 7 months ago

As far as the use of vroom and vroom-express is concerned, passing the c and g flags in options is possible, I use it and it works as expected. As for pyvroom, after creating the problem_instance I call .set_geometry() and gets an error:

set_geometry(): incompatible function arguments. The following argument types are supported:
1. (self: vroom._vroom.Input, arg0: bool) -> None
Input(servers={'driving-car': <vroom._vroom.Server object at 0x7f4b51bf65f0>, 'driving-hgv': <vroom._vroom.Server object at 0x7f4b51bf6930>}, router=ROUTER.ORS)

Fragment of the code: image

Moreover, I use .to_dict(), and when I don't use set_geometry, I get distances, but it doesn't look right.

jonathf commented 7 months ago

Hrmm... client has forced me over to a locked down mac, so the time I allocated to fix this issue got cut short as I don't have the right tooling in place. This is going to go slower than I planed.

But I made an update that in theory should fix both problems of relaying the flags from input to output and the set_geometry issue. I can't test it right now. Can you try again on 1.13.5-dev1.

If the distances still doesn't look right, do you mind elaborating on what about them are off?

drutkoowski commented 7 months ago

I have tested it now and it looks like it works for me. Good job!

jonathf commented 7 months ago

I have tested the feature on my side as well successfully, and merged the changes to the main branch.

Thank you for your feedback.

Closing.