In [1]:
from quimb import *
data = [1, 2j, -3]
Kets are column vectors, i.e. with shape (d, 1)
:
In [2]:
qu(data, qtype='ket')
Out[2]:
The normalized=True
option can be used to ensure a normalized output.
Bras are row vectors, i.e. with shape (1, d)
:
In [3]:
qu(data, qtype='bra') # also conjugates the data
Out[3]:
And operators are square matrices, i.e. have shape (d, d)
:
In [4]:
qu(data, qtype='dop')
Out[4]:
Which can also be sparse:
In [5]:
qu(data, qtype='dop', sparse=True)
Out[5]:
In [6]:
psi = 1.0j * bell_state('psi-')
psi
Out[6]:
In [7]:
psi.H
Out[7]:
In [8]:
psi = up()
psi
Out[8]:
In [9]:
psi.H @ psi # inner product
Out[9]:
In [10]:
X = pauli('X')
X @ psi # act as gate
Out[10]:
In [11]:
psi.H @ X @ psi # operator expectation
Out[11]:
In [12]:
expec(psi, psi)
Out[12]:
In [13]:
expec(psi, X)
Out[13]:
Here's an example for a much larger (20 qubit), sparse operator expecation, which will be automatically parallelized:
In [14]:
psi = rand_ket(2**20)
A = rand_herm(2**20, sparse=True) + speye(2**20)
A
Out[14]:
In [15]:
expec(A, psi) # should be ~ 1
Out[15]:
In [16]:
%%timeit
expec(A, psi)
In [17]:
dims = [2] * 10 # overall space of 10 qubits
X = pauli('X')
IIIXXIIIII = ikron(X, dims, inds=[3, 4]) # act on 4th and 5th spin only
IIIXXIIIII.shape
Out[17]:
In [18]:
dims = [2] * 3
XZ = pauli('X') & pauli('Z')
ZIX = pkron(XZ, dims, inds=[2, 0])
ZIX.real.astype(int)
Out[18]:
In [19]:
dims = [2] * 10
D = prod(dims)
psi = rand_ket(D)
rho_ab = ptr(psi, dims, [0, 9])
rho_ab.round(3) # probably pretty close to identity
Out[19]: