// Copyright 2010-2018 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // [START program] // [START import] using System; using System.Collections.Generic; using Google.OrTools.ConstraintSolver; // [END import] /// /// Minimal TSP. /// A description of the problem can be found here: /// http://en.wikipedia.org/wiki/Travelling_salesman_problem. /// public class Tsp { // [START data_model] class DataModel { // Constructor: public DataModel() { // Convert locations in meters using a city block dimension of 114m x 80m. for (int i=0; i < Locations.GetLength(0); i++) { Locations[i, 0] *= 114; Locations[i, 1] *= 80; } } public int[,] Locations = { {4, 4}, {2, 0}, {8, 0}, {0, 1}, {1, 1}, {5, 2}, {7, 2}, {3, 3}, {6, 3}, {5, 5}, {8, 5}, {1, 6}, {2, 6}, {3, 7}, {6, 7}, {0, 8}, {7, 8} }; public int VehicleNumber = 1; public int Depot = 0; }; // [END data_model] // [START manhattan_distance] /// /// Manhattan distance implemented as a callback. It uses an array of /// positions and computes the Manhattan distance between the two /// positions of two different indices. /// class ManhattanDistance { public ManhattanDistance( in DataModel data, in RoutingIndexManager manager) { // precompute distance between location to have distance callback in O(1) int locationNumber = data.Locations.GetLength(0); distancesMatrix_ = new long[locationNumber, locationNumber]; indexManager_ = manager; for (int fromNode = 0; fromNode < locationNumber; fromNode++) { for (int toNode = 0; toNode < locationNumber; toNode++) { if (fromNode == toNode) distancesMatrix_[fromNode, toNode] = 0; else distancesMatrix_[fromNode, toNode] = Math.Abs(data.Locations[toNode, 0] - data.Locations[fromNode, 0]) + Math.Abs(data.Locations[toNode, 1] - data.Locations[fromNode, 1]); } } } /// /// Returns the manhattan distance between the two nodes /// public long Call(long fromIndex, long toIndex) { // Convert from routing variable Index to distance matrix NodeIndex. int fromNode = indexManager_.IndexToNode(fromIndex); int toNode = indexManager_.IndexToNode(toIndex); return distancesMatrix_[fromNode, toNode]; } private long[,] distancesMatrix_; private RoutingIndexManager indexManager_; }; // [END manhattan_distance] // [START solution_printer] /// /// Print the solution. /// static void PrintSolution( in RoutingModel routing, in RoutingIndexManager manager, in Assignment solution) { Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); // Inspect solution. Console.WriteLine("Route for Vehicle 0:"); long routeDistance = 0; var index = routing.Start(0); 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); } // [END solution_printer] public static void Main(String[] args) { // Instantiate the data problem. // [START data] DataModel data = new DataModel(); // [END data] // Create Routing Index Manager // [START index_manager] RoutingIndexManager manager = new RoutingIndexManager( data.Locations.GetLength(0), data.VehicleNumber, data.Depot); // [END index_manager] // Create Routing Model. // [START routing_model] RoutingModel routing = new RoutingModel(manager); // [END routing_model] // Create and register a transit callback. // [START transit_callback] var distanceCallback = new ManhattanDistance(data, manager); int transitCallbackIndex = routing.RegisterTransitCallback(distanceCallback.Call); // [END transit_callback] // Define cost of each arc. // [START arc_cost] routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // [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] PrintSolution(routing, manager, solution); // [END print_solution] } } // [END program]