简介
Qiskit提供了表示状态、操作、求和、张量积和组成等。
这些代数结构允许我们构建表示运算符的表达式。
我们我们介绍通过从Pauli操作符创建表达数。在随后的小结中,我们会更加详细的探索操作符和状态,如何表达他们,和我们如何使用他们。在最后一部分,我们创建一个状态,用Hamiltonian演化它,计算可观测的期望值。
Pauli操作,求和,组成,张量积
最重要的基础操作是Pauli操作。Pauli操作表示成这样:
from qiskit.opflow import I, X, Y, Z
print(I, X, Y, Z)
# 结果
I X Y Z
这些操作也可以使用系数。
print(1.5 * I)
print(2.5 * X)
# 结果
1.5 * I
2.5 * X
系数也可以在求和中使用操作符。
print(X + 2.0 * Y)
# 结果
1.0 * X
+ 2.0 * Y
张量积用^表示
print(X^Y^Z)
# 结果
XYZ
组合用@符号表示
print(X @ Y @ Z)
# 结果
iI
在之前的两个例子中,张量积和Pauli操作的组合会马上减少到相当的Pauli操作(可能多个量子比特)。如果,我们用张量或组合构成更复杂的对象,结果就能只能表示不想当的操作。这就是代数表达式。
例如,组合两个和。
print((X + Y) @ (Y + Z))
1j * Z
+ -1j * Y
+ 1.0 * I
+ 1j * X
和两个和的张量积
print((X + Y) ^ (Y + Z))
1.0 * XY
+ 1.0 * XZ
+ 1.0 * YY
+ 1.0 * YZ
让我们更加仔细的查看上述表达。首先,Pauli操作。
(I, X)
(PauliOp(Pauli('I'), coeff=1.0), PauliOp(Pauli('X'), coeff=1.0))
每个Pauli操作都是PauliOp的实例,包含了qiskit.quantum_info.Pauli实例,然后加上了系数coeff。一般情况下,PauliOp表示带有权重的Pauli操作的张量积。
2.0 * X^Y^Z
PauliOp(Pauli('XYZ'), coeff=2.0)
对于Pauli操作的编码成一对布尔值,可以查看qiskit.quantum_info.Pauli文档。
所有的对象都表示操作符,不管是不是作为PauliOp的原始对象,或者代数表达式带有系数。
print(1.1 * ((1.2 * X)^(Y + (1.3 * Z))))
1.2 * (
1.1 * XY
+ 1.4300000000000002 * XZ
)
在后面,我们会更加深入的介绍Qiskit的操作符,状态和创建量子算法块。
部分一:状态函数和测量
量子状态都被表示为StateFn类的子类。有四种表示量子状态的方法:
- DictStateFn:是在计算基础上的一种稀疏表达,以dict为基础。
- VectorStateFn:是在计算基础上的一种紧密表达,以numpy向量为基础。
- CircuitStateFn:是一种基于电路的,表示通过执行在所有零为计算基础状态的电路获得的状态。
- OperatorStateFn:表示通过密度矩阵的混合状态。
我们后文可以看到,OperatorStateFn可以被观察参数。
一些StateFn实例,提供了方便的办法。例如,Zero,One,Plus,Minus。
from qiskit.opflow import (StateFn, Zero, One, Plus, Minus, H, DictStateFn, VectorStateFn, CircuitStateFn, OperatorStateFn)
Zero和One表示量子状态 和 。通过DictStateFn表示。
print(Zero, One)
DictStateFn({'0': 1}) DictStateFn({'1': 1})
Plus和Minus,表示电路的状态 和 。H与Plus表示同一个意思。
print(Plus, Minus)
# 结果
CircuitStateFn(
┌───┐
q: ┤ H ├
└───┘
) CircuitStateFn(
┌───┐┌───┐
q: ┤ X ├┤ H ├
└───┘└───┘
)
使用 eval 方法对量子态进行索引。这些例子都反悔0和1为基础状态的系数。(以下,我们能看到eval方法用于其他计算。)
print(Zero.eval('0'))
print(Zero.eval('1'))
print(One.eval('1'))
print(Plus.eval('0'))
print(Minus.eval('1'))
# 结果
1.0
0.0
1.0
(0.7071067811865475+0j)
(-0.7071067811865475+8.7e-17j)
量子态的对偶向量,即ket对应的bra是通过伴adjoint方法得到。 StateFn 带有一个标志 is_measurement,如果对象是 ket,则为 False,如果是bra,则为 True。
然后,我们创建
One.adjoint()
# 结果
DictStateFn({'1': 1}, coeff=1.0, is_measurement=True)
为了方便起见,用波浪线符号可以获得对偶像量,如
~One
# 结果
DictStateFn({'1': 1}, coeff=1.0, is_measurement=True)
代数操作和断言
在StateFn之间,许多代数操作和断言都是支持的,包括:
- +:加
- -:减,负号(标量的乘以-1)
- *:标量相乘
- /:标量相除
- @:组合
- ^:张量积货张量幂(张量自身相乘n次)
- **:组合幂(把自己组合n次)
- ==:相等
- ~:伴随,在State Function和测量之间替代。
很清楚的认识到,这些操作都优先遵守Python的操作规则,可能不是你想要的数学操作。例如I^X+X^I可能会被解析为I^(X+X)^I==2*(I^X^I),因为Python中在^之前执行+。这种情况下,你可以使用方法.tensor()等,或者圆括号。
StateFn带有系数。这允许我们用标量乘以一个状态,然后就能创建和。
这里,我们创建
(2.0 + 3.0j) * Zero
# 结果
DictStateFn({'0': 1}, coeff=(2+3j), is_measurement=False)
这里,我们相加两个DictStateFn,返回相同的对象。我们创建 。
print(Zero + One)
# 结果
DictStateFn({'0': 1.0, '1': 1.0})
注意,你必须手动的正则化状态,例如,创建 ,我们就会写
import math
v_zero_one = (Zero + One) / math.sqrt(2)
print(v_zero_one)
# 结果
DictStateFn({'0': 1.0, '1': 1.0}) * 0.7071067811865475
在其他情况下,结果就是求和符号表达式的结果。例如, 的表达式。
print(Plus + Minus)
# 结果
SummedOp([
CircuitStateFn(
┌───┐
q: ┤ H ├
└───┘
),
CircuitStateFn(
┌───┐┌───┐
q: ┤ X ├┤ H ├
└───┘└───┘
)
])
组合操作一般用于执行内积,默认情况下,用于非评估形式。这里有表示
print(~One @ One)
# 结果
ComposedOp([
DictMeasurement({'1': 1}),
DictStateFn({'1': 1})
])
注意,is_measurement标识会引起(bra)状态,~One会被打印成DictMeasurement。
符号表达式可以用eval方法解释
(~One @ One).eval()
# 结果
1.0
(~v_zero_one @ v_zero_one).eval()
# 结果
0.9999999999999998
这里有
(~Minus @ One).eval()
# 结果
(-0.7071067811865475-8.7e-17j)
组合操作符@等价于调用compose方法
print((~One).compose(One))
# 结果
ComposedOp([
DictMeasurement({'1': 1}),
DictStateFn({'1': 1})
])
内积可以直接使用eval方法,而不用创建ComposedOp。
(~One).eval(One)
# 结果
1.0
符号化的张量积可以像这样构建。有 。
print(Zero^Plus)
# 结果
TensoredOp([
DictStateFn({'0': 1}),
CircuitStateFn(
┌───┐
q: ┤ H ├
└───┘
)
])
可以简单表示为CircuitStateFn。
print((Zero^Plus).to_circuit_op())
# 结果
CircuitStateFn(
┌───┐
q_0: ┤ H ├
└───┘
q_1: ─────
)
张量幂可以使用^创建。有 和 。
print(600 * ((One^5) + (Zero^5)))
print((One^Zero)^3)
# 结果
DictStateFn({'11111': 1.0, '00000': 1.0}) * 600.0
DictStateFn({'101010': 1})
这个方法to_matrix_op转变为VectorStateFn。
print(((Plus^Minus)^2).to_matrix_op())
print(((Plus^One)^2).to_circuit_op())
print(((Plus^One)^2).to_matrix_op().sample())
# 结果
VectorStateFn(Statevector([ 0.25-6.1e-17j, -0.25+6.1e-17j, 0.25-6.1e-17j,
-0.25+6.1e-17j, -0.25+6.1e-17j, 0.25-6.1e-17j,
-0.25+6.1e-17j, 0.25-6.1e-17j, 0.25-6.1e-17j,
-0.25+6.1e-17j, 0.25-6.1e-17j, -0.25+6.1e-17j,
-0.25+6.1e-17j, 0.25-6.1e-17j, -0.25+6.1e-17j,
0.25-6.1e-17j],
dims=(2, 2, 2, 2)))
CircuitStateFn(
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ H ├
├───┤
q_2: ┤ X ├
├───┤
q_3: ┤ H ├
└───┘
)
{'1111': 0.291015625, '0101': 0.248046875, '1101': 0.232421875, '0111': 0.228515625}
创建StateFn非常简单。StateFn类可以用做工厂类,在创建时进行合适的初始化,并返回正确的StateFn子类。目前,如下初始化能够用于构建,能提供StateFn子类:
- str (equal to some basis bitstring) -> DictStateFn
- dict -> DictStateFn
- Qiskit Result object -> DictStateFn
- list -> VectorStateFn
- np.ndarray -> VectorStateFn
- Statevector -> VectorStateFn
- QuantumCircuit -> CircuitStateFn
- Instruction -> CircuitStateFn
- OperatorBase -> OperatorStateFn
print(StateFn({'0':1}))
print(StateFn({'0':1}) == Zero)
print(StateFn([0,1,1,0]))
from qiskit.circuit.library import RealAmplitudes
print(StateFn(RealAmplitudes(2)))
# 结果
DictStateFn({'0': 1})
True
VectorStateFn(Statevector([0.+0.j, 1.+0.j, 1.+0.j, 0.+0.j],
dims=(2, 2)))
CircuitStateFn(
┌──────────────────────────────────────────────────────────┐
q_0: ┤0 ├
│ RealAmplitudes(θ[0],θ[1],θ[2],θ[3],θ[4],θ[5],θ[6],θ[7]) │
q_1: ┤1 ├
└──────────────────────────────────────────────────────────┘
)
部分二:初始化操作PrimitiveOps
基础操作都是初始化操作PrimitiveOp的子类。例如StateFn,PrimitiveOp是一个工厂类,用于创建正确的PrimitiveOp类型。目前,如下初始化操作能够用于创建,同时列举了提供的PrimitiveOp的子类:
- Terra’s Pauli -> PauliOp
- Instruction -> CircuitOp
- QuantumCircuit -> CircuitOp
- 2d List -> MatrixOp
- np.ndarray -> MatrixOp
- spmatrix -> MatrixOp
- Terra’s quantum_info.Operator -> MatrixOp
from qiskit.opflow import X, Y, Z, I, CX, T, H, S, PrimitiveOp
矩阵元素
eval 方法从运算符返回一列。例如,Pauli 运算符由 PauliOp 表示。请求列会返回稀疏表示的一个实例,即 DictStateFn。
X
# 结果
PauliOp(Pauli('X'), coeff=1.0)
print(X.eval('0'))
# 结果
DictStateFn({'1': (1+0j)})
因此,通过两次调用 eval 方法执行对运算符的索引,即获取矩阵元素。我们有 。矩阵元素 是
X.eval('0').eval('1')
# 结果
(1+0j)
有例子,使用两个量子比特操作符cx,控制的x,用电路表示。
print(CX)
print(CX.to_matrix().real) # The imaginary part vanishes.
# 结果
q_0: ──■──
┌─┴─┐
q_1: ┤ X ├
└───┘
[[1. 0. 0. 0.]
[0. 0. 0. 1.]
[0. 0. 1. 0.]
[0. 1. 0. 0.]]
CX.eval('01') # 01 is the one in decimal. We get the first column.
# 结果
VectorStateFn(Statevector([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
dims=(2, 2)), coeff=1.0, is_measurement=False)
CX.eval('01').eval('11') # This returns element with (zero-based) index (1, 3)
# 结果
(1+0j)
原文链接