<jupyter_start><jupyter_text>Exercise 5: VQEName: <NAME> Score: 3 Error: 2.35881 mHa Number of parameters: 16 General approach: start with a custom hardware efficient ansatz (HEA) using simple rotation and entanglement blocks. Achieve an acceptable ground state energy by adjusting the transformers, reductions, ansatz repetitions, and optimizer hyperparameters based on the results.<jupyter_code>from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem
from qiskit_nature.circuit.library import HartreeFock
from qiskit_nature.mappers.second_quantization import ParityMapper
from qiskit_nature.converters.second_quantization.qubit_converter import QubitConverter
from qiskit_nature.drivers import PySCFDriver
from qiskit_nature.transformers import FreezeCoreTransformer
from qiskit_nature.algorithms.ground_state_solvers.minimum_eigensolver_factories import NumPyMinimumEigensolverFactory
from qiskit_nature.algorithms.ground_state_solvers import GroundStateEigensolver
from qiskit.algorithms.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal
from IPython.display import display, clear_output
from qiskit.algorithms import VQE
from qiskit.circuit import Parameter, QuantumCircuit, QuantumRegister
from qiskit import Aer

import numpy as np 

backend = Aer.get_backend('statevector_simulator')<jupyter_output><empty_output><jupyter_text>The first two cells define and preprocess LiH under the following assumptions:* Core orbitals were frozen.* Unoccupied orbitals were removed to simplify the quantum circuit. Specifically, the two spin orbitals that contribute to antibonding MO 3$\sigma^*$ were removed from the problem. These spin orbitals correspond to the row indices 3 and 4. Note that the orbital indices can be determined by the row number of a fully reduced row in qmolecule.one_body_integrals, but this step is omitted for brevity.<jupyter_code>molecule = 'Li 0.0 0.0 0.0; H 0.0 0.0 1.5474'
driver = PySCFDriver(atom=molecule)
qmolecule = driver.run()

# Freeze core
freezer = FreezeCoreTransformer(freeze_core = True, remove_orbitals=[3,4])
# VQE data callback function (provided in ex. 5)
def callback(eval_count, parameters, mean, std):  
    display("Evaluation: {}, Energy: {}, Std: {}".format(eval_count, mean, std))
    clear_output(wait=True)
    counts.append(eval_count)
    values.append(mean)
    params.append(parameters)
    deviation.append(std)<jupyter_output><empty_output><jupyter_text>The next two cells construct the ElectronicStructureProblem to then form the qubit operators, map the problem Hamiltonian to a minimum number of qubits, and sets the InitialState of the ansatz circuit as a Fock matrix.ParityMapper() was arbitrarily chosen as the fermionic mapping method among those available in Qiskit Nature because it best reduced the number of qubits used in the ansatz.<jupyter_code># Create e- structure
problem = ElectronicStructureProblem(driver, q_molecule_transformers=[freezer])

# Generate the second-quantized operators
second_q_ops = problem.second_q_ops()

# Hamiltonian
main_op = second_q_ops[0]

# Mapper - Parity selected in order to use two_qubit_reduction
mapper = ParityMapper()

# Converter
converter = QubitConverter(mapper=mapper, two_qubit_reduction=True, z2symmetry_reduction = [1])
# Operator mapping
num_particles = (problem.molecule_data_transformed.num_alpha,
             problem.molecule_data_transformed.num_beta)
qubit_op = converter.convert(main_op, num_particles=num_particles)

# Generate LiH data for initial state
num_particles = (problem.molecule_data_transformed.num_alpha,
             problem.molecule_data_transformed.num_beta)
num_spin_orbitals = 2 * problem.molecule_data_transformed.num_molecular_orbitals

# Hartree-Fock initial state creates Fock matrix for N-body approximation
init_state = HartreeFock(num_spin_orbitals, num_particles, converter)<jupyter_output><empty_output><jupyter_text>The eigenvalue for the ground state energy was solved by classical methods (diagonalization):<jupyter_code>def exact_diagonalizer(problem, converter):
    solver = NumPyMinimumEigensolverFactory()
    calc = GroundStateEigensolver(converter, solver)
    result = calc.solve(problem)
    return result

result_exact = exact_diagonalizer(problem, converter)
exact_energy = np.real(result_exact.eigenenergies[0])
print("Exact electronic energy", exact_energy)<jupyter_output>Exact electronic energy -1.0887060157347406<jupyter_text>The HEA used here, based on [Kandala et al.](https://arxiv.org/pdf/1704.05018.pdf), is constructed by the add_ansatz method with the number of qubits used by qubit_op and init_state. For ease of implementation, the HEA was constructed out of TwoLocal by changing the entanglement method and block. Full access to qubit phases is provided by the rotation block sequence of RYRZ, whereas amplitude access is provided by the RY component and the CX entanglement block.Only one repetition of TwoLocal was found necessary during the parameter reduction stage. The ansatz was initially run with 7 repetitions as recommended by the authors; however, VQE could not converge to an acceptable ground state energy with this large of an ansatz. Reducing the size to a less rigid QuantumCircuit, up to 3 repetitions, resulted in a ground state energy convergence within the required 4 mHa error bound. SLSQP was chosen as the optimizer among COBYLA and L_BFGS_B because it consistently reached more accurate ground state energies despite the other VQE parameters.<jupyter_code>def add_ansatz(qubit_op, init_state, reps):
    # Implement single-layer hardware efficient ansatz using TwoLocal()
    ansatz = TwoLocal(qubit_op.num_qubits, rotation_blocks = ['ry', 'rz'], 
                      entanglement_blocks = ['cx'], reps = 1, entanglement = 'linear', 
                      skip_final_rotation_layer = False)
    ansatz.compose(init_state, front=True, inplace=True)
    return ansatz
# Set ansatz
ansatz = add_ansatz(qubit_op, init_state, reps = 1)

optimizer = SLSQP(maxiter = 10000)

counts = []
values = []
params = []
deviation = []

# Set initial parameters of the ansatz with predefined displacements for challenge
try:
    initial_point = [0.01] * len(ansatz.ordered_parameters)
except:
    initial_point = [0.01] * ansatz.num_parameters

algorithm = VQE(ansatz,
                optimizer=optimizer,
                quantum_instance=backend,
                callback=callback,
                initial_point=initial_point)

result = algorithm.compute_minimum_eigenvalue(qubit_op)

print(result)
ansatz.draw(output='mpl')
print("Error: ", abs(exact_energy-result.optimal_value) * 1000, "mHa")<jupyter_output>Error:  2.358812338824734 mHa
{'fraction_non_alphanumeric': 0.06563013903423531, 'fraction_numerical': 0.01465091941994319, 'mean_word_length': 5.6041461006910165, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 20, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '89215', 'license': 'Apache-2.0', 'n_tokens_mistral': 2071, 'n_tokens_neox': 1867, 'n_words': 630, 'path': 'solutions by participants/ex5/ex5-SamanthaLang-3cnot-2.3588mHa-16params.ipynb', 'repo_name': 'fazliberkordek/ibm-quantum-challenge-2021', 'size': '6696'}