Skip to content

Commit

Permalink
Merge pull request Qiskit#41 from IBM-Q-Software/jen-update-qka
Browse files Browse the repository at this point in the history
Jen update qka
  • Loading branch information
jenglick authored and GitHub Enterprise committed May 4, 2021
2 parents ca0b748 + fde0a5f commit 3b8bdcf
Show file tree
Hide file tree
Showing 11 changed files with 857 additions and 333 deletions.
502 changes: 323 additions & 179 deletions QKA_demo_outer.ipynb

Large diffs are not rendered by default.

Binary file added qka/aux_files/chip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
200 changes: 200 additions & 0 deletions qka/aux_files/dataset_graph10.csv

Large diffs are not rendered by default.

128 changes: 128 additions & 0 deletions qka/aux_files/dataset_graph7.csv

Large diffs are not rendered by default.

Binary file added qka/aux_files/subgraphs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 14 additions & 8 deletions qka/featuremaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ class FeatureMapACME:
def __init__(self, feature_dimension, entangler_map=None):
"""
Args:
feature_dimension (int): number of features
feature_dimension (int): number of features (twice the number of qubits for this encoding)
entangler_map (list[list]): connectivity of qubits with a list of [source, target], or None for full entanglement.
Note that the order in the list is the order of applying the two-qubit gate.
"""
self._feature_dimension = feature_dimension
self._num_qubits = self._feature_dimension = feature_dimension
self._depth = 1
self._copies = 1

if isinstance(feature_dimension, int):
if feature_dimension % 2 == 0:
self._feature_dimension = feature_dimension
else:
raise ValueError('Feature dimension must be an even integer.')
else:
raise ValueError('Feature dimension must be an even integer.')

self._num_qubits = int(feature_dimension/2)

if entangler_map is None:
self._entangler_map = [[i, j] for i in range(self._feature_dimension) for j in range(i + 1, self._feature_dimension)]
self._entangler_map = [[i, j] for i in range(self._num_qubits) for j in range(i + 1, self._num_qubits)]
else:
self._entangler_map = entangler_map

Expand Down Expand Up @@ -48,8 +54,8 @@ def construct_circuit(self, x=None, parameters=None, q=None, inverse=False, name
if len(parameters) != self._num_parameters:
raise ValueError('The number of feature map parameters must be {}.'.format(self._num_parameters))

if len(x) != 2*self._num_qubits:
raise ValueError('The input vector must be of length {}.'.format(2*self._num_qubits))
if len(x) != self._feature_dimension:
raise ValueError('The input vector must be of length {}.'.format(self._feature_dimension))

if q is None:
q = QuantumRegister(self._num_qubits, name='q')
Expand Down
55 changes: 36 additions & 19 deletions qka/kernel_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@
class KernelMatrix:
"""Build the kernel matrix from a quantum feature map."""

def __init__(self, feature_map, backend):
def __init__(self, feature_map, backend, initial_layout):
"""
Args:
feature_map (int): the feature map object
backend (Backend): the backend instance
initial layout: FINISH ME
"""

self._feature_map = feature_map
self._feature_map_circuit = self._feature_map.construct_circuit # the feature map circuit
self._backend = backend

if initial_layout is None:
raise ValueError('Provide an initial layout matching the problem graph.')
else:
self._initial_layout = initial_layout

self.results = {} # store the results object (program_data)

def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None):
Expand Down Expand Up @@ -47,9 +54,11 @@ def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None):
my_product_list = list(itertools.combinations(range(len(x1_vec)), 2)) # all pairwise combos of datapoint indices
for index_1, index_2 in my_product_list:

circuit = self._feature_map_circuit(x=x1_vec[index_1], parameters=parameters, name='{}_{}'.format(index_1, index_2))
circuit += self._feature_map_circuit(x=x1_vec[index_2], parameters=parameters, inverse=True)
circuit_1 = self._feature_map_circuit(x=x1_vec[index_1], parameters=parameters, name='{}_{}'.format(index_1, index_2))
circuit_2 = self._feature_map_circuit(x=x1_vec[index_2], parameters=parameters, inverse=True)
circuit = circuit_1.compose(circuit_2)
circuit.measure_all()

experiments.append(circuit)

program_data = self._run_circuits(experiments)
Expand All @@ -64,16 +73,18 @@ def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None):
mat[index_1][index_2] = counts.get(measurement_basis, 0) / shots # kernel matrix element is the probability of measuring all 0s
mat[index_2][index_1] = mat[index_1][index_2] # kernel matrix is symmetric

