def main(data_choice='random_vertical_boundary'): # For Moons dataset, noise = 0.05 is added. data_train, data_test, true_labels_train, true_labels_test = generate_data( data_choice, num_points=1024, split=True) true_labels_test_flip = [] for label in true_labels_test: if label == 0: true_labels_test_flip.append(1) elif label == 1: true_labels_test_flip.append(0) else: raise ValueError('This label does not exist') plot_params_train = { 'colors': ['blue', 'magenta'], 'alpha': 0.5, 'size': 80 } scatter(data_train, true_labels_train, **plot_params_train, show=False) plot_params_test = { 'colors': ['blue', 'magenta'], 'alpha': 1, 'size': 40, 'linewidth': 1.5 } scatter(data_test, true_labels_test, true_labels_test_flip, **plot_params_test, show=False) plt.show()
def main(encoding='denseangle_param'): qc_name = '1q-qvm' qc = get_qc(qc_name) num_shots = 1024 device_qubits = qc.qubits() classifier_qubits = device_qubits if encoding.lower() == 'wavefunction_param': params = np.array([0.45811744, 0.2575122, 0.52902198]) else: params = np.random.rand(3) n_layers = 1 if encoding.lower() == 'denseangle_param': encoding_choice = 'denseangle_param' init_encoding_params = [np.pi, 2*np.pi] elif encoding.lower() == 'wavefunction_param': encoding_choice = 'wavefunction_param' init_encoding_params = [0] elif encoding.lower() == 'superdenseangle_param': encoding_choice = 'superdenseangle_param' init_encoding_params = [np.pi, 2*np.pi] else: raise NotImplementedError ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary ''' data_choice = 'full_vertical_boundary' num_grid_points = 2000 data_grid, grid_true_labels = generate_data(data_choice, num_grid_points) data_grid, grid_true_labels = remove_zeros(data_grid, grid_true_labels) predicted_labels_grid = ClassificationCircuit(classifier_qubits, data_grid).make_predictions(params, n_layers, encoding_choice, init_encoding_params, \ num_shots, qc) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1, 'size': 70} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show()
def main(train=False, retrain=False, data_choice='moons', noise_choice='amp_damp_before_measurement', noise_values=0.3): ### Firstly, generate the dataset: data_train, data_test, true_labels_train, true_labels_test = generate_data( data_choice, num_points=500, split=True) data_train, true_labels_train = remove_zeros(data_train, true_labels_train) data_test, true_labels_test = remove_zeros(data_test, true_labels_test) encodings = [ 'denseangle_param', 'wavefunction_param', 'superdenseangle_param' ] minimal_costs, ideal_costs, noisy_costs, noisy_costs_uncorrected = [ np.ones(len(encodings)) for _ in range(4) ] qc_name = '1q-qvm' n_layers = 1 qc = get_qc(qc_name) num_shots = 1024 classifier_qubits = qc.qubits() init_params = np.random.rand(3) ideal_params = [] ideal_encoding_params = [] init_encoding_params = [] for ii, encoding_choice in enumerate(encodings): print('\n**********************************') print('\nThe encoding is:', encoding_choice) print('\n**********************************') if encoding_choice.lower() == 'wavefunction_param': init_encoding_params.append( [0] ) # Generalized Wavefunction Encoding initialised to Wavefunction encoding else: init_encoding_params.append([np.pi, 2 * np.pi]) if train: optimiser = 'Powell' params, result_unitary_param = train_classifier( qc, num_shots, init_params, encoding_choice, init_encoding_params[ii], optimiser, data_train, true_labels_train) print('The optimised parameters are:', result_unitary_param.x) print( 'These give a cost of:', ClassificationCircuit(classifier_qubits, data_train).build_classifier( result_unitary_param.x, encoding_choice, init_encoding_params[ii], num_shots, qc, true_labels_train)) ideal_params.append(result_unitary_param.x) else: if data_choice.lower() == 'moons': if encoding_choice.lower() == 'denseangle_param': ideal_params.append([2.19342064, 1.32972029, -0.18308298]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append([-0.27365492, 0.83278854, 3.00092961]) elif encoding_choice.lower() == 'wavefunction': ideal_params.append([0.81647273, 0.41996708, 2.20603541]) elif encoding_choice.lower() == 'wavefunction_param': ideal_params.append([0.81647273, 0.41996708, 2.20603541]) elif data_choice.lower() == 'random_vertical_boundary': if encoding_choice.lower() == 'denseangle_param': ideal_params.append([1.67814786, 1.56516469, 1.77820848]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append([1.60642225, 0.23401504, 5.69422628]) elif encoding_choice.lower() == 'wavefunction': ideal_params.append([0.96291484, 0.18133714, 0.35436732]) elif encoding_choice.lower() == 'wavefunction_param': ideal_params.append([0.96291484, 0.18133714, 0.35436732]) elif data_choice.lower() == 'random_diagonal_boundary': if encoding_choice.lower() == 'denseangle_param': ideal_params.append([0.8579214, 1.22952647, 4.99408074]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append([2.0101407, 1.05916291, 1.14570489]) elif encoding_choice.lower() == 'wavefunction': ideal_params.append([0.69409285, 0.0862859, 0.42872711]) elif encoding_choice.lower() == 'wavefunction_param': ideal_params.append([0.69409285, 0.0862859, 0.42872711]) else: print('THIS DATASET HAS NOT BEEN TRAINED FOR') if encoding_choice.lower() == 'denseangle_param': ideal_params.append(init_params) elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append(init_params) elif encoding_choice.lower() == 'wavefunction': ideal_params.append(init_params) elif encoding_choice.lower() == 'wavefunction_param': ideal_params.append(init_params) ideal_costs[ii] = ClassificationCircuit( classifier_qubits, data_test, qc).build_classifier(ideal_params[ii], n_layers, encoding_choice, init_encoding_params[ii], num_shots, true_labels_test) print('In the ideal case, the cost is:', ideal_costs[ii]) predicted_labels_ideal = ClassificationCircuit( classifier_qubits, data_test, qc).make_predictions(ideal_params[ii], n_layers, encoding_choice, init_encoding_params[ii], num_shots) noisy_costs_uncorrected[ii] = ClassificationCircuit(classifier_qubits, data_test, qc, noise_choice, noise_values).build_classifier(ideal_params[ii], n_layers,\ encoding_choice, init_encoding_params[ii],\ num_shots, true_labels_test) print('\nWithout encoding training, the noisy cost is:', noisy_costs_uncorrected[ii]) noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params[ii], n_layers, noise_choice, noise_values, \ encoding_choice, init_encoding_params[ii],\ qc, classifier_qubits, num_shots, data_test, predicted_labels_ideal) print('The proportion classified differently after noise is:', 1 - number_classified_same) if retrain: if encoding_choice.lower() == 'wavefunction_param': optimiser = 'L-BFGS-B' else: optimiser = 'Powell' encoding_params, result_encoding_param = train_classifier_encoding( qc, noise_choice, noise_values, num_shots, ideal_params[ii], encoding_choice, init_encoding_params[ii], optimiser, data_train, true_labels_train) print('The optimised encoding parameters with noise are:', result_encoding_param.x) ideal_encoding_params.append(result_encoding_param.x) else: if data_choice.lower() == 'moons' and noise_choice.lower( ) == 'amp_damp_before_measurement' and isclose( noise_values, 0.3, abs_tol=1e-8): if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append([2.23855329, 7.57781576]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append([3.31296568, 6.34142188]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append([0.02884417]) elif data_choice.lower() == 'random_vertical_boundary': if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append([2.26042559, 8.99138928]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append([3.1786475, 8.36712745]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append([0.01503151]) elif data_choice.lower() == 'random_diagonal_boundary': if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append([2.11708966, 5.69354627]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append([0.08689283, 6.21166815]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append([0.0]) else: print('THIS DATASET HAS NOT BEEN TRAINED FOR') if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append(init_encoding_params[ii]) noisy_costs[ii] = ClassificationCircuit(classifier_qubits, data_test, qc, noise_choice, noise_values).build_classifier(ideal_params[ii], n_layers,\ encoding_choice, ideal_encoding_params[ii],\ num_shots, true_labels_test) print('\nWith encoding training, the noisy cost is:', noisy_costs[ii]) noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params[ii], n_layers, noise_choice, noise_values, \ encoding_choice, ideal_encoding_params[ii], qc, classifier_qubits, num_shots,\ data_test, predicted_labels_ideal) print( 'The proportion classified differently after noise with learned encoding is:', 1 - number_classified_same) for ii, encoding_choice in enumerate(encodings): print('\nThe encoding is:', encodings[ii]) print('The ideal params are:', ideal_params[ii]) print('The ideal encoding params are', ideal_encoding_params[ii]) print('The ideal cost for encoding', ideal_costs[ii]) print('The noisy cost with untrained encoding', noisy_costs_uncorrected[ii]) print('The noisy cost with trained encoding', noisy_costs[ii]) return encodings, ideal_params, init_encoding_params, ideal_encoding_params, ideal_costs, noisy_costs_uncorrected, noisy_costs
def main(train=False, encoding_choice='denseangle_param', retrain=False, data_choice='moons', noise=False): ### Firstly, generate for dataset: ''' # We use the transpose of the (scaled to unit square) Moons dataset in order to see a non-linear decision boundary ''' data_train, data_test, true_labels_train, true_labels_test = generate_data(data_choice, num_points=500, split=True) # data_train, true_labels_train = remove_zeros(data_train, true_labels_train) # data_test, true_labels_test = remove_zeros(data_test, true_labels_test) ### Next, generate correct classification parameters for dataset (perfect classification): ''' # Define parameters of model. Start with DenseAngle encoding with fixed parameters. ''' qc_name = '1q-qvm' qc = get_qc(qc_name) num_shots = 1024 qubits = qc.qubits() init_params = np.random.rand(3) if encoding_choice.lower() == 'wavefunction_param': init_encoding_params = [ 0 ] # Generalized Wavefunction Encoding initialised to Wavefunction encoding else: init_encoding_params = [np.pi, 2*np.pi] if train: optimiser = 'Powell' params, result_unitary_param = train_classifier(qc, num_shots, init_params, encoding_choice, init_encoding_params, optimiser, data_train, true_labels_train) print('The optimised parameters are:', result_unitary_param.x) print('These give a cost of:', ClassificationCircuit(qubits, data_train).build_classifier(result_unitary_param.x, encoding_choice, init_encoding_params, num_shots, qc, true_labels_train)) ideal_params = result_unitary_param.x else: if data_choice.lower() == 'moons': ### Define Ideal parameters for trained model. Simple model can acheieve classification of about 90 % ''' # 90% Classification parameters for dense angle encoding ''' if encoding_choice.lower() == 'denseangle_param': ideal_params= [ 2.19342064 , 1.32972029, -0.18308298] ### Define Ideal parameters for trained model. Simple model can acheieve classification of about 75 % ''' # 73% Classification parameters for superdense angle encoding ''' if encoding_choice.lower() == 'superdenseangle_param': ideal_params = [-0.27365492, 0.83278854, 3.00092961] ### Define Ideal parameters for trained model. Simple model can acheieve classification of about % ''' # 85% Classification parameters for wavefunction encoding ''' if encoding_choice.lower() == 'wavefunction': ideal_params = [0.81647273, 0.41996708, 2.20603541] if encoding_choice.lower() == 'wavefunction_param': ideal_params = [0.81647273, 0.41996708, 2.20603541] elif data_choice.lower() == 'random_vertical_boundary': if encoding_choice.lower() == 'superdenseangle_param': ideal_params = [1.606422245361118, 0.23401504261014927, 5.694226283697996] elif data_choice.lower() == 'random_diagonal_boundary': ### Define Ideal parameters for trained model. Simple model can acheieve classification of about 90 % ''' # 90% Classification parameters for dense angle encoding ''' if encoding_choice.lower() == 'denseangle_param': ideal_params = [0.8579214, 1.22952647, 4.99408074] ### Define Ideal parameters for trained model. Simple model can acheieve classification of about % ''' # % Classification parameters for superdense angle encoding ''' if encoding_choice.lower() == 'superdenseangle_param': ideal_params = [2.0101407, 1.05916291, 1.14570489] ### Define Ideal parameters for trained model. Simple model can acheieve classification of about 97% ''' # 97% Classification parameters for wavefunction encoding ''' if encoding_choice.lower() == 'wavefunction': ideal_params = [0.69409285 0.0862859 0.42872711] if encoding_choice.lower() == 'wavefunction_param': ideal_params = [0.69409285 0.0862859 0.42872711] print('These give a cost of:', ClassificationCircuit(qubits, data_test).build_classifier(ideal_params, encoding_choice, init_encoding_params, num_shots, qc, true_labels_test)) predicted_labels_ideal = ClassificationCircuit(qubits, data_test).make_predictions(ideal_params, encoding_choice, init_encoding_params, num_shots, qc) # nisqai.visual.scatter(data_test, true_labels_test, predicted_labels) ### Overlay decision bounday ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary ''' num_points = 400 data_grid, grid_true_labels = generate_data('full_vertical_boundary', num_points) data_grid, grid_true_labels = remove_zeros(data_grid, grid_true_labels) predicted_labels = ClassificationCircuit(qubits, data_test).make_predictions(ideal_params, encoding_choice, init_encoding_params, num_shots, qc) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_test, true_labels_test, predicted_labels, **plot_params) predicted_labels_grid = ClassificationCircuit(qubits, data_grid).make_predictions(ideal_params, encoding_choice, init_encoding_params, num_shots, qc) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show() ## Define noise parameters ''' # Define noise parameters to add to model to determine how classification is affected. ''' if noise: noise_choice = 'amp_damp_before_measurement' noise_values = 0.3 ### Add noise to circuit and classify ''' # Add noise to circuit, and determine number of points classified differently (not mis-classified since we can't achieve perfect classification) ''' if noise: noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params, noise_choice, noise_values, encoding_choice, init_encoding_params, qc, num_shots, data_test, predicted_labels_ideal) print('The proportion classified differently after noise is:', 1- number_classified_same) ## Overlay decision boundary ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary WITH noise added ''' if noise: print(noise_choice) predicted_labels = ClassificationCircuit(qubits, data_test, noise_choice, noise_values).make_predictions(ideal_params, encoding_choice, init_encoding_params, num_shots, qc) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_test, true_labels_test, predicted_labels, **plot_params) predicted_labels_grid = ClassificationCircuit(qubits, data_grid, noise_choice, noise_values).make_predictions(ideal_params, encoding_choice, init_encoding_params, num_shots, qc) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show() ### Retrain circuit with noise ''' # Given the noise in the circuit, train the parameters of encoding unitary to account for noise. Parameterised unitary parameters are fixed as the ideal ones learned. ''' if retrain: if encoding_choice.lower() == 'wavefunction_param': optimiser = 'L-BFGS-B' else: optimiser = 'Powell' if noise: encoding_params, result_encoding_param = train_classifier_encoding(qc, noise_choice, noise_values, num_shots, ideal_params, encoding_choice, init_encoding_params, optimiser, data_train, true_labels_train) print('The optimised encoding parameters with noise are:', result_encoding_param.x) ideal_encoding_params = result_encoding_param.x else: encoding_params, result_encoding_param = train_classifier_encoding(qc, None, None, num_shots, ideal_params, encoding_choice, init_encoding_params, optimiser, data_train, true_labels_train) print('The optimised encoding parameters without noise are:', result_encoding_param.x) ideal_encoding_params = result_encoding_param.x else: ### Define Ideal ENCODING parameters for trained model. Simple model can acheieve classification of about 90 with noise, 93% without noise % ''' # 90% Classification parameters for dense angle encoding ''' if data_choice.lower() == 'moons' and encoding_choice.lower() == 'denseangle_param' and noise: ideal_encoding_params = [2.23855329, 7.57781576] ''' # 93% Classification parameters for dense angle encoding without noise ''' elif data_choice.lower() == 'moons' and encoding_choice.lower() == 'denseangle_param': ideal_encoding_params = [3.05615259, 7.61215138] # No noise ### Define Ideal ENCODING parameters for trained model. Simple model can acheieve classification of about 90 % ''' # NO NOISE - 74-77% Classification parameters with training for superdense angle encoding # NOISE - Classification parameters for superdense angle encoding (0.3 amp damp = 20% different classification - 69% accuracy with noise before encoding training) # With learned encoding - ''' if data_choice.lower() == 'moons' and encoding_choice.lower() == 'superdenseangle_param' and noise: ideal_encoding_params = [3.31296568, 6.34142188] elif data_choice.lower() == 'moons' and encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params = [2.86603822, 6.14328274] # No noise ### Define Ideal ENCODING parameters for trained model. Simple model can acheieve classification of about 90 % ''' # NO NOISE - 82-84% Classification parameters with training for generalised wavefunction encoding # NOISE - Classification parameters for superdense angle encoding (0.3 amp damp = 20% different classification - 78% accuracy with noise before encoding training) # With learned encoding - ''' print(data_choice.lower(), encoding_choice.lower()) if data_choice.lower() == 'moons' and encoding_choice.lower() == 'wavefunction_param' and noise: ideal_encoding_params = [0.02884417] elif data_choice.lower() == 'moons' and encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params = [0.01582773] # No noise if noise: print('These give a cost with the noisy circuit of:',\ ClassificationCircuit(qubits, data_test, noise_choice, noise_values).build_classifier(ideal_params, encoding_choice, ideal_encoding_params , num_shots, qc, true_labels_test) ) else: print('These give a cost with the ideal circuit of:',\ ClassificationCircuit(qubits, data_test).build_classifier(ideal_params, encoding_choice, ideal_encoding_params , num_shots, qc, true_labels_test) ) ### Add noise to circuit and classify ''' # Using learned encoding parameters, check again proportion misclassified ''' if noise: noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params, noise_choice, noise_values, encoding_choice, ideal_encoding_params, qc, num_shots, data_test, predicted_labels) print('The proportion classified differently after noise with learned encoding is:', 1 - number_classified_same) ## Overlay decision boundary ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary WITH/WITHOUT noise added ''' if noise: predicted_labels = ClassificationCircuit(qubits, data_test, noise_choice, noise_values).make_predictions(ideal_params, encoding_choice, ideal_encoding_params, num_shots, qc) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_test, true_labels_test, predicted_labels, **plot_params) predicted_labels_grid = ClassificationCircuit(qubits, data_grid, noise_choice, noise_values).make_predictions(ideal_params, encoding_choice, ideal_encoding_params, num_shots, qc) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show() else: predicted_labels = ClassificationCircuit(qubits, data_test).make_predictions(ideal_params, encoding_choice, ideal_encoding_params, num_shots, qc) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_test, true_labels_test, predicted_labels, **plot_params) predicted_labels_grid = ClassificationCircuit(qubits, data_grid).make_predictions(ideal_params, encoding_choice, ideal_encoding_params, num_shots, qc) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show()
def main(data_choice='iris', amp_damp_noise=False, bit_flip_noise=False, dephasing_noise=False, global_depolarizing_noise=False, legend=False): # Generate data data_train, data_test, true_labels_train, true_labels_test = generate_data( data_choice, num_points=100, split=True) def unitary_evolved_noiseless(rho, params): ''' rho should be an encoded state. This function returns the evolved state with the unitary params. ''' unitary_layer_1_1 = rz(2 * params[2]) @ ry(2 * params[1]) @ rz( 2 * params[0]) unitary_layer_1_2 = rz(2 * params[5]) @ ry(2 * params[4]) @ rz( 2 * params[3]) U_1 = np.kron(unitary_layer_1_1, unitary_layer_1_2) # First layer rho = U_1 @ rho @ U_1.conj().T unitary_layer_2_1 = rx(2 * params[6] + np.pi) @ hmat unitary_layer_2_2 = rz(2 * params[7]) U_2 = np.kron(unitary_layer_2_1, unitary_layer_2_2) @ cnotmat # Second Layer rho = U_2 @ rho @ U_2.conj().T unitary_layer_3_1 = hmat unitary_layer_3_2 = rz(-2 * params[8]) U_3 = np.kron(unitary_layer_3_1, unitary_layer_3_2) @ cnotmat # Third Layer rho = U_3 @ rho @ U_3.conj().T unitary_layer_4_1 = rz(2 * params[11]) @ ry(2 * params[10]) @ rz( 2 * params[9]) unitary_layer_4_2 = imat U_4 = np.kron(unitary_layer_4_1, unitary_layer_4_2) @ cnotmat # Fourth Layer rho = U_4 @ rho @ U_4.conj().T return rho def unitary_evolved_noisy(rho, params, noise_choice='Pauli', noise_values=None, noise=True): ''' rho should be an encoded state. This function returns the evolved state with the unitary params. The noise channel is applied after each step in the unitary ''' if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_1_n = np.kron(rz(2 * params[0]), rz(2 * params[3])) rho = unitary_layer_1_n @ rho @ unitary_layer_1_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_2_n = np.kron(ry(2 * params[1]), ry(2 * params[4])) rho = unitary_layer_2_n @ rho @ unitary_layer_2_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_3_n = np.kron(rz(2 * params[2]), rz(2 * params[5])) rho = unitary_layer_3_n @ rho @ unitary_layer_3_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_4_n = cnotmat rho = unitary_layer_4_n @ rho @ unitary_layer_4_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_2_1 = rx(2 * params[6] + np.pi) @ hmat unitary_layer_2_2 = rz(2 * params[7]) unitary_layer_5_n = np.kron(unitary_layer_2_1, unitary_layer_2_2) rho = unitary_layer_5_n @ rho @ unitary_layer_5_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_6_n = cnotmat rho = unitary_layer_6_n @ rho @ unitary_layer_6_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_3_1 = hmat unitary_layer_3_2 = rz(-2 * params[8]) unitary_layer_7_n = np.kron(unitary_layer_3_1, unitary_layer_3_2) # Third Layer rho = unitary_layer_7_n @ rho @ unitary_layer_7_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_8_n = cnotmat rho = unitary_layer_8_n @ rho @ unitary_layer_8_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_9_n = np.kron(rz(2 * params[9]), imat) rho = unitary_layer_9_n @ rho @ unitary_layer_9_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_10_n = np.kron(ry(2 * params[10]), imat) rho = unitary_layer_10_n @ rho @ unitary_layer_10_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise unitary_layer_11_n = np.kron(rz(2 * params[11]), imat) rho = unitary_layer_11_n @ rho @ unitary_layer_11_n.conj().T if noise: rho = channels(rho, noise_choice=noise_choice, noise_values=noise_values) # Apply noise return rho # Encodings def state(f, g, x_1, y_1, x_2, y_2, encoding_params): # Encode first two features, x_1, y_1 in first qubit rho_1 = np.array([[ abs(f(x_1, y_1, encoding_params))**2, f(x_1, y_1, encoding_params) * np.conj(g(x_1, y_1, encoding_params)) ], [ np.conj(f(x_1, y_1, encoding_params)) * g(x_1, y_1, encoding_params), abs(g(x_1, y_1, encoding_params))**2 ]]) # Encode second two features, x_2, y_2 in second qubit rho_2 = np.array([[ abs(f(x_2, y_2, encoding_params))**2, f(x_2, y_2, encoding_params) * np.conj(g(x_2, y_2, encoding_params)) ], [ np.conj(f(x_2, y_2, encoding_params)) * g(x_2, y_2, encoding_params), abs(g(x_2, y_2, encoding_params))**2 ]]) rho = np.kron(rho_1, rho_2) # Tensor product state return rho / np.trace(rho) def f_dae(x, y, encoding_params): return np.cos(encoding_params[0] * x) def g_dae(x, y, encoding_params): return np.exp(encoding_params[1] * 1j * y) * np.sin( encoding_params[0] * x) def f_wf(x, y, encoding_params=None): return (np.sqrt(1 + encoding_params[0] * y**2) * x) / np.sqrt(x**2 + y**2) def g_wf(x, y, encoding_params=None): return (np.sqrt(1 - encoding_params[0] * x**2) * y) / np.sqrt(x**2 + y**2) def f_sdae(x, y, encoding_params): return np.cos(encoding_params[0] * x + encoding_params[1] * y) def g_sdae(x, y, encoding_params): return np.sin(encoding_params[0] * x + encoding_params[1] * y) def pauli(rho, pi=0.4, px=0.1, py=0.1, pz=0.4): """Applies a single qubit pauli channel to the state rho.""" assert np.isclose(sum((pi, px, py, pz)), 1.0) return (pi * rho + px * xmat @ rho @ xmat + py * ymat @ rho @ ymat + pz * zmat @ rho @ zmat) def one_q_pauli_kraus(pi, px, py, pz): kraus = [np.sqrt(pi) * imat, np.sqrt(px) * xmat, \ np.sqrt(py) * ymat, np.sqrt(pz) * zmat] return kraus def two_q_pauli_kraus(pi, px, py, pz): [pi_1, pi_2] = pi [px_1, px_2] = px [py_1, py_2] = py [pz_1, pz_2] = pz assert np.isclose(sum((pi_1, px_1, py_1, pz_1)), 1.0) assert np.isclose(sum((pi_2, px_2, py_2, pz_2)), 1.0) kraus_1 = one_q_pauli_kraus(pi_1, px_1, py_1, pz_1) kraus_2 = one_q_pauli_kraus(pi_2, px_2, py_2, pz_2) pauli_kraus = [np.kron(k1, k2) for k1 in kraus_1 for k2 in kraus_2] return pauli_kraus def two_q_pauli(rho, pi, px, py, pz): ''' Applies random single qubit Pauli gates to each qubit in the state with potentially different strengths ''' pauli_kraus = two_q_pauli_kraus(pi, px, py, pz) # constuct list of all Kraus operators being applied to the state and sum to # generate noisy state rho = np.array([k @ rho @ k.conj().T for k in pauli_kraus]).sum(axis=0) return rho def two_q_global_depolarizing(rho, p=0.1): return (1 - p) * rho + (p) * np.kron(imat, imat) / 2**2 def amplitude_damping(rho, p): E_00 = np.array([[1, 0], [0, np.sqrt(1 - p[0])]]) E_01 = np.array([[0, np.sqrt(p[0])], [0, 0]]) E_10 = np.array([[1, 0], [0, np.sqrt(1 - p[1])]]) E_11 = np.array([[0, np.sqrt(p[1])], [0, 0]]) rho = np.kron(E_00, E_10) @ rho @ np.kron(E_00, E_10).conj().T + np.kron(E_00, E_11) @ rho @ np.kron(E_00, E_11).conj().T \ + np.kron(E_01, E_10) @ rho @ np.kron(E_01, E_10).conj().T + np.kron(E_01, E_11) @ rho @ np.kron(E_01, E_11).conj().T return rho # Noise channels def channels(rho, noise_choice='Pauli', noise_values=None): if noise_choice.lower() == 'pauli': pi, px, py, pz = noise_values rho = two_q_pauli(rho, pi, px, py, pz) elif noise_choice.lower() == 'global_depolarizing': p = noise_values rho = two_q_global_depolarizing(rho, p) elif noise_choice.lower() == 'dephasing': pz = noise_values rho = two_q_pauli(rho, [1 - pz[0], 1 - pz[1]], pz, [0, 0], [0, 0]) elif noise_choice.lower() == 'bit_flip': px = noise_values rho = two_q_pauli(rho, [1 - px[0], 1 - px[1]], px, [0, 0], [0, 0]) elif noise_choice.lower() == 'amp_damp': p = noise_values rho = amplitude_damping(rho, p) else: raise NotImplementedError return rho # Predictions def make_prediction(rho): # Compute prediction for data sample in state rho proj_0 = np.kron(np.kron(pi0, imat), imat) elt = np.trace(proj_0 @ rho) if elt.real >= 0.499999999999999999: return 0 return 1 def compute_cost(ideal_labels, noisy_labels): """ Computes the cost between the ideal case labels, and the labels produced in the presence of noise. Simple indicator cost. """ assert len(ideal_labels) == len(noisy_labels) sum_count = 0 for ii in range(len(ideal_labels)): if not ideal_labels[ii] == noisy_labels[ii]: sum_count += 1 average_sum = sum_count / len(ideal_labels) return average_sum def set_params(data_choice='iris', encoding_choice='denseangle_param'): if data_choice.lower() == 'iris': if encoding_choice.lower() == 'denseangle_param': ideal_params = [ 2.02589489, 1.24358318, -0.6929718,\ 0.85764484, 2.7572075, 1.12317156, \ 4.01974889, 0.30921738, 0.88106973,\ 1.461694, 0.367226, 5.01508911 ] elif encoding_choice.lower() == 'superdenseangle_param': ideal_params = [1.1617383, -0.05837820, -0.7216498,\ 1.3195103, 0.52933357, 1.2854939,\ 1.2097700, 0.26920745, 0.4239539, \ 1.2999367, 0.37921617, 0.790320211] elif encoding_choice.lower() == 'wavefunction': ideal_params = [ 2.37732073, 1.01449711, 1.12025344,\ -0.087440021, 0.46937127, 2.14387135, \ 0.4696964, 1.444409282, 0.14412614,\ 1.4825742, 1.0817654, 6.30943537 ] elif encoding_choice.lower() == 'wavefunction_param': ideal_params = [ 2.37732073, 1.01449711, 1.12025344,\ -0.087440021, 0.46937127, 2.14387135, \ 0.4696964, 1.444409282, 0.14412614,\ 1.4825742, 1.0817654, 6.30943537] else: raise NotImplementedError else: raise ValueError('This dataset has not been trained for.') return ideal_params def average_fidelity(encoding_choice='denseangle_param', encoding_params=None, noise_choice='Pauli', noise_values=None): rho_noiseless, rho_noisy = [], [] params = set_params(data_choice='iris', encoding_choice=encoding_choice) fidelity = np.zeros( len(data_test)) # one element of fidelity per data point pred_labels_noisy = np.zeros(len(data_test), dtype=int) pred_labels_noiseless = np.zeros(len(data_test), dtype=int) print('------------------------------------') print('Encoding is:', encoding_choice) print('------------------------------------') for ii, point in enumerate(data_test): if true_labels_test[ii] == 0: label_qubit = np.array([[1, 0], [0, 0]]) else: label_qubit = np.array([[0, 0], [0, 1]]) if encoding_choice.lower() == 'denseangle_param': rho_encoded = state(f_dae, g_dae, point[0], point[1], point[2], point[3], encoding_params) # encode data point elif encoding_choice.lower() == 'wavefunction_param': rho_encoded = state(f_wf, g_wf, point[0], point[1], point[2], point[3], encoding_params) # encode data point elif encoding_choice.lower() == 'superdenseangle_param': rho_encoded = state(f_sdae, g_sdae, point[0], point[1], point[2], point[3], encoding_params) # encode data point else: raise NotImplementedError rhos_noiseless_indiv = unitary_evolved_noiseless( rho_encoded, params) rho_noisy_indiv = unitary_evolved_noisy(rho_encoded, params, noise_choice=noise_choice, noise_values=noise_values) rho_noiseless.append(np.kron(rhos_noiseless_indiv, label_qubit)) rho_noisy.append(np.kron(rho_noisy_indiv, label_qubit)) pred_labels_noiseless[ii] = make_prediction(rho_noiseless[ii]) pred_labels_noisy[ii] = make_prediction(rho_noisy[ii]) fidelity[ii] = (np.trace(sqrtm(rho_noisy[ii] @ rho_noiseless[ii])) )**2 # compute fidelity per sample cost_ideal = compute_cost(true_labels_test, pred_labels_noiseless) cost_noisy = compute_cost(true_labels_test, pred_labels_noisy) cost_difference = cost_noisy - cost_ideal rho_noiseless_mixed = np.array( (1 / len(rho_noiseless)) * np.array(rho_noiseless).sum(axis=0)) rho_noisy_mixed = (1 / len(rho_noisy)) * np.array(rho_noisy).sum(axis=0) avg_fidelity_mixed = ((np.trace( sqrtm( sqrtm(rho_noisy_mixed) @ rho_noiseless_mixed @ sqrtm(rho_noisy_mixed))))**2 ).real # compute fidelity for mixed state avg_fidelity = (1 / len(data_test)) * np.sum( fidelity, axis=0) # compute average fidelity over dataset avg_bound = (2 / len(data_test)) * np.sum( np.square(np.ones_like(fidelity) - fidelity), axis=0) # compute average bound over dataset print(avg_fidelity) if avg_fidelity_mixed > 1: avg_fidelity_mixed = 1 # reset fidelity less than one if numerical precision makes it > 1 mixed_bound = 2 * np.sqrt( 1 - avg_fidelity_mixed) # Bound on cost function error return cost_difference, avg_bound, mixed_bound, avg_fidelity, avg_fidelity_mixed encoding_params_dae = [np.pi / 2, 2 * np.pi] encoding_params_wf = [0] encoding_params_sdae = [np.pi, 2 * np.pi] encoding_params = [ encoding_params_dae, encoding_params_wf, encoding_params_sdae ] num_points = 50 if amp_damp_noise: fidelity_bound_plot(average_fidelity, encoding_params=encoding_params, noise_choice='amp_damp', show=True, num_points=num_points, num_qbs=2, legend=legend) fidelity_compare_plot(average_fidelity, encoding_params=encoding_params, noise_choice='amp_damp', show=True, num_points=num_points, num_qbs=2, legend=legend) if bit_flip_noise: fidelity_bound_plot(average_fidelity, encoding_params=encoding_params, noise_choice='bit_flip', show=True, num_points=num_points, num_qbs=2, legend=legend) fidelity_compare_plot(average_fidelity, encoding_params=encoding_params, noise_choice='bit_flip', show=True, num_points=num_points, num_qbs=2, legend=legend) if dephasing_noise: fidelity_bound_plot(average_fidelity, encoding_params=encoding_params, noise_choice='dephasing', show=True, num_points=num_points, num_qbs=2, legend=legend) fidelity_compare_plot(average_fidelity, encoding_params=encoding_params, noise_choice='dephasing', show=True, num_points=num_points, num_qbs=2, legend=legend) if global_depolarizing_noise: ''' Global depolarizing noise on both qubits together. ''' fidelity_bound_plot(average_fidelity, encoding_params=encoding_params, noise_choice='global_depolarizing', show=True, num_points=num_points, num_qbs=2, legend=legend) fidelity_compare_plot(average_fidelity, encoding_params=encoding_params, noise_choice='global_depolarizing', show=True, num_points=num_points, num_qbs=2, legend=legend)
def main(train=False, encoding='denseangle_param', ideal=False, noise=False, analytic=False, compare=False): """ # Find optimal parameters for linear decision boundary and add noise """ ### Firstly, generate for dataset: ''' # We use the transpose of the (scaled to unit square) Moons dataset in order to see a non-linear decision boundary ''' data_vertical_train, data_vertical_test, true_labels_train, true_labels_test = generate_data( 'random_vertical_boundary', num_points=500, split=True) ### Next, generate correct classification parameters for dataset (perfect classification): ''' # Define parameters of model. Start with DenseAngle encoding with fixed parameters. ''' qc_name = '1q-qvm' qc = get_qc(qc_name) num_shots = 1024 device_qubits = qc.qubits() classifier_qubits = device_qubits n_layers = 1 init_params = np.random.rand(3) if encoding.lower() == 'denseangle_param': encoding_choice = 'denseangle_param' # init_encoding_params = [np.pi, 2*np.pi] init_encoding_params = [np.pi, 2 * np.pi] elif encoding.lower() == 'wavefunction' or encoding.lower( ) == 'wavefunction_param': encoding_choice = 'wavefunction_param' init_encoding_params = [0] optimiser = 'Powell' if train: ### Train model, and check classification result of ideal parameters found ''' # Train model using scipy.optimize ''' params, result_unitary_param = train_classifier( qc, num_shots, init_params, encoding_choice, init_encoding_params, optimiser, data_vertical_train, true_labels_train) print('The optimised parameters are:', result_unitary_param.x) print('These give a cost of:', ClassificationCircuit(classifier_qubits, data_vertical_train).build_classifier(result_unitary_param.x, n_layers, \ encoding_choice, init_encoding_params, num_shots, qc, true_labels_train)) ideal_params_vertical = result_unitary_param.x else: ### Define Ideal parameters for trained model learned from previous. Simple model can acheieve classification of about 90 % if encoding_choice.lower() == 'denseangle_param': ''' # 100% Classification parameters (modulo points on the boundary) ''' # ideal_params_vertical = [3.8208,1.525,0.0808] ideal_params_vertical = [1.67814786, 1.56516469, 1.77820848] elif encoding_choice.lower() == 'wavefunction_param': ''' # 78% Classification parameters (modulo points on the boundary) ''' ideal_params_vertical = [2.2921198, 0.61375299, -5.15252796] plt.rcParams.update({ "font.size": 20, "font.serif": "Computer Modern Roman" }) ### Overlay decision bounday ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary ''' data_choice = 'full_vertical_boundary' num__grid_points = 1000 data_grid, grid_true_labels = generate_data(data_choice, num__grid_points) data_grid, grid_true_labels = remove_zeros(data_grid, grid_true_labels) if ideal: predicted_labels_test = ClassificationCircuit(classifier_qubits, data_vertical_test, qc).make_predictions(ideal_params_vertical, n_layers, \ encoding_choice, init_encoding_params, num_shots) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_vertical_test, true_labels_test, predicted_labels_test, **plot_params) predicted_labels_grid = ClassificationCircuit(classifier_qubits, data_grid, qc).make_predictions(ideal_params_vertical, n_layers,\ encoding_choice, init_encoding_params, num_shots) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid, **plot_params) plt.show() ### Define noise parameters ''' # Define noise parameters to add to model to determine how classification is affected. ''' noise_choice = 'amp_damp_before_measurement' noise_values = 0.4 ### Add noise to circuit and classify ''' # Add noise to circuit, and determine number of points classified differently (not mis-classified since we can't achieve perfect classification) ''' if noise: ## Overlay decision boundary ''' # Generate Grid of datapoints to determine and visualise ideal decision boundary WITH noise added ''' predicted_labels_test_noise = ClassificationCircuit(classifier_qubits, data_vertical_test, qc,\ noise_choice, noise_values).make_predictions(ideal_params_vertical, n_layers, encoding_choice, init_encoding_params, num_shots) plot_params = {'colors': ['blue', 'orange'], 'alpha': 1} scatter(data_vertical_test, true_labels_test, predicted_labels_test_noise, **plot_params) predicted_labels_grid_noise = ClassificationCircuit(classifier_qubits, data_grid, qc,\ noise_choice, noise_values).make_predictions(ideal_params_vertical, n_layers, \ encoding_choice, init_encoding_params, num_shots) plot_params = {'colors': ['red', 'green'], 'alpha': 0.2} scatter(data_grid, predicted_labels_grid_noise, **plot_params) plt.show() ''' # Define function to compute points which will remian correctly classified after noise is added ''' def correct_function(data_point, params, encoding_choice, encoding_params): [alpha_1, alpha_2, alpha_3] = params [x_1, x_2] = data_point if encoding_choice.lower() == 'denseangle_param': [theta, phi] = encoding_params function = (np.sin(alpha_2) )**2 * ( np.cos(theta * x_1) )**2 + (np.cos(alpha_2))**2 * (np.sin(theta * x_1))**2 \ + ((1/2)*(np.sin(2 * alpha_2) * np.sin(2 * theta * x_1) * np.exp(-1j*(2 * alpha_3 + phi * x_2)))).real elif encoding_choice.lower() == 'wavefunction_param': [theta] = encoding_params l2_norm = np.linalg.norm(np.array([x_1, x_2]))**2 function = (np.sin(alpha_2)**2 ) * ( x_1**2/(l2_norm) ) + (np.cos(alpha_2)**2) * (x_2**2/(l2_norm)) \ + ((1/(2*l2_norm))*(np.sin(2 * alpha_2) * (x_1) * (x_2) * np.exp(-1j*(2 * alpha_3)))).real return function def compute_analytic_misclassifed_condition(data, params, encoding_choice, encoding_params, noise_strength, true_labels): correct_classification_labels = [] for ii, data_point in enumerate(data): function = correct_function(data_point, params, encoding_choice, encoding_params) if true_labels[ii] == 0: correct_classification_labels.append( 0 ) # If datapoint was zero originally, it will be correctly classified regardless of noise else: if function > 1 / ( 2 * (1 - noise_strength) ): # If data point was classified as 1, it will be correctly classified if condition is met. correct_classification_labels.append(0) else: correct_classification_labels.append(1) number_robust = 1 - sum(correct_classification_labels) / len( correct_classification_labels) # percentage of misclassified points return np.array(correct_classification_labels), number_robust def plot_number_misclassified_amp_damp(ideal_params, num_shots, num_points, qc, noise_values): points_noise_inc = [] data_vertical_train, data_vertical_test, true_labels_train, true_labels_test = generate_data('random_vertical_boundary',\ num_points=num_points, split=True) interval = 0.2 encoding_choice = 'denseangle_param' theta = np.arange(0, 2 * np.pi, interval) phi = np.arange(0, 2 * np.pi, interval) X, Y = np.meshgrid(theta, phi) noise_choice = 'amp_damp_before_measurement' test_acc_ideal = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) test_acc_noise = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) number_robust = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) for ii, t in enumerate(theta): for jj, p in enumerate(phi): temp_encoding_params = [t, p] # Classification of encoding parameters *without* noise ideal_predictions, test_acc_ideal[ii,jj] = generate_noisy_classification(ideal_params, 1, None, None,\ encoding_choice, temp_encoding_params, qc,\ classifier_qubits, num_shots, data_vertical_test, true_labels_test) # Learned encoding parameters *with* noise noisy_predictions, test_acc_noise[ii,jj] = generate_noisy_classification(ideal_params, 1, noise_choice, noise_values,\ encoding_choice, temp_encoding_params, qc,\ classifier_qubits, num_shots, data_vertical_test, true_labels_test) # Number expected to be robust under analytic condition correct_classification_labels, number_robust[ii, jj] = compute_analytic_misclassifed_condition(data_vertical_test, ideal_params_vertical,\ encoding_choice, temp_encoding_params,\ noise_values, true_labels_test) print('Theta, Phi is:', t, p) print('Test accuracy ideal:', test_acc_ideal[ii, jj]) print('Test accuracy with noise:', test_acc_noise[ii, jj]) print('Proportion robust:', number_robust[ii, jj]) max_acc_indices_ideal = np.unravel_index( np.argmax(test_acc_ideal, axis=None), test_acc_ideal.shape) max_acc_indices = np.unravel_index( np.argmax(test_acc_noise, axis=None), test_acc_noise.shape) max_robust_indices = np.unravel_index( np.argmax(number_robust, axis=None), number_robust.shape) plt.rcParams.update({"font.size": 14, "font.family": "serif"}) # ---------------------- # Uncomment below for 3d plots # ---------------------- # fig = plt.figure(figsize=plt.figaspect(0.33)) # ax1 = fig.add_subplot(1, 3, 1, projection='3d') # surf1 = ax1.plot_surface(X, Y, test_acc_ideal, cmap=cm.coolwarm_r,linewidth=0, antialiased=False) # # ax1.set_zlim(0.45, 1.01) # cbar1 =fig.colorbar(surf1) # cbar1.ax.set_ylabel('Test Accuracy') # ax2 = fig.add_subplot(1, 3, 2, projection='3d') # surf2 = ax2.plot_surface(X, Y, test_acc_noise, cmap=cm.coolwarm_r, linewidth=0, antialiased=False) # # ax2.set_zlim(0.45, 1.01) # cbar2 = fig.colorbar(surf2) # cbar2.ax.set_ylabel('Test Accuracy') # ax3 = fig.add_subplot(1, 3, 3, projection='3d') # surf3 = ax3.plot_surface(X, Y, number_robust, cmap=cm.PuOr, linewidth=0, antialiased=False) # cbar3 = fig.colorbar(surf3) # cbar3.ax.set_ylabel('Proportion robust') # ax1.set_ylabel(r'$\theta (rads)$') # ax1.set_xlabel(r'$\phi (rads)$' ) # ax1.set_title( 'Best accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices_ideal] , 2) ) \ # + '\nBest accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices_ideal] , 2) ) \ # + '\nRobustness: ' + str( round( number_robust[max_acc_indices_ideal] , 2) ) + '\n' \ # + r'$[\theta, \phi]$ = ' + '['+str(round(theta [ max_acc_indices_ideal[0] ], 2) )+ ', ' + str( round( phi [ max_acc_indices_ideal[1] ] , 2) ) + ']' ) # ax2.set_ylabel(r'$\theta (rads)$') # ax2.set_xlabel(r'$\phi (rads)$' ) # ax2.set_title( 'Best accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices] , 2) ) \ # + '\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices] , 2) ) \ # + '\nRobustness: ' + str( round( number_robust[max_acc_indices] , 2) ) + '\n' \ # + r'$[\theta, \phi]$ = ' + '['+str(theta [ max_acc_indices[0] ])+ ', ' + str(round( phi [ max_acc_indices[1] ], 2) ) + ']' ) # ax3.set_ylabel(r'$\theta (rads)$') # ax3.set_xlabel(r'$\phi (rads)$' ) # ax3.set_title('Max. robustness: ' + str( round( number_robust[max_robust_indices] , 2) ) \ # +'\nBest accuracy with noise: ' + str( round( test_acc_noise[max_robust_indices] , 2) ) \ # +'\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_robust_indices] , 2) ) + '\n'\ # +r'$[\theta, \phi]$ = ' + '[' + str(theta [ max_robust_indices[0] ]) \ # + ', ' + str(phi [ max_robust_indices[1] ] ) + ']' ) ## 2D PLOTS fig, ax = plt.subplots(1, 3) im0 = ax[0].imshow(test_acc_ideal, cmap=cm.coolwarm_r, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[0]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar0 = fig.colorbar(im0, cax=cax, orientation='vertical') cbar0.ax.set_ylabel('Test Accuracy') im1 = ax[1].imshow(test_acc_noise, cmap=cm.coolwarm_r, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[1]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar1 = fig.colorbar(im1, cax=cax, orientation='vertical') cbar1.ax.set_ylabel('Test Accuracy') im2 = ax[2].imshow(number_robust, cmap=cm.PuOr, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[2]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar2 = fig.colorbar(im2, cax=cax, orientation='vertical') cbar2.ax.set_ylabel('Proportion robust') ax[0].set_title( 'Best accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices_ideal] , 2) ) \ + '\nBest accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices_ideal] , 2) ) \ + '\nRobustness: ' + str( round( number_robust[max_acc_indices_ideal] , 2) ) + '\n' \ + r'$[\theta, \phi]$ = ' + '['+str(round(theta [ max_acc_indices_ideal[0] ], 2) )+ ', ' + str( round( phi [ max_acc_indices_ideal[1] ] , 2) ) + ']' ) ax[1].set_title( 'Best accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices] , 2) ) \ + '\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices] , 2) ) \ + '\nRobustness: ' + str( round( number_robust[max_acc_indices] , 2) ) + '\n' \ + r'$[\theta, \phi]$ = ' + '['+str(theta [ max_acc_indices[0] ])+ ', ' + str(round( phi [ max_acc_indices[1] ], 2) ) + ']' ) ax[2].set_title('Max. robustness: ' + str( round( number_robust[max_robust_indices] , 2) ) \ +'\nBest accuracy with noise: ' + str( round( test_acc_noise[max_robust_indices] , 2) ) \ +'\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_robust_indices] , 2) ) + '\n'\ +r'$[\theta, \phi]$ = ' + '[' + str(theta [ max_robust_indices[0] ]) \ + ', ' + str(phi [ max_robust_indices[1] ] ) + ']' ) return if analytic: correct_classification_labels, number_robust = compute_analytic_misclassifed_condition(data_grid, ideal_params_vertical,\ encoding_choice, init_encoding_params,\ noise_values, grid_true_labels) plot_params = {'colors': ['blue', 'black'], 'alpha': 0.3} scatter(data_grid, correct_classification_labels, **plot_params) plt.show() if compare: plot_number_misclassified_amp_damp(ideal_params_vertical, num_shots, 500, qc, noise_values) plt.show()
def plot_number_misclassified_amp_damp(ideal_params, num_shots, num_points, qc, noise_values): points_noise_inc = [] data_vertical_train, data_vertical_test, true_labels_train, true_labels_test = generate_data('random_vertical_boundary',\ num_points=num_points, split=True) interval = 0.2 encoding_choice = 'denseangle_param' theta = np.arange(0, 2 * np.pi, interval) phi = np.arange(0, 2 * np.pi, interval) X, Y = np.meshgrid(theta, phi) noise_choice = 'amp_damp_before_measurement' test_acc_ideal = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) test_acc_noise = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) number_robust = np.zeros((theta.shape[0], phi.shape[0]), dtype=float) for ii, t in enumerate(theta): for jj, p in enumerate(phi): temp_encoding_params = [t, p] # Classification of encoding parameters *without* noise ideal_predictions, test_acc_ideal[ii,jj] = generate_noisy_classification(ideal_params, 1, None, None,\ encoding_choice, temp_encoding_params, qc,\ classifier_qubits, num_shots, data_vertical_test, true_labels_test) # Learned encoding parameters *with* noise noisy_predictions, test_acc_noise[ii,jj] = generate_noisy_classification(ideal_params, 1, noise_choice, noise_values,\ encoding_choice, temp_encoding_params, qc,\ classifier_qubits, num_shots, data_vertical_test, true_labels_test) # Number expected to be robust under analytic condition correct_classification_labels, number_robust[ii, jj] = compute_analytic_misclassifed_condition(data_vertical_test, ideal_params_vertical,\ encoding_choice, temp_encoding_params,\ noise_values, true_labels_test) print('Theta, Phi is:', t, p) print('Test accuracy ideal:', test_acc_ideal[ii, jj]) print('Test accuracy with noise:', test_acc_noise[ii, jj]) print('Proportion robust:', number_robust[ii, jj]) max_acc_indices_ideal = np.unravel_index( np.argmax(test_acc_ideal, axis=None), test_acc_ideal.shape) max_acc_indices = np.unravel_index( np.argmax(test_acc_noise, axis=None), test_acc_noise.shape) max_robust_indices = np.unravel_index( np.argmax(number_robust, axis=None), number_robust.shape) plt.rcParams.update({"font.size": 14, "font.family": "serif"}) # ---------------------- # Uncomment below for 3d plots # ---------------------- # fig = plt.figure(figsize=plt.figaspect(0.33)) # ax1 = fig.add_subplot(1, 3, 1, projection='3d') # surf1 = ax1.plot_surface(X, Y, test_acc_ideal, cmap=cm.coolwarm_r,linewidth=0, antialiased=False) # # ax1.set_zlim(0.45, 1.01) # cbar1 =fig.colorbar(surf1) # cbar1.ax.set_ylabel('Test Accuracy') # ax2 = fig.add_subplot(1, 3, 2, projection='3d') # surf2 = ax2.plot_surface(X, Y, test_acc_noise, cmap=cm.coolwarm_r, linewidth=0, antialiased=False) # # ax2.set_zlim(0.45, 1.01) # cbar2 = fig.colorbar(surf2) # cbar2.ax.set_ylabel('Test Accuracy') # ax3 = fig.add_subplot(1, 3, 3, projection='3d') # surf3 = ax3.plot_surface(X, Y, number_robust, cmap=cm.PuOr, linewidth=0, antialiased=False) # cbar3 = fig.colorbar(surf3) # cbar3.ax.set_ylabel('Proportion robust') # ax1.set_ylabel(r'$\theta (rads)$') # ax1.set_xlabel(r'$\phi (rads)$' ) # ax1.set_title( 'Best accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices_ideal] , 2) ) \ # + '\nBest accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices_ideal] , 2) ) \ # + '\nRobustness: ' + str( round( number_robust[max_acc_indices_ideal] , 2) ) + '\n' \ # + r'$[\theta, \phi]$ = ' + '['+str(round(theta [ max_acc_indices_ideal[0] ], 2) )+ ', ' + str( round( phi [ max_acc_indices_ideal[1] ] , 2) ) + ']' ) # ax2.set_ylabel(r'$\theta (rads)$') # ax2.set_xlabel(r'$\phi (rads)$' ) # ax2.set_title( 'Best accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices] , 2) ) \ # + '\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices] , 2) ) \ # + '\nRobustness: ' + str( round( number_robust[max_acc_indices] , 2) ) + '\n' \ # + r'$[\theta, \phi]$ = ' + '['+str(theta [ max_acc_indices[0] ])+ ', ' + str(round( phi [ max_acc_indices[1] ], 2) ) + ']' ) # ax3.set_ylabel(r'$\theta (rads)$') # ax3.set_xlabel(r'$\phi (rads)$' ) # ax3.set_title('Max. robustness: ' + str( round( number_robust[max_robust_indices] , 2) ) \ # +'\nBest accuracy with noise: ' + str( round( test_acc_noise[max_robust_indices] , 2) ) \ # +'\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_robust_indices] , 2) ) + '\n'\ # +r'$[\theta, \phi]$ = ' + '[' + str(theta [ max_robust_indices[0] ]) \ # + ', ' + str(phi [ max_robust_indices[1] ] ) + ']' ) ## 2D PLOTS fig, ax = plt.subplots(1, 3) im0 = ax[0].imshow(test_acc_ideal, cmap=cm.coolwarm_r, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[0]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar0 = fig.colorbar(im0, cax=cax, orientation='vertical') cbar0.ax.set_ylabel('Test Accuracy') im1 = ax[1].imshow(test_acc_noise, cmap=cm.coolwarm_r, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[1]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar1 = fig.colorbar(im1, cax=cax, orientation='vertical') cbar1.ax.set_ylabel('Test Accuracy') im2 = ax[2].imshow(number_robust, cmap=cm.PuOr, extent=[0, 2 * np.pi, 2 * np.pi, 0]) divider = make_axes_locatable(ax[2]) cax = divider.append_axes('right', size='5%', pad=0.1) cbar2 = fig.colorbar(im2, cax=cax, orientation='vertical') cbar2.ax.set_ylabel('Proportion robust') ax[0].set_title( 'Best accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices_ideal] , 2) ) \ + '\nBest accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices_ideal] , 2) ) \ + '\nRobustness: ' + str( round( number_robust[max_acc_indices_ideal] , 2) ) + '\n' \ + r'$[\theta, \phi]$ = ' + '['+str(round(theta [ max_acc_indices_ideal[0] ], 2) )+ ', ' + str( round( phi [ max_acc_indices_ideal[1] ] , 2) ) + ']' ) ax[1].set_title( 'Best accuracy with noise: ' + str( round( test_acc_noise[max_acc_indices] , 2) ) \ + '\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_acc_indices] , 2) ) \ + '\nRobustness: ' + str( round( number_robust[max_acc_indices] , 2) ) + '\n' \ + r'$[\theta, \phi]$ = ' + '['+str(theta [ max_acc_indices[0] ])+ ', ' + str(round( phi [ max_acc_indices[1] ], 2) ) + ']' ) ax[2].set_title('Max. robustness: ' + str( round( number_robust[max_robust_indices] , 2) ) \ +'\nBest accuracy with noise: ' + str( round( test_acc_noise[max_robust_indices] , 2) ) \ +'\nBest accuracy ideal: ' + str( round( test_acc_ideal[max_robust_indices] , 2) ) + '\n'\ +r'$[\theta, \phi]$ = ' + '[' + str(theta [ max_robust_indices[0] ]) \ + ', ' + str(phi [ max_robust_indices[1] ] ) + ']' ) return
def main(train=False, retrain=False, qc_name='2q-qvm', data_choice='iris', noise_choice='decoherence_symmetric_ro', noise_values=None): ### Firstly, generate for dataset: data_train, data_test, true_labels_train, true_labels_test = generate_data( data_choice, num_points=500, split=True) data_train, true_labels_train = remove_zeros(data_train, true_labels_train) data_test, true_labels_test = remove_zeros(data_test, true_labels_test) # encodings = [ 'denseangle_param','superdenseangle_param', 'wavefunction_param' ] encodings = ['superdenseangle_param'] minimal_costs, ideal_costs, noisy_costs, noisy_costs_uncorrected = [ np.ones(len(encodings)) for _ in range(4) ] # qc_name = '2q-qvm' qc = get_qc(qc_name) num_shots = 1024 device_qubits = qc.qubits() classifier_qubits = device_qubits n_layers = 1 # init_params = np.random.rand(len(qubits),n_layers, 3) # init_params = np.random.rand(len(qubits),n_layers, 3) # init_params = np.random.rand((7)) # TTN init_params = np.random.rand((12)) # General 2 qubit unitary ideal_params = [] ideal_encoding_params = [] init_encoding_params = [] for ii, encoding_choice in enumerate(encodings): print('\n**********************************') print('\nThe encoding is:', encoding_choice) print('\n**********************************') if encoding_choice.lower() == 'wavefunction_param': init_encoding_params.append( [0] ) # Generalized Wavefunction Encoding initialised to Wavefunction encoding else: init_encoding_params.append([np.pi, 2 * np.pi]) if train: optimiser = 'Powell' params, result_unitary_param = train_classifier(qc, classifier_qubits, num_shots, init_params, n_layers,\ encoding_choice, init_encoding_params[ii],\ optimiser, data_train, true_labels_train) print('The optimised parameters are:', result_unitary_param.x) print('These give a cost of:', ClassificationCircuit(classifier_qubits, data_train, qc).build_classifier(result_unitary_param.x, n_layers,\ encoding_choice, init_encoding_params[ii],\ num_shots, true_labels_train)) ideal_params.append(result_unitary_param.x) else: if data_choice.lower() == 'iris': if encoding_choice.lower() == 'denseangle_param': ideal_params.append([ 2.02589489, 1.24358318, -0.6929718,\ 0.85764484, 2.7572075, 1.12317156, \ 4.01974889, 0.30921738, 0.88106973,\ 1.461694, 0.367226, 5.01508911 ]) # elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append([1.1617383, -0.05837820, -0.7216498,\ # 1.3195103, 0.52933357, 1.2854939, # 1.2097700, 0.26920745, 0.4239539, # 1.2999367, 0.37921617, 0.790320211]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_params.append([ 2.91988765, 1.85012634, 1.75234515, 0.81420946,\ 1.286217,0.62223565, 0.8356422, 1.36681893, 0.58494563,\ -0.02031075, 0.80183355, 6.92525521]) elif encoding_choice.lower() == 'wavefunction': ideal_params.append([ 2.37732073, 1.01449711, 1.12025344,\ -0.087440021, 0.46937127, 2.14387135, \ 0.4696964, 1.444409282, 0.14412614,\ 1.4825742, 1.0817654, 6.30943537 ]) elif encoding_choice.lower() == 'wavefunction_param': ideal_params.append([ 2.37732073, 1.01449711, 1.12025344,\ -0.087440021, 0.46937127, 2.14387135, \ 0.4696964, 1.444409282, 0.14412614,\ 1.4825742, 1.0817654, 6.30943537 ]) ideal_costs[ii] = ClassificationCircuit(classifier_qubits, data_test, qc).build_classifier(ideal_params[ii], n_layers, \ encoding_choice, init_encoding_params[ii], \ num_shots, true_labels_test) print('In the ideal case, the cost is:', ideal_costs[ii]) predicted_labels_ideal = ClassificationCircuit(classifier_qubits, data_test, qc).make_predictions(ideal_params[ii], n_layers,\ encoding_choice, init_encoding_params[ii],\ num_shots) if noise_choice is not None: noisy_costs_uncorrected[ii] = ClassificationCircuit(classifier_qubits, data_test, qc, \ noise_choice, noise_values).build_classifier(ideal_params[ii], n_layers,\ encoding_choice, init_encoding_params[ii],\ num_shots, true_labels_test) print('\nWithout encoding training, the noisy cost is:', noisy_costs_uncorrected[ii]) noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params[ii], n_layers,\ noise_choice, noise_values,\ encoding_choice, init_encoding_params[ii],\ qc, classifier_qubits, num_shots, data_test, predicted_labels_ideal) print('The proportion classified differently after noise is:', 1 - number_classified_same) if retrain: if encoding_choice.lower() == 'wavefunction_param': optimiser = 'L-BFGS-B' else: optimiser = 'Powell' encoding_params, result_encoding_param = train_classifier_encoding( qc, noise_choice, noise_values, num_shots, ideal_params[ii], encoding_choice, init_encoding_params[ii], optimiser, data_train, true_labels_train) print('The optimised encoding parameters with noise are:', result_encoding_param.x) ideal_encoding_params.append(result_encoding_param.x) else: if data_choice.lower() == 'iris' and noise_choice.lower( ) == 'decoherence_symmetric_ro': if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append(init_encoding_params[ii]) else: print('THIS DATASET HAS NOT BEEN TRAINED FOR') if encoding_choice.lower() == 'denseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'superdenseangle_param': ideal_encoding_params.append(init_encoding_params[ii]) elif encoding_choice.lower() == 'wavefunction_param': ideal_encoding_params.append(init_encoding_params[ii]) noisy_costs[ii] = ClassificationCircuit(classifier_qubits, data_test, qc, \ noise_choice, noise_values).build_classifier(ideal_params[ii], n_layers, \ encoding_choice, ideal_encoding_params[ii],\ num_shots, true_labels_test) print('\nWith encoding training, the noisy cost is:', noisy_costs[ii]) noisy_predictions, number_classified_same = generate_noisy_classification(ideal_params[ii], n_layers, \ noise_choice, noise_values,\ encoding_choice, ideal_encoding_params[ii],\ qc, classifier_qubits, num_shots, data_test, predicted_labels_ideal) print( 'The proportion classified differently after noise with learned encoding is:', 1 - number_classified_same) # for ii, encoding_choice in enumerate(encodings): # print('\nThe encoding is:' , encodings[ii] ) # print('The ideal params are:' , ideal_params[ii] ) # print('The ideal encoding params are' , ideal_encoding_params[ii] ) # print('The ideal cost for encoding' , ideal_costs[ii] ) # print('The noisy cost with untrained encoding' , noisy_costs_uncorrected[ii] ) # print('The noisy cost with trained encoding' , noisy_costs[ii] ) return encodings, ideal_params, init_encoding_params, ideal_encoding_params, ideal_costs, noisy_costs_uncorrected, noisy_costs