Use this file to discover all available pages before exploring further.
View on GitHub
Open this notebook in GitHub to run it yourself
The “Travelling Salesman Problem” [1] refers to finding the shortest route between cities, given their relative distances. In a more general sense, given a weighted directed graph, find the shortest route along the graph that goes through all the cities, where the weights correspond to the distance between cities.For example, in the graph below, the route along 0→1→2→3 yields a total distance 3, which is the shortest:
As with many real world problems, this task can be cast as a combinatorial optimization problem.This demo shows how to employ the Quantum Approximate Optimization Algorithm [2] on the Classiq platform to solve the Travelling Salesperson Problem.
First, model the problem mathematically.The input is the set of distances between the cities: this is given by a matrix w, whose (i,j) entry refers to the distance between city i to city j.The output of the model is an optimized route.Any route can be captured by a binary matrix x that states at each step (row) which city was visited (column):xij={10at time step i the route is in city jelseFor example:x=0001100000100100means starting from city 1, going to city 3 and then to city 2, and ending at city
The constrained optimization problem is defined as follows:
Find x, which minimizes the path distance -$xi,p∈{0,1}minΣi,jwi,jΣpxi,pxj,p+1
(Note that the inner sum over $p$ is simply an indicator for whether to go from city $i$ to city $j$.)
such that
- each point is visited once -
$
\begin{aligned}
\forall i, \hspace{0.2cm} \Sigma_p x_{i, p} = 1\\
\end{aligned}
Building the Pyomo Model from a Matrix of Distances Input
import numpy as np # noqaimport pyomo.core as pyo
## Define a function that gets the matrix of distances and returns a Pyomo modeldef PyomoTSP(dis_mat: np.ndarray) -> pyo.ConcreteModel: model = pyo.ConcreteModel("TSP") assert dis_mat.shape[0] == dis_mat.shape[1], "error distance matrix is not square" NofCities = dis_mat.shape[0] # total number of cities cities = range(NofCities) # list of cities # Define the variable, which is the binary matrix x: x[i, j] = 1 indicates that point i is visited at step j model.x = pyo.Var(cities, cities, domain=pyo.Binary) # we add constraints @model.Constraint(cities) def each_step_visits_one_point_rule(model, ii): return sum(model.x[ii, jj] for jj in range(NofCities)) == 1 @model.Constraint(cities) def each_point_visited_once_rule(model, jj): return sum(model.x[ii, jj] for ii in range(NofCities)) == 1 # Define the Objective function def is_connected(i1: int, i2: int): return sum(model.x[i1, kk] * model.x[i2, kk + 1] for kk in cities[:-1]) model.cost = pyo.Objective( expr=sum( dis_mat[i1, i2] * is_connected(i1, i2) for i1, i2 in model.x.index_set() ) ) return model
Pick a specific problem: the graph introduced above:
# Generate a graph that defines the problemimport networkx as nxgraph = nx.DiGraph()graph.add_nodes_from([0, 1, 2, 3])graph.add_edges_from([(0, 1), (1, 2), (2, 1), (2, 3)], weight=1)graph.add_edges_from([(0, 2), (1, 3)], weight=2)pos = nx.planar_layout(graph)nx.draw_networkx(graph, pos=pos)labels = nx.get_edge_attributes(graph, "weight")nx.draw_networkx_edge_labels(graph, pos, edge_labels=labels);
Convert the graph object into a matrix of distances and then generate a Pyomo model for this example:
nonedge = 5 # this variable refers to how much we penalize for unconnected pointsdistance_matrix = nx.convert_matrix.to_numpy_array(graph, nonedge=nonedge)tsp_model = PyomoTSP(distance_matrix)
To solve the Pyomo model defined above, use the CombinatorialProblem Python class.Under the hood it translates the Pyomo model to a quantum model of QAOA [1], with the cost Hamiltonian translated from the Pyomo model.Choose the number of layers for the QAOA ansatz using the num_layers argument:
Synthesizing the QAOA Circuit and Solving the Problem
Synthesize and view the QAOA circuit (ansatz) used to solve the optimization problem:
qprog = combi.get_qprog()show(qprog)
Output:
Quantum program link: https://platform.classiq.io/circuit/2zJRXpc3YfcnB9t3wHdi4C956A7
Solve the problem by calling the optimize method of the CombinatorialProblem object.For the classical optimization part of QAOA, define the maximum number of classical iterations (maxiter) and the α-parameter (quantile) for running CVaR-QAOA, an improved variation of QAOA [2]: