How to implement custom soft constraints in OR-Tools Routing Solver? - or-tools

I've been working with the OR-Tools routing solver in Python for a couple of months and I still not understand how to implement custom soft constraints or even if it's possible in the routing solver.
I know that the following methods add penalties to the cumulative values:
SetCumulVarSoftUpperBound(self, index: int64, upper_bound: int64, coefficient: int64)
SetCumulVarSoftLowerBound(self, index: int64, upper_bound: int64, coefficient: int64)
One of the constraint I'm not able to implement is the following:
I want to penalize the distance/time consumed by empty vehicles. For instance, in a pickup and delivery scenario if the vehicle does a delivery and becomes empty, I want to penalize the distance traveled while empty until the vehicle reaches a pickup node (next node) or ends the route.
With the above methods I can only penalize with a fixed value when a bound is exceeded, but I would like to penalize the consumed distance or time to transit to the next node.
Meanwhile, is there any way to implement custom soft constraints with an explicit penalty value considering the state of the solution found (e.g., the next node and cumulative amount of the dimensions)?

Related

Multi pickup locations for a single delivery

I have a list of orders, each consists of a disjunction of pickup and a disjunction of delivery nodes (using AddDisjunction with a positive penalty and max cardinality of 1).
Some of these orders form groups that must be delivered to the same location at the same time by the same vehicle, or not at all.
AddPickupAndDelivery/AddPickupAndDeliverySets cannot be used on the same node/disjunction twice so I cannot merge the delivery disjunctions into one and link all pickup disjunctions to it.
I have tried setting the NextVar of one delivery disjunction to the other delivery disjunction, however the other disjunction was still sometimes reached without the first one (but not vice versa).
I have tried combining the NextVar method with giving penalty for reaching only part of the delivery nodes, in two different ways:
first by using AddSoftSameVehicleConstraint, however it did not give penalty for unperformed nodes,
second by creating a new dimension with positive arc values for reaching all disjunctions other than the first one in the NextVar chain, and a negative arc value for reaching the latter, which is the only one that can be reached only if all the rest of the disjunctions were reached. Combined with SetSpanCostCoefficientForAllVehicles and a big cumul var start value at the start nodes, the idea was that reaching part of the nodes would induce a positive span, while reaching all of them would reset the span back to 0.
However at this point the algorithm stopped reaching any nodes, I presume due to the fact that the local search operators do not include a single addition of multiple nodes, and each addition of a single node induces a higher cost. Is there a way of implementing multiple pickups to a single delivery which abides the constraints I have stated while using the python version of or-tools?

Can we specify forbidden edge constraints in Google OR Tools?

I'm trying to solve a classic Traveling Salesman Problem (TSP). I'm using Google OR Tools default TSP wrapper code. I want some arcs to be forbidden, in the sense that perhaps there is no path between node 10 and node 12. In this instance, I set the value to a large number, like 10^6, but the solver still uses that arc.
I verified that this particular instance has a feasible solution, in the sense that when I run the same code twice or extend the time limit of the solver from 30s to 60s, the solver found a solution that does not use this arc.
The question I have: is there a way to specify a hard constraint that this can't be used, instead of setting the arc cost to ∞? I imagine that in a classic TSP Linear Program, a constraint can be set on the binary decision variable.
You have two options:
Create a routing dimension so you can set a vehicle capacity (i.e. vehicle longest distance allowed). Thus any arc whose transit cost is above this capacity is effectively forbidden (vehicle capacity is an hard constraint).
e.g.
# Add Distance constraint.
dimension_name = 'Distance'
routing.AddDimension(
transit_callback_index, # you can reuse the same callback use in SetArcCost
0, # no slack
42_000, # vehicle maximum travel distance
True, # start cumul to zero
dimension_name)
now every arcs above 42_000 is forbidden.
You can remove some arcs by tweaking the routing.NextArc()
e.g. to remove arc {I,J}
i_index = manager.NodeToIndex(I)
j_index = manager.NodeToIndex(J)
routing.NextVar(i_index).RemoveValue(j_index)
note: you also have the RemoveValues([....]) to suppress a list of outgoing arcs.

OR-tools VRP with Multi-dimension. Optimize in one, constrains in others

I have a problem when I want to optimize the global Cost of the vehicules' route. So for that I register a Cost Dimension for returning the cost associated to each arc. But at the same time I have restrictions in another dimensions such as Time & Distance. How can I achieve this? Maybe I just only have to use AddDimension for each callback, but I don't know how to set the Objective function in RoutingModel.
All in your question: Does restriction aka constraint should be part of the objective cost ? or this is just, well constraints the solver need to fulfill ?
Adding new dimension using AddDimension() is a good start IMHO.
note: You may also add the span or global span of any dimension to the objective cost by setting the corresponding coefficient (zero by default thus dimension won't participate to the objective cost and only add "constraint" to the solution)
ref: https://github.com/google/or-tools/blob/b37d9c786b69128f3505f15beca09e89bf078a89/ortools/constraint_solver/routing.h#L2482-L2496

Get the current SearchDepth within the distance cost function of a Vehicle Routing Problem

I'm working on a Vehicle Routing Problem. In my cost function I need to find the current search depth in order to calculate a deferred cost which is dependent on the current length of the intermediate solution. Is this information available via some method? This is my distance cost function:
def distance_callback(from_index, to_index):
"""Returns the shortest path distance between the two nodes"""
from_node = self.routing_manager.IndexToNode(from_index)
to_node = self.routing_manager.IndexToNode(to_index)
return self.distance_matrix[from_node][to_node]
See discussion on:
https://groups.google.com/forum/#!topic/or-tools-discuss/lw_zdalvm6k
The current approach is not possible as the distance callback is called in many places, and is usually cached, especially if written in python.
The original request is to have time dependent demands. It can be modeled with duplicate nodes, in disjunctions, with non overlapping time windows, and different demands.

How should one set up the immediate reward in a RL program?

I want my RL agent to reach the goal as quickly as possible and at the same time to minimize the number of times it uses a specific resource T (which sometimes though is necessary).
I thought of setting up the immediate rewards as -1 per step, an additional -1 if the agent uses T and 0 if it reaches the goal.
But the additional -1 is completely arbitrary, how do I decide how much punishment should the agent get for using T?
You should use a reward function which mimics your own values. If the resource is expensive (valuable to you), then the punishment for consuming it should be harsh. The same thing goes for time (which is also a resource if you think about it).
If the ratio between the two punishments (the one for time consumption and the one for resource consumption) is in accordance to how you value these resources, then the agent will act precisely in your interest. If you get it wrong (because maybe you don't know the precise cost of the resource nor the precise cost of slow learning), then it will strive for a pseudo optimal solution rather than an optimal one, which in a lot of cases is okay.