Using Qiskit Aqua's quantum evolution functionality

This notebook demonstrates how to realize quantum evolution using the Qiskit Aqua library.

Further information is available for the algorithms in the github repo aqua/readme.md

First, an Operator instance is created for our randomly generated Hamiltonian. We also randomly generate an initial quantum state state_in.


In [1]:
import numpy as np
from qiskit_aqua.operator import Operator
from qiskit_aqua import get_initial_state_instance

num_qubits = 2
evo_time = 1
temp = np.random.random((2 ** num_qubits, 2 ** num_qubits))
h1 = temp + temp.T
qubitOp = Operator(matrix=h1)
state_in = get_initial_state_instance('CUSTOM')
state_in.init_args(num_qubits, state='random')

With the operator and the initial state, we can easily compute the groundtruth evolution result as follows.


In [2]:
from scipy.linalg import expm

state_in_vec = state_in.construct_circuit('vector')
groundtruth = expm(-1.j * h1 * evo_time) @ state_in_vec
print('The directly computed groundtruth evolution result state is\n{}.'.format(groundtruth))


The directly computed groundtruth evolution result state is
[-0.47937078+0.31977028j -0.15633652+0.38304763j -0.46790501-0.10220309j
 -0.37610106+0.35489639j].

The evolve method as provided by the Operator class also provides the ability to compute the evolution groundtruth via the same matrix and vector multiplication. Therefore, we can also compute the evolution's groundtruth result state as follows, which we can easily verify to be the same as the groundtruth we just computed.


In [3]:
groundtruth_evolution = qubitOp.evolve(state_in_vec, evo_time, 'matrix', 0)
print('The groundtruth evolution result as computed by the Dynamics algorithm is\n{}.'.format(groundtruth_evolution))
np.testing.assert_allclose(groundtruth_evolution, groundtruth)


The groundtruth evolution result as computed by the Dynamics algorithm is
[-0.47937078+0.31977028j -0.15633652+0.38304763j -0.46790501-0.10220309j
 -0.37610106+0.35489639j].

Next, let's actually build the quantum circuit, which involves the circuit for putting the system in the specified initial state, and the actual evolution circuit corresponding to the operator we generated, for which, let's, for example, use the 3rd order suzuki expansion.


In [4]:
from qiskit import QuantumCircuit, QuantumRegister

quantum_registers = QuantumRegister(qubitOp.num_qubits)
circuit = state_in.construct_circuit('circuit', quantum_registers)
circuit += qubitOp.evolve(
    None, evo_time, 'circuit', 1,
    quantum_registers=quantum_registers,
    expansion_mode='suzuki',
    expansion_order=3
)

With the circuit built, we can now execute the circuit to get the evolution result. We use the statevector_simulator backend for the purpose of this demonstration.


In [5]:
from qiskit.wrapper import execute as q_execute
from qiskit import Aer

backend = Aer.get_backend('statevector_simulator')

job = q_execute(circuit, backend)
circuit_execution_result = np.asarray(job.result().get_statevector(circuit))
print('The evolution result state from executing the Dynamics circuit is\n{}.'.format(circuit_execution_result))


The evolution result state from executing the Dynamics circuit is
[0.5684845 +0.09433242j 0.376057  -0.17251745j 0.27145294+0.39423795j
 0.51733189-0.00175642j].

We can then check the fidelity between the groundtruth and the circuit_execution_result.


In [6]:
from qiskit.tools.qi.qi import state_fidelity

print('Fidelity between the groundtruth and the circuit result states is {}.'.format(
    state_fidelity(groundtruth, circuit_execution_result)
))


Fidelity between the groundtruth and the circuit result states is 0.9999998362578388.

As seen, the fidelity is very close to 1, indicating that the quantum circuit produced is a good approximation of the intended evolution.