[1]:
import quanguru as qg
# QuanGuru uses sparse matrices by default,
# but sparse matrices are not easily readable when we print them
# so, in below examples, we use .A to print them as arrays
3 - Coupling quantum systems#
In this tutorial, we show how to create a coupling between the sub-system of a composite quantum system.
Two qubits exchange interaction#
A simple example is the exchange interaction between two qubits
where the first two terms () are the free evolution terms of each qubit, and the other two terms (
) are the exchange coupling between them.
The Qubit
objects already implement their free evolution terms, and we will create each coupling term below.
[2]:
qub1 = qg.Qubit(frequency=1)
qub2 = qg.Qubit(frequency=1)
twoQub = qub1 + qub2
In order to create a coupling, we call the createSysCoupling
method on our composite quantum system twoQub
. createSysCoupling
method cover various different usages, but here we will demonstrate its basic usage, where we pass 3 essential information regarding the coupling:
A list of systems to be coupled with (in our case
[qub1, qub2]
)A list of coupling operators (in our case
[qg.sigmap, qg.sigmam]
and[qg.sigmam, qg.sigmap]
)coupling frequency
createSysCoupling
method returns a coupling object that can later be used to modify coupling parameters, such as frequency
.
Note that the order of systems in the given list does not need to match the Hilbert space structure, but you need to make sure that the list of coupling operators are consistent with the systems. For example, below two couplings create and
, respectively, and we can understand this from the order of operators.
[3]:
couplingPM12 = twoQub.createTerm(operator=[qg.sigmap, qg.sigmam],
frequency=1,
qSystem=[qub1, qub2])
couplingMP12 = twoQub.createTerm(operator=[qg.sigmam, qg.sigmap],
frequency=1,
qSystem=[qub1, qub2])
Let’s print the total Hamiltonian (i.e. incl. coupling) of the coupled twoQub
system and verify.
[4]:
twoQub.totalHamiltonian.A
[4]:
array([[ 1., 0., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 0., -1.]])
Three qubits nearest-neighbor exchange interaction#
We can extend the above Hamiltonian to 3 qubits as
which in a more compact form and for n sub-systems written as
In order to extend our system, we first need to add a new qubits to twoQub
system then create a coupling between this new qubit and qub2
.
[5]:
qub3 = qg.Qubit(frequency=1)
threeQub = twoQub + qub3
couplingPM23 = threeQub.createTerm(operator=[qg.sigmap, qg.sigmam],
frequency=1,
qSystem=[qub2, qub3])
couplingMP23 = threeQub.createTerm(operator=[qg.sigmam, qg.sigmap],
frequency=1,
qSystem=[qub2, qub3])
Let’s print the total Hamiltonian (i.e. incl. coupling) of the coupled twoQub
system and verify.
[6]:
threeQub.totalHamiltonian.A
[6]:
array([[ 1.5, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 0.5, 1. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 1. , 0.5, 0. , 1. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , -0.5, 0. , 1. , 0. , 0. ],
[ 0. , 0. , 1. , 0. , 0.5, 0. , 0. , 0. ],
[ 0. , 0. , 0. , 1. , 0. , -0.5, 1. , 0. ],
[ 0. , 0. , 0. , 0. , 0. , 1. , -0.5, 0. ],
[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , -1.5]])
Many-body coupling#
In above cases, the coupling terms contain operators only for two of the systems. In more general cases, we might need terms with more systems. As an example consider the below arbitrary/artificial coupling term
QuanGuru
supports such many body terms, and we can create the above term as
[7]:
couplingXYZ = threeQub.createTerm(operator=[qg.sigmax, qg.sigmay, qg.sigmaz],
frequency=1,
qSystem=[qub1, qub2, qub3])
# we can also print the Hamiltonian term corresponding to a coupling as
print(couplingXYZ.totalHamiltonian.A)
[[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.-1.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+1.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+1.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.-1.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.-1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.-1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
[8]:
print(qg.tensorProd(qg.sigmax(), qg.sigmay(), qg.sigmaz()).A)
[[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.-1.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+1.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+1.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.-1.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.-1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.-1.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
[9]:
threeQub.totalHamiltonian.A
[9]:
array([[ 1.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j,
0. -1.j, 0. +0.j],
[ 0. +0.j, 0.5+0.j, 1. +0.j, 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +1.j],
[ 0. +0.j, 1. +0.j, 0.5+0.j, 0. +0.j, 1. +1.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, -0.5+0.j, 0. +0.j, 1. -1.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 1. -1.j, 0. +0.j, 0.5+0.j, 0. +0.j,
0. +0.j, 0. +0.j],
[ 0. +0.j, 0. +0.j, 0. +0.j, 1. +1.j, 0. +0.j, -0.5+0.j,
1. +0.j, 0. +0.j],
[ 0. +1.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j, 1. +0.j,
-0.5+0.j, 0. +0.j],
[ 0. +0.j, 0. -1.j, 0. +0.j, 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, -1.5+0.j]])