Loading [MathJax]/jax/output/HTML-CSS/jax.js
Japanese
言語
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

注釈

このページは tutorials/operators/01_operator_flow.ipynb から生成されました。

IBM Quantum lab でインタラクティブに実行します。

Operator Flow

はじめに

Qiskit には、状態と演算子、合計、テンソル積、合成を表すクラスが用意されています。これらの代数的構成物により、演算子を表す式を構築することができます。

まずパウリ演算子を用いて構築する式を紹介します。 後続のセクションでは、より詳細な演算子と状態、それらがどのように表現されるか、そしてそれらを使って何ができるかについて説明します。 最後のセクションでは、状態を構築し、ハミルトニアンでそれを発展させ、観測可能な期待値を計算します。

パウリ演算子、和、合成、およびテンソル積

最も重要な基礎的演算子は、パウリ演算子です。パウリ演算子は、このように表現されます。

[1]:
from qiskit.aqua.operators import I, X, Y, Z
print(I, X, Y, Z)
I X Y Z

これらの演算子は係数を持つこともできます。

[2]:
print(1.5 * I)
print(2.5 * X)
1.5 * I
2.5 * X

これらの係数により、演算子は和の項として使用できます。

[3]:
print(X + 2.0 * Y)
SummedOp([
  X,
  2.0 * Y
])

テンソル積は、次のようにキャレット(脱字記号) で表されます。

[4]:
print(X^Y^Z)
XYZ

合成は``@`` 記号で表されます。

[5]:
print(X @ Y @ Z)
1j * I

In the preceding two examples, the tensor product and composition of Pauli operators were immediately reduced to the equivalent (possibly multi-qubit) Pauli operator. If we tensor or compose more complicated objects, the result is objects representing the unevaluated operations. That is, algebraic expressions.

例えば、2つの和を合成すると:

[6]:
print((X + Y) @ (Y + Z))
ComposedOp([
  SummedOp([
    X,
    Y
  ]),
  SummedOp([
    Y,
    Z
  ])
])

また、2つの和のテンソル積を取ると:

[7]:
print((X + Y) ^ (Y + Z))
TensoredOp([
  SummedOp([
    X,
    Y
  ]),
  SummedOp([
    Y,
    Z
  ])
])

上記の種類を詳しく見てみましょう。まずはパウリ演算子です。

[8]:
(I, X)
[8]:
(PauliOp(Pauli(z=[False], x=[False]), coeff=1.0),
 PauliOp(Pauli(z=[False], x=[True]), coeff=1.0))

各パウリ演算子は PauliOp のインスタンスで、qiskit.quantum_info.Pauli のインスタンスをラップし、係数``coeff`` を追加します。一般的に, PauliOp はパウリ演算子の加重テンソル積を表します.

[9]:
2.0 * X^Y^Z
[9]:
PauliOp(Pauli(z=[True, True, False], x=[False, True, True]), coeff=2.0)

パウリ演算子をブール値のペアとしてエンコーディングするには、qiskit.quantum_info.Pauli のドキュメントを参照してください。

演算子を表現する全てのオブジェクトは、``PauliOp``のような「プリミティブ」でも代数式でも、係数を持ちます。

[10]:
print(1.1 * ((1.2 * X)^(Y + (1.3 * Z))))
1.1 * TensoredOp([
  1.2 * X,
  SummedOp([
    Y,
    1.3 * Z
  ])
])

以下では、Qiskitの演算子、状態、および量子アルゴリズムの構成要素をより幅広く詳しく見ていきます。

パートI: 状態関数と測定

Quantum states are represented by subclasses of the class StateFn. There are four representations of quantum states: DictStateFn is a sparse representation in the computational basis, backed by a dict. VectorStateFn is a dense representation in the computational basis backed by a numpy array. CircuitStateFn is backed by a circuit and represents the state obtained by executing the circuit on the all-zero computational-basis state. OperatorStateFn represents mixed states via a density matrix. (As we will see later, OperatorStateFn is also used to represent observables.)

便宜上、いくつかの``StateFn`` インスタンスが用意されています。例えば、Zero, One, Plus, Minus です。

[11]:
from qiskit.aqua.operators import (StateFn, Zero, One, Plus, Minus, H,
                                   DictStateFn, VectorStateFn, CircuitStateFn, OperatorStateFn)

ZeroOne は量子状態 |0|1 を表します。これらは DictStateFn で表されます。

[12]:
print(Zero, One)
DictStateFn({'0': 1}) DictStateFn({'1': 1})

PlusMinus``は、状態 :math:`(|0\rangle + |1\rangle)/\sqrt{2}` :math:`(|0\rangle - |1\rangle)/\sqrt{2}` であり、回路を介して表されます。 ``HPlus と同義です。

[13]:
print(Plus, Minus)
CircuitStateFn(
     ┌───┐
q_0: ┤ H ├
     └───┘
) CircuitStateFn(
     ┌───┐┌───┐
q_0: ┤ X ├┤ H ├
     └───┘└───┘
)

量子状態のインデックス作成は``eval`` メソッドで行われます。これらの例は``0`` と 1 基底状態の係数を返します。(以降、eval メソッドが他の計算でも使用されることを示します。)

[14]:
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.7071067811865476+0j)
(-0.7071067811865476+8.7e-17j)

量子状態の双対ベクトル( ket に対応する bra ) は、adjoint メソッドによって得られます。 StateFnis_measurement フラグを持ちます。オブジェクトが ket の場合は False で、ブラの場合は True です。

ここでは 1| を作成します。

[15]:
One.adjoint()
[15]:
DictStateFn({'1': 1}, coeff=1.0, is_measurement=True)

便宜上、以下のように、チルダを使用して双対ベクトルを得ることができます。

[16]:
~One
[16]:
DictStateFn({'1': 1}, coeff=1.0, is_measurement=True)

代数演算と述語

StateFn 間の代数演算と述語が数多くサポートされています: * + - 加算 * - - 減算もしくは否定 (-1のスカラー乗算) * * - スカラー乗算 * / - スカラー除算 * @ - 合成 * ^ - テンソル積もしくはテンソル乗 (自己n倍テンソル) * ** - 合成乗 (自己n回合成) * == - 等式 * ~ - 随伴、状態関数と測定値の切り替え

Be aware that parentheses are often necessary to override operator precedence.

StateFn は係数を持ちます。これにより状態にスカラーを掛けることができ、和を構築することができます。

ここでは、(2+3i)|0 を構成します。

[17]:
(2.0 + 3.0j) * Zero
[17]:
DictStateFn({'0': 1}, coeff=(2+3j), is_measurement=False)

ここでは、2 つの DictStateFn を足すと、同じ型のオブジェクトが返されることを見ましょう。 |0+|1 を構築します。

[18]:
print(Zero + One)
DictStateFn({'0': 1.0, '1': 1.0})

状態を手動で正規化する必要があることに注意してください。例えば、(|0+|1)/2 を構築するには、次のように記述します。

[19]:
import math

v_zero_one = (Zero + One) / math.sqrt(2)
print(v_zero_one)
DictStateFn({'0': 1.0, '1': 1.0}) * 0.7071067811865475

他の場合では、結果は和の記号表現になります。 例えば、次は |++| の表現です。

[20]:
print(Plus + Minus)
SummedOp([
  CircuitStateFn(
       ┌───┐
  q_0: ┤ H ├
       └───┘
  ),
  CircuitStateFn(
       ┌───┐┌───┐
  q_0: ┤ X ├┤ H ├
       └───┘└───┘
  )
])

The composition operator is used to perform an inner product, which by default is held in an unevaluated form. Here is a representation of 1|1.

[21]:
print(~One @ One)
ComposedOp([
  DictMeasurement({'1': 1}),
  DictStateFn({'1': 1})
])

is_measurement フラグは、 (ブラ) 状態 ~OneDictMeasurement を表示させることに注意してください。

記号式は``eval`` メソッドで評価することができます。

[22]:
(~One @ One).eval()
[22]:
1.0
[23]:
(~v_zero_one @ v_zero_one).eval()
[23]:
0.9999999999999998

次は、|1=(0|1|)/2|1 です。

[24]:
(~Minus @ One).eval()
[24]:
(-0.7071067811865476-8.7e-17j)

合成演算子 @ は、compose メソッドを呼び出すのと同等です。

[25]:
print((~One).compose(One))
ComposedOp([
  DictMeasurement({'1': 1}),
  DictStateFn({'1': 1})
])

内積は、ComposedOp``を構築せずに、``eval メソッドを直接使用して計算することもできます。

[26]:
(~One).eval(One)
[26]:
1.0

テンソル積の記号は次のように構築されます。次は |0|+ です。

[27]:
print(Zero^Plus)
TensoredOp([
  DictStateFn({'0': 1}),
  CircuitStateFn(
       ┌───┐
  q_0: ┤ H ├
       └───┘
  )
])

これは、シンプルな(複合していない)``CircuitStateFn`` として表現されています。

[28]:
print((Zero^Plus).to_circuit_op())
CircuitStateFn(
     ┌───┐
q_0: ┤ H ├
     └───┘
q_1: ─────

)

テンソル乗はキャレット ^ を使用して、以下のように構築されます。次は、 600(|11111+|00000)|103 です。

[29]:
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 に変換します。

[30]:
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 ├
     └───┘
)
{'1101': 0.2626953125, '0111': 0.251953125, '1111': 0.2470703125, '0101': 0.23828125}

StateFnを構築するのは簡単です。 StateFn クラスはファクトリーとしても機能し、該当するプリミティブをコンストラクターに取り込み、正しい StateFn サブクラスを返すことができます。 現在、以下のプリミティブをコンストラクタに渡すことができ、生成される StateFn サブクラスと一緒にリストしています。

  • str (ある基底ビット文字列に等しい) -> DictStateFn

  • dict -> DictStateFn

  • QisKitのResultオブジェクト -> DictStateFn

  • list -> VectorStateFn

  • np.ndarray -> VectorStateFn

  • Statevector -> VectorStateFn

  • QuantumCircuit -> CircuitStateFn

  • Instruction -> CircuitStateFn

  • OperatorBase -> OperatorStateFn

