public RoutingSolver(DataModel data) { if (this.Data.GetTimeWindows().GetLength(0) != this.Data.GetTimeMatrix().GetLength(0)) { throw new System.ComponentModel.DataAnnotations.ValidationException("Travel Time Matrix and Time Windows Matrix must have the same length."); } this.Data = data; // Create Routing Index Manager // [START index_manager] this.manager = new RoutingIndexManager( this.Data.GetTimeMatrix().GetLength(0), // Total Number of Sites this.Data.GetVehicleNumber(), this.Data.GetDepot()); // [END index_manager] this.timeCallback = new TimeCallback(this.Data, manager); }
/// <summary> /// Solves the current routing problem. /// </summary> private void Solve(int number_of_orders, int number_of_vehicles) { Console.WriteLine("Creating model with " + number_of_orders + " orders and " + number_of_vehicles + " vehicles."); // Finalizing model int number_of_locations = locations_.Length; RoutingIndexManager manager = new RoutingIndexManager(number_of_locations, number_of_vehicles, vehicle_starts_, vehicle_ends_); RoutingModel model = new RoutingModel(manager); // Setting up dimensions const int big_number = 100000; LongLongToLong manhattan_callback = new Manhattan(manager, locations_, 1); model.AddDimension( model.RegisterTransitCallback(manhattan_callback), big_number, big_number, false, "time"); RoutingDimension time_dimension = model.GetDimensionOrDie("time"); LongToLong demand_callback = new Demand(order_demands_); model.AddDimension(model.RegisterUnaryTransitCallback(demand_callback), 0, vehicle_capacity_, true, "capacity"); RoutingDimension capacity_dimension = model.GetDimensionOrDie("capacity"); // Setting up vehicles LongLongToLong[] cost_callbacks = new LongLongToLong[number_of_vehicles]; for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle) { int cost_coefficient = vehicle_cost_coefficients_[vehicle]; LongLongToLong manhattan_cost_callback = new Manhattan(manager, locations_, cost_coefficient); cost_callbacks[vehicle] = manhattan_cost_callback; int manhattan_cost_index = model.RegisterTransitCallback(manhattan_cost_callback); model.SetArcCostEvaluatorOfVehicle(manhattan_cost_index, vehicle); time_dimension.CumulVar(model.End(vehicle)).SetMax( vehicle_end_time_[vehicle]); } // Setting up orders for (int order = 0; order < number_of_orders; ++order) { time_dimension.CumulVar(order).SetRange(order_time_windows_[order].start_, order_time_windows_[order].end_); long[] orders = { manager.NodeToIndex(order) }; model.AddDisjunction(orders, order_penalties_[order]); } // Solving RoutingSearchParameters search_parameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.AllUnperformed; Console.WriteLine("Search"); Assignment solution = model.SolveWithParameters(search_parameters); //protect callbacks from the GC GC.KeepAlive(manhattan_callback); GC.KeepAlive(demand_callback); for (int cost_callback_index = 0; cost_callback_index < cost_callbacks.Length; cost_callback_index++) { GC.KeepAlive(cost_callbacks[cost_callback_index]); } if (solution != null) { String output = "Total cost: " + solution.ObjectiveValue() + "\n"; // Dropped orders String dropped = ""; for (int order = 0; order < number_of_orders; ++order) { if (solution.Value(model.NextVar(order)) == order) { dropped += " " + order; } } if (dropped.Length > 0) { output += "Dropped orders:" + dropped + "\n"; } // Routes for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle) { String route = "Vehicle " + vehicle + ": "; long order = model.Start(vehicle); if (model.IsEnd(solution.Value(model.NextVar(order)))) { route += "Empty"; } else { for (; !model.IsEnd(order); order = solution.Value(model.NextVar(order))) { IntVar local_load = capacity_dimension.CumulVar(order); IntVar local_time = time_dimension.CumulVar(order); route += order + " Load(" + solution.Value(local_load) + ") " + "Time(" + solution.Min(local_time) + ", " + solution.Max(local_time) + ") -> "; } IntVar load = capacity_dimension.CumulVar(order); IntVar time = time_dimension.CumulVar(order); route += order + " Load(" + solution.Value(load) + ") " + "Time(" + solution.Min(time) + ", " + solution.Max(time) + ")"; } output += route + "\n"; } Console.WriteLine(output); } }