return mat ** self._feature_map._copies
return mat

else:

for index_1, point_1 in enumerate(x1_vec):
for index_2, point_2 in enumerate(x2_vec):

circuit = self._feature_map_circuit(x=point_1, parameters=parameters, name='{}_{}'.format(index_1, index_2))
circuit += self._feature_map_circuit(x=point_2, parameters=parameters, inverse=True)
circuit_1 = self._feature_map_circuit(x=point_1, parameters=parameters, name='{}_{}'.format(index_1, index_2))
circuit_2 = self._feature_map_circuit(x=point_2, parameters=parameters, inverse=True)
circuit = circuit_1.compose(circuit_2)
circuit.measure_all()

experiments.append(circuit)

program_data = self._run_circuits(experiments)
Expand All @@ -90,19 +101,25 @@ def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None):
mat[index_1][index_2] = counts.get(measurement_basis, 0) / shots
i += 1

return mat ** self._feature_map._copies
return mat

def _run_circuits(self, circuits):
"""Execute the input circuits."""
try:
provider = self._backend.provider()
runtime_params = {'circuits': circuits, 'shots': 8192}
options = {'backend_name': self._backend.name()}
return provider.runtime.run(program_id="circuit-runner",
options=options,
inputs=runtime_params,
).result()
except Exception:
# Fall back to run without runtime.
transpiled = transpile(circuits, backend=self._backend)
return self._backend.run(transpiled, shots=8192).result()

transpiled = transpile(circuits, backend=self._backend, initial_layout=self._initial_layout)
return self._backend.run(transpiled, shots=8192).result()

# try:
# provider = self._backend.provider()
# runtime_params = {'circuits': circuits, 'shots': 8192, 'initial_layout': self._initial_layout}
# options = {'backend_name': self._backend.name()}
# job = provider.runtime.run(program_id="circuit-runner",
# options=options,
# inputs=runtime_params
# )
# return job.result()
#
# except Exception:
# # Fall back to run without runtime.
# transpiled = transpile(circuits, backend=self._backend, initial_layout=self._initial_layout)
# return self._backend.run(transpiled, shots=8192).result()
11 changes: 4 additions & 7 deletions qka/qka.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,26 @@
class QKA:
"""The quantum kernel alignment algorithm."""

def __init__(self, feature_map, backend, verbose=True):
def __init__(self, feature_map, backend, initial_layout, verbose=True):
"""Constructor.
Args:
feature_map (partial obj): the quantum feature map object
backend (Backend): the backend instance
initial_layout: FINISH ME
verbose (bool): print output during course of algorithm
"""

self.feature_map = feature_map
self.feature_map_circuit = self.feature_map.construct_circuit # the feature map circuit not yet evaluated with input arguments
self.backend = backend
self.num_qubits = self.feature_map._num_qubits
self.depth = self.feature_map._depth
self.entangler_map = self.feature_map._entangler_map
self.initial_layout = initial_layout
self.num_parameters = self.feature_map._num_parameters # number of parameters (lambdas) in the feature map

self.verbose = verbose
self.result = {}

self.kernel_matrix = KernelMatrix(feature_map=self.feature_map, backend=self.backend)
self.kernel_matrix = KernelMatrix(feature_map=self.feature_map, backend=self.backend, initial_layout=self.initial_layout)



Expand Down Expand Up @@ -186,14 +185,12 @@ def align_kernel(self, data, labels, initial_kernel_parameters=None, maxiters=10
# Pre-computed spsa parameters:
spsa_params = self.SPSA_parameters()

# Save data at each SPSA run in the following lists:
lambda_save = [] # updated kernel parameters after each spsa step
cost_final_save = [] # avgerage cost at each spsa step
cost_plus_save = [] # (+) cost at each spsa step
cost_minus_save = [] # (-) cost at each spsa step
program_data = []


# #####################
# Start the alignment:

Expand Down
96 changes: 76 additions & 20 deletions qka/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,87 @@
octave.addpath('/Users/jen/Q/code/quantum_kernel_data')


# configure settings for the tony line:
num_features=10 # number of features in the input data
num_train=10 # number of training samples per class
num_test=10 # number of test samples per class
C=1 # SVM soft-margin penalty
maxiters=21 # number of SPSA iterations

entangler_map=[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]]

# Generate the data:
state=42 # setting the state for the random number generator
data_plus, data_minus = octave.generate_data(num_train+num_test, state, nout=2)

