Initialization#

from juniqutils import save_ising_file, load_ising_file
import os
import json
import numpy as np
import pandas as pd
import dimod
from collections import defaultdict
np.__version__, pd.__version__, dimod.__version__
('2.3.2', '2.3.1', '0.12.20')

Generation#

Problem specification#

TSP_DATA = json.load(open('tsp_data.json'))
CITIES = TSP_DATA['CITIES']
CITIES
['Berlin',
 'Madrid',
 'Rome',
 'Paris',
 'Vienna',
 'Warsaw',
 'Hamburg',
 'Bucharest',
 'Budapest',
 'Barcelona',
 'Munich',
 'Milan',
 'Sofia',
 'Prague',
 'Cologne',
 'Stockholm',
 'Amsterdam',
 'Naples',
 'Marseille',
 'Turin',
 'Krakow',
 'Valencia',
 'Zagreb',
 'Frankfurt',
 'Seville']
COSTS = pd.read_csv('tsp_costs.csv').set_index('City',drop=True)
COSTS
Berlin Madrid Rome Paris Vienna Warsaw Hamburg Bucharest Budapest Barcelona ... Stockholm Amsterdam Naples Marseille Turin Krakow Valencia Zagreb Frankfurt Seville
City
Berlin 0.00 23.25 15.68 11.01 7.28 5.95 3.10 17.93 8.93 18.63 ... 12.48 6.89 17.47 15.40 12.32 6.50 21.82 11.04 5.89 27.51
Madrid 23.25 0.00 19.97 12.56 24.33 28.34 21.53 33.89 24.96 6.31 ... 32.68 17.65 21.63 10.83 14.83 27.50 3.75 22.09 17.91 5.16
Rome 15.68 19.97 0.00 14.37 11.50 18.05 17.57 21.00 12.03 14.29 ... 27.67 17.12 2.42 9.73 7.27 16.10 17.40 9.14 13.19 23.54
Paris 11.01 12.56 14.37 0.00 12.67 15.87 9.49 23.83 14.86 10.33 ... 20.51 5.59 15.98 7.57 8.16 15.42 13.45 14.14 5.84 16.97
Vienna 7.28 24.33 11.50 12.67 0.00 6.91 9.92 11.50 2.53 18.04 ... 19.17 11.91 12.98 14.29 10.15 5.03 21.24 4.09 7.65 27.34
Warsaw 5.95 28.34 18.05 15.87 6.91 0.00 8.46 17.14 8.50 23.20 ... 17.05 11.96 19.57 19.96 16.79 3.51 26.38 10.68 10.84 32.48
Hamburg 3.10 21.53 17.57 9.49 9.92 8.46 0.00 20.61 11.64 17.99 ... 11.52 4.95 19.41 14.76 13.20 9.19 21.18 13.21 5.41 25.94
Bucharest 17.93 33.89 21.00 23.83 11.50 17.14 20.61 0.00 9.40 28.63 ... 30.21 23.47 22.92 23.95 19.95 13.93 31.70 12.00 19.16 37.67
Budapest 8.93 24.96 12.03 14.86 2.53 8.50 11.64 9.40 0.00 19.30 ... 20.77 13.97 13.60 14.91 10.87 5.98 22.48 3.48 9.88 28.62
Barcelona 18.63 6.31 14.29 10.33 18.04 23.20 17.99 28.63 19.30 0.00 ... 29.80 15.18 16.02 5.26 9.21 22.15 3.70 16.51 13.38 9.80
Munich 6.09 19.43 9.75 8.54 4.53 10.65 8.07 15.96 6.76 13.82 ... 18.12 8.51 11.53 10.54 7.00 9.09 16.93 5.88 4.24 23.12
Milan 11.39 16.09 6.12 8.87 8.86 15.45 12.27 18.54 9.47 10.57 ... 23.55 11.57 7.71 6.10 2.01 13.70 13.61 6.68 7.46 19.71
Sofia 16.67 30.03 17.09 22.08 10.35 16.32 19.48 5.29 8.17 24.53 ... 28.77 21.97 18.71 20.04 16.01 13.96 27.65 8.44 17.88 33.75
Prague 3.91 22.35 13.67 10.58 3.52 7.22 6.59 14.21 5.13 17.29 ... 15.73 8.93 15.34 13.92 10.55 5.40 20.34 7.30 5.54 26.44
Cologne 6.09 17.41 14.62 5.24 9.36 11.16 4.57 20.87 11.59 13.91 ... 16.06 2.95 16.29 11.55 9.92 11.20 17.97 11.36 2.18 21.83
Stockholm 12.48 32.68 27.67 20.51 19.17 17.05 11.52 30.21 20.77 29.80 ... 0.00 16.02 29.51 26.05 24.44 17.88 32.47 22.97 16.52 37.08
Amsterdam 6.89 17.65 17.12 5.59 11.91 11.96 4.95 23.47 13.97 15.18 ... 16.02 0.00 18.81 12.25 12.46 12.44 18.50 13.93 4.76 22.03
Naples 17.47 21.63 2.42 15.98 12.98 19.57 19.41 22.92 13.60 16.02 ... 29.51 18.81 0.00 11.38 8.93 17.85 19.05 10.84 14.69 25.16
Marseille 15.40 10.83 9.73 7.57 14.29 19.96 14.76 23.95 14.91 5.26 ... 26.05 12.25 11.38 0.00 4.98 18.96 8.38 11.98 10.00 14.48
Turin 12.32 14.83 7.27 8.16 10.15 16.79 13.20 19.95 10.87 9.21 ... 24.44 12.46 8.93 4.98 0.00 14.79 12.23 7.85 8.26 18.33
Krakow 6.50 27.50 16.10 15.42 5.03 3.51 9.19 13.93 5.98 22.15 ... 17.88 12.44 17.85 18.96 14.79 0.00 25.39 8.77 9.97 31.49
Valencia 21.82 3.75 17.40 13.45 21.24 26.38 21.18 31.70 22.48 3.70 ... 32.47 18.50 19.05 8.38 12.23 25.39 0.00 19.83 16.48 6.51
Zagreb 11.04 22.09 9.14 14.14 4.09 10.68 13.21 12.00 3.48 16.51 ... 22.97 13.93 10.84 11.98 7.85 8.77 19.83 0.00 9.60 25.70
Frankfurt 5.89 17.91 13.19 5.84 7.65 10.84 5.41 19.16 9.88 13.38 ... 16.52 4.76 14.69 10.00 8.26 9.97 16.48 9.60 0.00 22.49
Seville 27.51 5.16 23.54 16.97 27.34 32.48 25.94 37.67 28.62 9.80 ... 37.08 22.03 25.16 14.48 18.33 31.49 6.51 25.70 22.49 0.00