[31]:
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: ┤ RY(θ[0]) ├──■──┤ RY(θ[2]) ├──■──┤ RY(θ[4]) ├──■──┤ RY(θ[6]) ├
     ├──────────┤┌─┴─┐├──────────┤┌─┴─┐├──────────┤┌─┴─┐├──────────┤
q_1: ┤ RY(θ[1]) ├┤ X ├┤ RY(θ[3]) ├┤ X ├┤ RY(θ[5]) ├┤ X ├┤ RY(θ[7]) ├
     └──────────┘└───┘└──────────┘└───┘└──────────┘└───┘└──────────┘
)

パート II: PrimitiveOp

基本的な演算子は PrimitiveOp のサブクラスです。 StateFn``と同じように、``PrimitiveOp``は与えられたプリミティブに対して正しい型の``PrimitiveOp``を作成するためのファクトリーでもあります。 現在、以下のプリミティブをコンストラクタに渡すことができ、生成される ``PrimitiveOp サブクラスと一緒にリストしています。

  • TerraのPauli -> PauliOp

  • Instruction -> CircuitOp

  • QuantumCircuit -> CircuitOp

  • 2d List -> MatrixOp

  • np.ndarray -> MatrixOp

  • spmatrix -> MatrixOp

  • Terra の quantum_info.Operator -> MatrixOp

[32]:
from qiskit.aqua.operators import X, Y, Z, I, CX, T, H, S, PrimitiveOp

行列要素

The eval method returns a column from an operator. For example, the Pauli X operator is represented by a PauliOp. Asking for a column returns an instance of the sparse representation, a DictStateFn.

[33]:
X
[33]:
PauliOp(Pauli(z=[False], x=[True]), coeff=1.0)
[34]:
print(X.eval('0'))
DictStateFn({'1': (1+0j)})

演算子のインデックス生成、すなわち行列要素の取得は、2回``eval`` メソッドを呼び出すことで実行されます。

X=(0110) であるので、行列要素 {X}0,1 は、以下の通りです。

[35]:
X.eval('0').eval('1')
[35]:
(1+0j)

回路で示したように、2量子ビット演算子 CX、制御``X`` を使用した例は以下の通りです。

