All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.alg.tour.NearestNeighborHeuristicTSP Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2019-2023, by Peter Harman and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.alg.tour;

import org.jgrapht.*;

import java.util.*;

import static org.jgrapht.util.ArrayUtil.*;

/**
 * The nearest neighbour heuristic algorithm for the TSP problem.
 *
 * 

* The travelling salesman problem (TSP) asks the following question: "Given a list of cities and * the distances between each pair of cities, what is the shortest possible route that visits each * city exactly once and returns to the origin city?". *

* *

* This is perhaps the simplest and most straightforward TSP heuristic. The key to this algorithm is * to always visit the nearest city. *

* *

* The tour computed with a {@code Nearest-Neighbor-Heuristic} can vary depending on the first * vertex visited. The first vertex for the next or for multiple subsequent tour computations (calls * of {@link #getTour(Graph)}) can be specified in the constructors * {@link #NearestNeighborHeuristicTSP(Object)} or {@link #NearestNeighborHeuristicTSP(Iterable)}. * This can be used for example to ensure that the first vertices visited are different for * subsequent calls of {@code getTour(Graph)}. Once each specified first vertex is used, the first * vertex in subsequent tour computations is selected randomly from the graph. Alternatively * {@link #NearestNeighborHeuristicTSP(Random)} or {@link #NearestNeighborHeuristicTSP(long)} can be * used to specify a {@code Random} used to randomly select the vertex visited first. *

* *

* The implementation of this class is based on:
* Nilsson, Christian. "Heuristics for the traveling salesman problem." Linkoping University 38 * (2003) *

* *

* The runtime complexity of this class is $O(V^2)$. *

* *

* This algorithm requires that the graph is complete. *

* * @param the graph vertex type * @param the graph edge type * * @author Peter Harman * @author Hannes Wellmann */ public class NearestNeighborHeuristicTSP extends HamiltonianCycleAlgorithmBase { private Random rng; /** Nulled, if it has no next */ private Iterator initiaVertex; /** * Constructor. By default a random vertex is chosen to start. */ public NearestNeighborHeuristicTSP() { this(null, new Random()); } /** * Constructor * * @param first First vertex to visit * @throws NullPointerException if first is null */ public NearestNeighborHeuristicTSP(V first) { this( Collections.singletonList( Objects.requireNonNull(first, "Specified initial vertex cannot be null")), new Random()); } /** * Constructor * * @param initialVertices The Iterable of vertices visited first in subsequent tour computations * (per call of {@link #getTour(Graph)} another vertex of the Iterable is used as first) * @throws NullPointerException if first is null */ public NearestNeighborHeuristicTSP(Iterable initialVertices) { this( Objects.requireNonNull(initialVertices, "Specified initial vertices cannot be null"), new Random()); } /** * Constructor * * @param seed seed for the random number generator */ public NearestNeighborHeuristicTSP(long seed) { this(null, new Random(seed)); } /** * Constructor * * @param rng Random number generator * @throws NullPointerException if rng is null */ public NearestNeighborHeuristicTSP(Random rng) { this(null, Objects.requireNonNull(rng, "Random number generator cannot be null")); } /** * Constructor * * @param initialVertices The Iterable of vertices visited first in subsequent tour * computations, or null to choose at random * @param rng Random number generator */ private NearestNeighborHeuristicTSP(Iterable initialVertices, Random rng) { if (initialVertices != null) { Iterator iterator = initialVertices.iterator(); this.initiaVertex = iterator.hasNext() ? iterator : null; } this.rng = rng; } // algorithm /** * Computes a tour using the nearest neighbour heuristic. * * @param graph the input graph * @return a tour * @throws IllegalArgumentException if the graph is not undirected * @throws IllegalArgumentException if the graph is not complete * @throws IllegalArgumentException if the graph contains no vertices * @throws IllegalArgumentException if the specified initial vertex is not in the graph */ @Override public GraphPath getTour(Graph graph) { checkGraph(graph); if (graph.vertexSet().size() == 1) { return getSingletonTour(graph); } Set vertexSet = graph.vertexSet(); int n = vertexSet.size(); @SuppressWarnings("unchecked") V[] path = (V[]) vertexSet.toArray(new Object[n + 1]); List pathList = Arrays.asList(path); // List backed by path-array // move initial vertex to the beginning int initalIndex = getFirstVertexIndex(pathList); swap(path, 0, initalIndex); // search nearest neighbors int limit = n - 1; // last vertex won't be changed -> no need to check it for (int i = 1; i < limit; i++) { V v = path[i - 1]; // path before i is established. The element at i must be the closest to element at i-1. // -> get nearest of remaining elements (index >= i) and set it as next in path int nearestNeighbor = getNearestNeighbor(v, path, i, graph); swap(path, i, nearestNeighbor); } path[n] = path[0]; // close tour manually. Arrays.asList does not support add return closedVertexListToTour(pathList, graph); } /** * Returns the start vertex of the tour about to compute. * * @param path the initial path, containing all vertices in unspecified order * @return the vertex to start with * @throws IllegalArgumentException if the specified initial vertex is not in the graph */ private int getFirstVertexIndex(List path) { if (initiaVertex != null) { V first = initiaVertex.next(); if (!initiaVertex.hasNext()) { initiaVertex = null; // release the resource backing the iterator immediately } int initialIndex = path.indexOf(first); if (initialIndex < 0) { throw new IllegalArgumentException("Specified initial vertex is not in graph"); } return initialIndex; } else { // first not specified return rng.nextInt(path.size() - 1); // path has size n+1 } } /** * Find the vertex in the range staring at {@code from} that is closest to the element at index * from-1. * * @param current the vertex for which the nearest neighbor is searched * @param vertices the vertices of the graph. The unvisited neighbors start at index * {@code start} * @param start the index of the first vertex to consider * @param g the graph containing the vertices * * @return the index of the unvisited vertex closest to the vertex at firstNeighbor-1. */ private static int getNearestNeighbor(V current, V[] vertices, int start, Graph g) { int closest = -1; double minDist = Double.MAX_VALUE; int n = vertices.length - 1; // last element in vertices is null for (int i = start; i < n; i++) { V v = vertices[i]; double vDist = g.getEdgeWeight(g.getEdge(current, v)); if (vDist < minDist) { closest = i; minDist = vDist; } } return closest; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy