量子对象的基本操作
首要事项
警告
不要从安装目录运行QuTiP。
要加载 qutip 模块,首先调用导入语句:
from qutip import *
这将加载所有用户可用的函数。通常,我们还需要导入NumPy和Matplotlib库:
import numpy as np
import matplotlib.pyplot as plt
在文档的其余部分,函数使用qutip.module.function()符号表示,该符号链接到QuTiP API中的相应函数:API文档。然而,在调用import *时,我们已经加载了所有的QuTiP模块。因此,在从解释器提示符、Python脚本或Jupyter笔记本调用函数时,我们只需要函数名称,而不需要完整的路径。
量子对象类
介绍
经典力学和量子力学之间的关键区别在于使用算符而不是数字作为变量。此外,我们需要指定状态向量及其属性。因此,在计算量子系统的动力学时,我们需要一个数据结构来封装量子算符和ket/bra向量的属性。量子对象类qutip.Qobj通过矩阵表示来实现这一点。
首先,让我们创建一个空白的 Qobj:
print(Qobj())
输出:
Quantum object: dims = [[1], [1]], shape = (1, 1), type = bra
Qobj data =
[[0.]]
在这里,我们看到了空白的 Qobj 对象,它具有维度、形状和数据。这里的数据对应于一个由单个零条目组成的1x1维矩阵。
提示
按照惯例,Python类的名称,如Qobj(),是大写的,而函数的名称则不是。
我们可以通过将数据列表或数组传递到Qobj中来创建一个带有用户定义数据集的Qobj:
print(Qobj([[1],[2],[3],[4],[5]]))
输出:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[1.]
[2.]
[3.]
[4.]
[5.]]
x = np.array([[1, 2, 3, 4, 5]])
print(Qobj(x))
输出:
Quantum object: dims = [[1], [5]], shape = (1, 5), type = bra
Qobj data =
[[1. 2. 3. 4. 5.]]
r = np.random.rand(4, 4)
print(Qobj(r))
输出:
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[0.37454012 0.95071431 0.73199394 0.59865848]
[0.15601864 0.15599452 0.05808361 0.86617615]
[0.60111501 0.70807258 0.02058449 0.96990985]
[0.83244264 0.21233911 0.18182497 0.18340451]]
请注意,dims 和 shape 如何根据输入数据而变化。尽管 dims 和 shape 看起来相同,dims 会跟踪多部分系统中各个组件的形状,而 shape 则不会。我们建议读者参考张量积和部分迹部分以获取更多信息。
注意
如果你从python脚本运行QuTiP,你必须使用print函数来查看Qobj属性。
状态和操作符
手动为每个量子对象指定数据是低效的。尤其是当大多数对象对应于常用类型时,例如谐振子的阶梯算子、两级系统的泡利自旋算子,或者像福克态这样的态矢量。因此,QuTiP 包含了各种状态和算子的预定义对象:
状态 |
命令(# 表示可选) |
输入 |
|---|---|---|
福克态基矢 |
|
N = 希尔伯特空间中的能级数, m = 包含激发的能级 (如果没有给出m,则为0) |
空态矢量 |
|
N = 希尔伯特空间中的能级数, |
Fock密度矩阵 (基的外积) |
|
与basis(N,m) / fock(N,m)相同 |
相干态 |
|
alpha = 复数(特征值) 用于请求的相干态 |
相干密度矩阵 (外积) |
|
与coherent(N,alpha)相同 |
热密度矩阵 (对于n个粒子) |
|
n = 粒子数期望值 |
最大混合密度矩阵 |
|
N = 希尔伯特空间中的能级数 |
操作符 |
命令(# 表示可选) |
输入 |
|---|---|---|
电荷操作符 |
|
具有从M..0..N的条目的对角操作符。 |
交换子 |
|
类型 = ‘normal’ 或 ‘anti’。 |
对角线操作符 |
|
从给定偏移量的对角线数组创建的量子对象。 |
位移算子 (单模) |
|
N=希尔伯特空间中的能级数, alpha = 复位移幅度。 |
高自旋算子 |
|
j = 整数或半整数 表示自旋,s = ‘x’, ‘y’, ‘z’, ‘+’, 或 ‘-’ |
单位矩阵 |
|
N = 希尔伯特空间中的能级数。 |
类似单位矩阵 |
|
qobj = 从中复制维度的对象。 |
降低(销毁)操作符 |
|
同上 |
动量算子 |
|
同上 |
数字运算符 |
|
同上 |
相位算子 (单模) |
|
具有参考相位 phi0 的单模 Pegg-Barnett 相位算子。 |
位置操作符 |
|
同上 |
提升(创建)操作符 |
|
同上 |
压缩算子 (单模) |
|
N=希尔伯特空间中的能级数, sp = 压缩参数。 |
压缩算子 (广义) |
|
q1,q2 = 量子算子 (Qobj) sp = 压缩参数。 |
Sigma-X |
|
|
Sigma-Y |
|
|
Sigma-Z |
|
|
西格玛加 |
|
|
Sigma 减 |
|
|
隧道操作符 |
|
具有形式为 \(|N> |
作为一个例子,我们给出了这些函数中一些的输出:
>>> basis(5,3)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]
[0.]]
>>> coherent(5,0.5-0.5j)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[ 0.7788017 +0.j ]
[ 0.38939142-0.38939142j]
[ 0. -0.27545895j]
[-0.07898617-0.07898617j]
[-0.04314271+0.j ]]
>>> destroy(4)
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[0. 1. 0. 0. ]
[0. 0. 1.41421356 0. ]
[0. 0. 0. 1.73205081]
[0. 0. 0. 0. ]]
>>> sigmaz()
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 1. 0.]
[ 0. -1.]]
>>> jmat(5/2.0,'+')
Quantum object: dims = [[6], [6]], shape = (6, 6), type = oper, isherm = False
Qobj data =
[[0. 2.23606798 0. 0. 0. 0. ]
[0. 0. 2.82842712 0. 0. 0. ]
[0. 0. 0. 3. 0. 0. ]
[0. 0. 0. 0. 2.82842712 0. ]
[0. 0. 0. 0. 0. 2.23606798]
[0. 0. 0. 0. 0. 0. ]]
Qobj 属性
我们已经看到,量子对象有几个内部属性,例如data、dims和shape。这些可以通过以下方式访问:
>>> q = destroy(4)
>>> q.dims
[[4], [4]]
>>> q.shape
(4, 4)
一般来说,Qobj对象(或任何Python对象)的属性(属性)可以使用Q.attribute符号来检索。
除了使用print函数显示的那些属性外,Qobj类的实例还具有以下属性:
属性 |
特性 |
描述 |
|---|---|---|
数据 |
|
表示状态或操作符的矩阵 |
维度 |
|
列表,用于跟踪多部分系统中各个组件的形状(用于张量积和部分迹)。 |
形状 |
|
基础数据矩阵的维度。 |
是厄米矩阵吗? |
|
操作符是否是厄米的? |
类型 |
|
对象是‘ket’、‘bra’、‘oper’还是‘super’类型? |
将 Qobj 类视为用于描述量子算子或状态向量所需属性的容器。
对于上述的销毁操作符:
>>> q.type
'oper'
>>> q.isherm
False
>>> q.data
Dia(shape=(4, 4), num_diag=1)
data 属性返回一个 Qutip 对角矩阵。
Qobj 实例将其数据存储在 Qutip 矩阵格式中。
在核心 qutip 模块中,Dense、CSR 和 Dia 格式是可用的,但其他包可以添加其他格式。
例如,qutip-jax 模块添加了 Jax 和 JaxDia 格式。
可以使用 Qobj.full 始终将底层矩阵作为 numpy 数组访问。
也可以使用 Qobj.data_as 以通用格式访问底层数据。
>>> q.data_as("dia_matrix")
<4x4 sparse matrix of type '<class 'numpy.complex128'>'
with 3 stored elements (1 diagonals) in DIAgonal format>
存储类型之间的转换是使用Qobj.to方法完成的。
>>> q.to("CSR").data
CSR(shape=(4, 4), nnz=3)
>>> q.to("CSR").data_as("csr_matrix")
<4x4 sparse matrix of type '<class 'numpy.complex128'>'
with 3 stored elements in Compressed Sparse Row format>
请注意,Qobj.data_as 不会进行转换。
QuTiP 在需要时会进行转换,以确保在任何格式下都能正常工作。
然而,这些转换可能会减慢计算速度,因此建议尽可能保持使用一种格式系列。
例如,核心 QuTiP 的 Dense 和 CSR 可以很好地协同工作,并且这些格式之间的二进制操作是高效的。
然而,应避免在 Dense 和 Jax 之间进行二进制操作,因为并不总是清楚操作是由 Jax(可能在 GPU 上执行,如果有的话)还是由 numpy 执行的。
Qobj 数学
Qobj 实例上的数学运算规则与标准矩阵算术类似:
>>> q = destroy(4)
>>> x = sigmax()
>>> q + 5
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[5. 1. 0. 0. ]
[0. 5. 1.41421356 0. ]
[0. 0. 5. 1.73205081]
[0. 0. 0. 5. ]]
>>> x * x
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[1. 0.]
[0. 1.]]
>>> q ** 3
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[0. 0. 0. 2.44948974]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]]
>>> x / np.sqrt(2)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.70710678]
[0.70710678 0. ]]
当然,就像矩阵一样,将两个形状不兼容的对象相乘会抛出错误:
>>> print(q * x)
------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-0b599f41213e> in <module>
----> 1 print(q * x)
~/Documents/qutip_dev/qutip/qutip/qobj.py in __mul__(self, other)
553
554 else:
--> 555 raise TypeError("Incompatible Qobj shapes")
556
557 elif isinstance(other, np.ndarray):
TypeError: Incompatible Qobj shapes
此外,还支持逻辑运算符“等于”==和“不等于”!=。
在Qobj类上操作的函数
与属性类似,量子对象类定义了操作Qobj类实例的函数(方法)。对于一个一般的量子对象Q:
函数 |
命令 |
描述 |
|---|---|---|
检查厄米性 |
|
检查量子对象是否为厄米矩阵 |
共轭 |
|
量子对象的共轭。 |
余弦 |
|
量子对象的余弦。 |
Dagger (伴随) |
|
返回对象的伴随(dagger)。 |
对角线 |
|
返回对角线元素。 |
钻石范数 |
|
返回钻石范数。 |
特征能量 |
|
算子的特征能量(值)。 |
本征态 |
|
返回特征值和特征向量。 |
指数 |
|
操作符的矩阵指数。 |
完整 |
|
返回Q数据的完整(非稀疏)数组。 |
基态 |
|
Qobj 基态的本征值和本征态。 |
矩阵逆 |
|
Qobj的矩阵逆。 |
矩阵元素 |
|
矩阵元素 |
Norm |
|
返回状态的L2范数, 操作符的迹范数。 |
重叠 |
|
当前 Qobj 与给定状态之间的重叠。 |
部分迹 |
|
部分迹返回使用‘sel’参数选择的组件。 |
Permute |
|
按照给定的顺序排列复合对象的张量结构。 |
投影器 |
|
从给定的ket或bra向量形成投影算子。 |
正弦 |
|
量子算符的正弦。 |
Sqrt |
|
操作符的矩阵平方根。 |
整理 |
|
从Qobj中移除小元素。 |
Trace |
|
返回量子对象的迹。 |
转换 |
|
转换矩阵格式为 CSR / 密集。 |
变换 |
|
由矩阵或基态列表 'inpt' 定义的基变换。 |
转置 |
|
量子对象的转置。 |
截断负值 |
|
截断负特征值 |
单位 |
|
返回归一化(单位)向量 Q/Q.norm()。 |
>>> basis(5, 3)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]
[0.]]
>>> basis(5, 3).dag()
Quantum object: dims = [[1], [5]], shape = (1, 5), type = bra
Qobj data =
[[0. 0. 0. 1. 0.]]
>>> coherent_dm(5, 1)
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0.36791117 0.36774407 0.26105441 0.14620658 0.08826704]
[0.36774407 0.36757705 0.26093584 0.14614018 0.08822695]
[0.26105441 0.26093584 0.18523331 0.10374209 0.06263061]
[0.14620658 0.14614018 0.10374209 0.05810197 0.035077 ]
[0.08826704 0.08822695 0.06263061 0.035077 0.0211765 ]]
>>> coherent_dm(5, 1).diag()
array([0.36791117, 0.36757705, 0.18523331, 0.05810197, 0.0211765 ])
>>> coherent_dm(5, 1).full()
array([[0.36791117+0.j, 0.36774407+0.j, 0.26105441+0.j, 0.14620658+0.j,
0.08826704+0.j],
[0.36774407+0.j, 0.36757705+0.j, 0.26093584+0.j, 0.14614018+0.j,
0.08822695+0.j],
[0.26105441+0.j, 0.26093584+0.j, 0.18523331+0.j, 0.10374209+0.j,
0.06263061+0.j],
[0.14620658+0.j, 0.14614018+0.j, 0.10374209+0.j, 0.05810197+0.j,
0.035077 +0.j],
[0.08826704+0.j, 0.08822695+0.j, 0.06263061+0.j, 0.035077 +0.j,
0.0211765 +0.j]])
>>> coherent_dm(5, 1).norm()
1.0000000175063126
>>> coherent_dm(5, 1).sqrtm()
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = False
Qobj data =
[[0.36791117+3.66778589e-09j 0.36774407-2.13388761e-09j
0.26105441-1.51480558e-09j 0.14620658-8.48384618e-10j
0.08826704-5.12182118e-10j]
[0.36774407-2.13388761e-09j 0.36757705+2.41479965e-09j
0.26093584-1.11446422e-09j 0.14614018+8.98971115e-10j
0.08822695+6.40705133e-10j]
[0.26105441-1.51480558e-09j 0.26093584-1.11446422e-09j
0.18523331+4.02032413e-09j 0.10374209-3.39161017e-10j
0.06263061-3.71421368e-10j]
[0.14620658-8.48384618e-10j 0.14614018+8.98971115e-10j
0.10374209-3.39161017e-10j 0.05810197+3.36300708e-10j
0.035077 +2.36883273e-10j]
[0.08826704-5.12182118e-10j 0.08822695+6.40705133e-10j
0.06263061-3.71421368e-10j 0.035077 +2.36883273e-10j
0.0211765 +1.71630348e-10j]]
>>> coherent_dm(5, 1).tr()
1.0
>>> (basis(4, 2) + basis(4, 1)).unit()
Quantum object: dims = [[4], [1]], shape = (4, 1), type = ket
Qobj data =
[[0. ]
[0.70710678]
[0.70710678]
[0. ]]