25 rows × 25 columns

Generate and save problems#

def build_qubo_time_encoding(n, scale):
    Q = defaultdict(float)
    offset = 0
    # cost function
    for i in range(n):
        for j in range(n):
            if j != i:
                for t in range(n):
                    k = i*n + t
                    l = j*n + (t + 1) % n
                    Q[k,l] += scale * COSTS.loc[CITIES[i]][CITIES[j]]
    # first constraint
    for i in range(n):
        for t1 in range(n):
            for t2 in range(n):
                k = i*n + t1
                l = i*n + t2
                Q[k,l] += 1
        for t in range(n):
            k = i*n + t
            Q[k,k] += -2
        offset += 1
    # second constraint
    for t in range(n):
        for i in range(n):
            for j in range(n):
                k = i*n + t
                l = j*n + t
                Q[k,l] += 1
        for i in range(n):
            k = i*n + t
            Q[k,k] += -2
        offset += 1
    return Q,offset
problems = defaultdict(list)
for instance,n in enumerate(range(3,len(CITIES)+1)):
    
    # generate BQM
    scale = 0.01  # if the constraints are satisifed, energy / scale will be the total drive time in hours
    Q,offset = build_qubo_time_encoding(n, scale=scale)
    variablemap = {i*n+t: f'x{i},{t}' for i in range(n) for t in range(n)}  # x_i,t = 1  <=>  traveller will be at city i at time t
    bqm = dimod.BQM.from_qubo(Q, offset)
    bqm.change_vartype(dimod.SPIN)
    bqm.relabel_variables(variablemap)
    nqubits = bqm.num_variables
    ncouplers = bqm.num_interactions
    nvalid = 2*n
    noptimal = 2

    # store optimum reference for benchmark
    tour = [CITIES.index(c) for c in TSP_DATA['OPTIMAL_TOURS'][f'{n}']]
    optimum = sum(COSTS.loc[CITIES[tour[i]]][CITIES[tour[(i+1)%n]]] for i in range(len(tour)))

    # generate information for save_ising_file
    hs, Js, offset = bqm.to_ising()
    qubitmap = {value: key for key,value in variablemap.items()}
    cities = CITIES[:n]
    metadata = {
        'n': n,
        'nqubits': nqubits,
        'ncouplers': ncouplers,
        'nvalid': nvalid,
        'noptimal': noptimal,
        'lambda': scale,
        'optimal_energy': optimum*scale,
        'optimal_cost': optimum,
        'optimal_tour': tour,
        'cities': cities,
        'scale': scale,
    }   
    filename = save_ising_file(instance, hs, Js, offset, qubitmap, metadata)
    print(f'Generated {filename}')

    # gather information for each problem
    problems['filename'].append(filename)
    problems['instance'].append(instance)
    problems['n'].append(n)
    problems['nqubits'].append(nqubits)
    problems['ncouplers'].append(ncouplers)
    problems['nvalid'].append(nvalid)
    problems['noptimal'].append(noptimal)
    problems['lambda'].append(scale)
    problems['optimal_energy'].append(optimum*scale)
    problems['optimal_cost'].append(optimum)
    problems['optimal_tour'].append(tour)
    problems['cities'].append(cities)
    problems['scale'].append(scale)
