public void SimpleLambdaCallback(bool callGC) { // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( 5 /*locations*/, 1 /*vehicle*/, 0 /*depot*/); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create a distance callback. int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(Math.Abs(toNode - fromNode)); }); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); if (callGC) { GC.Collect(); } // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; Assignment solution = routing.SolveWithParameters(searchParameters); // 0 --(+1)-> 1 --(+1)-> 2 --(+1)-> 3 --(+1)-> 4 --(+4)-> 0 := +8 Assert.Equal(8, solution.ObjectiveValue()); }
private void AddTimeWindowConstrains(WorkData data, RoutingIndexManager manager, RoutingModel routing) { // Create and register a transit callback int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { int fromNode = manager.IndexToNode(fromIndex); int toNode = manager.IndexToNode(toIndex); return(data.DurationMatrix[fromNode, toNode] + data.ServiceTimes[fromNode]); }); routing.AddDimension(transitCallbackIndex, 120, MAX_VEHICLE_ROUTING_TIME, false, "Time"); // Add time window constraints for each location except depot RoutingDimension timeDimension = routing.GetDimensionOrDie("Time"); for (int i = 1; i < data.TimeWindows.GetLength(0); ++i) { long index = manager.NodeToIndex(i); timeDimension.CumulVar(index).SetRange(data.TimeWindows[i][0], data.TimeWindows[i][1]); } // Add time window constraints for each vehicle start node for (int i = 0; i < data.VehiclesAmount; ++i) { long index = routing.Start(i); timeDimension.CumulVar(index).SetRange(data.TimeWindows[0][0], data.TimeWindows[0][1]); routing.AddVariableMinimizedByFinalizer(timeDimension.CumulVar(routing.Start(i))); routing.AddVariableMinimizedByFinalizer(timeDimension.CumulVar(routing.End(i))); } }
private void AddCapacityConstrains(WorkData data, RoutingIndexManager manager, RoutingModel routing) { // Create and register a transit callback int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex int fromNode = manager.IndexToNode(fromIndex); int toNode = manager.IndexToNode(toIndex); return(data.DistanceMatrix[fromNode, toNode]); }); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Add Capacity constraint int demandCallbackIndex = routing.RegisterUnaryTransitCallback( (long fromIndex) => { int fromNode = manager.IndexToNode(fromIndex); return(data.Demands[fromNode]); }); // AddDimensionWithVehicleCapacity method, which takes a vector of capacities routing.AddDimensionWithVehicleCapacity(demandCallbackIndex, 0, data.VehicleCapacities, true, "Capacity"); }
public static int[] Run(long[] DistanceMatrix, int num, int VehicleNumber, int Depot, RoutingSearchParameters searchParameters) { // Instantiate the data problem. // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( num, VehicleNumber, Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(DistanceMatrix[fromNode * num + toNode]); } ); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Solve the problem. Assignment solution = routing.SolveWithParameters(searchParameters); // Print solution on console. return(GetOrder(routing, manager, solution)); }
override public long Run(long fromIndex, long toIndex) { // Convert from routing variable Index to time matrix NodeIndex. int fromNode = indexManager.IndexToNode(fromIndex); int toNode = indexManager.IndexToNode(toIndex); return(timeMatrix[fromNode, toNode] + timeDemand_[fromNode]); }
public void PrintToConsole( Day day, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { Console.WriteLine("Day " + day.DayNum); if (day.Locations.Count != 0) { // Display dropped nodes. string droppedNodes = "Dropped nodes:"; for (int index = 0; index < routing.Size(); ++index) { if (routing.IsStart(index) || routing.IsEnd(index)) { continue; } if (solution.Value(routing.NextVar(index)) == index) { droppedNodes += " " + manager.IndexToNode(index); } } Console.WriteLine("{0}", droppedNodes); // Inspect solution. for (int i = 0; i < day.Vehicles.Count; i++) { Console.WriteLine("Route for Vehicle {0}:", i); long routeDuration = 0; var index = routing.Start(i); while (routing.IsEnd(index) == false) { Console.Write("{0} -> ", manager.IndexToNode((int)index)); var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDuration += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode((int)index)); Console.WriteLine("Duration of the route: {0}mins", routeDuration); } Console.WriteLine("Minimum duration of the routes: {0}mins", day.MinDur); Console.WriteLine("Maximum duration of the routes: {0}mins", day.MaxDur); } else { Console.WriteLine("This day is holiday."); } }
/// <summary> /// Print the solution. /// </summary> static void VRP_LongestSingleRoute() { Console.WriteLine("VRP_LongestSingleRoute!"); // Instantiate the data problem. ORDataModel data = new ORDataModel(); // public RoutingIndexManager(int num_nodes, int num_vehicles, int depot); //public RoutingIndexManager(int num_nodes, int num_vehicles, int[] starts, int[] ends); // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( data.DistanceMatrix.GetLength(0), data.VehicleNumber, data.Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create and register a transit callback. int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(data.DistanceMatrix[fromNode, toNode]); } ); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Add Distance constraint. routing.AddDimension(transitCallbackIndex, 0, 3000, true, // start cumul to zero "Distance"); RoutingDimension distanceDimension = routing.GetMutableDimension("Distance"); distanceDimension.SetGlobalSpanCostCoefficient(100); // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; // Solve the problem. Assignment solution = routing.SolveWithParameters(searchParameters); // Print solution on console. PrintSolutionPathCheapest(data, routing, manager, solution); }
private void Distancia() { long routeDistance = 0; RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; DataModel data = new DataModel(Distancias, 1, 0); RoutingIndexManager manager = new RoutingIndexManager( data.DistanceMatrix.GetLength(0), data.VehicleNumber, data.Depot); RoutingModel routing = new RoutingModel(manager); int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(data.DistanceMatrix[fromNode, toNode]); }); routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); Assignment solution = routing.SolveWithParameters(searchParameters); var index = routing.Start(0); int indice = 1; string CadenaR = ""; string c = ""; while (routing.IsEnd(index) == false) { //Recorrido[indice] = manager.IndexToNode((int)index); c = manager.IndexToNode((int)index).ToString(); CadenaR = CadenaR + " - " + c; var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); indice++; } //Recorrido[indice] = manager.IndexToNode((int)index); c = manager.IndexToNode((int)index).ToString(); CadenaR = CadenaR + " - " + c; Km = routeDistance; CadenaRecorrido = CadenaR; }
/// <summary> /// Print the solution. /// </summary> public static int[] Solve() { int[] result = new int[200]; int cnt = 0; // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager(Ranks, VehicleNumber, Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return((long)distMat[fromNode, toNode]); } ); routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; // Solve the problem. Assignment solution = routing.SolveWithParameters(searchParameters); // Inspect solution. var index = routing.Start(0); while (routing.IsEnd(index) == false) { result[cnt++] = Convert.ToInt32(index); var previousIndex = index; index = solution.Value(routing.NextVar(index)); } return(result); }
static int[] GetOrder(RoutingModel routing, RoutingIndexManager manager, Assignment solution) { List <int> order = new List <int>(); var index = routing.Start(0); while (routing.IsEnd(index) == false) { order.Add(manager.IndexToNode((int)index)); index = solution.Value(routing.NextVar(index)); } return(order.ToArray()); }
/// <summary> /// Print the solution. /// </summary> static string PrintSolution(RoutingModel routing, RoutingIndexManager manager, Assignment solution) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Objective: {0} miles\r\n", solution.ObjectiveValue()); // Inspect solution. sb.AppendFormat("Route:"); long routeDistance = 0; var index = routing.Start(0); while (routing.IsEnd(index) == false) { sb.AppendFormat("{0} -> ", manager.IndexToNode((int)index)); var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); } sb.AppendFormat("{0}\r\n", manager.IndexToNode((int)index)); sb.AppendFormat("Route distance: {0}miles\r\n", routeDistance); return(sb.ToString()); }
/// <summary> /// Print the solution. /// </summary> static void PrintSolution(DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { long totalDistance = 0; for (int i = 0; i < data.VehicleNumber; ++i) { Console.WriteLine("Route for Vehicle {0}:", i); long routeDistance = 0; var index = routing.Start(i); while (routing.IsEnd(index) == false) { Console.Write("{0} -> ", manager.IndexToNode((int)index)); var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode((int)index)); Console.WriteLine("Distance of the route: {0}m", routeDistance); totalDistance += routeDistance; } Console.WriteLine("Total Distance of all routes: {0}m", totalDistance); }
void ShowOnMap(Day day, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { List <List <int> > routes = new List <List <int> >(); for (int i = 0; i < day.Vehicles.Count; ++i) { var index = routing.Start(i); List <int> route = new List <int>(); while (routing.IsEnd(index) == false) { route.Add(manager.IndexToNode((int)index)); index = solution.Value(routing.NextVar(index)); } route.Add(manager.IndexToNode((int)index)); routes.Add(route); } for (int i = 0; i < routes.Count; i++) { string url = "https://www.google.com.tr/maps/dir/"; foreach (var item in routes[i]) { url += day.Addresses[item].Replace('+', ',') + "/"; } //url += data.addresses[data.Depot]; Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.FileName = "chrome"; process.StartInfo.Arguments = url; process.Start(); } }
private IList <Dropped> GetDroppedLocations(FileInput input, RoutingIndexManager manager, RoutingModel routing, Assignment solution) { IDictionary <int, string> locationsNames = input.Locations.ToDictionary(k => k.Id - 1, v => v.Name); List <Dropped> droppedLocations = new List <Dropped>(); for (int index = 0; index < routing.Size(); ++index) { if (routing.IsStart(index) || routing.IsEnd(index)) { continue; } if (solution.Value(routing.NextVar(index)) == index) { int node = manager.IndexToNode(index); droppedLocations.Add(new Dropped { LocationName = locationsNames[node] }); } } return(droppedLocations); }
public static void Main(String[] args) { // Instantiate the data problem. DataModel data = new DataModel(); // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( data.DistanceMatrix.GetLength(0), data.VehicleNumber, data.Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create and register a transit callback. int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(data.DistanceMatrix[fromNode, toNode]); } ); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Add Distance constraint. routing.AddDimension( transitCallbackIndex, 0, 3000, true, // start cumul to zero "Distance"); RoutingDimension distanceDimension = routing.GetMutableDimension("Distance"); distanceDimension.SetGlobalSpanCostCoefficient(100); // Define Transportation Requests. Solver solver = routing.solver(); for (int i = 0; i < data.PickupsDeliveries.GetLength(0); i++) { long pickupIndex = manager.NodeToIndex(data.PickupsDeliveries[i][0]); long deliveryIndex = manager.NodeToIndex(data.PickupsDeliveries[i][1]); routing.AddPickupAndDelivery(pickupIndex, deliveryIndex); solver.Add(solver.MakeEquality( routing.VehicleVar(pickupIndex), routing.VehicleVar(deliveryIndex))); solver.Add(solver.MakeLessOrEqual( distanceDimension.CumulVar(pickupIndex), distanceDimension.CumulVar(deliveryIndex))); } // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; // Solve the problem. Assignment solution = routing.SolveWithParameters(searchParameters); // Print solution on console. PrintSolution(data, routing, manager, solution); }
//IntVar x; //IntVar y;//Reduntant public void SolveVrpProblem(Day day, ConfigParams cfg, VrpProblem vrpProblem, IDataOutput dataOutput, int[] VCMinMax) { this.day = day; this.cfg = cfg; //Google Distance Matrix API (Duration matrix) // Create Routing Index Manager manager = new RoutingIndexManager( day.TimeMatrix.GetLength(0), day.Vehicles.Count, day.Depot); // Create Routing Model. routing = new RoutingModel(manager); // Create and register a transit callback. int transitCallbackIndex = routing.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to distance matrix NodeIndex. var fromNode = manager.IndexToNode(fromIndex); var toNode = manager.IndexToNode(toIndex); return(day.TimeMatrix[fromNode, toNode]); } ); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Add Distance constraint. if (day.TimeWindowsActive != true) { routing.AddDimension(transitCallbackIndex, 0, 700000, true, // start cumul to zero "Distance"); RoutingDimension distanceDimension = routing.GetMutableDimension("Distance"); distanceDimension.SetGlobalSpanCostCoefficient(100); } else { routing.AddDimension( transitCallbackIndex, // transit callback 1000, // allow waiting time 600, // vehicle maximum capacities false, // start cumul to zero "Time"); TimeWindowInit(day, routing, manager);//Set Time Window Constraints } if (day.MaxVisitsActive != 0) { int demandCallbackIndex = routing.RegisterUnaryTransitCallback( (long fromIndex) => { // Convert from routing variable Index to demand NodeIndex. var fromNode = manager.IndexToNode(fromIndex); return(day.Demands[fromNode]); } ); routing.AddDimensionWithVehicleCapacity( demandCallbackIndex, 0, // null capacity slack day.VehicleCapacities, // vehicle maximum capacities true, // start cumul to zero "Capacity"); } // Allow to drop nodes. for (int i = 1; i < day.TimeMatrix.GetLength(0); ++i) { routing.AddDisjunction( new long[] { manager.NodeToIndex(i) }, day.Locations.ElementAt(i).Penalty); } // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathMostConstrainedArc; //metaheuristic searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.GuidedLocalSearch; searchParameters.TimeLimit = new Duration { Seconds = cfg.SolutionDuration }; searchParameters.LogSearch = true; solver = routing.solver(); //TODO //Some location must be on same route. //solver.Add(routing.VehicleVar(manager.NodeToIndex(2)) == routing.VehicleVar(manager.NodeToIndex(5))); //One node takes precedence over the another. //routing.AddPickupAndDelivery(manager.NodeToIndex(2), manager.NodeToIndex(5)); //Constraint variable //x = solver.MakeIntVar(day.Vehicles.Count, day.Vehicles.Count, "x"); //Number of vehicle restriction - old version //solver.Add(x < 7); //Number of vehicle restriction -new version //y = solver.MakeIntVar(routing.Vehicles(), routing.Vehicles(), "y"); //solver.Add(y <= VCMinMax[1]);//Reduntant // Solve the problem. solution = routing.SolveWithParameters(searchParameters); day.LocationDropped = false; // Display dropped nodes. List <int> droppedNodes = new List <int>(); for (int index = 0; index < routing.Size(); ++index) { if (routing.IsStart(index) || routing.IsEnd(index)) { continue; } if (solution.Value(routing.NextVar(index)) == index) { droppedNodes.Add(manager.IndexToNode((int)index)); day.LocationDropped = true; } } day.DroppedLocations.Clear(); Console.WriteLine(day.Locations.ElementAt(0).Name); if (droppedNodes != null) { foreach (var item in droppedNodes) { Location location = LocationDB.Locations.Where(x => x.Position.strPos_ == day.Addresses[item]).ToList().ElementAt(0); if (location != null) { Console.WriteLine(location.Name); day.DroppedLocations.Add(location); } } } List <int> AssignedNodes = new List <int>(); Console.WriteLine(manager.GetNumberOfNodes()); //Inspect Infeasable Nodes for (int i = 0; i < day.Vehicles.Count; i++) { var index = routing.Start(i); int j = 0; while (routing.IsEnd(index) == false) { j++; index = solution.Value(routing.NextVar(index)); } if (j == 1) { day.InfeasibleNodes = true; foreach (var item in day.DroppedLocations) { LocationDB.Locations.Where(x => x.ClientRef == item.ClientRef).ToList().ElementAt(0).Infeasible = true; } if (day.Vehicles.Count - 1 >= 1) { day.SetVehicleNumber(day.Vehicles.Count - 1); day.ResetResults(); vrpProblem.SolveVrpProblem(day, cfg, vrpProblem, dataOutput, VCMinMax); } return; } } // Inspect solution. day.TotalDur = 0; day.MinDur = 100000; for (int i = 0; i < day.Vehicles.Count; i++) { long routeDuration = 0; var index = routing.Start(i); while (routing.IsEnd(index) == false) { var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDuration += routing.GetArcCostForVehicle(previousIndex, index, 0); } day.TotalDur += routeDuration; day.MaxDur = Math.Max(routeDuration, day.MaxDur); day.MinDur = Math.Min(routeDuration, day.MinDur); } day.AvgDur = day.TotalDur / day.Vehicles.Count; }
/// <summary> /// Solves the current routing problem. /// </summary> static void Solve() { // Instantiate the data problem. // [START data] const int num_location = 5; const int num_vehicles = 1; const int depot = 0; // [END data] // Create Routing Index Manager // [START index_manager] RoutingIndexManager manager = new RoutingIndexManager(num_location, num_vehicles, depot); // [END index_manager] // Create Routing Model. // [START routing_model] RoutingModel routing = new RoutingModel(manager); // [END routing_model] // Define cost of each arc. // [START arc_cost] routing.SetArcCostEvaluatorOfAllVehicles( routing.RegisterTransitCallback( (long FromIndex, long ToIndex) => { return(1L); } )); // [END arc_cost] // Setting first solution heuristic. // [START parameters] RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; // [END parameters] // Solve the problem. // [START solve] Assignment solution = routing.SolveWithParameters(searchParameters); // [END solve] // Print solution on console. // [START print_solution] Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); // Inspect solution. long index = routing.Start(0); Console.WriteLine("Route for Vehicle 0:"); long route_distance = 0; while (routing.IsEnd(index) == false) { Console.Write("{0} -> ", manager.IndexToNode((int)index)); long previousIndex = index; index = solution.Value(routing.NextVar(index)); route_distance += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode(index)); Console.WriteLine("Distance of the route: {0}m", route_distance); // [END print_solution] }
public void Init() { if (DataModel != null) { // Create RoutingModel Index RoutingIndexManager if (DataModel.Starts != null && DataModel.Ends != null) { RoutingIndexManager = new RoutingIndexManager( DataModel.TravelTimes.GetLength(0), DataModel.VehicleCapacities.Length, DataModel.Starts, DataModel.Ends); } else { throw new Exception("Starts or Ends in DataModel is null"); } //Create routing model RoutingModel = new RoutingModel(RoutingIndexManager); // Create and register a transit callback. var transitCallbackIndex = RoutingModel.RegisterTransitCallback( (long fromIndex, long toIndex) => { // Convert from routing variable Index to time matrix or distance matrix NodeIndex. var fromNode = RoutingIndexManager.IndexToNode(fromIndex); var toNode = RoutingIndexManager.IndexToNode(toIndex); return(DataModel.TravelTimes[fromNode, toNode]); } ); //Create and register demand callback var demandCallbackIndex = RoutingModel.RegisterUnaryTransitCallback( (long fromIndex) => { // Convert from routing variable Index to demand NodeIndex. var fromNode = RoutingIndexManager.IndexToNode(fromIndex); return(DataModel.Demands[fromNode]); } ); if (DropNodesAllowed) { // Allow to drop nodes. //The penalty should be larger than the sum of all travel times locations (excluding the depot). //As a result, after dropping one location to make the problem feasible, the solver won't drop any additional locations, //because the penalty for doing so would exceed any further reduction in travel time. //If we want to make as many deliveries as possible, penalty value should be larger than the sum of all travel times between locations long penalty = 99999999; for (int j = 0; j < DataModel.Starts.GetLength(0); j++) { var startIndex = DataModel.Starts[j]; for (int i = 0; i < DataModel.TravelTimes.GetLength(0); ++i) { if (startIndex != i) { RoutingModel.AddDisjunction(new long[] { RoutingIndexManager.NodeToIndex(i) }, penalty);//adds disjunction to all stop besides start stops } } } } var vehicleCost = 10000; RoutingModel.SetFixedCostOfAllVehicles(vehicleCost); //adds a penalty for using each vehicle RoutingModel.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); //Sets the cost function of the model such that the cost of a segment of a route between node 'from' and 'to' is evaluator(from, to), whatever the route or vehicle performing the route. //Adds capacity constraints RoutingModel.AddDimensionWithVehicleCapacity( demandCallbackIndex, 0, // null capacity slack DataModel.VehicleCapacities, // vehicle maximum capacities false, // start cumul to zero "Capacity"); RoutingDimension capacityDimension = RoutingModel.GetMutableDimension("Capacity"); //Add Time window constraints RoutingModel.AddDimension( transitCallbackIndex, // transit callback 86400, // allow waiting time (24 hours in seconds) 86400, // maximum travel time per vehicle (24 hours in seconds) DataModel.ForceCumulToZero, // start cumul to zero "Time"); RoutingDimension timeDimension = RoutingModel.GetMutableDimension("Time"); //timeDimension.SetGlobalSpanCostCoefficient(10); var solver = RoutingModel.solver(); // Add time window constraints for each location except depot. for (int i = 0; i < DataModel.TimeWindows.GetLength(0); i++) { long index = RoutingIndexManager.NodeToIndex(i); //gets the node index if (index != -1) { var lowerBound = DataModel.TimeWindows[i, 0]; //minimum time to be at current index (lower bound for the timeWindow of current Index) var softUpperBound = DataModel.TimeWindows[i, 1]; //soft maxUpperBound for the timeWindow at current index var upperBound = softUpperBound + MaximumDeliveryDelayTime; //maxUpperBound to be at current index (upperbound for the timeWindow at current index) //softupperbound and upperbound are different because the upperbound is usually bigger than the softuppberbound in order to soften the current timeWindows, enabling to generate a solution that accomodates more requests timeDimension.CumulVar(index).SetRange(lowerBound, upperBound); //sets the maximum upper bound and lower bound limit for the timeWindow at the current index timeDimension.SetCumulVarSoftUpperBound(index, softUpperBound, 10000); //adds soft upper bound limit which is the requested time window RoutingModel.AddToAssignment(timeDimension.SlackVar(index)); //add timeDimension slack var for current index to the assignment RoutingModel.AddToAssignment(timeDimension.TransitVar(index)); // add timeDimension transit var for current index to the assignment RoutingModel.AddToAssignment(capacityDimension.TransitVar(index)); //add transit capacity var for current index to assignment } } // Add time window constraints for each vehicle start node, and add to assignment the slack and transit vars for both dimensions for (int i = 0; i < DataModel.VehicleCapacities.Length; i++) { long index = RoutingModel.Start(i); var startDepotIndex = DataModel.Starts[i]; timeDimension.CumulVar(index).SetRange(DataModel.TimeWindows[startDepotIndex, 0], DataModel.TimeWindows[startDepotIndex, 1]); //this guarantees that a vehicle must visit the location during its time RoutingModel.AddToAssignment(timeDimension.SlackVar(index)); //add timeDimension slack var for depot index for vehicle i depotto assignment RoutingModel.AddToAssignment(timeDimension.TransitVar(index)); //add timeDimension transit var for depot index for vehicle i depot to assignment RoutingModel.AddToAssignment(capacityDimension.TransitVar(index)); //add capacityDimension transit var for vehicle i depot } //Add client max ride time constraint, enabling better service quality for (int i = 0; i < DataModel.PickupsDeliveries.Length; i++) //iterates over each pickupDelivery pair { int vehicleIndex = -1; if (DataModel.PickupsDeliveries[i][0] == -1) //if the pickupDelivery is a customer inside a vehicle { vehicleIndex = DataModel.CustomersVehicle[i]; //gets the vehicle index } var pickupIndex = vehicleIndex == -1 ? RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][0]):RoutingModel.Start(vehicleIndex); //if is a customer inside a vehicle the pickupIndex will be the vehicle startIndex, otherwise its the customers real pickupIndex var deliveryIndex = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][1]); var rideTime = DataModel.CustomersRideTimes[i]; var directRideTimeDuration = DataModel.TravelTimes[pickupIndex, DataModel.PickupsDeliveries[i][1]]; var realRideTimeDuration = rideTime + (timeDimension.CumulVar(deliveryIndex) - timeDimension.CumulVar(pickupIndex)); //adds the currentRideTime of the customer and subtracts cumulative value of the ride time of the delivery index with the current one of the current index to get the real ride time duration solver.Add(realRideTimeDuration < directRideTimeDuration + DataModel.MaxCustomerRideTime); //adds the constraint so that the current ride time duration does not exceed the directRideTimeDuration + maxCustomerRideTimeDuration } //Add precedence and same vehicle Constraints for (int i = 0; i < DataModel.PickupsDeliveries.GetLength(0); i++) { if (DataModel.PickupsDeliveries[i][0] != -1) { long pickupIndex = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][0]); //pickup index long deliveryIndex = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][1]); //delivery index RoutingModel.AddPickupAndDelivery(pickupIndex, deliveryIndex); //Notifies that the pickupIndex and deliveryIndex form a pair of nodes which should belong to the same route. solver.Add(solver.MakeEquality(RoutingModel.VehicleVar(pickupIndex), RoutingModel.VehicleVar(deliveryIndex))); //Adds a constraint to the solver, that defines that both these pickup and delivery pairs must be picked up and delivered by the same vehicle (same route) solver.Add(solver.MakeLessOrEqual(timeDimension.CumulVar(pickupIndex), timeDimension.CumulVar(deliveryIndex))); //Adds the precedence constraint to the solver, which defines that each item must be picked up at pickup index before it is delivered to the delivery index //timeDimension.SlackVar(pickupIndex).SetMin(4);//mininimum slack will be 3 seconds (customer enter timer) //timeDimension.SlackVar(deliveryIndex).SetMin(3); //minimum slack will be 3 seconds (customer leave time) } } //Constraints to enforce that if there is a customer inside a vehicle, it has to be served by that vehicle for (int customerIndex = 0; customerIndex < DataModel.CustomersVehicle.GetLength(0); customerIndex++) { var vehicleIndex = DataModel.CustomersVehicle[customerIndex]; if (vehicleIndex != -1) //if the current customer is inside a vehicle { var vehicleStartIndex = RoutingModel.Start(vehicleIndex); //vehicle start depot index var deliveryIndex = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[customerIndex][1]); //gets the deliveryIndex solver.Add(solver.MakeEquality(RoutingModel.VehicleVar(vehicleStartIndex), RoutingModel.VehicleVar(deliveryIndex))); //vehicle with vehicleIndex has to be the one that delivers customer with nodeDeliveryIndex; //this constraint enforces that the vehicle indexed by vehicleIndex has to be the vehicle which services (goes to) the nodeDeliveryIndex as well } } for (int i = 0; i < DataModel.VehicleCapacities.Length; i++) { RoutingModel.AddVariableMinimizedByFinalizer( timeDimension.CumulVar(RoutingModel.Start(i))); RoutingModel.AddVariableMinimizedByFinalizer( timeDimension.CumulVar(RoutingModel.End(i))); } } }