x_train = np.concatenate((data_plus.T[:num_train], data_minus.T[:num_train]))
y_train = np.concatenate((-1*np.ones(num_train), np.ones(num_train)))

x_test = np.concatenate((data_plus.T[num_train:], data_minus.T[num_train:]))
y_test = np.concatenate((-1*np.ones(num_test), np.ones(num_test)))

# save data to csv:
# samples = 64 # per label
# features=2*7
# state=42 # setting the state for the random number generator
#
# data_plus, data_minus = octave.generate_data(samples, state, nout=2)
#
# dat = np.empty((samples*2, features))
# dat[::2,:] = data_plus.T
# dat[1::2,:] = data_minus.T
#
# lab = np.reshape(np.asarray([1,-1]*samples), (samples*2,1))
# full = np.concatenate((dat, lab), axis=1)
#
# np.savetxt("/Users/jen/Q/code/quantum_kernel_data/dataset_graph7.csv", full, delimiter=",")
# print('done')

# load data from csv:
import pandas as pd
df = pd.read_csv('/Users/jen/Q/code/quantum_kernel_data/dataset_graph7.csv',sep = ',', header = None)
dat = df.values

num_features = np.shape(dat)[1]-1 # feature dimension determined by dataset
num_train = 10
num_test = 10
C = 1
maxiters = 11

entangler_map=[[0,2],[3,4],[2,5],[1,4],[2,3],[4,6]]
initial_layout=[10,11,12,13,14,15,16]

x_train = dat[:2*num_train, :-1]
y_train = dat[:2*num_train, -1]

x_test = dat[2*num_train:2*(num_train+num_test), :-1]
y_test = dat[2*num_train:2*(num_train+num_test), -1]





# configure settings for the problem graph:
# num_features=2*7 # number of features in the input data
# num_train=10 # number of training samples per class
# num_test=10 # number of test samples per class
# C=1 # SVM soft-margin penalty
# maxiters=11 # number of SPSA iterations
#
# entangler_map=[[0,2],[3,4],[2,5],[1,4],[2,3],[4,6]]
# initial_layout=[10,11,12,13,14,15,16]
#
# # entangler_map=[[0,1],[1,2],[1,3]]
# # initial_layout=[0,1,2,4]
#
# # entangler_map=[[0,1],[2,3],[4,5],[6,7],[8,9],[1,2],[3,4],[5,6],[7,8]]
# # initial_layout = [9, 8, 11, 14, 16, 19, 22, 25, 24, 23]
#
#
# # Generate the data:
# state=42 # setting the state for the random number generator
# data_plus, data_minus = octave.generate_data(num_train+num_test, state, nout=2)
#
# x_train = np.concatenate((data_plus.T[:num_train], data_minus.T[:num_train]))
# y_train = np.concatenate((-1*np.ones(num_train), np.ones(num_train)))
#
# x_test = np.concatenate((data_plus.T[num_train:], data_minus.T[num_train:]))
# y_test = np.concatenate((-1*np.ones(num_test), np.ones(num_test)))






# Specify the backend
bk = Aer.get_backend('qasm_simulator')

# Define the feature map and its initial parameters:
initial_kernel_parameters = [0.1] # np.pi/2 should yield 100% test accuracy
fm = FeatureMapACME(feature_dimension=num_features, entangler_map=entangler_map)
km = KernelMatrix(feature_map=fm, backend=bk)
km = KernelMatrix(feature_map=fm, backend=bk, initial_layout=initial_layout)

# Train and test the initial kernel:
kernel_init_train = km.construct_kernel_matrix(x1_vec=x_train, x2_vec=x_train, parameters=initial_kernel_parameters)
Expand All @@ -48,7 +104,7 @@
print('Initial Kernel | Balanced Test Accuracy: {}'.format(accuracy_test))

# Align the parametrized kernel:
qka = QKA(feature_map=fm, backend=bk)
qka = QKA(feature_map=fm, backend=bk, initial_layout=initial_layout)
qka_results = qka.align_kernel(data=x_train, labels=y_train,
initial_kernel_parameters=initial_kernel_parameters,
maxiters=maxiters, C=C)
Expand Down
2 changes: 1 addition & 1 deletion runtime/circuit_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def main(backend, user_messenger, circuits,

# Compute raw results
result = backend.run(circuits, **kwargs).result()

# Do the actual mitigation here
if measurement_error_mitigation:
quasi_probs = []
Expand Down
Loading

0 comments on commit 3b8bdcf

Please sign in to comment.