Generated ../problems/000.ising
Generated ../problems/001.ising
Generated ../problems/002.ising
Generated ../problems/003.ising
Generated ../problems/004.ising
Generated ../problems/005.ising
Generated ../problems/006.ising
Generated ../problems/007.ising
Generated ../problems/008.ising
Generated ../problems/009.ising
Generated ../problems/010.ising
Generated ../problems/011.ising
Generated ../problems/012.ising
Generated ../problems/013.ising
Generated ../problems/014.ising
Generated ../problems/015.ising
Generated ../problems/016.ising
Generated ../problems/017.ising
Generated ../problems/018.ising
Generated ../problems/019.ising
Generated ../problems/020.ising
Generated ../problems/021.ising
Generated ../problems/022.ising
pd.DataFrame(problems).set_index('instance',drop=True)
filename n nqubits ncouplers nvalid noptimal lambda optimal_energy optimal_cost optimal_tour cities scale
instance
0 ../problems/000.ising 3 9 36 6 2 0.01 0.5890 58.90 [0, 1, 2] [Berlin, Madrid, Rome] 0.01
1 ../problems/001.ising 4 16 96 8 2 0.01 0.5922 59.22 [0, 2, 1, 3] [Berlin, Madrid, Rome, Paris] 0.01
2 ../problems/002.ising 5 25 200 10 2 0.01 0.6232 62.32 [0, 3, 1, 2, 4] [Berlin, Madrid, Rome, Paris, Vienna] 0.01
3 ../problems/003.ising 6 36 360 12 2 0.01 0.6790 67.90 [0, 3, 1, 2, 4, 5] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw] 0.01
4 ../problems/004.ising 7 49 588 14 2 0.01 0.6948 69.48 [0, 5, 4, 2, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
5 ../problems/005.ising 8 64 896 16 2 0.01 0.9048 90.48 [0, 5, 4, 7, 2, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
6 ../problems/006.ising 9 81 1296 18 2 0.01 0.9091 90.91 [0, 5, 4, 7, 8, 2, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
7 ../problems/007.ising 10 100 1800 20 2 0.01 0.9154 91.54 [0, 5, 4, 7, 8, 2, 9, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
8 ../problems/008.ising 11 121 2420 22 2 0.01 0.9505 95.05 [0, 5, 7, 8, 4, 10, 2, 9, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
9 ../problems/009.ising 12 144 3168 24 2 0.01 0.9745 97.45 [0, 5, 7, 8, 4, 10, 2, 11, 9, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
10 ../problems/010.ising 13 169 4056 26 2 0.01 1.0151 101.51 [0, 5, 7, 12, 8, 4, 10, 2, 11, 9, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
11 ../problems/011.ising 14 196 5096 28 2 0.01 1.0428 104.28 [0, 5, 13, 10, 4, 8, 7, 12, 2, 11, 9, 1, 3, 6] [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
12 ../problems/012.ising 15 225 6300 30 2 0.01 1.0460 104.60 [0, 5, 13, 10, 4, 8, 7, 12, 2, 11, 9, 1, 3, 14... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
13 ../problems/013.ising 16 256 7680 32 2 0.01 1.2550 125.50 [0, 5, 13, 10, 4, 8, 7, 12, 2, 11, 9, 1, 3, 14... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
14 ../problems/014.ising 17 289 9248 34 2 0.01 1.2880 128.80 [0, 5, 13, 10, 4, 8, 7, 12, 2, 11, 9, 1, 3, 16... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
15 ../problems/015.ising 18 324 11016 36 2 0.01 1.3281 132.81 [0, 5, 13, 10, 4, 8, 7, 12, 2, 17, 11, 9, 1, 3... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
16 ../problems/016.ising 19 361 12996 38 2 0.01 1.3360 133.60 [0, 5, 13, 10, 4, 8, 7, 12, 2, 17, 11, 18, 9, ... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
17 ../problems/017.ising 20 400 15200 40 2 0.01 1.3449 134.49 [0, 5, 13, 10, 4, 8, 7, 12, 2, 17, 11, 19, 18,... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
18 ../problems/018.ising 21 441 17640 42 2 0.01 1.3513 135.13 [0, 5, 20, 7, 12, 8, 4, 13, 10, 2, 17, 11, 19,... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
19 ../problems/019.ising 22 484 20328 44 2 0.01 1.3627 136.27 [0, 5, 20, 7, 12, 8, 4, 13, 10, 2, 17, 11, 19,... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
20 ../problems/020.ising 23 529 23276 46 2 0.01 1.3781 137.81 [0, 5, 20, 13, 10, 4, 8, 7, 12, 22, 2, 17, 11,... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
21 ../problems/021.ising 24 576 26496 48 2 0.01 1.4039 140.39 [0, 6, 15, 5, 20, 4, 8, 7, 12, 22, 2, 17, 11, ... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01
22 ../problems/022.ising 25 625 30000 50 2 0.01 1.4831 148.31 [0, 6, 15, 5, 20, 4, 8, 7, 12, 22, 2, 17, 11, ... [Berlin, Madrid, Rome, Paris, Vienna, Warsaw, ... 0.01