def test_k4(self): # good routes are 0,1,2,3 or 3,2,1,0 (and their rotations) G = nx.Graph() G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1), (3, 0, 1), (0, 2, 2), (1, 3, 2)]) Q = tsp.traveling_salesperson_qubo(G, lagrange=10) bqm = dimod.BinaryQuadraticModel.from_qubo(Q) # good routes won't have 0<->2 or 1<->3 min_routes = [(0, 1, 2, 3), (1, 2, 3, 0), (2, 3, 0, 1), (1, 2, 3, 0), (3, 2, 1, 0), (2, 1, 0, 3), (1, 0, 3, 2), (0, 3, 2, 1)] # get the min energy of the qubo sampleset = dimod.ExactSolver().sample(bqm) ground_energy = sampleset.first.energy # all possible routes are equally good for route in min_routes: sample = {v: 0 for v in bqm} for idx, city in enumerate(route): sample[(city, idx)] = 1 self.assertAlmostEqual(bqm.energy(sample), ground_energy) # all min-energy solutions are valid routes ground_count = 0 for sample, energy in sampleset.data(['sample', 'energy']): if abs(energy - ground_energy) > .001: break ground_count += 1 self.assertEqual(ground_count, len(min_routes))
def test_k4_equal_weights(self): # k5 with all equal weights so all paths are equally good G = nx.Graph() G.add_weighted_edges_from( (u, v, .5) for u, v in itertools.combinations(range(4), 2)) Q = tsp.traveling_salesperson_qubo(G, lagrange=10) bqm = dimod.BinaryQuadraticModel.from_qubo(Q) # all routes are min weight min_routes = list(itertools.permutations(G.nodes)) # get the min energy of the qubo sampleset = dimod.ExactSolver().sample(bqm) ground_energy = sampleset.first.energy # all possible routes are equally good for route in min_routes: sample = {v: 0 for v in bqm} for idx, city in enumerate(route): sample[(city, idx)] = 1 self.assertAlmostEqual(bqm.energy(sample), ground_energy) # all min-energy solutions are valid routes ground_count = 0 for sample, energy in sampleset.data(['sample', 'energy']): if abs(energy - ground_energy) > .001: break ground_count += 1 self.assertEqual(ground_count, len(min_routes))
def test_docstring_size(self): # in the docstring we state the size of the resulting BQM, this checks # that for n in range(3, 20): G = nx.Graph() G.add_weighted_edges_from( (u, v, .5) for u, v in itertools.combinations(range(n), 2)) Q = tsp.traveling_salesperson_qubo(G) bqm = dimod.BinaryQuadraticModel.from_qubo(Q) self.assertEqual(len(bqm), n**2) self.assertEqual(len(bqm.quadratic), 2 * n * n * (n - 1))
def test_weighted_complete_graph(self): G = nx.Graph() G.add_weighted_edges_from({(0, 1, 1), (0, 2, 100), (0, 3, 1), (1, 2, 1), (1, 3, 100), (2, 3, 1)}) lagrange = 5.0 Q = tsp.traveling_salesperson_qubo(G, lagrange, 'weight') N = G.number_of_nodes() correct_sum = G.size( 'weight') * 2 * N - 2 * N * N * lagrange + 2 * N * N * ( N - 1) * lagrange actual_sum = sum(Q.values()) self.assertEqual(correct_sum, actual_sum)
def test_exceptions(self): G = nx.Graph([(0, 1)]) with self.assertRaises(ValueError): tsp.traveling_salesperson_qubo(G)
def test_empty(self): Q = tsp.traveling_salesperson_qubo(nx.Graph()) self.assertEqual(Q, {})
def TSP_solver(G, token=None): """ The TSP_solver function actually uses Ocean SDK and a call to dwave's computer to solve the Traveling Salesperson Problem. :param G: This is the networkx graph to be solved. Usually the output of make_graph is directly plugged into this. :return: It returns the route as a List, a directed networkx graph, and the cost of the route. """ endpoint = 'https://cloud.dwavesys.com/sapi/' client = 'qpu' #solver = 'DW_2000Q_5' # Use this to specify a solver, but leave commented out to let D-Wave's system autochoose a solver try: qpu_sampler = DWaveSampler(client=client, endpoint=endpoint, token=token) #solver=solver) except Exception as e: print(e) return {'error': 'Token not accepted'} # Lagrange multiplier, to weigh the constraints versus the mileage lagrange = 8000 n = len(G) # Use dwave_networkx method to get the QUBO Q = traveling_salesperson_qubo(G, lagrange=lagrange) # Include the energy offset so that the energy comes out in miles offset = 2 * n * lagrange # Choose a sampler # sampler = TabuSampler() sampler = KerberosSampler() # Get a BQM and run the problem bqm = dimod.BinaryQuadraticModel.from_qubo(Q, offset=offset) # response = sampler.sample(bqm) response = sampler.sample(bqm, max_iter=1, convergence=1, qpu_sampler=qpu_sampler) # Turn the bitstring result into a trip/loop start = None sample = response.first.sample cost = response.first.energy route = [None] * n for (city, time), val in sample.items(): if val: route[time] = city if start is not None and route[0] != start: # rotate to put the start in front idx = route.index(start) route = route[-idx:] + route[:-idx] # If there is a valid solution, print it if None not in route: ans = nx.Graph() tmp_edges = [] for i in range(0, len(route) - 1): tmp_edges.append((route[i], route[i + 1], G.get_edge_data(route[i], route[i + 1]))) ans.add_weighted_edges_from(tmp_edges) print(route) print(cost) print(ans) else: print("No valid solution") route = None cost = None ans = None return route, cost, ans