ankane / or-tools-ruby

Operations research tools for Ruby
Apache License 2.0
171 stars 20 forks source link

Feature request SetStartValue #24

Closed stevenshack closed 2 years ago

stevenshack commented 3 years ago

The python API for or-tools has a number of useful tools for setting values and ranges - particularly useful for VRP problems. Could we add:

SetStartValue setstartmin setstartmax setstartrange

setendmin setendmax setendrange setendvalue

I believe these should make it easier to for example set the starting time of a vehicle (no more midnight deliveries!). Further making it easier to directly use the planners output without adding or subtracting error prone time offsets.

ankane commented 3 years ago

Added the min, max, and range methods to IntervalVar. Can you share the Python code that uses SetStartValue and SetEndValue?

stevenshack commented 3 years ago

I don't have Python code handy, but let me illustrate with some ruby code.

Here's what I'm doing currently. I'm specifying that each vehicle should operate within its shift timeframe. Shift timeframes are relative seconds from midnight. Eg 32400 = 9AM

@shifts.each_with_index do |shift, vehicle_id| startofday = shift.start_time.beginning_of_day starttime = (shift.start_time - startofday).to_i endtime = (shift.end_time - startofday).to_i vehicle_index_start = @routing.start(vehicle_id) vehicle_index_end = @routing.end(vehicle_id) @traveltime_dimension.cumul_var(vehicle_index_start).set_range(starttime, endtime) @traveltime_dimension.cumul_var(vehicle_index_end).set_range(starttime, endtime) end

In my time dimension I have start cumul to zero set to false Time windows for delivery are similarly relative from midnight.

trip_windows.each_with_index do |time_window, location_idx| index = @manager.node_to_index(location_idx) @traveltime_dimension.cumul_var(index).set_range(time_window[0], time_window[1]) end

However I'm having problems forcing my vehicles to start within their shift timeframe. it would be useful to be able to simply force a vehicles start time to say 9am.

What I'd like to be able to do is something like this:

Set vehicle to start at 9am

@traveltime_dimension.cumul_var(vehicle_index_start).SetStartValue(32400)

ankane commented 3 years ago

From what I can tell, there's no SetStartValue method on IntVar (the return type of CumulVar) in Python or C++.

stevenshack commented 3 years ago

ah You're right, it's on IntervalVar.

So what's the right way to make a vehicle only operate within a specific timeframe? Setting start/end times doesn't seem to work. Do I iterate through every location and set the range on each one?

stevenshack commented 3 years ago

For reference I've looked at these or-tools threads: https://github.com/google/or-tools/issues/1052 https://github.com/google/or-tools/issues/1564 and tried setting start/end. But my vehicles still break the start time.

ankane commented 3 years ago

Setting the start and end time should be the way. Check out the VRPTW test for an example of start times:

https://github.com/ankane/or-tools/blob/e4f97893b1e3413dfe0e3c9361d88d69eb932602/test/routing_test.rb#L466-L469

stevenshack commented 3 years ago

Yup. I've checked I've got the the same code but for both start and end locations. But my vehicle keeps moving before start time. It services a node well before its shift starts.

@shifts.each_with_index do |shift, vehicle_id| startofday = shift.start_time.beginning_of_day starttime = (shift.start_time - startofday).to_i endtime = (shift.end_time - startofday).to_i vehicle_index_start = @routing.start(vehicle_id) vehicle_index_end = @routing.end(vehicle_id) @traveltime_dimension.cumul_var(vehicle_index_start).set_range(starttime, endtime) @traveltime_dimension.cumul_var(vehicle_index_end).set_range(starttime, endtime) end

stevenshack commented 3 years ago

I'll try and generate the smallest counterexample case I can.

stevenshack commented 3 years ago

As an aside I'm seeing odd behaviour with node_to_index(location_idx). I have my location matrix setup as starts[0..4], ends[4..9], Pickup/Delivery[10,11]

When I call manager.node_to_index(end_location) I get back -1. Is this expected? I only get -1 on end locations, start and P/D locations return as normal. I've checked and my starts/ends are created correctly.

I was going to simply set a time window for each and every location. Since each vehicle has a unique starting/end point that in theory would constrain the shift.

@manager.node_to_index(1) = 1 @manager.node_to_index(4) = 4 Vehicle end location gets -1 index. @manager.node_to_index(5) = -1 @manager.node_to_index(10) = 5 @manager.node_to_index(11) = 6

ankane commented 2 years ago

Yeah, that's expected for end nodes.

ankane commented 2 years ago

Cleaning up issues