Path: blob/main/notebooks/summer-school/2022/resources/lab-notebooks/lab-2.ipynb
3855 views
Lab 2: Advanced Circuits
Welcome to Qiskit! Before starting with the exercises, please run the cell below by pressing 'shift' + 'return'.
II.1: Operators and Qiskit Opflow
In this notebook we will learn the fundamentals of Qiskit Opflow module, this has advanced features that aim to bridge the gap from quantum information theory to experiments. The Qiskit Opflow module will allow us to quickly enter the realm of quantum simulation. Quoting the Qiskit documentation:
"The Operator Flow is meant to serve as a lingua franca between the theory and implementation of Quantum Algorithms & Applications. Meaning, the ultimate goal is that when theorists speak their theory in the Operator Flow, they are speaking valid implementation, and when the engineers speak their implementation in the Operator Flow, they are speaking valid physical formalism."
Here you can find more documentation and examples on the module. To start, let's get familiar with how to define operators.
1.) Define Pauli operators for one qubit
Define operators for the four pauli matrices: X, Y, Z, I; and collect them in a list pauli_list.
There's a few operations that we can do on operators which are implemented in Qiskit Opflow. For example, we can rescale an operator by a scalar factor using *, we can compose operators using @ and we can take the tensor product of operators using ^. In the following, let us try to use these operations. Note that we need to be careful with the operations' precedences as python evaluates + before ^ and that may change the intended value of an expression. For example, I^X+X^I is actually interpreted as I^(X+X)^I=2(I^X^I). Therefore the use of parenthesis is strongly recommended to avoid these types of errors. Also, keep in mind that the imaginary unit i is defined as 1j in Python.
2.) Define the ladder operator: and
We can take the operators defined in Qiskit Opflow and translate them into other representation. For example the to_matrix() method of an Operator object allows us to retrieve the matrix representation of the operator (as a numpy array)
3.) Obtain the matrix representation of the pauli operators (sigma_X, sigma_Y, sigma_Z and identity )
Please submit the result as a list with the operators ordered as above.
We can also generate a circuit representation of the operator using the to_circuit() method
4.) Obtain the circuit representation of the pauli operators (sigma_X, sigma_Y, sigma_Z and identity )
Please submit the result as a list with the operators ordered as above.
II.2: Simulating Time-Evolution with Quantum Circuits
Now that we are a little more familiar with the syntax of the Qiskit Opflow module we can put this knowledge to use to build the first quantum circuit simulating the dynamics (or time-evolution) of a system described by a given Hamiltonian. As a first step, let us introduce parametrized circuits. Below we'll create a circuit with a parametrized rotation with an angle . The goal is not to directly use parametrized rotations but to understand how Qiskit's quantum circuit can accept parameters whose values will be defined later on. We'll need that to create circuits that represent time-evolution operators with a parametrized value for the time.
1.) Create a circuit with a parametrized RX rotation of an angle
This creates a circuit where the parameter of the RX gate is a placeholder which is waiting for a value. Once we decide on the value of , we can bind it to the circuit using the bind_parameters({parameter: parameter_value}) method of the QuantumCircuit object.
2.) Bind numerical value of the angle
Let us start to prepare the building blocks we'll need to calculate the time-evolution of a quantum system using a quantum computer. First let's define the Hamiltonian of the system to be the Heisenberg Hamiltonian for two qubits:
3.) Define the Heisenberg Hamiltonian using Qiskit Opflow
Next, let's create a quantum circuit for time evolution! We'll parametrize the time t with a Qiskit Parameter and exponentiate the Heisenberg Hamiltonian with the Qiskit Opflow method exp_i() which implements the corressponding time-evolution operator
4.) Define the time evolution operator for the Heisenberg Hamiltonian and the time step
We can then generate a circuit which implements the necessary operations that compute the time-evolution operator for a given evolution time. First, let's try to do this exactly with the MatrxEvolution class of Qiskit Opflow.
5.) Use MatrixEvolution to calculate the exact exponentiation at time
*Hint: First you'll need to instantiate a MatrixEvolution() object. This object has a method called convert(operator) which takes a time-evolution operator and generates a quantum circuit implementing the operation. Finally, you'll need to bind the value of the evolution time to the circuit.
As a last step, let us also generate the circuit corresponding to the time-evolution operator calculated using the Trotter-Suzuki decomposition. For this we'll use the PauliTrotterEvolution class in the same way we've used the MatrixEvolution() one.
6.) Use PauliTrotterEvolution to calculate the approximate exponentiation for a small time step
The full evolution can then be obtained by putting together several Trotter steps up to the desired evolution time. For each Trotter step you can compose the single-step Trotter using the @ operator.
7.) Concatenate several Trotter steps to generate the desired evolution
Consider now a system of three qubits initially in the state, whose evolution is determined by the tight binding Hamiltonian
Determine the final state at time by evolving the initial state with the time-evolution operator generated by the tight binding Hamiltonian. You can proceed in a similar way as the previous exercises, be careful to compose the circuit for the state preparation and for the time evolution correctly. Note that you should define the Hamiltonian operator exactly as the definition above to get the right aswer for the grader.