#!/usr/bin/env python3 """ This script runs Variational-Quantum-Eigensolver using Qiskit library Example running it partially using CK infrastructure: ck virtual env --tag_groups='compiler,python qiskit,lib vqe,utils vqe,hamiltonian deployed,ansatz deployed,optimizer' \ --shell_cmd="$HOME/CK/ck-qiskit/program/qiskit-vqe/qiskit_vqe_common.py --start_param_value=0.5" """ import os import json import time import inspect import numpy as np from scipy import linalg as la from qiskit import QuantumProgram, register, QISKitError from qiskit.tools.apps.optimization import make_Hamiltonian, group_paulis from qiskit.tools.qi.pauli import Pauli, label_to_pauli from eval_hamiltonian import eval_hamiltonian from vqe_utils import cmdline_parse_and_report, get_first_callable, NumpyEncoder from vqe_hamiltonian import label_to_hamiltonian_coeff # the file contents will be different depending on the plugin choice import custom_ansatz # the file contents will be different depending on the plugin choice fun_evaluation_counter = 0 # global def vqe_for_qiskit(sample_number, pauli_list, timeout_seconds, json_stream_file): def expectation_estimation(current_params, report): timestamp_before_ee = time.time() timestamp_before_q_run = timestamp_before_ee # no point in taking consecutive timestamps ansatz_circuit = ansatz_function(current_params) global fun_evaluation_counter # Trying to recover from a timed-out run assuming it to be a temporary glitch: # for attempt in range(1,8): try: complex_energy, q_run_seconds = eval_hamiltonian(Q_program, pauli_list_grouped, ansatz_circuit, sample_number, q_device_name, timeout=timeout_seconds) energy = complex_energy.real break except QISKitError as e: print("{}, trying again -- attempt number {}, timeout: {} seconds".format(e, attempt, timeout_seconds)) if len(q_run_seconds)>0: # got the real measured q time total_q_run_seconds = sum( q_run_seconds ) else: # have to assume total_q_run_seconds = time.time() - timestamp_before_q_run q_run_seconds = [ total_q_run_seconds ] q_runs = len(q_run_seconds) total_q_run_shots = sample_number * q_runs q_run_shots = [sample_number] * q_runs report_this_iteration = { 'total_q_seconds_per_c_iteration' : total_q_run_seconds, 'seconds_per_individual_q_run' : q_run_seconds, 'total_q_shots_per_c_iteration' : total_q_run_shots, 'shots_per_individual_q_run' : q_run_shots, 'energy' : energy, } if report != 'TestMode': report['iterations'].append( report_this_iteration ) report['total_q_seconds'] += report_this_iteration['total_q_seconds_per_c_iteration'] # total_q_time += total report['total_q_shots'] += report_this_iteration['total_q_shots_per_c_iteration'] fun_evaluation_counter += 1 report_this_iteration['total_seconds_per_c_iteration'] = time.time() - timestamp_before_ee print(report_this_iteration, "\n") json_stream_file.write( json.dumps(report_this_iteration, cls=NumpyEncoder)+"\n" ) json_stream_file.flush() return energy # Initialise quantum program Q_program = QuantumProgram() # Groups a list of (coeff,Pauli) tuples into tensor product basis (tpb) sets pauli_list_grouped = group_paulis(pauli_list) report = { 'total_q_seconds': 0, 'total_q_shots':0, 'iterations' : [] } # Initial objective function value fun_initial = expectation_estimation(start_params, 'TestMode') print('Initial guess at start_params is: {:.4f}'.format(fun_initial)) timestamp_before_optimizer = time.time() optimizer_output = minimizer_function(expectation_estimation, start_params, my_args=(report), my_options = minimizer_options) report['total_seconds'] = time.time() - timestamp_before_optimizer # Also generate and provide a validated function value at the optimal point fun_validated = expectation_estimation(optimizer_output['x'], 'TestMode') print('Validated value at solution is: {:.4f}'.format(fun_validated)) # Exact (noiseless) calculation of the energy at the given point: complex_energy, _ = eval_hamiltonian(Q_program, pauli_list, ansatz_function(optimizer_output['x']), 1, 'local_statevector_simulator') optimizer_output['fun_exact'] = complex_energy.real optimizer_output['fun_validated'] = fun_validated print('Total Q seconds = %f' % report['total_q_seconds']) print('Total Q shots = %d' % report['total_q_shots']) print('Total seconds = %f' % report['total_seconds']) return (optimizer_output, report) if __name__ == '__main__': start_params, sample_number, q_device_name, minimizer_method, minimizer_options, minimizer_function = cmdline_parse_and_report( num_params = custom_ansatz.num_params, q_device_name_default = 'local_qasm_simulator', q_device_name_help = "Real devices: 'ibmqx4' or 'ibmqx5'. Use 'ibmq_qasm_simulator' for remote simulator or 'local_qasm_simulator' for local", minimizer_options_default = '{"maxfev":200, "xatol": 0.001, "fatol": 0.001}', start_param_value_default = 0.0 ) # q_device_name = os.environ.get('VQE_QUANTUM_BACKEND', 'local_qasm_simulator') # try 'local_qasm_simulator', 'ibmq_qasm_simulator', 'ibmqx4', 'ibmqx5' try: import Qconfig register(Qconfig.APItoken, Qconfig.config["url"], verify=False, hub=Qconfig.config["hub"], group=Qconfig.config["group"], project=Qconfig.config["project"]) except: print(""" WARNING: There's no connection with IBMQuantumExperience servers. cannot test I/O intesive tasks, will only test CPU intensive tasks running the jobs in the local simulator """) # Ignore warnings due to chopping of small imaginary part of the energy #import warnings #warnings.filterwarnings('ignore') # Load the Hamiltonian into Qiskit-friendly format: pauli_list = [ [label_to_hamiltonian_coeff[label], label_to_pauli(label)] for label in label_to_hamiltonian_coeff ] # Calculate Exact Energy classically, to compare with quantum solution: # H = make_Hamiltonian(pauli_list) classical_energy = np.amin(la.eigh(H)[0]) print('The exact ground state energy (the smallest eigenvalue of the Hamiltonian) is: {:.4f}'.format(classical_energy)) # Load the ansatz function from the plug-in ansatz_method = get_first_callable( custom_ansatz ) ansatz_function = getattr(custom_ansatz, ansatz_method) # ansatz_method is a string/name, ansatz_function is an imported callable timeout_seconds = int( os.environ.get('VQE_QUANTUM_TIMEOUT', '120') ) json_stream_file = open('vqe_stream.json', 'a') # ---------------------------------------- run VQE: -------------------------------------------------- (vqe_output, report) = vqe_for_qiskit(sample_number, pauli_list, timeout_seconds, json_stream_file) # ---------------------------------------- store the results: ---------------------------------------- json_stream_file.write( '# Experiment finished\n' ) json_stream_file.close() minimizer_src = inspect.getsource( minimizer_function ) ansatz_src = inspect.getsource( ansatz_function ) vqe_input = { "q_device_name" : q_device_name, "minimizer_method" : minimizer_method, "minimizer_src" : minimizer_src, "minimizer_options" : minimizer_options, "ansatz_method" : ansatz_method, "ansatz_src" : ansatz_src, "sample_number" : sample_number, "classical_energy" : classical_energy } output_dict = { "vqe_input" : vqe_input, "vqe_output" : vqe_output, "report" : report } formatted_json = json.dumps(output_dict, cls=NumpyEncoder, sort_keys = True, indent = 4) # print(formatted_json) with open('ibm_vqe_report.json', 'w') as json_file: json_file.write( formatted_json )