File "/.../python3.7/site-packages/ortools/constraint_solver/pywrapcp.py", line 453, in ConditionalExpression
return _pywrapcp.Solver_ConditionalExpression(self, condition, expr, unperformed_value)
SystemError: <built-in function Solver_ConditionalExpression> returned NULL without setting an error
depot_first should be added to the solver but declared as:
depot_first = count_dimension.CumulVar(depot_type_idx) <= count_dimension.CumulVar(start_index)
But now the solver doesn't find a solution when I add the condition
same_vehicle = routing.VehicleVar(depot_type_idx) == routing.VehicleVar(start_index)
depot_first = time_dimension.CumulVar(depot_type_idx) <= time_dimension.CumulVar(start_index)
conditional = routing.solver().ConditionalExpression(same_vehicle, depot_first, 1)
routing.solver().Add(conditional >= 1)
Is there a way of debugging what is happening? I will post my code here, which doesn't find solutions unless the conditional is set to be >=0
"""Capacited Vehicles Routing Problem (CVRP)."""
from __future__ import print_function
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
from collections import namedtuple
def create_data_model():
"""Stores the data for the problem."""
data = {}
data['time_matrix'] = [
[0, 1, 1, 2, 3, 6, 2, 3, 4],
[1, 0, 1, 3, 2, 6, 8, 4, 3],
[1, 1, 0, 11, 10, 6, 3, 9, 1],
[8, 3, 11, 0, 1, 7, 10, 6, 2],
[7, 2, 10, 1, 0, 6, 9, 4, 3],
[3, 6, 6, 7, 6, 0, 2, 3, 3],
[6, 8, 3, 10, 9, 2, 0, 6, 6],
[2, 4, 9, 6, 4, 3, 6, 0, 2],
[2, 4, 9, 6, 4, 3, 6, 2, 0]
]
PickUpDeliveryInfo = namedtuple('PickUpDeliveryInfo', ['start_node', 'end_node', 'load_type', 'duration'])
pickups_deliveries_test = [
[3, 4, 0, 1],
[5, 6, 0, 1]
]
data['pickups_deliveries'] = [
PickUpDeliveryInfo(start_node, end_node, load_type, duration)
for start_node, end_node, load_type, duration in pickups_deliveries_test
]
data['type_depots'] = {
0: 1,
1: 2
}
data['max_time'] = 100
data['capacity'] = 100
data['demands'] = {
'TypeA': [x * data['capacity']/10 for x in [0, 0, 0, 10, -10, 10, -10, 0, 0]],
'TypeB': [x * data['capacity']/10 for x in [0, 0, 0, 0, 0, 0, 0, 0, 0]]
}
data['num_vehicles'] = 1
data['depot'] = 0
return data
def get_type_depot(data, load_type):
return data['type_depots'][load_type]
def print_node_dimension(routing, solution, index, dimension, end=False):
cumul_var = dimension.CumulVar(index)
plan_output = f'Cumul[{solution.Min(cumul_var)},{solution.Max(cumul_var)}] {solution.Value(cumul_var)}'
if not routing.IsStart(index) and not end:
trans_var = dimension.TransitVar(index)
plan_output += f'; Transit[{solution.Min(trans_var)},{solution.Max(trans_var)}] {solution.Value(trans_var)}'
slack_var = dimension.SlackVar(index)
plan_output += f'; Slack[{solution.Min(slack_var)},{solution.Max(slack_var)}] {solution.Value(slack_var)}'
print(plan_output)
def print_solution(data, manager, routing, solution):
"""Prints solution on console."""
total_distance = 0
total_load = 0
capacityA: pywrapcp.RoutingDimension = routing.GetDimensionOrDie('CapacityA')
capacityB: pywrapcp.RoutingDimension = routing.GetDimensionOrDie('CapacityB')
count: pywrapcp.RoutingDimension = routing.GetDimensionOrDie('count')
for vehicle_id in range(data['num_vehicles']):
index = routing.Start(vehicle_id)
print('Route for vehicle {}:\n'.format(vehicle_id))
route_distance = 0
route_load_A = 0
while not routing.IsEnd(index):
print(f'[[[[{manager.IndexToNode(index)}]]]]: ')
print('CapacityA')
print_node_dimension(routing, solution, index, capacityA)
print('CapacityB')
print_node_dimension(routing, solution, index, capacityB)
print('Count')
print_node_dimension(routing, solution, index, count, True)
print(' -> ')
index = solution.Value(routing.NextVar(index))
print(f'[[[[{manager.IndexToNode(index)}]]]]: ')
print_node_dimension(routing, solution, index, capacityA, True)
print_node_dimension(routing, solution, index, capacityB, True)
total_distance += route_distance
total_load += route_load_A
print('Total distance of all routes: {}m'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main():
"""Solve the CVRP problem."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(
len(data['time_matrix']),
data['num_vehicles'],
data['depot'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
def time_callback(from_index, to_index):
"""Returns the travel time between the two nodes."""
# Convert from routing variable Index to time matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data['time_matrix'][from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(time_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# Add Time constraint.
time = 'Time'
routing.AddDimension(
transit_callback_index,
data['max_time'], # allow waiting time
data['max_time'], # maximum time per vehicle
True, # Don't force start cumul to zero.
time)
time_dimension = routing.GetDimensionOrDie(time)
count_dimension_name = 'count'
# count
routing.AddConstantDimension(
1,# increment by one every time
len(data['time_matrix']), # max count is visit all the nodes
True, # set count to zero
count_dimension_name)
count_dimension = routing.GetDimensionOrDie(count_dimension_name)
for i in range(data['num_vehicles']):
routing.AddVariableMinimizedByFinalizer(
time_dimension.CumulVar(routing.Start(i)))
routing.AddVariableMinimizedByFinalizer(
time_dimension.CumulVar(routing.End(i)))
# Add Capacity constraint.
def a_demand_callback(from_index):
"""Returns the demand of the node."""
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return data['demands']['TypeA'][from_node]
a_demand_callback_index = routing.RegisterUnaryTransitCallback(a_demand_callback)
routing.AddDimension(
a_demand_callback_index,
0,
data['capacity'], # vehicle maximum capacities
True, # start cumul to zero
'CapacityA')
# Add Capacity constraint.
def b_demand_callback(from_index):
"""Returns the demand of the node."""
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return data['demands']['TypeB'][from_node]
b_demand_callback_index = routing.RegisterUnaryTransitCallback(b_demand_callback)
routing.AddDimension(
b_demand_callback_index,
0, # null capacity slack
data['capacity'], # vehicle maximum capacities
True, # start cumul to zero
'CapacityB')
a_dimension = routing.GetDimensionOrDie('CapacityA')
b_dimension = routing.GetDimensionOrDie('CapacityB')
# for node_index in range(len(data['time_matrix'][0])):
# index = manager.NodeToIndex(node_index)
# if node_index == 1:
# a_dimension.SlackVar(index).SetRange(0, data['capacity'])
# b_dimension.SlackVar(index).SetValue(0)
# elif node_index == 2:
# a_dimension.SlackVar(index).SetValue(0)
# b_dimension.SlackVar(index).SetRange(0, data['capacity'])
# elif node_index != 0:
# a_dimension.SlackVar(index).SetValue(0)
# b_dimension.SlackVar(index).SetValue(0)
for pd_info in data['pickups_deliveries']:
start_index = manager.NodeToIndex(pd_info.start_node)
end_index = manager.NodeToIndex(pd_info.end_node)
routing.solver().Add(routing.NextVar(start_index) == end_index)
routing.AddPickupAndDelivery(start_index, end_index)
routing.solver().Add(
routing.VehicleVar(start_index) == routing.VehicleVar(
end_index))
routing.solver().Add(
time_dimension.CumulVar(start_index) <=
time_dimension.CumulVar(end_index))
depot_type_idx = manager.NodeToIndex(get_type_depot(data, pd_info.load_type))
same_vehicle = routing.VehicleVar(depot_type_idx) == routing.VehicleVar(start_index)
depot_first = time_dimension.CumulVar(depot_type_idx) <= time_dimension.CumulVar(start_index)
conditional = routing.solver().ConditionalExpression(same_vehicle, depot_first, 1)
routing.solver().Add(conditional >= 1)
for location_index in range(routing.nodes()):
index = manager.NodeToIndex(location_index)
if routing.IsEnd(index) or routing.IsStart(index):
continue
routing.AddToAssignment(a_dimension.TransitVar(index))
routing.AddToAssignment(a_dimension.SlackVar(index))
routing.AddToAssignment(b_dimension.TransitVar(index))
routing.AddToAssignment(b_dimension.SlackVar(index))
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)
search_parameters.time_limit.seconds = 5 # Amount of time you want to give the solver, for searching for better solutions
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.SIMULATED_ANNEALING
)
search_parameters.log_search = True
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
print(solution)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
if __name__ == '__main__':
main()
for set in data['sets']:
#For all possible combinations in a set:
for i,index in enumerate(set):
for j in range((i+1), len(set)):
# A comes before B by at least N
A_then_B_constraint = time_dimension.CumulVar(set[i]) <= time_dimension.CumulVar(set[j]) - constants['MIN_BETWEEN_ORDERS']
# or B comes before A by at least N
B_then_A_constraint = time_dimension.CumulVar(set[j]) <= time_dimension.CumulVar(set[i]) - constants['MIN_BETWEEN_ORDERS']
gap_constraint = A_then_B_constraint + B_then_A_constraint == 1
routing.solver().Add(gap_constraint)
> To unsubscribe from this group and stop receiving emails from it, send an email to or-tools...@googlegroups.com.