[36]:
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.]]
[37]:
CX.eval('01')  # 01 is the one in decimal. We get the first column.
[37]:
VectorStateFn(Statevector([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
            dims=(2, 2)), coeff=1.0, is_measurement=False)
[38]:
CX.eval('01').eval('11')  # This returns element with (zero-based) index (1, 3)
[38]:
(1+0j)

状態ベクトルに演算子を適用する

状態ベクトルに演算子を適用するには、 compose``メソッド ( ``@ 演算子と同等)を使用します。X|1=|0 は次のように表されます。

[39]:
print(X @ One)
ComposedOp([
  X,
  DictStateFn({'1': 1})
])

:math:`|0rangle`のよりシンプルな表現、``DictStateFn``表現は``eval``で取得できます。

[40]:
(X @ One).eval()
[40]:
DictStateFn({'0': (1+0j)}, coeff=1.0, is_measurement=False)

eval を直接使用することで、中間の ComposedOp ステップを回避することができます。

[41]:
X.eval(One)
[41]:
DictStateFn({'0': (1+0j)}, coeff=1.0, is_measurement=False)

演算子の合成とテンソル積は @^ で表現されます。以下にいくつかの例を示します。

[42]:
print(((~One^2) @ (CX.eval('01'))).eval())

print(((H^5) @ ((CX^2)^I) @ (I^(CX^2)))**2)
print((((H^5) @ ((CX^2)^I) @ (I^(CX^2)))**2) @ (Minus^5))
print(((H^I^I)@(X^I^I)@Zero))
(1+0j)
          ┌───┐┌───┐     ┌───┐┌───┐
q_0: ──■──┤ I ├┤ H ├──■──┤ I ├┤ H ├
     ┌─┴─┐└───┘├───┤┌─┴─┐└───┘├───┤
q_1: ┤ X ├──■──┤ H ├┤ X ├──■──┤ H ├
     └───┘┌─┴─┐├───┤└───┘┌─┴─┐├───┤
q_2: ──■──┤ X ├┤ H ├──■──┤ X ├┤ H ├
     ┌─┴─┐└───┘├───┤┌─┴─┐└───┘├───┤
q_3: ┤ X ├──■──┤ H ├┤ X ├──■──┤ H ├
     ├───┤┌─┴─┐├───┤├───┤┌─┴─┐├───┤
q_4: ┤ I ├┤ X ├┤ H ├┤ I ├┤ X ├┤ H ├
     └───┘└───┘└───┘└───┘└───┘└───┘
CircuitStateFn(
     ┌───┐┌───┐     ┌───┐          ┌───┐
q_0: ┤ X ├┤ H ├──■──┤ H ├───────■──┤ H ├─────
     ├───┤├───┤┌─┴─┐└───┘┌───┐┌─┴─┐└───┘┌───┐
q_1: ┤ X ├┤ H ├┤ X ├──■──┤ H ├┤ X ├──■──┤ H ├
     ├───┤├───┤└───┘┌─┴─┐├───┤└───┘┌─┴─┐├───┤
q_2: ┤ X ├┤ H ├──■──┤ X ├┤ H ├──■──┤ X ├┤ H ├
     ├───┤├───┤┌─┴─┐└───┘├───┤┌─┴─┐└───┘├───┤
q_3: ┤ X ├┤ H ├┤ X ├──■──┤ H ├┤ X ├──■──┤ H ├
     ├───┤├───┤└───┘┌─┴─┐├───┤└───┘┌─┴─┐├───┤
q_4: ┤ X ├┤ H ├─────┤ X ├┤ H ├─────┤ X ├┤ H ├
     └───┘└───┘     └───┘└───┘     └───┘└───┘
)
CircuitStateFn(

q_0: ──────────

q_1: ──────────
     ┌───┐┌───┐
q_2: ┤ X ├┤ H ├
     └───┘└───┘
)
[43]:
print(~One @ Minus)
ComposedOp([
  DictMeasurement({'1': 1}),
  CircuitStateFn(
       ┌───┐┌───┐
  q_0: ┤ X ├┤ H ├
       └───┘└───┘
  )
])

パート III ListOp とサブクラス

ListOp

ListOp は、演算子と状態のリストに対し、効果的に演算をベクトル化するためのコンテナです。

[44]:
from qiskit.aqua.operators import ListOp

print((~ListOp([One, Zero]) @ ListOp([One, Zero])))
ComposedOp([
  ListOp([
    DictMeasurement({'1': 1}),
    DictMeasurement({'0': 1})
  ]),
  ListOp([
    DictStateFn({'1': 1}),
    DictStateFn({'0': 1})
  ])
])

例えば、上記の合成は簡約化メソッド``reduce``を使用してリスト(ListOp) に分配されます。

[45]:
print((~ListOp([One, Zero]) @ ListOp([One, Zero])).reduce())
ListOp([
  ListOp([
    ComposedOp([
      DictMeasurement({'1': 1}),
      DictStateFn({'1': 1})
    ]),
    ComposedOp([
      DictMeasurement({'1': 1}),
      DictStateFn({'0': 1})
    ])
  ]),
  ListOp([
    ComposedOp([
      DictMeasurement({'0': 1}),
      DictStateFn({'1': 1})
    ]),
    ComposedOp([
      DictMeasurement({'0': 1}),
      DictStateFn({'0': 1})
    ])
  ])
])

ListOps: SummedOp, ComposedOp, TensoredOp

上記で紹介した ListOp はベクトル化演算に役立ちますが、リストのような複合クラスのスーパークラスとしても機能します。 すでに上記の演算を行っている場合、 CircuitOp の加算など、一般的に効率的に実行する方法がわからない``OperatorBase`` の演算を簡単にできることに気づくでしょう (あるいはまだ効率的な手順を実装していないだけです)。そのような場合、演算の遅延実行を表す演算から ListOp の結果 (またはそれらのサブクラス) を受け取ることができます。 例えば、DictStateFnCircuitStateFn を加算しようとした場合、2つの合計を表す SummedOp を受け取ります。 この 合成状態関数は eval が作用できます (ただし、両方をベクトルに変換するなど、内部でスケーラブルでない計算を実行する必要があるかもしれません) 。

これらの合成 OperatorBase は、PrimitiveOpStateFn の構成要素から、ますます複雑で豊富な計算を構築する方法です。

すべての ListOp には以下の 4 つのプロパティがあります: * oplist - 項、因数などを表すことができる OperatorBase のリスト。 * combo_fn - 複素数のリストを出力値として、oplist の出力の組み合わせ方法を定義する関数。 簡便化のため、この関数は Numpy 配列で定義されています。 * coeff - プリミティブに掛ける係数。 coeff は、int、float、complex または my_op.bind_parameters``を使ってあとからバインドする(Terra ``qiskit.circuit の) Parameter オブジェクトを取り得ることに注意してください。 * abelian - oplist のOperatorが相互に可換と知られているかどうかを示します (通常は AbelianGrouper コンバーターによって変換された後に設定されます)。

ListOp は、典型的なイテレーターのオーバーロードをサポートしているので、my_op[4] のように添字を使って、``oplist``中の``OperatorBase``にアクセスすることができます。

OperatorStateFn

前述のように OperatorStateFn は密度演算子を表していますが、is_measurement フラグが True の場合、OperatorStateFn は 観測量を表します。 この観測量の期待値は ComposedOp を用いて構築することもできます。または、直接 eval を使用して構築することもできます。 is_measurement フラグ(プロパティ) が adjoint メソッドで設定されることを思い出してください。

ここでは、 パウリ Z 演算子に対応する観測量を構築します。 出力時には、OperatorMeasurement と呼ばれることに注意してください。

[46]:
print(StateFn(Z).adjoint())
StateFn(Z).adjoint()
OperatorMeasurement(Z)
[46]:
OperatorStateFn(PauliOp(Pauli(z=[True], x=[False]), coeff=1.0), coeff=1.0, is_measurement=True)

ここでは、0|Z|0langle 1 | Z | 1 rangle`、+|Z|+ を計算します。ここで、|+=(|0+|1)/2 です。

[47]:
print(StateFn(Z).adjoint().eval(Zero))
print(StateFn(Z).adjoint().eval(One))
print(StateFn(Z).adjoint().eval(Plus))
(1+0j)
(-1+0j)
0j

パートIV: コンバーター

コンバーターは、演算子と状態を操作し、アルゴリズムの構成要素を実行するクラスです。例えば、演算子とトロッター化の基底を変更することなどがあります。 コンバーターは式をトラバースし、演算子内のコンバーターの convert() メソッドによって定義された特定の操作または置き換えを実行します。 通常、コンバーターが 変換目的とは関係のない再帰中に`OperatorBase` に遭遇した場合、OperatorBase は変更されません。

[48]:
import numpy as np
from qiskit.aqua.operators import I, X, Y, Z, H, CX, Zero, ListOp, PauliExpectation, PauliTrotterEvolution, CircuitSampler, MatrixEvolution, Suzuki
from qiskit.circuit import Parameter
from qiskit import BasicAer

時間発展と``exp_i()``、EvolvedOp

全ての``PrimitiveOp`` と ListOp は、H.exp_i()eiH.exp_i()`` 関数を持ちます。 実際には、効率的に計算可能な指数を持つ演算子は数個しかありません (単位行列ではない単一量子ビットのパウリのみを持つMatrixOp や PauliOpsのように)。 ですから、プレースホルダーや記号表現を返す必要があります (加算できない場合 SummedOp がプレースホルダーであることに似ています)。 このプレースホルダーは EvolvedOp と呼ばれ、.primitive プロパティで指数化される OperatorBase を保持します。

Qiskit 演算子はパラメーター化を完全にサポートしているため、ここでは発展時間に Parameter を使用できます。 どの関数にも「発展時間」引数がないことに注意してください。 どのような演算子でも、指数パラメーターに反映される発展時間 eiHt を演算子にかけることを選択した場合、Operator flowは指数関数に取ります。

パウリ演算子の加重和

多量子ビットパウリ演算子の線型結合として表現されるハミルトニアンは、次のように構築することができます。

[49]:
two_qubit_H2 =  (-1.0523732 * I^I) + \
                (0.39793742 * I^Z) + \
                (-0.3979374 * Z^I) + \
                (-0.0112801 * Z^Z) + \
                (0.18093119 * X^X)

ここで、two_qubit_H2 は、項が PauliOp である SummedOp として表現されます。

[50]:
print(two_qubit_H2)
SummedOp([
  -1.0523732 * II,
  0.39793742 * IZ,
  -0.3979374 * ZI,
  -0.0112801 * ZZ,
  0.18093119 * XX
])

次に、ハミルトニアンに``Parameter`` を掛けます。この ParameterSummedOpcoeff プロパティに保存されています。 結果に対し exp_i() を呼び出すと、指数化を表す EvolvedOp でラップされます。

[51]:
evo_time = Parameter('θ')
evolution_op = (evo_time*two_qubit_H2).exp_i()
print(evolution_op) # Note, EvolvedOps print as exponentiations
print(repr(evolution_op))
e^(-i*1.0*θ * SummedOp([
  -1.0523732 * II,
  0.39793742 * IZ,
  -0.3979374 * ZI,
  -0.0112801 * ZZ,
  0.18093119 * XX
]))
EvolvedOp(SummedOp([PauliOp(Pauli(z=[False, False], x=[False, False]), coeff=-1.0523732), PauliOp(Pauli(z=[True, False], x=[False, False]), coeff=0.39793742), PauliOp(Pauli(z=[False, True], x=[False, False]), coeff=-0.3979374), PauliOp(Pauli(z=[True, True], x=[False, False]), coeff=-0.0112801), PauliOp(Pauli(z=[False, False], x=[True, True]), coeff=0.18093119)], coeff=1.0*θ, abelian=False), coeff=1.0)

two_qubit_H2 の観測量として、h2_measurement を構築しましょう。

[52]:
h2_measurement = StateFn(two_qubit_H2).adjoint()
print(h2_measurement)
OperatorMeasurement(SummedOp([
  -1.0523732 * II,
  0.39793742 * IZ,
  -0.3979374 * ZI,
  -0.0112801 * ZZ,
  0.18093119 * XX
]))

CX(HI)|00 を用いて、ベル状態 |Φ+ を構築します。

[53]:
bell = CX @ (I ^ H) @ Zero
print(bell)
CircuitStateFn(
     ┌───┐
q_0: ┤ H ├──■──
     └───┘┌─┴─┐
q_1: ─────┤ X ├
          └───┘
)

次は、 HeiHt|Φ+ の式です。

[54]:
evo_and_meas = h2_measurement @ evolution_op @ bell
print(evo_and_meas)
ComposedOp([
  OperatorMeasurement(SummedOp([
    -1.0523732 * II,
    0.39793742 * IZ,
    -0.3979374 * ZI,
    -0.0112801 * ZZ,
    0.18093119 * XX
  ])),
  e^(-i*1.0*θ * SummedOp([
    -1.0523732 * II,
    0.39793742 * IZ,
    -0.3979374 * ZI,
    -0.0112801 * ZZ,
    0.18093119 * XX
  ])),
  CircuitStateFn(
       ┌───┐
  q_0: ┤ H ├──■──
       └───┘┌─┴─┐
  q_1: ─────┤ X ├
            └───┘
  )
])

通常、2量子ビットゲートを使用して、 eiHt を近似します。 これは 、出現する全ての``EvolvedOp``をトロッター化した式をトラバースする``PauliTrotterEvolution`` の convert メソッドによって達成されます。 ここでは PauliTrotterEvolution を使用していますが、他にも正確に指数化を実行する MatrixEvolution のような可能性があります。

[55]:
trotterized_op = PauliTrotterEvolution(trotter_mode=Suzuki(order=2, reps=1)).convert(evo_and_meas)
# We can also set trotter_mode='suzuki' or leave it empty to default to first order Trotterization.
print(trotterized_op)
ComposedOp([
  OperatorMeasurement(SummedOp([
    -1.0523732 * II,
    0.39793742 * IZ,
    -0.3979374 * ZI,
    -0.0112801 * ZZ,
    0.18093119 * XX
  ])),
  CircuitStateFn(
  global phase: 1.0524
       ┌───┐     ┌───┐┌───┐┌──────────────────┐┌───┐┌───┐┌───┐»
  q_0: ┤ H ├──■──┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├┤ X ├»
       └───┘┌─┴─┐├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤└─┬─┘»
  q_1: ─────┤ X ├┤ H ├──■────────────────────────■──┤ H ├──■──»
            └───┘└───┘                              └───┘     »
  «     ┌──────────────────┐┌───┐┌──────────────────┐┌──────────────────┐┌───┐»
  «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ RZ(0.39793742*θ) ├┤ RZ(0.39793742*θ) ├┤ X ├»
  «     └──────────────────┘└─┬─┘├──────────────────┤├──────────────────┤└─┬─┘»
  «q_1: ──────────────────────■──┤ RZ(-0.3979374*θ) ├┤ RZ(-0.3979374*θ) ├──■──»
  «                              └──────────────────┘└──────────────────┘     »
  «     ┌──────────────────┐┌───┐┌───┐┌───┐┌──────────────────┐┌───┐┌───┐
  «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├
  «     └──────────────────┘└─┬─┘├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤
  «q_1: ──────────────────────■──┤ H ├──■────────────────────────■──┤ H ├
  «                              └───┘                              └───┘
  )
])

trotterized_opParameter を含んでいます。bind_parameters メソッドは、dict で指定されたパラメータ名をバインドする式をトラバースします。 この場合、パラメータは一つしかありません。

[56]:
bound = trotterized_op.bind_parameters({evo_time: .5})

boundComposedOp です。2番目の因子は回路です。バインディングが行われたことを確認するために、描画してみましょう。

[57]:
bound[1].to_circuit().draw()
[57]:
global phase: 1.0524
     ┌───┐     ┌───┐┌───┐┌────────────────────────┐┌───┐┌───┐┌───┐»
q_0: ┤ H ├──■──┤ H ├┤ X ├┤ RZ(0.0904655950000000) ├┤ X ├┤ H ├┤ X ├»
     └───┘┌─┴─┐├───┤└─┬─┘└────────────────────────┘└─┬─┘├───┤└─┬─┘»
q_1: ─────┤ X ├┤ H ├──■──────────────────────────────■──┤ H ├──■──»
          └───┘└───┘                                    └───┘     »
«     ┌──────────────────────────┐┌───┐┌───────────────────────┐ »
«q_0: ┤ RZ(-0.00564005000000000) ├┤ X ├┤ RZ(0.198968710000000) ├─»
«     └──────────────────────────┘└─┬─┘├───────────────────────┴┐»
«q_1: ──────────────────────────────■──┤ RZ(-0.198968700000000) ├»
«                                      └────────────────────────┘»
«     ┌───────────────────────┐ ┌───┐┌──────────────────────────┐┌───┐┌───┐»
«q_0: ┤ RZ(0.198968710000000) ├─┤ X ├┤ RZ(-0.00564005000000000) ├┤ X ├┤ H ├»
«     ├───────────────────────┴┐└─┬─┘└──────────────────────────┘└─┬─┘├───┤»
«q_1: ┤ RZ(-0.198968700000000) ├──■────────────────────────────────■──┤ H ├»
«     └────────────────────────┘                                      └───┘»
«     ┌───┐┌────────────────────────┐┌───┐┌───┐
«q_0: ┤ X ├┤ RZ(0.0904655950000000) ├┤ X ├┤ H ├
«     └─┬─┘└────────────────────────┘└─┬─┘├───┤
«q_1: ──■──────────────────────────────■──┤ H ├
«                                         └───┘

期待値

Expectation は、観測量の期待値の計算を可能にするコンバーターです。 これらは OperatorStateFn (観測量) を、量子ハードウェアや古典ハードウェア上の計算により適している等価な命令に置き換えるよう、Operator構造をトラバースします。 例えば、 ある状態関数に対するパウリ行列の合計として表現されたOperator o の期待値を測定したいけれど、量子ハードウェア上の対角化された測定にしかアクセスできない場合、 観測可能な``~StateFn(o)`` を作成し``PauliExpectation`` を使用して、対角化測定と状態に追加する回路のプリローテーションに変換します。

興味深いもう一つの ExpectationAerPauliExpectation です。 これは、期待値を、Aer が高性能でネイティブに実行できる特別な期待値スナップショットの命令を含む CircuitStateFn に変換します。

[58]:
# Note that XX was the only non-diagonal measurement in our H2 Observable
print(PauliExpectation(group_paulis=False).convert(h2_measurement))
SummedOp([
  ComposedOp([
    OperatorMeasurement(-1.0523732 * II),
    II
  ]),
  ComposedOp([
    OperatorMeasurement(0.39793742 * IZ),
    II
  ]),
  ComposedOp([
    OperatorMeasurement(-0.3979374 * ZI),
    II
  ]),
  ComposedOp([
    OperatorMeasurement(-0.0112801 * ZZ),
    II
  ]),
  ComposedOp([
    OperatorMeasurement(0.18093119 * ZZ),
         ┌───┐
    q_0: ┤ H ├
         ├───┤
    q_1: ┤ H ├
         └───┘
  ])
])

デフォルトの``group_paulis=True``では、 AbrianGrouper を使用して SummedOp を互いに量子的に可換なパウリのグループに変換します。 これにより、各グループが同じ回路実行を共有できるため、回路の実行オーバーヘッドが低減されます。

[59]:
print(PauliExpectation().convert(h2_measurement))
SummedOp([
  ComposedOp([
    OperatorMeasurement(AbelianSummedOp([
      -1.0523732 * II,
      0.18093119 * ZZ
    ])),
         ┌───┐
    q_0: ┤ H ├
         ├───┤
    q_1: ┤ H ├
         └───┘
  ]),
  ComposedOp([
    OperatorMeasurement(AbelianSummedOp([
      0.39793742 * IZ,
      -0.3979374 * ZI,
      -0.0112801 * ZZ
    ])),
    II
  ])
])

コンバーターは再帰的に動作することに注意してください。つまり、可能な限りアクションを適用する式にトラバースします。 時間発展と測定の完全な表現を変換することができます。 変換された h2_measurement を 時間発展``CircuitStateFn`` と同等に構成することができます。式全体を変換して進めます。

[60]:
diagonalized_meas_op = PauliExpectation().convert(trotterized_op)
print(diagonalized_meas_op)
SummedOp([
  ComposedOp([
    OperatorMeasurement(AbelianSummedOp([
      -1.0523732 * II,
      0.18093119 * ZZ
    ])),
    CircuitStateFn(
    global phase: 1.0524
         ┌───┐     ┌───┐┌───┐┌──────────────────┐┌───┐┌───┐┌───┐»
    q_0: ┤ H ├──■──┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├┤ X ├»
         └───┘┌─┴─┐├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤└─┬─┘»
    q_1: ─────┤ X ├┤ H ├──■────────────────────────■──┤ H ├──■──»
              └───┘└───┘                              └───┘     »
    «     ┌──────────────────┐┌───┐┌──────────────────┐┌──────────────────┐┌───┐»
    «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ RZ(0.39793742*θ) ├┤ RZ(0.39793742*θ) ├┤ X ├»
    «     └──────────────────┘└─┬─┘├──────────────────┤├──────────────────┤└─┬─┘»
    «q_1: ──────────────────────■──┤ RZ(-0.3979374*θ) ├┤ RZ(-0.3979374*θ) ├──■──»
    «                              └──────────────────┘└──────────────────┘     »
    «     ┌──────────────────┐┌───┐┌───┐┌───┐┌──────────────────┐┌───┐┌───┐┌───┐
    «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├┤ H ├
    «     └──────────────────┘└─┬─┘├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤├───┤
    «q_1: ──────────────────────■──┤ H ├──■────────────────────────■──┤ H ├┤ H ├
    «                              └───┘                              └───┘└───┘
    )
  ]),
  ComposedOp([
    OperatorMeasurement(AbelianSummedOp([
      0.39793742 * IZ,
      -0.3979374 * ZI,
      -0.0112801 * ZZ
    ])),
    CircuitStateFn(
    global phase: 1.0524
         ┌───┐     ┌───┐┌───┐┌──────────────────┐┌───┐┌───┐┌───┐»
    q_0: ┤ H ├──■──┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├┤ X ├»
         └───┘┌─┴─┐├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤└─┬─┘»
    q_1: ─────┤ X ├┤ H ├──■────────────────────────■──┤ H ├──■──»
              └───┘└───┘                              └───┘     »
    «     ┌──────────────────┐┌───┐┌──────────────────┐┌──────────────────┐┌───┐»
    «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ RZ(0.39793742*θ) ├┤ RZ(0.39793742*θ) ├┤ X ├»
    «     └──────────────────┘└─┬─┘├──────────────────┤├──────────────────┤└─┬─┘»
    «q_1: ──────────────────────■──┤ RZ(-0.3979374*θ) ├┤ RZ(-0.3979374*θ) ├──■──»
    «                              └──────────────────┘└──────────────────┘     »
    «     ┌──────────────────┐┌───┐┌───┐┌───┐┌──────────────────┐┌───┐┌───┐
    «q_0: ┤ RZ(-0.0112801*θ) ├┤ X ├┤ H ├┤ X ├┤ RZ(0.18093119*θ) ├┤ X ├┤ H ├
    «     └──────────────────┘└─┬─┘├───┤└─┬─┘└──────────────────┘└─┬─┘├───┤
    «q_1: ──────────────────────■──┤ H ├──■────────────────────────■──┤ H ├
    «                              └───┘                              └───┘
    )
  ])
])

次に、複数のパラメータ値を ListOp にバインドし、式全体を評価するために eval を追加します。 先にバインドすれば eval を使えたかもしれませんが、効率的ではありません。 ここで、eval は内部シミュレーションを通じて``CircuitStateFn``を``VectorStateFn``に変換します。

[61]:
evo_time_points = list(range(8))
h2_trotter_expectations = diagonalized_meas_op.bind_parameters({evo_time: evo_time_points})

パラメータの異なる値に対応する Φ+|eiHtHeiHt|Φ+ の期待値は次のとおりです。

[62]:
h2_trotter_expectations.eval()
[62]:
array([-0.88272211-1.111e-15j, -0.88272211-1.165e-15j,
       -0.88272211-1.065e-15j, -0.88272211-1.178e-15j,
       -0.88272211-1.113e-15j, -0.88272211-9.250e-16j,
       -0.88272211-1.054e-15j, -0.88272211-1.156e-15j])

CircuitSampler を用いて CircuitStateFn を実行する

CircuitSampler はOperatorをトラバースし、CircuitStateFns を量子バックエンドを使用して、DictStateFn または VectorStateFn により結果の状態関数の近似に変換します。 CircuitStateFn の値を近似するには、1) 全ての位相情報を破壊する脱分極チャネルを介して状態関数を送信、2) サンプルした周波数を、サンプリングした生の確率 ではなく、周波数の 平方根 に置き換える(Bornの規則により、状態関数の 平方 をサンプリングするのと同等です)、必要があることに注意してください。

[63]:
sampler = CircuitSampler(backend=BasicAer.get_backend('qasm_simulator'))
# sampler.quantum_instance.run_config.shots = 1000
sampled_trotter_exp_op = sampler.convert(h2_trotter_expectations)
sampled_trotter_energies = sampled_trotter_exp_op.eval()
print('Sampled Trotterized energies:\n {}'.format(np.real(sampled_trotter_energies)))
Sampled Trotterized energies:
 [-0.88272211 -0.88272211 -0.88272211 -0.88272211 -0.88272211 -0.88272211
 -0.88272211 -0.88272211]

回路は、回路のサンプリング確率の**平方根** のdictに置き換えられることに再度注意してください。 変換前と変換後のひとつの部分式を見てみましょう。

[64]:
print('Before:\n')
print(h2_trotter_expectations.reduce()[0][0])
print('\nAfter:\n')
print(sampled_trotter_exp_op[0][0])
Before:

ComposedOp([
  OperatorMeasurement(AbelianSummedOp([
    -1.0523732 * II,
    0.18093119 * ZZ
  ])),
  CircuitStateFn(
  global phase: 1.0524
       ┌───┐     ┌───┐┌───┐┌───────┐┌───┐┌───┐┌───┐┌───────┐┌───┐┌───────┐»
  q_0: ┤ H ├──■──┤ H ├┤ X ├┤ RZ(0) ├┤ X ├┤ H ├┤ X ├┤ RZ(0) ├┤ X ├┤ RZ(0) ├»
       └───┘┌─┴─┐├───┤└─┬─┘└───────┘└─┬─┘├───┤└─┬─┘└───────┘└─┬─┘├───────┤»
  q_1: ─────┤ X ├┤ H ├──■─────────────■──┤ H ├──■─────────────■──┤ RZ(0) ├»
            └───┘└───┘                   └───┘                   └───────┘»
  «     ┌───────┐┌───┐┌───────┐┌───┐┌───┐┌───┐┌───────┐┌───┐┌───┐┌───┐
  «q_0: ┤ RZ(0) ├┤ X ├┤ RZ(0) ├┤ X ├┤ H ├┤ X ├┤ RZ(0) ├┤ X ├┤ H ├┤ H ├
  «     ├───────┤└─┬─┘└───────┘└─┬─┘├───┤└─┬─┘└───────┘└─┬─┘├───┤├───┤
  «q_1: ┤ RZ(0) ├──■─────────────■──┤ H ├──■─────────────■──┤ H ├┤ H ├
  «     └───────┘                   └───┘                   └───┘└───┘
  )
])

After:

ComposedOp([
  OperatorMeasurement(AbelianSummedOp([
    -1.0523732 * II,
    0.18093119 * ZZ
  ])),
  DictStateFn({'00': 0.7207851621669248, '11': 0.6931585316505886})
])
[65]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
QiskitNone
Terra0.17.0.dev0+8c40b02
Aer0.5.2
Ignis0.4.0.dev0+15b7177
Aqua0.9.0.dev0+2734384
IBM Q Provider0.7.2
System information
Python3.8.3 (default, May 17 2020, 18:15:42) [GCC 10.1.0]
OSLinux
CPUs12
Memory (Gb)62.77165603637695
Wed Nov 04 13:35:52 2020 EST

This code is a part of Qiskit

© Copyright IBM 2017, 2020.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.